#lang scheme/base

(require mzlib/process)

(provide more-help)
(define (more-help name top-line)
  (lambda (help)
    (printf "This is `~a', ~a.\nUsage: " name top-line)
    (display (regexp-replace
              #rx"\n where" help
              "\n where an \"-\" input file specifies standard input\n and"))
    (display "See \"plt/preprocessor/doc.txt\" for more details.\n")
    (exit 0)))

(provide run)
(define (run preprocess run-cmd output files)
  (let ([files (map (lambda (f) (if (equal? f "-") (current-input-port) f))
                    (if (null? files) '("-") files))]
        [exit-code 0])
    (define (do-run-subst f)
      (set! exit-code (system/exit-code (regexp-replace
                                         #rx"\\*" run-cmd (format "~s" f)))))
    (cond
      [(and run-cmd (not (regexp-match #rx"\\*" run-cmd)))
       (when output
         (error 'mzpp "cannot run a command with piped stdin when an ~a"
                "output name is specified"))
       (let ([p (process/ports (current-output-port) #f (current-error-port)
                               run-cmd)])
         (parameterize ([current-output-port (list-ref p 1)])
           (apply preprocess files))
         (close-output-port (list-ref p 1))
         ((list-ref p 4) 'wait)
         (set! exit-code ((list-ref p 4) 'exit-code)))]
      [(and run-cmd (not (or (= 1 (length files)) output)))
       (error 'mzpp "cannot run a command that expects a filename with ~a"
              "multiple input files and no output name")]
      [(and run-cmd (not output))
       (let* ([file (car files)]
              [temp (format "~a-mzpp-temporary" file)])
         (when (file-exists? temp)
           (error 'mzpp "~s already exists!" temp))
         (dynamic-wind
           (lambda () (rename-file-or-directory file temp))
           (lambda ()
             (with-output-to-file file (lambda () (preprocess temp)))
             (do-run-subst file))
           (lambda ()
             (delete-file file)
             (rename-file-or-directory temp file))))]
      [output
       (with-output-to-file output #:exists 'replace
         (lambda () (apply preprocess files)))
       (when run-cmd (do-run-subst output))]
      [else (apply preprocess files)])
    (exit exit-code)))
