|
|
1.1 ! root 1: ;$Header: vlp.l 1.4 83/05/11 23:55:23 layer Exp $ ! 2: ;$Locker: $ ! 3: ; ! 4: ; -[Wed Feb 16 12:25:15 1983 by jkf]- ! 5: ; ! 6: ; Filter for nroffing or troffing Lisp code. ! 7: ; This program reads files containing Lisp code and writes them out ! 8: ; along with the nroff (troff) commands required to make the Lisp line up. ! 9: ; It does this alignment by insuring that the leftmost ! 10: ; blank character lines up with the closest non blank character above it. ! 11: ; ! 12: ; The program operates in one of two modes: filter mode or non-filter mode. ! 13: ; ! 14: ; In filter mode, only characters between lines beginning with .Ls and .Le ! 15: ; are processed. The directive .Ls accepts an optional argument that is ! 16: ; the point size of the output. Pages have no titles and point size is set ! 17: ; by the macro, so most shell arguments are ignored. ! 18: ; ! 19: ; In non-filter mode, all lines in the file are processed. ! 20: ; ! 21: ; The output goes to the standard output, unless the v switch is set, ! 22: ; in which case it goes to vtroff. ! 23: ; ! 24: ; Usage: ! 25: ; vlp [-p size] [-d] [-f] [-l] [-v] [-T title1] file1 .... ! 26: ; ! 27: ; where, ! 28: ; -p Sets the point size to "size" ! 29: ; -d Turn on debugging mode ! 30: ; -f Run in filtered mode ! 31: ; -l Turns OFF the labeling of functions ! 32: ; -v Sends the output to vtroff ! 33: ; -T Sets the title of the next file to "titleN" ! 34: ; ! 35: ; NOTE: If vlp is on the right side of a pipe, the "-T" switch can not be ! 36: ; used. ! 37: ; ! 38: ; ! 39: ; Written by John Foderaro ! 40: ; Modified by: ! 41: ; Kevin Layer to have enough tags. ! 42: ; Jim Larus to work in filtered mode. ! 43: ; ! 44: ! 45: (declare (macros t)) ! 46: ! 47: (allocate 'list 220) ! 48: ! 49: (declare (special user-top-level EOF lines g-psize inport ! 50: spaces sps chs tls trname errport outfilename ! 51: filtermode g-title rest funcname readstdin debug ! 52: spout outfile tagsleft LabelFunctions)) ! 53: ! 54: (defvar space-count 500.) ; large number ! 55: ! 56: ;--- toplev :: top level lisp ! 57: ; ! 58: (defun toplev nil ! 59: (let ((args (command-line-args))) ! 60: (signal 2 'vlp-interrupt-routine) ! 61: (signal 15 'vlp-interrupt-routine) ! 62: (errset (apply 'vlp args)) ! 63: (exit 0))) ! 64: ! 65: (eval-when (load) (setq user-top-level 'toplev)) ! 66: ! 67: (setq g-psize 8 ! 68: debug nil ! 69: g-filtmode nil ! 70: readstdin nil ! 71: filtermode nil ! 72: outfilename nil ! 73: LabelFunctions t) ! 74: ! 75: ! 76: (defun GetModTime (FileName) ! 77: ; ! 78: ; Returns the last modification time as a string. ! 79: ; ! 80: (time-string (filestat:mtime (filestat (get_pname FileName))))) ! 81: ! 82: ! 83: (defun vlp fexpr (args) ! 84: (prog (inport outfile) ! 85: ;check command line for switches ! 86: (setq args (do ((i args (cdr i)) (ll) (tem)) ! 87: ((null i) (reverse ll)) ! 88: (setq tem (aexplodec (car i))) ! 89: (cond ((eq '- (car tem)) ; if switch ! 90: (cond ((eq 'd (cadr tem)) ! 91: (setq debug t)) ! 92: ((eq 'f (cadr tem)) ! 93: (setq filtermode t)) ! 94: ((eq 'l (cadr tem)) ! 95: (setq LabelFunctions nil)) ! 96: ((eq 'p (cadr tem)) ! 97: (setq g-psize ! 98: (cond ((eq '|6| (cadr i)) 6) ! 99: ((eq '|10| (cadr i)) 10) ! 100: ((eq '|12| (cadr i)) 12) ! 101: (t 8))) ! 102: (setq i (cdr i))) ! 103: ((eq 'v (cadr tem)) ! 104: (setq outfilename ! 105: (concat "/tmp/vlp" (sys:getpid)))) ! 106: (t (setq ll (cons (car i) ll))))) ! 107: (t (setq ll (cons (car i) ll)))))) ; else skip it ! 108: ; ! 109: (If debug then (msg (P errport) "args = " args N)) ! 110: ; ! 111: ; insure all file names given actually exist before starting. ! 112: (cond ((null (do ((xx args (cdr xx))) ! 113: ((null xx) t) ! 114: (If (eq '- (getchar (car xx) 1)) ! 115: then (setq xx (cdr xx)) ; skip switches ! 116: else (If (not (probef (car xx))) ! 117: then (msg (P errport) ! 118: "File does not exist: " ! 119: (car xx)) ! 120: (return nil))))) ! 121: (return nil))) ! 122: ; ! 123: ; do before-starting-first-file actions ! 124: ; ! 125: (If outfilename then (setq outfile (outfile outfilename))) ! 126: (If (null args) then (setq readstdin t)) ! 127: ;;; NOTE: the following concat'ing of strings is neccessary because ! 128: ;;; when vlp'ing vlp.l soelim would source the file. ! 129: (msg (P outfile) (concat "." "so /usr/lib/vlpmacs") N) ! 130: (setq g-title "") ! 131: ; ! 132: ; ! 133: (If readstdin ! 134: then (setq EOF nil) ! 135: (setq lines nil) ! 136: (If (not filtermode) ! 137: then (msg (P outfile) ".ps " g-psize N ! 138: ".vs " (+ g-psize 2) "p" N) ! 139: (msg (P outfile) ".Ti " '\" g-title '\" N) ! 140: (msg (P outfile) ".wh -1.25i He" N) ! 141: (msg (P outfile) ".nf" N)) ! 142: (do () ! 143: (EOF t) ! 144: (If filtermode then (skiptostarter)) ! 145: (processblock)) ! 146: else (do ((files args (cdr files))) ! 147: ((null files) t) ! 148: (If (eq '- (getchar (car files) 1)) ! 149: then (If (eq '-p (car files)) ! 150: then (If (null (setq g-psize ! 151: (cdr (assoc (cadr files) ! 152: '((\6 . 6) ! 153: (\8 . 8) ! 154: (\10 . 10) ! 155: (\12 . 12)))))) ! 156: then (error "bad point size" ! 157: (cadr files))) ! 158: elseif (eq '-T (car files)) ! 159: then (setq g-title (cadr files)) ! 160: else (error "bad switch " (car files))) ! 161: (setq files (cdr files)) ! 162: else (setq EOF nil) ! 163: (setq lines nil) ! 164: (cond ((null (errset ! 165: (setq inport (infile (car files))))) ! 166: (msg (P errport) "Can't open file: " ! 167: (car args)) ! 168: (return nil))) ! 169: (If (not filtermode) ! 170: then (msg (P outfile) ! 171: ".ps " g-psize N ! 172: ".vs " (+ g-psize 2) "p" N) ! 173: (msg (P outfile) ! 174: ".Fi " (car files) ! 175: " \"" (GetModTime (car files)) '\" ! 176: " \"" (time-string) '\" ! 177: N) ! 178: (msg (P outfile) ! 179: ".Ti " '\" g-title '\" N) ! 180: (msg (P outfile) ".wh -1.25i He" N) ! 181: (msg (P outfile) ".nf" N)) ! 182: (do () ! 183: (EOF) ! 184: (If filtermode then (skiptostarter)) ! 185: (processblock)) ! 186: (close inport)))) ! 187: (If outfilename ! 188: then ! 189: (close outfile) ! 190: (apply 'process ! 191: (ncons (concat "/bin/cat " outfilename ! 192: " | /usr/ucb/vtroff"))) ! 193: (If debug ! 194: then (msg (P errport) ! 195: "Troff filename is " outfilename N) ! 196: else (sys:unlink outfilename))))) ! 197: ! 198: ! 199: ;--- skiptostarter :: skip to start directive (.Ls) ! 200: ; ! 201: (defun skiptostarter nil ! 202: ; ! 203: ; Define a simple finite state machine that reads and prints everything ! 204: ; up-to and including the directive .Ls. ! 205: ; All text outside of the .Ls directive is simply sent on to the output. ! 206: ; ! 207: (do ((State 0) ! 208: (c (tyi inport) (tyi inport))) ! 209: ((=& 4 State)) ! 210: (cond ((and (=& State 0) (=& c #/.)) ! 211: (setq State 1)) ! 212: ((and (=& State 1) (=& c #/L)) ! 213: (setq State 2)) ! 214: ((and (=& State 2) (=& c #/s)) ! 215: (setq State 3)) ! 216: ((=& State 3) ; Read through arguments ! 217: (cond ((=& c #\lf) ! 218: (setq State 4) ! 219: (untyi c inport)))) ; In case text starts immed. ! 220: ((=& c #\eof) ! 221: (setq EOF t) ! 222: (return)) ! 223: (t ! 224: (setq State 0))) ! 225: (tyo c outfile))) ! 226: ! 227: (defun processblock nil ! 228: ; ! 229: ; Read lines until we come to one that has no blank space at its begining. ! 230: ; Then process the previously accumulated lines. ! 231: ; If the last line contains the directive .Le, then find the next block ! 232: ; enclosed by .Ls. ! 233: ; ! 234: (do ((newline (getline) (getline))) ! 235: (nil) ! 236: (If (or EOF (and (zerop (car newline)) (cadr newline))) ! 237: then (flushlines) ! 238: (setq lines nil) ! 239: (If (=& (caadr newline) #/') ;then must quote ' for troff ! 240: then (msg (P outfile) "\\") ! 241: elseif (and filtermode ! 242: (=& (caadr newline) #/.) ! 243: (=& (cadadr newline) #/L) ! 244: (=& (caddadr newline) #/e)) ! 245: then (msg (P outfile) ".Le" N) ! 246: (return nil)) ! 247: (If EOF then (return nil))) ! 248: (setq lines (cons newline lines)))) ! 249: ! 250: ! 251: ;--- getline :: read in new line and return structure: ! 252: ; (spaces chars) ! 253: ; spaces is a fixnum giving the number of spaces before the first ! 254: ; non-blank on the line. ! 255: ; chars is the list of characters appearing on the line, in order. ! 256: ; ! 257: (defun getline nil ! 258: (do ((col 1) ! 259: (spaces 0) ! 260: (chars nil) ! 261: (spacemode t) ! 262: (newc (tyi inport) (tyi inport) )) ! 263: (nil) ! 264: (If (=& #\eof newc) ! 265: then (If (null chars) ! 266: then (setq EOF t) ! 267: (return nil) ! 268: else (setq newc #\lf))) ! 269: (If (=& #\lf newc) ! 270: then (if (null chars) ! 271: then ; for totally blank lines return a large ! 272: ; space count so this won't be used for tags ! 273: (return (list space-count nil)) ! 274: else (return (list spaces (nreverse chars))))) ! 275: (If (=& #\ff newc) ! 276: then (return (list spaces (nreverse (cons newc chars))))) ! 277: (If spacemode ! 278: then (If (=& #\sp newc) ! 279: then (setq spaces (1+ spaces)) ! 280: elseif (=& #\tab newc) ! 281: then (setq spaces (* (/ (+ spaces 8) 8) 8)) ! 282: else (setq spacemode nil ! 283: chars (list newc))) ! 284: else (setq chars (cons newc chars))))) ! 285: ! 286: ! 287: ;--- flushlines ! 288: ; go back on all lines and determine where to put tags and reference ! 289: ; tags. ! 290: ; ! 291: (defun flushlines nil ! 292: (let (thistag tagref rlines tagloc) ! 293: (inittagslist '(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ! 294: a b c d e f g h i j k l m n o p q r s t u v w x y z ! 295: 1 2 3 4 5 6 7 8 9 0)) ! 296: (setq tagref nil tagloc nil rlines nil) ! 297: (do ((xx lines (cdr xx)) ! 298: (thistagloc nil nil) ! 299: (pendingtags) ! 300: (thistagref)) ! 301: ((null xx)) ! 302: (setq rlines (cons (car xx) rlines) ! 303: spaces (caar xx) ! 304: thistag (alloctag)) ! 305: ; determine which of the pending tags we can insert at this level ! 306: (do ((yy pendingtags (cdr yy))) ! 307: ((or (null yy) (>& spaces (caar yy))) ! 308: (setq pendingtags yy)) ! 309: (setq thistagloc (cons (car yy) thistagloc))) ! 310: (setq tagloc (cons thistagloc tagloc)) ! 311: ; free up the tags we allocated at this level. ! 312: (mapc '(lambda (x) (freetag (cadr x))) thistagloc) ! 313: ; ! 314: ; we only need to refer to a tags at this level if ! 315: ; we are not at the left edge of the paper ! 316: ; ! 317: (If (greaterp spaces 0) ! 318: then (setq tagref (cons thistag tagref)) ! 319: (setq pendingtags (addtotags spaces thistag pendingtags)) ! 320: else (setq tagref (cons nil tagref)))) ! 321: (If debug then (msg " **tagref = " tagref N " **tagloc = " tagloc N)) ! 322: ; ! 323: ; print out the lines. ! 324: ; the lines we want to print are in the list rlines. They are ! 325: ; in the correct order. ! 326: ; ! 327: (do ((yy rlines (cdr yy)) ! 328: (commentmode nil nil) ! 329: (escapemode nil nil)) ! 330: ((null yy)) ! 331: ; first print out spaces ! 332: (setq sps (caar yy) ! 333: chs (cadar yy) ! 334: tls (car tagloc) ! 335: trname (car tagref)) ! 336: (headercheck sps chs) ! 337: (If debug ! 338: then (msg " spaces " sps N " chs " chs N ! 339: " tagloc " (car tagloc) N " tagref " (car tagref) N)) ! 340: (setq spout 0) ! 341: ; if there are characters on this line, print out ! 342: ; leading spaces ! 343: (if chs ! 344: then (do () ! 345: ((eq spout sps)) ! 346: (tyo #\sp outfile) ! 347: (setq spout (1+ spout))) ! 348: ! 349: (If trname then (tagrefprint trname))) ! 350: ! 351: (do ((xx chs (cdr xx))) ! 352: ((null xx) ! 353: (If (and tls (not (<& (caar tls) spout))) ! 354: then (do ((i spout (1+ i))) ! 355: ((null tls)) ! 356: (If (=& (caar tls) i) ! 357: then (taglocprint (cadar tls)) ! 358: (setq tls (cdr tls))))) ! 359: (If commentmode then (msg (P outfile) "\\fP")) ! 360: (terpr outfile)) ! 361: (If (and tls (eq (caar tls) spout)) ! 362: then (taglocprint (cadar tls)) ! 363: (setq tls (cdr tls))) ! 364: (If (and (not escapemode) ! 365: (null commentmode) ! 366: (=& #/; (car xx))) ! 367: then (msg (P outfile) "\\fI") ! 368: (setq commentmode t) ! 369: elseif (=& #/\ (car xx)) ! 370: then (tyo #/\ outfile)) ; escape backslashes ! 371: (If (memq (car xx) '(#/\ #//)) ! 372: then (setq escapemode t) ! 373: else (setq escapemode nil)) ! 374: (If (=& (car xx) #\ff) ! 375: then (msg (P outfile) N ".bp" N) ! 376: else (tyo (car xx) outfile)) ! 377: (setq spout (1+ spout))) ! 378: (setq tagloc (cdr tagloc) ! 379: tagref (cdr tagref))))) ! 380: ! 381: ! 382: ; headercheck :: check if this is a function declaration. ! 383: ; currently this means that there are no more than 2 spaces before ! 384: ; the line begins and that the line begins with (defxxx <name>) ! 385: (defun headercheck (spaces chars) ! 386: (If (<& spaces 3) ! 387: then (If (setq rest (match chars '(#/( #/d #/e #/f))) ! 388: then (setq funcname (skippastblkn rest)) ! 389: (If (and funcname LabelFunctions) ! 390: then (msg (P outfile) ".Lf " funcname N))))) ! 391: ! 392: ;--- match :: match lists ! 393: ; list1 - list of characters (fixnum rep) ! 394: ; list2 - master list of characters (fixnum rep) ! 395: ; list2 should be shorter than list1. If list2 is a substring of list1 ! 396: ; then the rest of list1 will be returned. Otherwise nil is returned. ! 397: ; ! 398: (defun match (list1 list2) ! 399: (cond ((null list1) nil) ! 400: ((null list2) list1) ! 401: ((or (eq (car list1) (car list2)) ! 402: (eq (car list1) (uppercase (car list2)))) ! 403: (match (cdr list1) (cdr list2))) ! 404: (t nil))) ! 405: ! 406: ;--- uppercase :: convert fixnum rep to upper case ! 407: ; char - fixnum representation of character ! 408: ; convert character to upper case. ! 409: ; ! 410: (defun uppercase (ch) ! 411: (If (and (not (<& ch #/a)) (not (>& ch #/z))) ! 412: then (- ch #.(- #/a #/A)))) ! 413: ! 414: ! 415: ! 416: ;--- skippastblnk :: skip to and past blank field and return following name ! 417: ; list - list of characters (fixnums) ! 418: ; ! 419: ; We skip past all non blanks then all blanks and finally implode the next ! 420: ; word after that and return it. ! 421: ; ! 422: ; bug- we can't tell the difference between a function named nil and ! 423: ; no valid function, but then again you can't have a function named nil. ! 424: ; ! 425: (defun skippastblkn (list) ! 426: (let (res) ! 427: ; skip to first blank ! 428: (do () ! 429: ((null list) nil) ! 430: (If (=& (car list) #\sp) then (return nil)) ! 431: (setq list (cdr list))) ! 432: ; skip to first non-blank ! 433: (do () ! 434: ((null list) nil) ! 435: (If (not (=& (car list) #\sp)) then (return nil)) ! 436: (setq list (cdr list))) ! 437: ; collect non blanks ! 438: (If list ! 439: then (do () ! 440: ((null list)) ! 441: (If (and (=& #\lpar (car list)) ! 442: (null res)) ! 443: then (setq list (cdr list)) ; form like "defun (foo ..)" ! 444: elseif (or (=& #\lpar (car list)) ! 445: (=& #\rpar (car list)) ! 446: (=& #\sp (car list))) ! 447: then (return nil) ! 448: else (setq res (cons (car list) res)) ! 449: (setq list (cdr list)))) ! 450: (If res then (implode (nreverse res)))))) ! 451: ! 452: ; ! 453: ; add (spaces character) to list so that the spaces number are in ! 454: ; ascending order. ! 455: ; ! 456: (defun addtotags (spaces character oldlist) ! 457: (If (or (null oldlist) (>& spaces (caar oldlist))) ! 458: then (cons (list spaces character) oldlist) ! 459: else (do ((prevtag oldlist (cdr prevtag)) ! 460: (thistag (cdr oldlist) (cdr thistag))) ! 461: ((or (null thistag) (>& spaces (caar thistag))) ! 462: (setq thistag (cons (list spaces character) thistag)) ! 463: (rplacd prevtag thistag))))) ! 464: ! 465: (defun inittagslist (list) ! 466: (setq tagsleft list)) ! 467: ! 468: (defun alloctag nil ! 469: (If (null tagsleft) ! 470: then (msg "Out of tags, aauuuuggh " N) ! 471: (exit) ! 472: else (prog1 (car tagsleft) (setq tagsleft (cdr tagsleft))))) ! 473: ! 474: (defun freetag (tagname) ! 475: (setq tagsleft (cons tagname tagsleft))) ! 476: ! 477: ! 478: (defun taglocprint (name) ! 479: (msg (P outfile) "\\k" name)) ! 480: ! 481: ! 482: (defun tagrefprint (name) ! 483: (msg (P outfile) "\\h'|\\n" name "u'")) ! 484: ! 485: ! 486: ;---new stuff ! 487: ; ! 488: ;--- programs deal in lineblk's ! 489: ; A lineblk has these components: ! 490: ; class : normal or comment ! 491: ; comment is a line beginning with ;, in which case it is ! 492: ; not counted as far as spacing goes. ! 493: ; spaces : number of spaces before first useful info ! 494: ; dead : list of dead linblk's, that is those ready to print but ! 495: ; waiting for this line to be done. ! 496: ; tagref: tag to go to at the beginning of this line ! 497: ; tagloc : tags defined on this line ! 498: ; chars : list of characters to print ! 499: ! 500: (defun make-lineblk (class spaces chars) ! 501: (list class spaces nil nil nil chars)) ! 502: (defmacro get:class (lineblk) `(car ,lineblk)) ! 503: (defmacro set:class (lineblk val) `(setf (get:class ,lineblk) ,val)) ! 504: (defmacro get:spaces (lineblk) `(cadr ,lineblk)) ! 505: (defmacro set:spaces (lineblk val) `(setf (get:spaces ,lineblk) ,val)) ! 506: (defmacro get:dead (lineblk) `(caddr ,lineblk)) ! 507: (defmacro set:dead (lineblk val) `(setf (get:dead ,lineblk) ,val)) ! 508: (defmacro get:tagref (lineblk) `(cadddr ,lineblk)) ! 509: (defmacro set:tagref (lineblk val) `(setf (get:tagref ,lineblk) ,val)) ! 510: (defmacro get:tagloc (lineblk) `(caddddr ,lineblk)) ! 511: (defmacro set:tagloc (lineblk val) `(setf (get:tagloc ,lineblk) ,val)) ! 512: (defmacro get:chars (lineblk) `(cadddddr ,lineblk)) ! 513: (defmacro set:chars (lineblk val) `(setf (get:chars ,lineblk) ,val)) ! 514: ! 515: ! 516: (defun vlp-interrupt-routine (sig) ! 517: (If (and (boundp 'outfilename) outfilename) ! 518: then (sys:unlink outfilename)) ! 519: (exit 1))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.