;;; news-to-texi.scm — Convert a GNU-style NEWS file to Texinfo ;;; ;;; Usage: guile news-to-texi.scm NEWS > version-history.texi ;;; ;;; The NEWS format is: ;;; ;;; Version X.Y (date) ;;; ;;; * First item. ;;; * Second item, possibly ;;; continued on the next line. ;;; ;;; Lines before the first "Version" heading (title, copyright notice) ;;; are skipped. (use-modules (ice-9 rdelim) (ice-9 regex) (ice-9 match)) (define (news->texi port out) (let loop ((line (read-line port)) (in-version? #f) (in-item? #f)) (cond ((eof-object? line) ;; Close any open item/version. (when in-item? (display "\n" out)) (when in-version? (format out "@end itemize~%~%"))) ;; Version heading: "Version X.Y ..." ((string-match "^Version " line) ;; Close previous version if open. (when in-item? (display "\n" out)) (when in-version? (format out "@end itemize~%~%")) (format out "@item ~a~%" line) (format out "@itemize~%" ) (loop (read-line port) #t #f)) ;; Bullet item: " * text" ((string-match "^ \\* (.+)" line) => (lambda (m) ;; Close previous item if open. (when in-item? (display "\n" out)) (format out "@item~%") (display (match:substring m 1) out) (loop (read-line port) in-version? #t))) ;; Continuation line: " text" (indented, no bullet) ((and in-item? (string-match "^ (.+)" line)) => (lambda (m) (display "\n" out) (display (match:substring m 1) out) (loop (read-line port) in-version? #t))) ;; Blank or preamble line — skip. (else (loop (read-line port) in-version? in-item?))))) (match (command-line) ((_ news-file) (call-with-input-file news-file (lambda (in) (news->texi in (current-output-port))))) ((_ . _) (format (current-error-port) "Usage: guile news-to-texi.scm NEWS~%") (exit 1)))