Annotation of 43BSD/ucb/vlp/vlp.l, revision 1.1

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))

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.