home *** CD-ROM | disk | FTP | other *** search
- From: tml@hemuli.tik.vtt.fi (Tor Lillqvist)
- Newsgroups: alt.sources
- Subject: [tex] Producing Latin-1 Extended Computer Modern VPL files
- Message-ID: <11633@stag.math.lsa.umich.edu>
- Date: 5 Apr 90 20:26:19 GMT
-
- Archive-name: accentify/05-Apr-90
- Original-posting-by: tml@hemuli.tik.vtt.fi (Tor Lillqvist)
- Original-subject: Producing Latin-1 Extended Computer Modern VPL files
- Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)
-
- [This is an experimental alt.sources re-posting from the newsgroup(s)
- comp.text.tex. Comments on this service to emv@math.lsa.umich.edu
- (Edward Vielmetti).]
-
-
-
- With TeX 3.0 you have the possibility to use so called virtual fonts.
- I wrote this GNU Emacs Lisp code to automatically make VPL (Virtual
- font Property List) files with the ISO Latin-1 accented letters from
- Computer Modern PL files.
-
- Why GNU Emacs Lisp? Well, PL and VPL files look a bit like Lisp, so I
- thought that it would be easy to hack together the necessary code in
- Lisp. I considered doing it in Scheme at first, but ran into trouble
- because Scheme does case conversion. On the other hand, Elisp doesn't
- have floating-point numbers, so I had to represent them using
- (integer-part . fraction-part) Lisp dotted pairs. I don't have any
- other Lisps available.
-
- I hope this is useful to those wanting to try the new TeX 3.0
- features.
-
- Is there any group working on a standard way to extend Computer Modern
- fonts? ISO Latin-1 covers only a part of the necessary letters. (See
- the article by Yannis Haralambous in TUGboat 10:3, pp 342--344.) Has
- anybody written MF code for the Icelandic thorn and eth letters?
-
- You typically would do something like:
-
- mkdir /tmp/latin1
- cd /tmp/latin1
- F=/usr/local/lib/tex/fonts
- for file in $F/cm*.tfm; do
- tftopl $file `basename $file'.pl
- done
-
- start Emacs, and do M-x extend-directory-of-cm-fonts /tmp/latin1
-
- for file in *.vpl; do
- bn=`basename $file .vpl`
- vptovf $file $F/$bn.vf $F/$bn.tfm
- done
-
- Now if only more DVI drivers would support VF files... Thanks to Tom
- Rokicki and Don Knuth for virtual font support in dvips 5.01.
-
- Enough said, here is the code: Use as you please. If you do anything
- useful with it, or make enhancements, please tell me.
-
- ;; accentify.el -- extend a Computer Modern font with accented letters
- ;; Tor Lillqvist <tml@tik.vtt.fi>
-
- (defvar interesting-pl-properties
- '(CHARACTER CHECKSUM DESIGNSIZE FONTDIMEN KRN LABEL LIGTABLE SKIP))
-
- (defvar accented-versions
- '((?A ?\300 ?\301 ?\302 ?\303 ?\304 ?\305)
- (?C ?\307)
- (?E ?\310 ?\311 ?\312 ?\313)
- (?I ?\314 ?\315 ?\316 ?\317)
- ;; (?D ?\320)
- (?N ?\321)
- (?O ?\322 ?\323 ?\324 ?\325 ?\326)
- (?U ?\331 ?\332 ?\333 ?\334)
- (?Y ?\335)
- (?a ?\340 ?\341 ?\342 ?\343 ?\344 ?\345)
- (?c ?\347)
- (?e ?\350 ?\351 ?\352 ?\353)
- (?i ?\354 ?\355 ?\356 ?\357)
- (?n ?\361)
- (?o ?\362 ?\363 ?\364 ?\365 ?\366)
- (?u ?\371 ?\372 ?\373 ?\374)
- (?y ?\375 ?\377))
- "A list containing ASCII characters and the corresponding accented
- ISO Latin-1 characters' codes.")
-
- (defvar cm-text-fonts "^cm\\(r\\|bx\\|tt\\|sltt\\|vtt\\|tex\\|ss\\|ssi\\|ssdc\\|ssbx\\|ssqi\\|dunh\\|bxsl\\|b\\|ti\\|bxti\\|csc\\|tcsc\\)\\([0-9]+\\)\\(\\.pl\\)$")
-
- (defun extend-directory-of-cm-fonts (directory)
- "For all Computer Modern PL files in a direcory create the
- corresponding Extended Computer Modern VP file."
- (interactive "DExtend fonts in directory: ")
- (mapcar 'extend-pl-file (directory-files directory nil cm-text-fonts)))
-
- (defun extend-pl-file (filename)
- "Create a Extended Computer Modern VP (Virtual font Property list) file
- from the PL (font Property List) file FILENAME."
- (interactive)
- (set-buffer (get-buffer-create "*extend-pl-file-temp*"))
- (insert-file-contents filename t)
- (message "Working on %s" (file-name-nondirectory filename))
- (set-buffer (extend-cm-font-in-buffer))
- (write-file (buffer-file-name (current-buffer))))
-
- (defun extend-cm-font-in-buffer ()
- "Convert a Computer Modern PL file to the corresponding Latin-1
- Extended Computer Modern VP file."
- (interactive)
- (let (font-name font-basename font-size tempbuffer vp-file)
- (setq font-name (file-name-nondirectory (buffer-file-name (current-buffer))))
- (if (not (string-match cm-text-fonts font-name))
- (error "Cannot handle this font.")
- (setq font-name (substring font-name 0 (match-beginning 3)))
- (setq font-basename (substring font-name 0 (match-beginning 2)))
- (setq font-size (substring font-name (match-beginning 2) (match-beginning 3))))
- (setq tempbuffer (get-buffer-create "*temp*"))
- (copy-to-buffer tempbuffer (point-min) (point-max))
- (set-buffer tempbuffer)
- (goto-char (point-min))
- ;; First convert C values to decimal
- (clean-char-values)
- (goto-char (point-min))
- ;; Convert R values to dotted pairs
- (dotted-floatify-buffer)
- (goto-char (point-min))
- ;; (read) will read from the temp buffer
- (setq standard-input (current-buffer))
- ;; We produce a VP file, with l1 prefixed to the original font name
- (set-buffer (get-buffer-create "*new-vp-file*"))
- (set-visited-file-name (concat "l1" font-name ".vpl"))
- (erase-buffer)
- (setq standard-output (current-buffer))
- (setq char-metrics (make-vector 256 nil))
- (princ (format "(MAPFONT D 0 (FONTNAME %s))\n" font-name))
- ;; Parse the PL file, inserting ligtable labels and kerns
- ;; for the accented letters on the fly
- (condition-case nil
- (while t
- (convert-expr (read)))
- (end-of-file nil))
- ;; Output the character descriptions for the accented characters
- (output-additions)
- ;; (kill-buffer temp-buffer)
- (current-buffer)
- ))
-
- (defun dotted-floatify-buffer ()
- "Replaces floating-point values in the current buffer
- with lists of the form (!fix! integer-part fraction-part).
- The fraction part is multiplied by 1000000."
- (interactive)
- (while (re-search-forward "\\(-?\\)\\([0-9]+\\)\\.\\([0-9]+\\)" nil t)
- (replace-match
- (make-float-string
- (string-to-int (buffer-substring (match-beginning 2)
- (match-end 2)))
- (buffer-substring (match-beginning 3)
- (match-end 3))
- (< (match-beginning 1) (match-end 1))))))
-
- (defun clean-char-values ()
- "Replace C (character) values of non-alphanumeric characters with
- the corresponding D (decimal) value."
- (while (re-search-forward " [Cc] \\([^A-Za-z]\\) " nil t)
- (replace-match
- (format " d %d " (aref (buffer-substring
- (match-beginning 1)
- (1+ (match-end 1))) 0)))))
-
- (defun myprint (e)
- (cond ((atom e) (prin1 e))
- ((and (integerp (car e)) (integerp (cdr e)))
- (myprint-dottedfloat (car e) (cdr e)))
- ((eq (car e) 'COMMENT) nil)
- (t (terpri)
- (insert "(")
- (myprint (car e))
- (myprint-rest (cdr e)))))
-
- (defun abs (e)
- (if (< e 0) (- 0 e) e))
-
- (defun myprint-dottedfloat (int fract)
- (if (or (< int 0) (< fract 0))
- (princ "-"))
- (prin1 (abs int))
- (princ ".")
- (princ (format "%06d" (abs fract))))
-
- (defun myprint-rest (e)
- (cond ((null e) (insert ")"))
- (t (insert " ")
- (myprint (car e))
- (myprint-rest (cdr e)))))
-
- (defun depth (e)
- (cond ((atom e) 0)
- (t (max (1+ (depth (car e))) (depth (cdr e))))))
-
- (defun convert-expr (e)
- (cond ((listp e)
- (let ((handler(get (car e) 'prop-handler)))
- (if handler (apply handler e nil)
- (myprint e))))
- (t (error "Invalid property list"))))
-
- (defun put-handler (prop)
- (put prop 'prop-handler
- (intern (concat (downcase (symbol-name prop)) "-handler"))))
-
- (mapcar 'put-handler interesting-pl-properties)
-
- (defun comment-handler (prop)
- nil)
-
- (defun checksum-handler (prop)
- nil)
-
- (defun designsize-handler (prop)
- (setq designsize (car (cdr (cdr prop))))
- (myprint prop))
-
- (defun fontdimen-handler (prop)
- (myprint prop)
- (setq fontdimens (cdr prop))
- (setq font-xheight
- (car (cdr (cdr (assq 'XHEIGHT fontdimens)))))
- (setq font-slant
- (car (cdr (cdr (assq 'SLANT fontdimens))))))
-
- (defun ligtable-handler (prop)
- (princ "\n(LIGTABLE\n")
- (mapcar 'ligstep-handler (cdr prop))
- (princ ")\n"))
-
- (defun ligstep-handler (step)
- (myprint step)
- (let ((handler (get (car step) 'prop-handler)))
- (if handler
- (apply handler step nil))))
-
- (defun label-handler (step)
- (label-accented (assq (int-value (cdr step)) accented-versions)))
-
- (defun label-accented (list)
- (while (and list (setq list (cdr list)))
- (princ " ")
- (prin1 (list 'LABEL 'D (car list)))))
-
- (defun krn-handler (step)
- (krn-accented (car (cdr (cdr (cdr (cdr step)))))
- (assq (int-value (cdr step)) accented-versions)))
-
- (defun krn-accented (kern list)
- (while (and list (setq list (cdr list)))
- (princ " ")
- (princ "(KRN D ")
- (prin1 (car list))
- (princ " R ")
- (myprint kern)
- (princ ")")))
-
- (defun skip-handler (step)
- (error "Cannot handle SKIPs (yet)."))
-
- (defun character-handler (prop)
- (myprint prop)
- (aset char-metrics (int-value (cdr prop)) (cdr (cdr (cdr prop)))))
-
- (defun checksum-handler (prop)
- nil)
-
- ;; The combinations list contains for each accented letter a sublist
- ;; with its code, the code of the unaccented letter, and the
- ;; code of the accent
-
- (setq combinations
- '((?\300 ?A ?\022) ; Agrave
- (?\301 ?A ?\023) ; Aacute
- (?\302 ?A ?\136) ; Acircumflex
- (?\303 ?A ?\176) ; Atilde
- (?\304 ?A ?\177) ; Adiaeresis
- (?\305 ?A ?\027) ; Aring
- (?\307 ?C ?\030) ; Ccedilla
- (?\310 ?E ?\022) ; Egrave
- (?\311 ?E ?\023) ; Eacute
- (?\312 ?E ?\136) ; Ecircumflex
- (?\313 ?E ?\177) ; Ediaeresis
- (?\314 ?I ?\022) ; Igrave
- (?\315 ?I ?\023) ; Iacute
- (?\316 ?I ?\136) ; Icircumflex
- (?\317 ?I ?\177) ; Idiaeresis
- (?\321 ?N ?\176) ; Ntilde
- (?\322 ?O ?\022) ; Ograve
- (?\323 ?O ?\023) ; Oacute
- (?\324 ?O ?\136) ; Ocircumflex
- (?\325 ?O ?\176) ; Otilde
- (?\326 ?O ?\177) ; Odiaeresis
- (?\331 ?U ?\022) ; Ugrave
- (?\332 ?U ?\023) ; Uacute
- (?\333 ?U ?\136) ; Ucircumflex
- (?\334 ?U ?\177) ; Udiaeresis
- (?\335 ?Y ?\023) ; Yacute
- (?\340 ?a ?\022) ; agrave
- (?\341 ?a ?\023) ; aacute
- (?\342 ?a ?\136) ; acircumflex
- (?\343 ?a ?\176) ; atilde
- (?\344 ?a ?\177) ; adiaeresis
- (?\345 ?a ?\027) ; aring
- (?\347 ?c ?\030) ; ccedilla
- (?\350 ?e ?\022) ; egrave
- (?\351 ?e ?\023) ; eacute
- (?\352 ?e ?\136) ; ecircumflex
- (?\353 ?e ?\177) ; ediaeresis
- (?\354 ?\020 ?\022) ; igrave
- (?\355 ?\020 ?\023) ; iacute
- (?\356 ?\020 ?\136) ; icircumflex
- (?\357 ?\020 ?\177) ; idiaeresis
- (?\361 ?n ?\176) ; ntilde
- (?\362 ?o ?\022) ; ograve
- (?\363 ?o ?\023) ; oacute
- (?\364 ?o ?\136) ; ocircumflex
- (?\365 ?o ?\176) ; otilde
- (?\366 ?o ?\177) ; odiaeresis
- (?\371 ?u ?\022) ; ugrave
- (?\372 ?u ?\023) ; uacute
- (?\373 ?u ?\136) ; ucircumflex
- (?\374 ?u ?\177) ; udiaeresis
- (?\375 ?y ?\023) ; yacute
- (?\377 ?y ?\177) ; ydiaeresis
- ))
-
- (defun output-additions ()
- (mapcar 'output-combination combinations))
-
- (defun output-combination (recipe)
- (let* ((basechar (car (cdr recipe)))
- (accent (car (cdr (cdr recipe))))
- (basechar-metrics (aref char-metrics basechar))
- (accent-metrics (aref char-metrics accent))
- (aw (car (cdr (cdr (assq 'CHARWD accent-metrics)))))
- (cw (car (cdr (cdr (assq 'CHARWD basechar-metrics)))))
- (ch (or (car (cdr (cdr (assq 'CHARHT basechar-metrics)))) '(0 . 0)))
- (ah (or (car (cdr (cdr (assq 'CHARHT accent-metrics)))) '(0 . 0)))
- (cd (or (car (cdr (cdr (assq 'CHARDP basechar-metrics)))) '(0 . 0)))
- (ad (or (car (cdr (cdr (assq 'CHARDP accent-metrics)))) '(0 . 0)))
- (ci (or (car (cdr (cdr (assq 'CHARIC basechar-metrics)))) '(0 . 0)))
- (downkern (float- font-xheight ch)))
- (myprint
- (append
- (list 'CHARACTER 'D (car recipe))
- (list (list 'CHARWD 'R cw))
- (list (list 'CHARHT 'R (floatmax (float- ah downkern) ch)))
- (if (not (equal (floatmax cd ad) '(0 . 0)))
- (list (list 'CHARDP 'R (floatmax cd ad))))
- (if (not (equal ci '(0 . 0))) (list (list 'CHARIC 'R ci)))
- (list
- (append (list 'MAP '(PUSH))
- (if (not (equal font-xheight ch))
- (if (equal ah '(0 . 0)) ; Cedilla?
- nil
- (list (list 'MOVEDOWN 'R
- downkern))))
- ;; Ignore slants for now
- (let ((rightkern (float/ (float- cw aw) 2)))
- (if (not (equal rightkern '(0 . 0)))
- (list (list 'MOVERIGHT 'R rightkern))))
- (list (list 'SETCHAR 'D accent))
- (list '(POP))
- (list (list 'SETCHAR 'D basechar))))))
- (terpri)))
-
- ;; Auxiliary functions
-
- (defun make-float-string (int fract neg)
- "Returns a string containing the special dotted-pair representation of
- a floating-point number. INT is the integer part (a number)
- and FRACT is the fractional part (as a string!)."
- (let ((x (make-float int fract (if neg -1 1))))
- (format "(%d . %d)" (car x) (cdr x))))
-
- (defun make-float (int fract neg)
- "Converts a floating point number to a dotted-pair fixed-point
- representation. INT is the integer part, FRACT is the fractional part
- as a string, and NEG is 1 or -1.
- The result is a dotted pair the car of which is the integer
- part and the cdr is the fractional part multiplied by 1000000."
- (interactive)
- (cons int
- (* neg (let ((l (length fract)) (f (string-to-int fract)))
- (cond ((= l 7) (/ (+ f 5) 10))
- ((= l 6) f)
- ((= l 5) (* f 10))
- ((= l 4) (* f 100))
- ((= l 3) (* f 1000))
- ((= l 2) (* f 10000))
- ((= l 1) (* f 100000))
- (t (error "Too long fractional part: %s" fract)))))))
-
- (defun float+ (a b)
- "Add two dottedfloats."
- (let (i f)
- (setq i (+ (car a) (car b)))
- (setq f (+ (cdr a) (cdr b)))
- (cond ((>= f 1000000)
- (setq i (1+ i))
- (setq f (- f 1000000)))
- ((<= f -1000000)
- (setq i (1- i))
- (setq f (+ f 1000000))))
- (cond ((and (< i 0) (> f 0))
- (setq i (1+ i))
- (setq f (- f 1000000)))
- ((and (> i 0) (< f 0))
- (setq i (1- i))
- (setq f (+ 1000000 f))))
- (cons i f)))
-
- (defun float- (a &rest b)
- "Negate a dottedfloat or subtract two dottedfloats."
- (if b
- (float+ a (float- (car b)))
- (cons (- (car a)) (- (cdr a)))))
-
- (defun float/ (a i)
- "Divide a dottedfloat by an integer."
- (cons (/ (car a) i) (/ (cdr a) i)))
-
- (defun floatmax (a b)
- (if (or (> (car a) (car b)) (and (= (car a) (car b)) (> (cdr a) (cdr b))))
- a
- b))
-
- (defun octal-to-int (value)
- (if (zerop value)
- 0
- (+ (* 8 (octal-to-int (/ value 10))) (% value 10))))
-
- (defun int-value (list)
- (let ((type (car list)) (value (car (cdr list))))
- (cond ((eq type 'C)
- (cond
- ((symbolp value) (aref (symbol-name value) 0))
- ((integerp value) (+ value ?0))
- (t (error "Invalid C type value."))))
- ((eq type 'D) value)
- ((eq type 'O) (octal-to-int value))
- (t (error "Unknown value type.")))))
-