private/mpost-interface.rkt
#lang racket
(provide insert generate-figure)
;;----------------------------------------
(require (planet wcy/anaphora))
(require racket/port)
(require "mpost-utils.rkt")
(define *mpost-stream* (make-parameter 1))
(define (my-find-executable-path program)
  (or 
   (find-executable-path program)
   (find-executable-path (string-append program ".exe"))))

(define /dev/null-out
  (make-output-port
   'null
   always-evt
   (lambda (s start end non-block? breakable?) (- end start))
   void
   (lambda (special non-block? breakable?) #t)
   (lambda (s start end) (wrap-evt
                          always-evt
                          (lambda (x)
                            (- end start))))
   (lambda (special) always-evt)))
(define (call-process program . args)
  (let-values (((proc in out err) 
                (apply subprocess #f #f #f 
                       (my-find-executable-path program)
                       args)))
    (close-output-port out)
    (copy-port in (current-output-port))
    (close-input-port in)
    (close-input-port err)
    (subprocess-wait proc)))

(define mpost-pre 
  (make-parameter 
   "
input TEX;
prologues := 1;
%if scantokens(mpversion) < 1.200:
%   filenametemplate
%else:
%   outputtemplate :=
%fi
% \"%j.eps\";

beginfig(1)
"))
(define mpost-post 
  (make-parameter
   "currentpicture := currentpicture shifted 
                      -llcorner currentpicture shifted (1cm,2cm);
    endfig;
     end;"))
(define (mpost-stream-port)
  (if (output-port? (*mpost-stream*))
      (*mpost-stream*)
      (current-output-port)))
(define (insert . args)
  (for ((arg (in-list args)))
       (write-string arg (mpost-stream-port))))
(define (generate-eps job-name fun-name)  
  (define (create-mp-file-name job-name)
    (path-add-suffix job-name ".mp"))
  (define (generate-mp-file out)
    (parameterize ((*mpost-stream* out))
      (insert (mpost-pre))
      (fun-name)
      (insert (mpost-post))))
  (define (rename-to-eps-file job-name)
    (when (file-exists? (path-add-suffix job-name ".1"))
      (rename-file-or-directory
       (path-add-suffix job-name ".1")
       (path-add-suffix job-name ".eps")
       #t)))
  (define (convert-to-png job-name)
    (let ((eps-file-name (path-add-suffix job-name ".eps"))
          (png-file-name (path-add-suffix job-name ".png")))
      (aif (my-find-executable-path "gs")
           (call-process it
                         "-q"
                         "-r300"
                         "-dEPSCrop"
                         "-dTextAlphaBits=4"
                         "-sDEVICE=png16m"
                         (string-append "-sOutputFile=" (path->string png-file-name))
                         "-dBATCH" "-dNOPAUSE"
                         eps-file-name)
           (printf "warning: gs is not found in path ~a\n" (getenv "PATH")))))
  (define (mpost-check-log log-name)
    (let ((log (file->string log-name)))
      (if (not (regexp-match #px"1 output file written:" log)) log #f)))
  (define (mpost-failed? job-name)
    (let ((log-name (path-add-suffix job-name ".log")))
      (or (not (file-exists? log-name))
          (mpost-check-log log-name))))
  (let* ((mp-file-name (create-mp-file-name job-name)))
    (call-with-output-file*  mp-file-name generate-mp-file #:exists 'replace)
    (parameterize ((current-output-port /dev/null-out))
      (call-process "mpost" "-jobname" job-name mp-file-name))
    (aif (mpost-failed? job-name)
         (begin (display (file->string mp-file-name))
                (newline)
                (display it)
                (with-handlers ((exn:fail:filesystem? (lambda _ _)))
                  (delete-file (path-add-suffix  job-name ".png")))
                #f)
         (begin
           (rename-to-eps-file job-name)
           (convert-to-png job-name)
           job-name))))
(define (check-program-installed prog f)
  (aif (my-find-executable-path prog)
       it
      (raise (f (format "~a is not found. path is ~a" prog (getenv "PATH"))))))
(require "mpost-new-name.rkt")
(define (generate-figure name func)
  (check-program-installed "mpost" (lambda (x) x))
  (reset-new-var)
  (let* ((name (if (path? name) name (string->path name)))
         (path (or (path-only name) (current-directory)))
         (file-name (file-name-from-path name)))
    (parameterize ((current-directory path))
      (generate-eps file-name func))))