|
|
1.1 ! root 1: ;$Header: vlp.l,v 1.5 84/05/07 15:09:59 jkf Exp $ ! 2: ;$Locker: layer $ ! 3: ; ! 4: ; -[Mon May 7 15:04:34 1984 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: ! 128: (if (and LabelFunctions (null filtermode)) ! 129: then ;; NOTE: the following concat'ing of strings ! 130: ;; is neccessary because when vlp'ing vlp.l ! 131: ;; soelim would source the file. ! 132: (msg (P outfile) (concat "." "so /usr/lib/vlpmacs") N)) ! 133: (setq g-title "") ! 134: ; ! 135: ; ! 136: (if readstdin ! 137: then (setq EOF nil) ! 138: (setq lines nil) ! 139: (if (not filtermode) ! 140: then (msg (P outfile) ".ps " g-psize N ! 141: ".vs " (+ g-psize 2) "p" N) ! 142: (msg (P outfile) ".Ti " '\" g-title '\" N) ! 143: (msg (P outfile) ".wh -1.25i He" N) ! 144: (msg (P outfile) ".nf" N)) ! 145: (do () ! 146: (EOF t) ! 147: (if filtermode then (skiptostarter)) ! 148: (processblock)) ! 149: else (do ((files args (cdr files))) ! 150: ((null files) t) ! 151: (if (eq '- (getchar (car files) 1)) ! 152: then (if (eq '-p (car files)) ! 153: then (if (null (setq g-psize ! 154: (cdr (assoc (cadr files) ! 155: '((\6 . 6) ! 156: (\8 . 8) ! 157: (\10 . 10) ! 158: (\12 . 12)))))) ! 159: then (error "bad point size" ! 160: (cadr files))) ! 161: elseif (eq '-T (car files)) ! 162: then (setq g-title (cadr files)) ! 163: else (error "bad switch " (car files))) ! 164: (setq files (cdr files)) ! 165: else (setq EOF nil) ! 166: (setq lines nil) ! 167: (cond ((null (errset ! 168: (setq inport (infile (car files))))) ! 169: (msg (P errport) "Can't open file: " ! 170: (car args)) ! 171: (return nil))) ! 172: (if (not filtermode) ! 173: then (msg (P outfile) ! 174: ".ps " g-psize N ! 175: ".vs " (+ g-psize 2) "p" N) ! 176: (msg (P outfile) ! 177: ".Fi " (car files) ! 178: " \"" (GetModTime (car files)) '\" ! 179: " \"" (time-string) '\" ! 180: N) ! 181: (msg (P outfile) ! 182: ".Ti " '\" g-title '\" N) ! 183: (msg (P outfile) ".wh -1.25i He" N) ! 184: (msg (P outfile) ".nf" N)) ! 185: (do () ! 186: (EOF) ! 187: (if filtermode then (skiptostarter)) ! 188: (processblock)) ! 189: (close inport)))) ! 190: (if outfilename ! 191: then ! 192: (close outfile) ! 193: (apply 'process ! 194: (ncons (concat "/bin/cat " outfilename ! 195: " | /usr/ucb/vtroff"))) ! 196: (if debug ! 197: then (msg (P errport) ! 198: "Troff filename is " outfilename N) ! 199: else (sys:unlink outfilename))))) ! 200: ! 201: ! 202: ;--- skiptostarter :: skip to start directive (.Ls) ! 203: ; ! 204: (defun skiptostarter nil ! 205: ; ! 206: ; Define a simple finite state machine that reads and prints everything ! 207: ; up-to and including the directive .Ls. ! 208: ; All text outside of the .Ls directive is simply sent on to the output. ! 209: ; ! 210: (do ((State 0) ! 211: (c (tyi inport) (tyi inport))) ! 212: ((=& 4 State)) ! 213: (cond ((and (=& State 0) (=& c #/.)) ! 214: (setq State 1)) ! 215: ((and (=& State 1) (=& c #/L)) ! 216: (setq State 2)) ! 217: ((and (=& State 2) (=& c #/s)) ! 218: (setq State 3)) ! 219: ((=& State 3) ; Read through arguments ! 220: (cond ((=& c #\lf) ! 221: (setq State 4) ! 222: (untyi c inport)))) ; In case text starts immed. ! 223: ((=& c #\eof) ! 224: (setq EOF t) ! 225: (return)) ! 226: (t ! 227: (setq State 0))) ! 228: (tyo c outfile))) ! 229: ! 230: (defun processblock nil ! 231: ; ! 232: ; Read lines until we come to one that has no blank space at its begining. ! 233: ; Then process the previously accumulated lines. ! 234: ; If the last line contains the directive .Le, then find the next block ! 235: ; enclosed by .Ls. ! 236: ; ! 237: (do ((newline (getline) (getline))) ! 238: (nil) ! 239: (if (or EOF (and (zerop (car newline)) (cadr newline))) ! 240: then (flushlines) ! 241: (setq lines nil) ! 242: (if (=& (caadr newline) #/') ;then must quote ' for troff ! 243: then (msg (P outfile) "\\") ! 244: elseif (and filtermode ! 245: (=& (caadr newline) #/.) ! 246: (=& (cadadr newline) #/L) ! 247: (=& (caddadr newline) #/e)) ! 248: then (msg (P outfile) ".Le" N) ! 249: (return nil)) ! 250: (if EOF then (return nil))) ! 251: (setq lines (cons newline lines)))) ! 252: ! 253: ! 254: ;--- getline :: read in new line and return structure: ! 255: ; (spaces chars) ! 256: ; spaces is a fixnum giving the number of spaces before the first ! 257: ; non-blank on the line. ! 258: ; chars is the list of characters appearing on the line, in order. ! 259: ; ! 260: (defun getline nil ! 261: (do ((col 1) ! 262: (spaces 0) ! 263: (chars nil) ! 264: (spacemode t) ! 265: (newc (tyi inport) (tyi inport) )) ! 266: (nil) ! 267: (if (=& #\eof newc) ! 268: then (if (null chars) ! 269: then (setq EOF t) ! 270: (return nil) ! 271: else (setq newc #\lf))) ! 272: (if (=& #\lf newc) ! 273: then (if (null chars) ! 274: then ; for totally blank lines return a large ! 275: ; space count so this won't be used for tags ! 276: (return (list space-count nil)) ! 277: else (return (list spaces (nreverse chars))))) ! 278: (if (=& #\ff newc) ! 279: then (return (list spaces (nreverse (cons newc chars))))) ! 280: (if spacemode ! 281: then (if (=& #\sp newc) ! 282: then (setq spaces (1+ spaces)) ! 283: elseif (=& #\tab newc) ! 284: then (setq spaces (* (/ (+ spaces 8) 8) 8)) ! 285: else (setq spacemode nil ! 286: chars (list newc))) ! 287: else (setq chars (cons newc chars))))) ! 288: ! 289: ! 290: ;--- flushlines ! 291: ; go back on all lines and determine where to put tags and reference ! 292: ; tags. ! 293: ; ! 294: (defun flushlines nil ! 295: (let (thistag tagref rlines tagloc) ! 296: (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 ! 297: 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 ! 298: 1 2 3 4 5 6 7 8 9 0)) ! 299: (setq tagref nil tagloc nil rlines nil) ! 300: (do ((xx lines (cdr xx)) ! 301: (thistagloc nil nil) ! 302: (pendingtags) ! 303: (thistagref)) ! 304: ((null xx)) ! 305: (setq rlines (cons (car xx) rlines) ! 306: spaces (caar xx) ! 307: thistag (alloctag)) ! 308: ; determine which of the pending tags we can insert at this level ! 309: (do ((yy pendingtags (cdr yy))) ! 310: ((or (null yy) (>& spaces (caar yy))) ! 311: (setq pendingtags yy)) ! 312: (setq thistagloc (cons (car yy) thistagloc))) ! 313: (setq tagloc (cons thistagloc tagloc)) ! 314: ; free up the tags we allocated at this level. ! 315: (mapc '(lambda (x) (freetag (cadr x))) thistagloc) ! 316: ; ! 317: ; we only need to refer to a tags at this level if ! 318: ; we are not at the left edge of the paper ! 319: ; ! 320: (if (and (greaterp spaces 0) (cdr xx)) ! 321: then (setq tagref (cons thistag tagref)) ! 322: (setq pendingtags (addtotags spaces thistag pendingtags)) ! 323: else (setq tagref (cons nil tagref)))) ! 324: (if debug then (msg " **tagref = " tagref N " **tagloc = " tagloc N)) ! 325: ; ! 326: ; print out the lines. ! 327: ; the lines we want to print are in the list rlines. They are ! 328: ; in the correct order. ! 329: ; ! 330: (do ((yy rlines (cdr yy)) ! 331: (commentmode nil nil) ! 332: (escapemode nil nil)) ! 333: ((null yy)) ! 334: ; first print out spaces ! 335: (setq sps (caar yy) ! 336: chs (cadar yy) ! 337: tls (car tagloc) ! 338: trname (car tagref)) ! 339: (headercheck sps chs) ! 340: (if debug ! 341: then (msg " spaces " sps N " chs " chs N ! 342: " tagloc " (car tagloc) N " tagref " (car tagref) N)) ! 343: (setq spout 0) ! 344: ; if there are characters on this line, print out ! 345: ; leading spaces ! 346: (if chs ! 347: then (do () ! 348: ((eq spout sps)) ! 349: (tyo #\sp outfile) ! 350: (setq spout (1+ spout))) ! 351: ! 352: (if trname then (tagrefprint trname))) ! 353: ! 354: (do ((xx chs (cdr xx))) ! 355: ((null xx) ! 356: (if (and tls (not (<& (caar tls) spout))) ! 357: then (do ((i spout (1+ i))) ! 358: ((null tls)) ! 359: (if (=& (caar tls) i) ! 360: then (taglocprint (cadar tls)) ! 361: (setq tls (cdr tls))))) ! 362: (if commentmode then (msg (P outfile) "\\fP")) ! 363: (terpr outfile)) ! 364: (if (and tls (eq (caar tls) spout)) ! 365: then (taglocprint (cadar tls)) ! 366: (setq tls (cdr tls))) ! 367: (if (and (not escapemode) ! 368: (null commentmode) ! 369: (=& #/; (car xx))) ! 370: then (msg (P outfile) "\\fI") ! 371: (setq commentmode t) ! 372: elseif (=& #/\ (car xx)) ! 373: then (tyo #/\ outfile)) ; escape backslashes ! 374: (if (memq (car xx) '(#/\ #//)) ! 375: then (setq escapemode t) ! 376: else (setq escapemode nil)) ! 377: (if (=& (car xx) #\ff) ! 378: then (msg (P outfile) N ".bp" N) ! 379: else (tyo (car xx) outfile)) ! 380: (setq spout (1+ spout))) ! 381: (setq tagloc (cdr tagloc) ! 382: tagref (cdr tagref))))) ! 383: ! 384: ! 385: ; headercheck :: check if this is a function declaration. ! 386: ; currently this means that there are no more than 2 spaces before ! 387: ; the line begins and that the line begins with (defxxx <name>) ! 388: (defun headercheck (spaces chars) ! 389: (if (<& spaces 3) ! 390: then (if (setq rest (match chars '(#/( #/d #/e #/f))) ! 391: then (setq funcname (skippastblkn rest)) ! 392: (if (and funcname LabelFunctions) ! 393: then (msg (P outfile) ".Lf " funcname N))))) ! 394: ! 395: ;--- match :: match lists ! 396: ; list1 - list of characters (fixnum rep) ! 397: ; list2 - master list of characters (fixnum rep) ! 398: ; list2 should be shorter than list1. If list2 is a substring of list1 ! 399: ; then the rest of list1 will be returned. Otherwise nil is returned. ! 400: ; ! 401: (defun match (list1 list2) ! 402: (cond ((null list1) nil) ! 403: ((null list2) list1) ! 404: ((or (eq (car list1) (car list2)) ! 405: (eq (car list1) (uppercase (car list2)))) ! 406: (match (cdr list1) (cdr list2))) ! 407: (t nil))) ! 408: ! 409: ;--- uppercase :: convert fixnum rep to upper case ! 410: ; char - fixnum representation of character ! 411: ; convert character to upper case. ! 412: ; ! 413: (defun uppercase (ch) ! 414: (if (and (not (<& ch #/a)) (not (>& ch #/z))) ! 415: then (- ch #.(- #/a #/A)))) ! 416: ! 417: ! 418: ! 419: ;--- skippastblnk :: skip to and past blank field and return following name ! 420: ; list - list of characters (fixnums) ! 421: ; ! 422: ; We skip past all non blanks then all blanks and finally implode the next ! 423: ; word after that and return it. ! 424: ; ! 425: ; bug- we can't tell the difference between a function named nil and ! 426: ; no valid function, but then again you can't have a function named nil. ! 427: ; ! 428: (defun skippastblkn (list) ! 429: (let (res) ! 430: ; skip to first blank ! 431: (do () ! 432: ((null list) nil) ! 433: (if (=& (car list) #\sp) then (return nil)) ! 434: (setq list (cdr list))) ! 435: ; skip to first non-blank ! 436: (do () ! 437: ((null list) nil) ! 438: (if (not (=& (car list) #\sp)) then (return nil)) ! 439: (setq list (cdr list))) ! 440: ; collect non blanks ! 441: (if list ! 442: then (do () ! 443: ((null list)) ! 444: (if (and (=& #\lpar (car list)) ! 445: (null res)) ! 446: then (setq list (cdr list)) ; form like "defun (foo ..)" ! 447: elseif (or (=& #\lpar (car list)) ! 448: (=& #\rpar (car list)) ! 449: (=& #\sp (car list))) ! 450: then (return nil) ! 451: else (setq res (cons (car list) res)) ! 452: (setq list (cdr list)))) ! 453: (if res then (implode (nreverse res)))))) ! 454: ! 455: ; ! 456: ; add (spaces character) to list so that the spaces number are in ! 457: ; ascending order. ! 458: ; ! 459: (defun addtotags (spaces character oldlist) ! 460: (if (or (null oldlist) (>& spaces (caar oldlist))) ! 461: then (cons (list spaces character) oldlist) ! 462: else (do ((prevtag oldlist (cdr prevtag)) ! 463: (thistag (cdr oldlist) (cdr thistag))) ! 464: ((or (null thistag) (>& spaces (caar thistag))) ! 465: (setq thistag (cons (list spaces character) thistag)) ! 466: (rplacd prevtag thistag))))) ! 467: ! 468: (defun inittagslist (list) ! 469: (setq tagsleft list)) ! 470: ! 471: (defun alloctag nil ! 472: (if (null tagsleft) ! 473: then (msg "Out of tags, aauuuuggh " N) ! 474: (exit) ! 475: else (prog1 (car tagsleft) (setq tagsleft (cdr tagsleft))))) ! 476: ! 477: (defun freetag (tagname) ! 478: (setq tagsleft (cons tagname tagsleft))) ! 479: ! 480: ! 481: (defun taglocprint (name) ! 482: (msg (P outfile) "\\k" name)) ! 483: ! 484: ! 485: (defun tagrefprint (name) ! 486: (msg (P outfile) "\\h'|\\n" name "u'")) ! 487: ! 488: ! 489: ;---new stuff ! 490: ; ! 491: ;--- programs deal in lineblk's ! 492: ; A lineblk has these components: ! 493: ; class : normal or comment ! 494: ; comment is a line beginning with ;, in which case it is ! 495: ; not counted as far as spacing goes. ! 496: ; spaces : number of spaces before first useful info ! 497: ; dead : list of dead linblk's, that is those ready to print but ! 498: ; waiting for this line to be done. ! 499: ; tagref: tag to go to at the beginning of this line ! 500: ; tagloc : tags defined on this line ! 501: ; chars : list of characters to print ! 502: ! 503: (defun make-lineblk (class spaces chars) ! 504: (list class spaces nil nil nil chars)) ! 505: (defmacro get:class (lineblk) `(car ,lineblk)) ! 506: (defmacro set:class (lineblk val) `(setf (get:class ,lineblk) ,val)) ! 507: (defmacro get:spaces (lineblk) `(cadr ,lineblk)) ! 508: (defmacro set:spaces (lineblk val) `(setf (get:spaces ,lineblk) ,val)) ! 509: (defmacro get:dead (lineblk) `(caddr ,lineblk)) ! 510: (defmacro set:dead (lineblk val) `(setf (get:dead ,lineblk) ,val)) ! 511: (defmacro get:tagref (lineblk) `(cadddr ,lineblk)) ! 512: (defmacro set:tagref (lineblk val) `(setf (get:tagref ,lineblk) ,val)) ! 513: (defmacro get:tagloc (lineblk) `(caddddr ,lineblk)) ! 514: (defmacro set:tagloc (lineblk val) `(setf (get:tagloc ,lineblk) ,val)) ! 515: (defmacro get:chars (lineblk) `(cadddddr ,lineblk)) ! 516: (defmacro set:chars (lineblk val) `(setf (get:chars ,lineblk) ,val)) ! 517: ! 518: ! 519: (defun vlp-interrupt-routine (sig) ! 520: (if (and (boundp 'outfilename) outfilename) ! 521: then (sys:unlink outfilename)) ! 522: (exit 1))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.