]> git.donarmstrong.com Git - lilypond.git/blob - scripts/as2text.scm
d9a41a08343299f7e2d562e963c3948a18b6010f
[lilypond.git] / scripts / as2text.scm
1 #!@GUILE@ \
2 -e main -s
3 !#
4 ;;;; as2text.scm -- Translate AsciiScript to Text
5 ;;;;
6 ;;;; source file of the GNU LilyPond music typesetter
7 ;;;; 
8 ;;;; (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
9
10 ;;;; library funtions
11 (use-modules
12    (ice-9 debug)
13   (ice-9 getopt-long)
14   (ice-9 string-fun)
15   (ice-9 regex))
16
17 ;;; Script stuff
18 (define program-name "as2text")
19
20 (define lily-home "/usr/share/lilypond")
21 (define cur-output-name "-")
22 (define cur-output-file '())
23
24 (define subst-version "@TOPLEVEL_VERSION@")
25
26 (define program-version         
27   (if (eq? subst-version (string-append "@" "TOPLEVEL_VERSION" "@"))
28       "unknown"
29       subst-version))
30
31 (define (show-version port)
32   (display (string-append 
33             program-name " - LilyPond version " program-version "\n")
34            port))
35
36 (define (show-help)
37   (display "Convert AsciiScript to text.
38
39
40 Usage: as2text [OPTION]... AS-FILE
41
42 Options:
43   -h,--help          this help
44   -o,--output=FILE   set output file
45   -v,--version       show version
46 "))
47
48 ;;
49 ;; FIXME: use (separate-fields-discarding-char) and (read-delimited "")
50 ;;
51 (define (gulp-file name)
52   (let ((port (if (equal? name "-")
53                   (current-input-port)
54                   (catch 'system-error (lambda () (open-file name "r"))
55                          (lambda args #f)))))
56         (if port 
57             (begin
58              (display (string-append "[" name) (current-error-port))
59              (let ((content (let loop ((text ""))
60                                  (let ((line (read-line port)))
61                                       (if (or (eof-object? line)
62                                               (not line)) 
63                                           text
64                                           (loop (string-append text line "\n")))))))
65                   (close port)
66                   (display "]" (current-error-port))
67                   content))
68             (begin
69              (display 
70               (string-append "warning: no such file: " name "\n")
71               (current-error-port))
72              "")))) 
73
74 (define (with-extention name ext)
75   (if (or (equal? name "-") 
76           (equal? ext (substring name (max 0 (- (string-length name) 
77                                                 (string-length ext))))))
78       name 
79       (string-append name ext)))
80
81 (define (do-file file-name output-name)
82   (let ((ascii-script (gulp-file (with-extention file-name ".as"))))
83        ;; urg
84        (set! cur-output-name output-name)
85        (eval-string ascii-script)))
86
87 ;;; Script entry point
88 (define (main args)
89   (set! lily-home (string-append 
90                      (dirname (dirname (car args))) 
91                      "/share/lilypond"))
92   (let ((options (getopt-long args
93                               `((output (single-char #\o)
94                                           (value #t))
95                                 (help (single-char #\h))
96                                 (version (single-char #\v))))))
97     (define (opt tag default)
98       (let ((pair (assq tag options)))
99         (if pair (cdr pair) default)))
100
101     (if (assq 'help options)
102         (begin (show-version (current-output-port)) (show-help) (exit 0)))
103
104     (if (assq 'version options)
105         (begin (show-version (current-output-port)) (exit 0)))
106
107     (show-version (current-error-port))
108     (let ((output-name (opt 'output "-"))
109           (files (let ((foo (opt '() '())))
110                       (if (null? foo) 
111                           (list "-")
112                           foo))))
113          (do-file (car files) output-name))))
114
115 ;;;;
116 ;;;; Ascii Script plotting
117 ;;;;
118
119 ;;; Global variables
120
121 ;; Ascii-Art signature
122 (define tag-line "lily")
123
124 (define first-line #t)
125
126 (define scaling 1)
127
128 ;; cursor
129 (define cur-x 0)
130 (define cur-y 0)
131
132 ;; canvas dimensions
133 (define canvas-width 65)
134 (define canvas-height 20)
135
136 ;; font database
137 (define fonts '())
138
139 ;; current font
140 (define cur-font "")
141
142 ;; 
143 (define line-char "-")
144
145 ;; 
146 (define half-char-kludge #f)
147
148 ;; the plotting fields
149 (define canvas 0)
150 ;; urg: 
151 ;; make-uniform array of characters,
152 ;; or 1-dim array of strings?
153 ;; (set! canvas (make-array " " canvas-height canvas-width))
154
155 ;; urg, this kind of naming costs too much indenting
156 (define (split c s r)
157   (separate-fields-discarding-char c s r))
158
159 (define (strip s)
160   (sans-surrounding-whitespace s))
161
162
163 ;;; Helper functions
164
165 (define (af-gulp-file name)
166   ;; urg
167   (let ((old-load-path %load-path))
168        (set! %load-path 
169              (cons (string-append 
170                     (or (getenv 'LILYPONDPREFIX) ".") "/mf")
171                    (cons (string-append lily-home "/mf") %load-path)))
172        (let* ((path (%search-load-path name)) 
173               (text (if path
174                         (gulp-file path)
175                         (gulp-file name))))
176              (set! %load-path old-load-path)
177              text)))
178
179 (define (char-width c)
180   (let ((bbox (car c)))
181        (inexact->exact (* .001 (caddr bbox)))))
182
183 ;; urg: use smart table
184 (define (xmerge-chars old new)
185   (cond ((equal? new " ") old)
186         ((and (equal? old "|") (equal? new "-")) "+")
187         ((and (equal? old "-") (equal? new "|")) "+")
188         (else new)))
189
190 (define (merge-chars old new)
191   (cond ((equal? new " ") old)
192         (else new)))
193
194 (define (plot-raw x y c)
195   (if (array-in-bounds? canvas y x)
196       (array-set! canvas (merge-chars (array-ref canvas y x) c) y x)
197       (display (string-append "ouch: " (number->string x)  ","
198                               (number->string y) "\n")
199                (current-error-port))))
200
201 (define (plot x neg-y c)
202   (let ((y (- (* -1 neg-y) 1)))
203     (plot-raw (inexact->exact x) (inexact->exact y) c)))
204
205 (define (plot-char c)
206   (let ((bbox (car c))
207         (glyph (cadr c))
208         (scur-x (* scaling cur-x))
209         (scur-y (* scaling cur-y)))
210     ;; BBox: (llx lly urx ury) * 1000
211     (let ((dx (inexact->exact (* .001 (car bbox))))
212           ;;(dy (inexact->exact (* .001 (cadr bbox))))
213           (dy (inexact->exact (- (* .001 (cadddr bbox)) 1)))
214           (len (length glyph)))
215       ;;(display "Bbox: ") (display bbox) (newline)
216       ;;(display "dy: ") (display dy) (newline)
217       (do ((line glyph (cdr line))
218            (i 0 (+ i 1)))
219           ((= i len))
220         (plot-string (+ scur-x dx) (+ (- scur-y i) dy) (car line))))))
221   
222 (define (plot-string x y s)
223   (do ((i 0 (+ i 1)))
224       ((= i (string-length s)))
225     (plot (+ x i) y (substring s i (+ i 1)))))
226
227 (define (show-char char)
228   (display char))
229
230 (define (show-font name)
231         (let ((font (assoc name fonts)))
232              (map (lambda (x) (show-char x)) font)))
233
234 (define (sign x)
235   (if (= x 0)
236       1
237       (inexact->exact (/ x (abs x)))))
238
239 (define (generate-default-font)
240   (let loop ((chars '()) (i 0))
241        (if (= 256 i) 
242            chars 
243            (loop 
244             (cons (list i '(0 0 1000 1000) 
245                         (list (make-string 1 (integer->char i)))) 
246                   chars) 
247             (+ i 1)))))
248
249 (define (get-font name)
250   ;; urg
251   (if (equal? (substring name 0 (min (string-length name) 8)) "as-dummy")
252       (get-font "default")
253       (let ((entry (assoc name fonts)))
254            (if entry
255                (cdr entry)
256                (begin
257                 (display 
258                  (string-append "warning: no such font: " name "\n")
259                  (current-error-port))
260                 (get-font "default"))))))
261
262 (define (get-char font n)
263   (let ((entry (assoc n font)))
264        (if entry
265            (cdr entry)
266            (begin
267             (display 
268              (string-append "warning: no such char: (" 
269                             cur-font
270                             ", "
271                             (number->string n ) ")\n")
272              (current-error-port))
273             '()))))
274
275
276 ;;; AsciiScript commands
277
278 (define (char n)
279   (let* ((font (get-font cur-font))
280          (c
281           (if (and half-char-kludge
282                    (assoc (+ n 0.5) font))
283               (get-char font (+ n 0.5))
284               (get-char font n))))
285          (if (pair? c)
286              (plot-char c))))
287
288 (define (end-output) 
289   (display (string-append 
290             (make-string 
291              (- canvas-width (string-length tag-line)) #\space)
292             tag-line "\n")
293            cur-output-file)
294   (close cur-output-file)
295   (set! cur-output-file '()))
296
297 ;; use plot-string
298 (define (h-line len)
299   (let ((scur-x (* scaling cur-x))
300         (scur-y (* scaling cur-y))
301         (slen (* scaling len)))
302     (let ((step (sign len)))
303           (do ((i 0 (+ i step)))
304               ((= i slen))
305             (plot (+ scur-x i) scur-y line-char)))))
306
307 (define (v-line len)
308   (let ((scur-x (* scaling cur-x))
309         (scur-y (* scaling cur-y))
310         (slen (* scaling len)))
311     (let ((step (sign len)))
312       (do ((i 0 (+ i step)))
313           ((= i len))
314         (plot scur-x (+ scur-y i) line-char)))))
315
316 (define (header x y)
317   ;(display (string-append x y "\n") (current-error-port))
318   "")
319
320 (define (header-end) "")
321
322 ;; FIXME: scale
323 (define (rline-to dx dy)
324   (plot (inexact->exact cur-x) (inexact->exact cur-y) line-char)
325   (plot (inexact->exact (+ cur-x dx)) (inexact->exact (+ cur-y dy)) line-char)
326   (if (or (> (abs dx) 1) (> (abs dy) 1))
327       (let ((x cur-x)
328             (y cur-y)
329             (hx (/ dx 2))
330             (hy (/ dy 2))
331             )
332            (plot (inexact->exact (+ cur-x hx)) (inexact->exact (+ cur-y hy)) line-char)
333            (rline-to hx hy)
334            (move-to x y)
335            (rmove-to hx hy)
336            (rline-to hx hy)
337            )))
338
339 (define (dissect-char text)
340   (let* ((char (split #\nl text list))
341          (id (car char))
342          (code (string->number 
343                 (strip 
344                  (substring id 
345                             (+ (string-index id #\C) 1)
346                             (string-index id #\;)))))
347          (bbox (map string->number 
348                     (split #\space (strip (substring
349                                            id 
350                                            (+ (string-rindex id #\B) 1)
351                                            (string-rindex id #\;)))
352                            list))))
353         (list (list code bbox (cdr char)))))
354
355 (define (load-font name mag)
356   ;; urg: don't load dummy font
357   (if (not (equal? (substring name 0 (min (string-length name) 8)) "as-dummy"))
358       (let ((text (af-gulp-file (string-append name ".af"))))
359            (if (< 0 (string-length text))
360                (let* ((char-list (cdr 
361                                   (split #\np 
362                                          (regexp-substitute/global 
363                                           #f "\t[^\n]*\n" text 'pre "" 'post) 
364                                          list)))
365                       (font (apply append (map dissect-char char-list))))
366                      (if (< 0 (length font))
367                          (set! fonts (cons (cons name font) fonts))))))))
368
369 (define (number->rounded-exact x)
370   (* (sign x) (inexact->exact (abs x))))
371   
372 (define (move-to x y)
373   (set! cur-x x)
374   (let ((ey (number->rounded-exact y)))
375     (if (= 0.5 (- (abs ey) (abs y)))
376         (set! half-char-kludge #t)
377         (set! half-char-kludge #f))
378     (set! cur-y ey)))
379
380 (define (put c)
381   (plot cur-x cur-y c))
382
383 (define (rmove-to dx dy)
384   (set! cur-x (+ cur-x dx))
385   (set! cur-y (+ cur-y dy)))
386
387 (define (select-font name)
388   (set! cur-font name))
389
390 (define (set-line-char c)
391   (set! line-char c))
392
393 (define (start-line height)
394   (if first-line 
395       (begin
396        (set! fonts (cons (cons "default" (generate-default-font)) fonts))
397        (display "\n" (current-error-port))
398        (if (defined? 'lilypondpaperoutputscale)
399            (set! scaling (inexact->exact (string->number lilypondpaperoutputscale))))
400        (if (defined? 'lilypondpaperlinewidth)
401            (let ((width (inexact->exact
402                          (string->number lilypondpaperlinewidth))))
403              (if (> width 0)
404                  (set! canvas-width width)
405                  ;; need long line...
406                  ;;(set! canvas-width 200)
407                  (set! canvas-width 80)
408                  )))
409        ))
410   (set! canvas-height (inexact->exact (* scaling height)))
411   (set! canvas (make-array " " canvas-height canvas-width)))
412
413 (define (stop-line)
414   (if first-line
415       (let ((output-file (if (equal? cur-output-name "-")
416                               (current-output-port)
417                               (open-file cur-output-name "w")))
418              (output-name (if (equal? cur-output-name "-")
419                               "<stdout>"
420                               cur-output-name)))
421             (set! first-line #f)
422             (set! cur-output-file output-file)
423             (display (string-append "text output to " output-name "...\n")
424                      (current-error-port))))
425   (display 
426    (apply string-append 
427           (map (lambda (x) (string-append (apply string-append x) "\n")) 
428                (array->list canvas)))
429    cur-output-file))
430
431 (define (text s)
432   (let ((n (string-length s))
433         (font (get-font cur-font)))
434        (do ((i 0 (+ i 1)))
435            ((= i n)) 
436             (let* ((n (char->integer (string-ref s i)))
437                    (c (get-char font n)))
438               (if (pair? c) (plot-char c))
439                   (rmove-to (char-width c) 0)))))
440