; file reversal

(define (read-line . port)
  (define (eat p c)
    (if (and (not (eof-object? (peek-char p)))
             (char=? (peek-char p) c))
        (read-char p)))
  (let ((p (if (null? port) (current-input-port) (car port))))
    (let loop ((c (read-char p)) (line '()))
      (cond ((eof-object? c) (if (null? line) c (list->string (reverse line))))
            ((char=? #\newline c) (eat p #\return) (list->string (reverse line)))
            ((char=? #\return c) (eat p #\newline) (list->string (reverse line)))
            (else (loop (read-char p) (cons c line)))))))

; read up to max-lines from current input, return lines
(define (read-lines max-lines)
  (let loop ((x (read-line)) (xs (list)) (k max-lines))
    (if (or (zero? k) (eof-object? x))
        (reverse xs)
        (loop (read-line) (cons x xs) (- k 1)))))

(define (temp num)
  (string-append
    "./file-reversal."
    (number->string (get-process-id))
    "."
    (number->string num)))

(define max-lines 10000)

(define (read-into-temps)
  (let loop ((file-num 1))
    (let ((lines (read-lines max-lines)))
      (if (null? lines) (- file-num 1)
        (let ((temp-file-name (temp file-num)))
          (with-output-to-file temp-file-name
            (lambda ()
              (do ((lines lines (cdr lines)))
                  ((null? lines))
                (display (car lines)) (newline))))
          (loop (+ file-num 1)))))))

(define (write-output num-files)
  (let loop ((num num-files))
    (when (positive? num)
      (with-input-from-file (temp num)
        (lambda ()
          (do ((lines (reverse (read-lines -1)) (cdr lines)))
              ((null? lines))
            (display (car lines)) (newline))))
      (loop (- num 1)))))

(define (reverse-file in-file out-file)
  (with-input-from-file in-file (lambda ()
    (with-output-to-file out-file (lambda ()
      (write-output (read-into-temps)))))))

(reverse-file "bible.txt" "txt.elbib")