home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / lisp / liszt / lxref.l < prev    next >
Encoding:
Text File  |  1984-02-02  |  15.0 KB  |  508 lines

  1. (setq rcs-lxref-ident
  2.    "$Header: lxref.l,v 1.2 84/02/03 08:04:37 jkf Exp $")
  3.  
  4. ;------   lxref: lisp cross reference program        
  5. ;-- author: j foderaro
  6. ;  This program generates a cross reference listing of a set of one or
  7. ; more lisp files.  It reads the output of cross reference files 
  8. ; generated by the compiler.  These files usually have the extension .x .
  9. ; the .x files are lisp readable.  There format is:
  10. ; The first s-expression is (File  <filename>) where <filename> is the
  11. ; name of the lisp source file.
  12. ; Then there is one s-expression for each function (including macros)
  13. ; which is defined in the file.  The car of each expression is the function
  14. ; name, the cadr is the function type and the cddr is a list of those
  15. ; functions called
  16. ; lxref can be run from the command level
  17. ; % lxref foo.x bar.x
  18. ; or in this way
  19. ; % lxref
  20. ; -> (lxref foo.x bar.x)
  21. ;
  22. ; There is one option, that is changing the ignorelevel.  If a function
  23. ; is called by more than ignorelevel functions then all those functions
  24. ; are listed, instead a summary of the number of calls is printed.  This
  25. ; is useful for preventing  the printing of massive lists for common
  26. ; system functions such as setq.
  27. ; To change the ignorelevel to 40 you would type:
  28. ;
  29. ; % lxref -40 foo.x bar.x
  30. ;
  31. ;; internal data structures used in lxref:
  32. ;   funcs : list of functions mentioned either as caller or as callee
  33. ;  on each function in funcs, the property list contains some of these
  34. ;  indicators:
  35. ;    i-seen : always contains t [this is so we can avoid (memq foo funcs)
  36. ;    i-type : list of the types this function was declared as. In 1-1
  37. ;         corresp with i-home
  38. ;    i-home : list of files this function was declared in. In 1-1 corresp
  39. ;             with i-type
  40. ;    i-callers: list of functions calling this function
  41.  
  42.  
  43.  
  44.  
  45.  
  46. ; insure we have plenty of space to grow into
  47. (opval 'pagelimit 9999)
  48.  
  49.  
  50. (declare (special xref-readtable width ignorefuncs ignorelevel readtable 
  51.           user-top-level poport i-seen i-type i-callers docseen
  52.           i-Chome i-Doc i-home funcs
  53.           callby-marker debug-mode
  54.           anno-off-marker liszt-internal
  55.           anno-on-marker))
  56.  
  57. (setq ignorelevel 50)
  58. (setq callby-marker   (exploden ";.. ")    
  59.       anno-off-marker (exploden ";.-")    
  60.       anno-on-marker  (exploden ";.+"))    
  61.  
  62. ; internal liszt functions
  63. (setq liszt-internal '(Internal-bcdcall liszt-internal-do))
  64.  
  65. ;--- xrefinit :: called automatically upon startup
  66. ;
  67. (def xrefinit
  68.    (lambda nil
  69.       (let ((args (command-line-args))
  70.         (retval))
  71.      ; readtable should be the same as it was when liszt wrote
  72.      ; the xref file
  73.      (if args
  74.         then (signal 2 'exit)    ; die on interrupt
  75.          (signal 15 'exit)     ; die on sigterm
  76.          (setq user-top-level nil)
  77.          (let ((retval (car (errset (funcall 'lxref args)))))
  78.             (exit (if retval thenret else -1)))
  79.         else (patom "Lxref - lisp cross reference program")
  80.          (terpr poport)
  81.          (setq user-top-level nil)))))
  82.  
  83. (setq user-top-level 'xrefinit)
  84.  
  85. ;--- lxref :: main function
  86. ;
  87. (defun lxref fexpr (files)
  88.    (prog (p funcs i-seen i-home i-type i-callers filenm caller callee name
  89.         home type caller temp fname callers clength i-Chome i-Doc docseen
  90.         Chome Doc anno-mode debug-mode)
  91.  
  92.       (setq xref-readtable (makereadtable t))
  93.       (setq i-seen (gensym) i-home (gensym) i-type (gensym)
  94.         i-callers (gensym) i-Chome (gensym) i-Doc (gensym))
  95.  
  96.       ; check for the ignorelevel option
  97.       ; it must be the first option given.
  98.       ;
  99.       (If (and files (eq #/- (getcharn (car files) 1)))
  100.      then (If (fixp
  101.              (setq temp (readlist (cdr (explode (car files))))))
  102.          then (setq ignorelevel temp)
  103.               (setq files (cdr files))))
  104.  
  105.       ; process all files.  if a -a is seen, go into annotate mode.
  106.       ; otherwise generate an xref file.
  107.       ;
  108.       (do ((ii files (cdr ii)))
  109.       ((null ii))
  110.       (if (eq '-d (car ii))
  111.          then (setq debug-mode t)
  112.        elseif anno-mode
  113.          then (process-annotate-file (car ii))
  114.        elseif (eq '-a (car ii))
  115.          then (setq anno-mode t)
  116.          else (process-xref-file (car ii))))
  117.       (if (not anno-mode) (generate-xref-file))
  118.       (return 0)))
  119.  
  120. ;.. process-xref-file
  121. (defun illegal-file (name)
  122.    (msg "File " name " is not a valid cross reference file" N))
  123.  
  124. ;--- process-xref-file :: scan the information in an xref file
  125. ; if the name ends in .l then change it to .x
  126. ;
  127. ;.. lxref
  128. (defun process-xref-file (name)
  129.    (if debug-mode then (msg "process-xref-file: " name N))
  130.    (let (p fname filenm)
  131.       ; convert foo.l to foo.x
  132.       (setq fname (nreverse (exploden name)))
  133.       (If (and (eq #/l (car fname)) (eq #/. (cadr fname)))
  134.      then (setq fname (implode (nreverse (cons #/x (cdr fname)))))
  135.      else (setq fname name))
  136.  
  137.       ; now look for foo or foo.x
  138.       (If (and (null (errset (setq p (infile fname)) nil))
  139.            (null (errset (setq p (infile (concat fname ".x"))) nil)))
  140.      then (msg "Couldn't open " name N)
  141.      else (setq filenm (car (errset (read p))))
  142.           (If (dtpr filenm)
  143.          then (If (eq 'File (car filenm))
  144.              then (setq filenm (cadr filenm))
  145.                   (process-File p filenm)
  146.                elseif (eq 'Chome (car filenm))
  147.              then (process-Chome p)
  148.                elseif (eq 'Doc (car filenm))
  149.              then (setq docseen t) (process-Doc p)
  150.              else (illegal-file name))
  151.          else (illegal-file name))
  152.           (close p))))
  153.  
  154.  
  155. ;--- process-File :: process an xref file from liszt
  156. ;
  157. ;.. process-xref-file
  158. (defun process-File (p filenm)
  159.    (let ((readtable xref-readtable))
  160.       (do ((jj (read p) (read p))
  161.        (caller)
  162.        (callee))
  163.       ((null jj) (close p))
  164.       (setq caller (car jj))
  165.       (If (not (get caller i-seen))
  166.          then (putprop caller t i-seen)
  167.           (push caller funcs))    ; add to global list
  168.       ; remember home of this function (and allow multiple homes)
  169.       (push filenm (get caller i-home))
  170.  
  171.       ; remember type of this function (and allow multiple types)
  172.       (push (cadr jj) (get caller i-type))
  173.  
  174.       ; for each function the caller calls
  175.       (do ((kk (cddr jj) (cdr kk)))
  176.           ((null kk))
  177.           (setq callee (car kk))
  178.           (If (not (get callee i-seen)) then (putprop callee t i-seen)
  179.           (push callee funcs))
  180.           (push (cons caller filenm) (get callee i-callers))))))
  181.  
  182. ;.. process-xref-file
  183. (defun process-Chome (p)
  184.    (do ((jj (read p) (read p))
  185.     (caller))
  186.        ((null jj) (close p))
  187.        (setq caller (car jj))
  188.        (If (not (get caller i-seen))
  189.        then (putprop caller t i-seen)
  190.        (push caller funcs))    ; add to global list
  191.        ; remember home of this function (and allow multiple homes)
  192.        (putprop caller (cons (cdr jj) (get caller i-Chome)) i-Chome)))
  193.  
  194. ;--- process-Doc :: process a Doc file
  195. ;
  196. ; A doc file begins with an entry (Doc).
  197. ; subsequent entries are (Name File)  and this means that function
  198. ; Name is defined in file File.  This type of file is generated
  199. ; by a sed and awk script passing over the franz manual. (see the
  200. ; Makefile in the doc directory).
  201. ;
  202. ;.. process-xref-file
  203. (defun process-Doc (p)
  204.    (do ((jj (read p) (read p))
  205.     (caller))
  206.        ((null jj) (close p))
  207.        (setq caller (car jj))
  208.        (If (not (get caller i-seen))
  209.        then (putprop caller t i-seen)
  210.        (push caller funcs))    ; add to global list
  211.        ; remember home of this function (and allow multiple homes)
  212.        (putprop caller (cons (cadr jj) (get caller i-Doc)) i-Doc)))
  213.  
  214. ;.. generate-xref-file
  215. (defun terprchk (wid)
  216.   (cond ((> (setq width (+ wid width)) 78.) 
  217.      (terpr)
  218.      (patom "    ")
  219.      (setq width (+ 8 wid)))))
  220.  
  221. ; determine type of function
  222. ;.. generate-xref-file
  223. (defun typeit (fcn)
  224.   (cond ((bcdp fcn) (getdisc fcn))
  225.     ((dtpr fcn) (car fcn))))
  226.  
  227.  
  228. ;.. lxref
  229. (defun generate-xref-file ()
  230.    ; sort alphabetically
  231.    (setq funcs (sort funcs 'alphalessp))
  232.  
  233.    ; now print out the cross reference
  234.    (do ((ii funcs (cdr ii))
  235.     (name) (home) (type) (callers) (Chome) (Doc) (clength))
  236.        ((null ii))
  237.        (setq name (car ii)
  238.          home (get name i-home)
  239.          type (get name i-type)
  240.          callers (get name i-callers)
  241.          Chome (get name i-Chome)
  242.          Doc (get name i-Doc))
  243.  
  244.        (If (lessp (setq clength (length callers)) ignorelevel)
  245.       then (setq callers (sortcar callers 'alphalessp)))
  246.  
  247.        (do ((xx Chome (cdr xx)))
  248.        ((null xx))
  249.        (setq home (cons (concat "<C-code>:" (caar xx))
  250.                 home)
  251.          type (cons (cadar xx) type)))
  252.  
  253.        (If (null home)
  254.       then (setq home (If (getd name)
  255.                  then (setq type
  256.                     (ncons (typeit (getd name))))
  257.                   '(Franz-initial)
  258.                elseif (memq name liszt-internal)
  259.                  then '(liszt-internal-function)
  260.                elseif (get name 'autoload)
  261.                  then (list (concat "autoload: "
  262.                         (get name 'autoload)))
  263.                  else '(Undefined))))
  264.  
  265.        (patom name)
  266.        (patom "    ")
  267.  
  268.  
  269.        (If (null (cdr type))
  270.       then (patom (car type))
  271.            (patom "    ")
  272.            (patom (car home))
  273.       else (patom "Mult def: ")
  274.            (mapcar '(lambda (typ hom)
  275.                (patom typ)
  276.                (patom " in ")
  277.                (patom hom)
  278.                (patom ", "))
  279.                type
  280.                home))
  281.  
  282.  
  283.        (If docseen
  284.       then (If Doc then (msg "  [Doc: " (If (cdr Doc) then Doc
  285.                            else (car Doc)) "]")
  286.           else (msg "  [**undoc**]")))
  287.        (If (null callers) then (msg "    *** Unreferenced ***"))
  288.        (terpr)
  289.        (patom "    ")
  290.        (cond ((null callers))
  291.          ((not (lessp clength ignorelevel))
  292.           (patom "Called by ")
  293.           (print clength)
  294.           (patom " functions"))
  295.          (t (do ((jj callers (cdr jj))
  296.              (calle)
  297.              (width 8))
  298.             ((null jj))
  299.             ; only print name if in same file
  300.             (setq calle (caar jj))
  301.             (cond ((memq (cdar jj) home)
  302.                (terprchk (+ (flatc calle) 2))
  303.                (patom calle))
  304.               (t (terprchk (+ (flatc calle) 6 (flatc (cdar jj))))
  305.                  (patom calle)
  306.                  (patom " in ")
  307.                  (patom (cdar jj))))
  308.             (If (cdr jj) then (patom ", ")))))
  309.        (terpr)
  310.        (terpr)
  311.        botloop ))
  312.  
  313.  
  314. ;--- annotate code
  315.  
  316.  
  317.            
  318. ;--- process-annotate-file :: anotate a file
  319. ;
  320. ;.. lxref
  321. (defun process-annotate-file (filename)
  322.    (let (sourcep outp)
  323.       ; make sure file exists and write annotate file as a
  324.       ; file with the prefix #,
  325.       (if (null (errset (setq sourcep (infile filename))))
  326.      then (msg "will ignore that file " N)
  327.      else ; will write to file.A (erasing the final l)
  328.           (let ((filen (concat "#," filename)))
  329.          (setq outp (outfile filen))
  330.          (anno-it sourcep outp)
  331.          (close outp)
  332.          (close sourcep)
  333.          ; now mv the original filename to #dfilename
  334.          ; and the annotated file to the original file
  335.          (let ((oldcopy (concat "#." filename)))
  336.             (if (null (errset
  337.                  (progn (if (probef oldcopy)
  338.                        then (sys:unlink oldcopy))
  339.                     (sys:link filename oldcopy)
  340.                     (sys:unlink filename)
  341.                     (sys:link filen filename)
  342.                     (sys:unlink filen))))
  343.                then (msg "An error occured while mving files around "
  344.                  N
  345.                  "files possibly affected "
  346.                  filename oldcopy filen)))))))
  347.  
  348.  
  349. ;.. process-annotate-file
  350. (defun anno-it (inp outp)
  351.    (do ((xx (read-a-line inp) (read-a-line inp))
  352.     (anno-it t))
  353.        ((null xx))
  354.        (if (match xx 1 callby-marker)  ; flush anno lines
  355.       then (flush-a-line outp inp)
  356.     elseif (match xx 1 anno-off-marker)
  357.       then (setq anno-it nil)    ; ';#-'  turns off annotating
  358.            (write-a-line xx outp inp)
  359.     elseif (match xx 1 anno-on-marker)
  360.       then (setq anno-it t)
  361.            (write-a-line xx outp inp)
  362.       else (if anno-it then (anno-check xx outp))
  363.            (write-a-line xx outp inp))))
  364.  
  365.  
  366. ;;; file reading code for annotate function
  367. ; lines are read with (read-a-line port).  It will read up to the
  368. ; first 127 characters in the line, returning a hunk whose cxr 0 is the
  369. ; max(index) + 1 of the characters in the hunk.  the oversize-line flag
  370. ; will be set if there are still more character to be read from this line.
  371. ;
  372. ; the line should be printed by calling (print-a-line buffer) or if it isn't
  373. ; to be printed, (flush-a-line) should be called (which will check the
  374. ; oversize-line flag and flush unread input too).
  375. ;
  376. (declare (special inp-buffer oversize-line))
  377.  
  378. (setq inp-buffer (makhunk 128))
  379.  
  380. ;.. anno-it
  381. (defun read-a-line (port)
  382.    (setq oversize-line nil)
  383.    (do ((i 1 (1+ i))
  384.     (ch (tyi port) (tyi port)))
  385.        ((or (eq #\newline ch)
  386.         (eq #\eof ch))
  387.     (if (or (eq #\newline ch) (>& i 1))
  388.        then (rplacx 0 inp-buffer i)        ; store size
  389.         inp-buffer            ; return buffer
  390.        else nil))    ; return nil upon eof
  391.        (rplacx i inp-buffer ch)
  392.        (if (>& i 126)
  393.       then (setq oversize-line t)
  394.            (rplacx 0 inp-buffer (1+ i))
  395.            (return inp-buffer))))
  396.  
  397. ;--- write-a-line :: write the given buffer and check for oversize-line
  398. ;
  399. ;.. anno-it
  400. (defun write-a-line (buf oport iport)
  401.    (do ((max (cxr 0 buf))
  402.     (i 1 (1+ i)))
  403.        ((not (<& i max))
  404.     (if oversize-line
  405.         then (oversize-check oport iport t)
  406.         else (terpr oport)))
  407.        (tyo (cxr i buf) oport)))
  408.  
  409. ;.. anno-it
  410. (defun flush-a-line (oport iport)
  411.    (oversize-check oport iport nil))
  412.  
  413. ;.. flush-a-line, write-a-line
  414. (defun oversize-check (oport iport printp)
  415.    (if oversize-line
  416.       then (do ((ch (tyi iport) (tyi iport)))
  417.            ((or (eq ch #\eof) (eq ch #\newline))
  418.         (cond ((and printp (eq ch #\newline))
  419.                (tyo ch oport))))
  420.            (if printp then (tyo ch oport)))))
  421.  
  422.     
  423.                
  424. ;.. anno-it
  425. (defun anno-check (buffer outp)
  426.    (if (match buffer 1 '(#\lpar #/d #/e #/f))
  427.       then (let (funcname)
  428.           (if (setq funcname (find-func buffer))
  429.           (let ((recd (get funcname i-callers)))
  430.              (if recd
  431.             then (printrcd recd outp)))))))
  432.  
  433. ;--- printrcd :: print a description
  434. ;
  435. ;.. anno-check
  436. (defun printrcd (fcns port)
  437.    (let ((functions (sortcar fcns 'alphalessp)))
  438.       (print-rec functions port 0)))
  439.  
  440. ;.. print-rec, printrcd
  441. (defun print-rec (fcns p wide)
  442.    (if fcns
  443.       then (let ((size (flatc (caar fcns))))
  444.           (if (>& (+ size wide 2) 78)
  445.          then (msg (P p) N )
  446.               (setq wide 0))
  447.           (if (=& wide 0)
  448.          then (mapc '(lambda (x) (tyo x p)) callby-marker)
  449.               (setq wide (length callby-marker)))
  450.           (if (not (=& wide 4))
  451.          then (msg (P p) ", ")
  452.               (setq wide (+ wide 2)))
  453.           (msg (P p) (caar fcns))
  454.           (print-rec (cdr fcns) p (+ wide size 2)))
  455.       else (msg (P p) N)))
  456.  
  457.               
  458.             
  459. ;--- match :: try to locate pattern in buffer
  460. ; start at 'start' in buf.
  461. ;.. anno-check, anno-it, match
  462. (defun match (buf start pattern)
  463.    (if (null pattern)
  464.       then t
  465.     elseif (and (<& start (cxr 0 buf))
  466.         (eq (car pattern) (cxr start buf)))
  467.       then (match buf (1+ start) (cdr pattern))))
  468.  
  469. ;--- find-func :: locate function name on line
  470. ;
  471. ;.. anno-check
  472. (defun find-func (buf)
  473.    ; first locate first space or tab
  474.    (do ((i 1 (1+ i))
  475.     (max (cxr 0 buf))
  476.     (die))
  477.        ((or (setq die (not (<& i max)))
  478.         (memq (cxr i buf) '(#\space #\tab)))
  479.     (if die
  480.        then nil    ; can find it, so give up
  481.        else ; find first non blank
  482.         (do ((ii i (1+ ii)))
  483.             ((or (setq die (not (<& ii max)))
  484.              (not (memq (cxr ii buf) '(#\space #\tab))))
  485.              (if (or die (eq (cxr ii buf) #\lpar))
  486.             then nil
  487.             else ; fid first sep or left paren
  488.                  (do ((iii (1+ ii) (1+ iii)))
  489.                  ((or (not (<& iii max))
  490.                       (memq (cxr iii buf)
  491.                         '(#\space #\tab #\lpar)))
  492.                   (implode-fun buf ii (1- iii)))))))))))
  493.  
  494. ;--- implode-fun :: return implode of everything between from and to in buf
  495. ;
  496. ;.. find-func
  497. (defun implode-fun (buf from to)
  498.    (do ((xx (1- to) (1- xx))
  499.     (res (list (cxr to buf)) (cons (cxr xx buf) res)))
  500.        ((not (<& from xx))
  501.     (implode (cons (cxr from buf) res)))))
  502.  
  503.  
  504.  
  505.  
  506.  
  507.