home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume01 / cxref < prev    next >
Encoding:
Internet Message Format  |  1988-09-11  |  44.3 KB

  1. From: linus!gatech!arnold
  2. Date:     17 Jan 85 16:30:36-EST (Thu)
  3. Original-From:     Arnold Robbins <arnold@gatech>
  4. Subject:  Cxref -- C cross referencer
  5.  
  6. Here is the latest version of my 'cxref' program, ready for posting.  It
  7. has been posted to net.sources several times before; This version has
  8. one or two small enhancements, and should port across Unix versions fairly
  9. easily.
  10.  
  11. Arnold Robbins
  12. CSNET:    arnold@gatech
  13. ARPA:    arnold%gatech.csnet@csnet-relay.arpa
  14. UUCP:    { akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold
  15.  
  16. ------------------ tear here --------------------
  17. #! /bin/sh
  18. echo 'extracting --- README' 1>&2
  19. cat > README << 'End of README'
  20. README:
  21.  
  22. This directory contains the files for 'cxref', a C language cross
  23. referencing program.
  24.  
  25. The makefile will build the program. Use 'make install' to put a copy in
  26. the right places.  Cxref is a driver, and goes in DESTDIR, which will be your
  27. local bin of choice.  LIB is where the programs go that do the work. The
  28. makefile makes the directory /usr/local/lib/cxref (i.e. LIB) to hold the
  29. programs.  The cxref driver is dependant on where LIB is.  I have them set to
  30. use my BIN.  BIN is taken from the environment, since I use the UNIX 4.0 make.
  31. SORT is the full pathname for the Unix sort program, sometimes /bin/sort,
  32. other times /usr/bin/sort.  Edit the makefile to set everything up properly.
  33.  
  34. System III and V users should edit the file 'basename.c' to change the
  35. call to 'rindex' to 'strrchr'.
  36.  
  37. The flow of information between programs is shown below.
  38. I suggest that you run the programs separately, successively adding the next
  39. program in a particular pipeline, to see how the information is transformed.
  40. The outline below of the flow of control does not necessarily show all
  41. the arguments that each program requires; see the source code to
  42. be sure, when you run the programs by hand.
  43.  
  44. With some work in the cscan.l and cxref.c files, this program could be
  45. easily made to cross reference other languages.
  46.  
  47. Here is a list of the files, and what they contain:
  48.  
  49. README        --- this file.
  50. cxref.1        --- man page.
  51. makefile    --- the makefile.
  52.  
  53. cxref.c        --- driver, calls all the other programs, does arg handling.
  54. old.cxref.c    --- old version, used the shell to do the dirty work.
  55.             (this file can probably be deleted.)
  56.  
  57. constdefs.h    --- header file, used by cscan.l and cxrfilt.c.
  58.  
  59. cscan.l        --- does the work of finding indentifiers and contsants.
  60. docxref.c    --- main program and some other stuff to drive lex.
  61.  
  62. cxrfilt.c    --- filters int and floats to their own files.
  63.             also puts ints and floats back together after sorting.
  64.  
  65. fmtxref.c    --- formats output for printing.
  66.  
  67. SORT[1-3]    --- shell files to save typing during testing and development.
  68.  
  69.  
  70. For development, the flow of programs is:
  71.  
  72.     docxref files | SORT1 | cxrfilt | fmtxref
  73.     SORT2 < tempfile1 | cxrfilt -i | fmtxref
  74.     SORT3 < tempfile2 | cxrfilt -f | fmtxref
  75.  
  76. Arnold Robbins, Information and Computer Science, Georgia Tech
  77.     gatech!arnold
  78. January 1985.
  79. Copyright (c) 1985 by Arnold Robbins.
  80. All rights reserved.
  81. End of README
  82. echo 'extracting --- SORT1' 1>&2
  83. cat > SORT1 << 'End of SORT1'
  84. # SORT1 -- do the first sorting job for cxref.
  85. #
  86. # the purpose of this file is to save typing during testing and development.
  87. #
  88. # Arnold Robbins, Information and Computer Science, Georgia Tech
  89. #    gatech!arnold
  90. # Copyright (c) 1984 by Arnold Robbins.
  91. # All rights reserved.
  92. # This program may not be sold, but may be distributed
  93. # provided this header is included.
  94.  
  95. exec sort -u +0b -2 +2n
  96. End of SORT1
  97. echo 'extracting --- SORT2' 1>&2
  98. cat > SORT2 << 'End of SORT2'
  99. # SORT2 -- do the second sorting job for cxref.
  100. #
  101. # the purpose of this file is to save typing during testing and development.
  102. #
  103. # Arnold Robbins, Information and Computer Science, Georgia Tech
  104. #    gatech!arnold
  105. # Copyright (c) 1984 by Arnold Robbins.
  106. # All rights reserved.
  107. # This program may not be sold, but may be distributed
  108. # provided this header is included.
  109.  
  110. exec sort -u +0n -1 +1b -2 +2n
  111. End of SORT2
  112. echo 'extracting --- SORT3' 1>&2
  113. cat > SORT3 << 'End of SORT3'
  114. # SORT3 -- do the third sorting job for cxref.
  115. #
  116. # the purpose of this file is to save typing during testing and development.
  117. #
  118. # Arnold Robbins, Information and Computer Science, Georgia Tech
  119. #    gatech!arnold
  120. # Copyright (c) 1984 by Arnold Robbins.
  121. # All rights reserved.
  122. # This program may not be sold, but may be distributed
  123. # provided this header is included.
  124.  
  125. exec sort -u +0n +1n -2 +2b -3 +3n
  126. End of SORT3
  127. echo 'extracting --- basename.c' 1>&2
  128. cat > basename.c << 'End of basename.c'
  129. /*
  130. ** basename.c
  131. **
  132. ** return the last portion of a path name.
  133. ** included by all the cxref component programs.
  134. **
  135. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  136. **    gatech!arnold
  137. ** Copyright (c) 1984 by Arnold Robbins.
  138. ** All rights reserved.
  139. ** This program may not be sold, but may be distributed
  140. ** provided this header is included.
  141. */
  142.  
  143. char *basename(str)    /* return last portion of a path name */
  144. char *str;
  145. {
  146.     char *cp, *rindex();    /* change to strrchr() for USG systems */
  147.  
  148.     if((cp = rindex(str, '/')) == NULL)
  149.         return(str);
  150.     else
  151.         return(++cp);
  152. }
  153. End of basename.c
  154. echo 'extracting --- constdefs.h' 1>&2
  155. cat > constdefs.h << 'End of constdefs.h'
  156. /*
  157. ** constdefs.h
  158. **
  159. ** definitions of keyletters for different constants.
  160. ** arbitrary, as long as char < string < int < float.
  161. **
  162. ** used by several of the cxref component programs.
  163. **
  164. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  165. **    gatech!arnold
  166. ** Copyright (c) 1984 by Arnold Robbins.
  167. ** All rights reserved.
  168. ** This program may not be sold, but may be distributed
  169. ** provided this header is included.
  170. **
  171. */
  172.  
  173. #define CHAR    'a'
  174. #define STRING    'b'
  175. #define INT    'c'
  176. #define FLOAT    'd'
  177. End of constdefs.h
  178. echo 'extracting --- cscan.l' 1>&2
  179. cat > cscan.l << 'End of cscan.l'
  180. /*
  181. ** cscan.l
  182. **
  183. ** Does the major work of removing identifiers and constants
  184. ** from the input stream, for Cxref. Its output is then extensively
  185. ** postprocessed.
  186. **
  187. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  188. **    gatech!arnold
  189. ** Copyright (c) 1984 by Arnold Robbins.
  190. ** All rights reserved.
  191. ** This program may not be sold, but may be distributed
  192. ** provided this header is included.
  193. */
  194.  
  195. %{
  196. extern int line_no;
  197. extern char *fname, *basename();
  198. %}
  199.  
  200. letter        [A-Za-z_]
  201. digit        [0-9]
  202.  
  203. %%
  204. int        |
  205. char        |
  206. float        |
  207. double        |
  208. struct        |
  209. union        |
  210. long        |
  211. short        |
  212. unsigned    |
  213. auto        |
  214. extern        |
  215. register    |
  216. typedef        |
  217. static        |
  218. goto        |
  219. return        |
  220. sizeof        |
  221. break        |
  222. continue           |
  223. if        |
  224. else        |
  225. for        |
  226. do        |
  227. while        |
  228. switch        |
  229. case        |
  230. default        |
  231. entry        |
  232. enum        |
  233. void        |
  234. define        |
  235. undef        |
  236. include        |
  237. ifdef        |
  238. ifndef        |
  239. defined        |
  240. endif        ;    /* ignore C and cpp keywords */
  241.  
  242. "<".+">"    ;    /* forget about include-file names */
  243.  
  244. "\n"        line_no++;
  245.  
  246. "/*"        {    /* get rid of comments */
  247.             register char c, c1;
  248.  
  249.           loop: while((c = input()) != '*' && c != 0)
  250.                 if(c == '\n')
  251.                     line_no++;
  252.  
  253.             if(c == 0)
  254.             {
  255.                 fprintf(stderr,
  256.                 "unexpected EOF in comment at line %d, file %s\n",
  257.                     line_no, basename(fname));
  258.                 exit(1);
  259.             }
  260.  
  261.             if((c1 = input()) != '/')
  262.             {
  263.                 unput(c1);    /* could be '*' before '/' */
  264.                 goto loop;
  265.             }
  266.         }
  267.  
  268. {letter}({letter}|{digit})*    outid();  /* what we actually want */
  269.  
  270. '[^\\']'        |
  271. '\\{digit}{1,3}'    |
  272. '\\[\\bfrnlt']'            outchar();
  273.  
  274. \"            {    /* collect quoted strings */
  275.                 register char c;
  276.                 register int i;
  277.  
  278.                 for(i = 1, c = input(); ; i++, c = input())
  279.                     switch (c) {
  280.                     case '"':
  281.                         yytext[i] = c;
  282.                         yytext[++i] = '\0';
  283.                         yyleng = i - 1;
  284.                         goto fini;
  285.                     
  286.                     case '\\':
  287.                         yytext[i] = '\\';
  288.                         yytext[++i] = input();
  289.                         if (yytext[i] == '\n')
  290.                         {
  291.                             line_no++;
  292.                             yytext[i] = 'N';
  293.                             /* make visible */
  294.                         }
  295.                         break;
  296.  
  297.                     case 0:
  298.                         fprintf(stderr,
  299.                     "unexpected EOF inside string at line %d, file %s\n",
  300.                             line_no, basename(fname));
  301.                         exit(1);
  302.                         break;
  303.  
  304.                     default:
  305.                         yytext[i] = c;
  306.                         break;
  307.                     }
  308.  
  309.                 fini:
  310.                     outstring();
  311.         }
  312.  
  313. [+-]?{digit}+[lL]?            |
  314. [+-]?0[Xx]({digit}|[a-fA-F])+[lL]?        outint();
  315.  
  316. [+-]?{digit}*"."{digit}+([Ee][+-]?{digit}+)?    |
  317. [+-]?{digit}+"."{digit}*([Ee][+-]?{digit}+)?    |
  318. [+-]?{digit}+[Ee][+-]?{digit}+                outfloat();
  319.  
  320. .            ;    /* delete everything else */
  321.  
  322. %%
  323.  
  324. yywrap()    /* wrap up for lex, return 1 */
  325. {
  326.     return(1);
  327. }
  328.  
  329. #include "constdefs.h"
  330.  
  331. extern char *fname;
  332. extern char *basename();
  333.  
  334. outchar()
  335. {
  336.     outtext(CHAR);
  337. }
  338.  
  339. outstring()
  340. {
  341.     outtext(STRING);
  342. }
  343.  
  344. outint()
  345. {
  346.     int i = strlen(yytext);
  347.  
  348.     /* handle long integer constants */
  349.  
  350.     if (yytext[i-1] == 'l' || yytext[i-1] == 'L')
  351.         yytext[i-1] = '\0';
  352.  
  353.     outtext(INT);
  354. }
  355.  
  356. outfloat()
  357. {
  358.     outtext(FLOAT);
  359. }
  360.  
  361. outtext(type)
  362. char type;
  363. {
  364.     printf("~%c%s\t%s\t%d\n", type, yytext, basename(fname), line_no);
  365. }
  366. End of cscan.l
  367. echo 'extracting --- cxref.1' 1>&2
  368. cat > cxref.1 << 'End of cxref.1'
  369. .TH CXREF 1 "Georgia Tech"
  370. .SH NAME
  371. cxref \- cross reference C source files
  372. .SH SYNOPSIS
  373. .B cxref
  374. [
  375. .B \-FSCcfis
  376. ] [
  377. .B \-w
  378. .IR width " ]"
  379. [files]
  380. .SH DESCRIPTION
  381. .PP
  382. .I Cxref
  383. reads the named C source files and produces on the standard output
  384. a cross reference of all the identifiers and constants in the files.
  385. Constants are integer constants (12, 0421, 0x1A),
  386. floating point constants (123.45, 0.2e-4),
  387. string constants ("this is a string\en"),
  388. and character constants ('a', '\e033').
  389. Identifiers, character constants, and string constants
  390. are sorted lexicographically, i.e. according to the machine collating
  391. sequence (7-bit ASCII on the Vax or the Pyramid).
  392. Integer and floating point constants are sorted numerically.
  393. The trailing 'l' or 'L' on long integer constants will not show
  394. up in the output listing.
  395. .PP
  396. If no files are named,
  397. .I cxref
  398. reads the standard input. For multiple files, the argument "\-"
  399. (a single dash) indicates that the standard input should be read
  400. at that point.
  401. .PP
  402. If arguments are given, they must come before any file names.
  403. .PP
  404. .I Cxref
  405. recognizes the following arguments:
  406. .RS
  407. .TP
  408. .B \-F
  409. Fold case in comparison.  By default, case is distinct in comparison of
  410. identifiers and string and character constants.
  411. .RI ( cxref
  412. simply passes the "\-F" option on to
  413. .IR sort (1)
  414. as "\-f".)
  415. .TP
  416. .B \-S
  417. Cross reference all files separately.
  418. The default action is to cross reference all named files together.
  419. .TP
  420. .B \-c
  421. Leave character constants out of the cross reference listing.
  422. .TP
  423. .B \-f
  424. Leave floating point constants out of the cross reference listing.
  425. .TP
  426. .B \-i
  427. Leave integer constants out of the cross reference listing.
  428. .TP
  429. .B \-s
  430. Leave string constants out of the cross reference listing.
  431. .TP
  432. .B \-C
  433. Leave
  434. .I all
  435. constants, character, string, integer, and floating point, out of
  436. the cross reference listing.
  437. By default, all types of constants are included in the cross reference.
  438. .TP
  439. .BI "\-w " width
  440. Make the output be
  441. .I width
  442. columns wide.
  443. The output width will never be less than 51 or more than 132 columns.
  444. .I Cxref
  445. silently adjusts incorrect settings to the nearest allowable setting.
  446. If no width is specified, the output will default to 80 columns wide.
  447. .RE
  448. .PP
  449. .IR Cxref " does " not
  450. include #include files, or expand macro definitions.  Files named
  451. in #include lines can be listed on the command line if they should
  452. also be cross referenced.
  453. .PP
  454. If a quoted string has an escaped newline in it (see ``The C Programming
  455. Language'', page 181, or Section 2.5 of the C Reference Manual),
  456. it will show up inside the string in the output listing as \eN.
  457. This is to make it visible to the programmer, and to keep the
  458. various filters which
  459. .I Cxref
  460. uses to actually do the work from getting terribly confused.
  461. .PP
  462. .I Cxref
  463. is best run in the background, with its output redirected into
  464. a file or the line printer spooler
  465. .IR lpr (1),
  466. since it reads all
  467. the named files, using
  468. .IR sort (1)
  469. as an intermediate pass.
  470. The sorting can take time which the user can probably put to more productive
  471. use.
  472. .SH DIAGNOSTICS
  473. .PP
  474. Self explanatory.
  475. .SH BUGS
  476. .PP
  477. Systems running UNIX 4.0 and later already have a program named
  478. .IR cxref .
  479. Therefore, on those systems, this program should be renamed.
  480. .PP
  481. .I Cxref
  482. does not do any formatting on its output (other than to
  483. insure that it writes the proper number of columns),
  484. so it should probably be run piping its output into
  485. .IR pr (1).
  486. .PP
  487. Floating point constants are converted to a common format for sorting,
  488. therefore they may appear in the output in a format different from
  489. (but numerically equivalent to) their form in the original source code.
  490. .SH "SEE ALSO"
  491. .IR lex (1),
  492. .IR lpr (1),
  493. .IR pr (1),
  494. .IR sort (1)
  495. .SH FILES
  496. .TP
  497. /tmp/cxr.$$.*
  498. temporary files for integer and floating point contstants.
  499. .I Cxref
  500. removes these files when it is through.
  501. .SH AUTHOR
  502. .PP
  503. .nf
  504. Arnold Robbins
  505. School of Information and Computer Science
  506. Georgia Institute of Technology
  507. Atlanta, Geogia  30332
  508.  
  509. UUCP:    gatech!arnold
  510. CSNET:    arnold@gatech
  511. ARPANET:    arnold%gatech.csnet@csnet-relay.arpa
  512. .fi
  513.  
  514. Copyright (c) 1984 by Arnold Robbins.
  515. All rights reserved.
  516. This program may not be sold, but may be distributed
  517. provided this notice is included.
  518. End of cxref.1
  519. echo 'extracting --- cxref.c' 1>&2
  520. cat > cxref.c << 'End of cxref.c'
  521. /*
  522. ** cxref.c
  523. **
  524. ** C driver for Cxref program.
  525. ** does argument handling, then builds the right
  526. ** shell commands for passing to the system() routine.
  527. **
  528. ** Set up the argument vectors ourselves, the i/o with a pipe()
  529. ** call, and do all the forking and execing ourselves.
  530. **
  531. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  532. **    gatech!arnold
  533. ** Copyright (c) 1984 by Arnold Robbins
  534. ** All rights reserved
  535. ** This program may not be sold, but may be distributed
  536. ** provided this header is included.
  537. */
  538.  
  539. #include <stdio.h>
  540. #include <ctype.h>
  541. #include <signal.h>
  542.  
  543. #define TRUE    1
  544. #define FALSE    0
  545.  
  546. char name[BUFSIZ];    /* save command name */
  547.  
  548. int xargc;        /* make argc and argv available globally */
  549. char **xargv;
  550.  
  551. int width = 0;        /* output width */
  552.  
  553. int sepflag = FALSE;    /* do each one separately */
  554.  
  555. int iflag = TRUE;    /* print out ints */
  556. int fflag = TRUE;    /* print out floats */
  557. int cflag = TRUE;    /* print out chars */
  558. int sflag = TRUE;    /* print out strings */
  559. int Fflag = FALSE;    /* fold case in indentifiers */
  560.  
  561. int ancestor;        /* id of this process, used by children */
  562.  
  563. char *filename();    /* turns "-" into "stdin" */
  564.  
  565. #define do_pipe(x)    if (pipe(x) < 0) { fprintf(stderr, "x: pipe failed\n");\
  566.                 fflush(stderr); exit (1); }
  567.  
  568. main(argc, argv)
  569. int argc;
  570. char **argv;
  571. {
  572.     int i;
  573.     int catchem();
  574.  
  575.     signal (SIGQUIT, catchem);
  576.     signal (SIGINT, catchem);
  577.  
  578.     strcpy (name, filename(argv[0]));
  579.  
  580.     ancestor = getpid();
  581.  
  582.     for(argv++, argc--; argc > 0; argv++, argc--)
  583.         if (argv[0][0] != '-')
  584.             break;
  585.         else if(argv[0][1] == '\0')    /* filename of "-" */
  586.             break;
  587.         else
  588.             for(i = 1; argv[0][i] != '\0'; i++)
  589.             {
  590.                 switch(argv[0][i]) {
  591.                 case 'F':
  592.                     Fflag = TRUE;
  593.                     break;
  594.  
  595.                 case 'S':
  596.                     sepflag = TRUE;
  597.                     break;
  598.                 
  599.                 case 'C':
  600.                     /* leave out all constants */
  601.                     cflag =
  602.                     iflag =
  603.                     fflag =
  604.                     sflag = FALSE;
  605.                     break;
  606.  
  607.                 case 'c':
  608.                     cflag = FALSE;
  609.                     break;
  610.                 
  611.                 case 'i':
  612.                     iflag = FALSE;
  613.                     break;
  614.                 
  615.                 case 'f':
  616.                     fflag = FALSE;
  617.                     break;
  618.                 
  619.                 case 's':
  620.                     sflag = FALSE;
  621.                     break;
  622.                 
  623.                 case 'w':
  624.                     if (isdigit(argv[0][i+1]))
  625.                     {
  626.                         width = 0;
  627.                         for(i++; isdigit(argv[0][i]); i++)
  628.                             width = width * 10 + argv[0][i] - '0';
  629.                         i--;
  630.                     }
  631.                     else
  632.                     {
  633.                         width = atoi(argv[1]);
  634.                         argv++;
  635.                         argc--;
  636.                     }
  637.                     break;
  638.  
  639.                 default:
  640.                     usage();
  641.                     break;
  642.                 }
  643.             }
  644.     
  645.     if (width != 0)
  646.         if (width < 51)
  647.             width = 80;
  648.         else if (width > 132)
  649.             width = 132;
  650.  
  651.     xargc = argc;
  652.     xargv = argv;
  653.  
  654.     setargs();        /* set up various argv buffers */
  655.  
  656.     runprogs();        /* set up and run pipelines */
  657.  
  658.     exit (0);
  659. }
  660.  
  661. /* argv vectors for various commands */
  662.  
  663. char *docxref[BUFSIZ] = { "docxref" };    /* allows BUFSIZ - 2 files */
  664. char *cxrfilt[] = { "cxrfilt", NULL, NULL, NULL };
  665. char *fmtxref[] = { "fmtxref", NULL, NULL, NULL };
  666. char *sort1[] = { "sort", "-u", "+0b", "-2", "+2n", NULL, NULL };
  667. char *sort2[] = { "sort", "-u", "+0n", "-1", "+1b", "-2", "+2n", NULL };
  668. char *sort3[] = { "sort", "-u", "+0n", "+1n", "-2", "+2b", "-3", "+3n", NULL };
  669.  
  670. /* pipes to connect programs */
  671.  
  672. typedef int PIPE[2];
  673.  
  674. PIPE pipe1, pipe2, pipe3;
  675.  
  676. setargs()        /* initialize argv vectors */
  677. {
  678.     static char widthbuf[100];
  679.     static char pidbuf[100];
  680.  
  681.     if (width != 0)
  682.     {
  683.         fmtxref[1] = "-w";
  684.         sprintf(widthbuf, "%d", width);
  685.         fmtxref[2] = widthbuf;
  686.         fmtxref[3] = NULL;
  687.     }
  688.  
  689.     sprintf(pidbuf, "%d", getpid());
  690.  
  691.     if (Fflag)
  692.         sort1[5] = "-f";    /* fold case in identifiers */
  693.  
  694.     if (! cflag && sflag)
  695.     {
  696.         cxrfilt[1] = "-c";
  697.         cxrfilt[2] = pidbuf;
  698.         cxrfilt[3] = NULL;
  699.     }
  700.  
  701.     else if (cflag && ! sflag)
  702.     {
  703.         cxrfilt[1] = "-s";
  704.         cxrfilt[2] = pidbuf;
  705.         cxrfilt[3] = NULL;
  706.     }
  707.  
  708.     else if (! cflag && ! sflag)
  709.     {
  710.         cxrfilt[1] = "-cs";
  711.         cxrfilt[2] = pidbuf;
  712.         cxrfilt[3] = NULL;
  713.     }
  714.  
  715.     else
  716.     {
  717.         cxrfilt[1] = pidbuf;
  718.         cxrfilt[2] = NULL;
  719.     }
  720. }
  721.  
  722.  
  723. /*
  724. flow of control is:
  725.  
  726.     docxref  pipe1 sort1 pipe2 cxrfilt -userargs pipe3 fmtxref -userargs
  727.     sort2 pipe1 cxrfilt -i pipe2 fmtxref -userargs
  728.     sort3 pipe1 cxrfilt -f pipe2 fmtxref -userargs
  729. */
  730.  
  731. runprogs()        /* run the programs, obeying user's options */
  732. {
  733.     int i;
  734.  
  735.     if (sepflag)
  736.     {
  737.         for (i = 0; i < xargc; i++)
  738.         {
  739.             printf("\tC Cross Reference Listing of %s\n\n",
  740.                     filename(xargv[i]));
  741.             fflush(stdout);
  742.  
  743.             docxref[1] = xargv[i];
  744.             docxref[2] = NULL;
  745.  
  746.             idens();
  747.  
  748.             if (iflag)
  749.                 integers();
  750.  
  751.             if (fflag)
  752.                 floats();
  753.  
  754.             fflush(stdout);
  755.  
  756.             if (!isatty(fileno(stdout)))
  757.                 putchar('\f');
  758.         }
  759.     }
  760.     else
  761.     {
  762.         if (xargc == 1)
  763.             printf("\tC Cross Reference Listing of %s\n\n",
  764.                 filename(xargv[0]));
  765.         else
  766.             printf("\tC Cross Reference Listing\n\n");
  767.         fflush(stdout);
  768.  
  769.         for (i = 0; xargv[i] != NULL; i++)
  770.             docxref[i+1] = xargv[i];
  771.  
  772.         docxref[i+1] = NULL;
  773.  
  774.         idens();
  775.  
  776.         if (iflag)
  777.             integers();
  778.  
  779.         if (fflag)
  780.             floats();
  781.  
  782.         fflush(stdout);
  783.  
  784.         if (! isatty(fileno(stdout)))
  785.             putchar('\f');
  786.     }
  787.  
  788.     deltemps();
  789. }
  790.  
  791. deltemps()    /* delete temp files used for ints and floats */
  792. {
  793.     char buf[BUFSIZ];
  794.     int i;
  795.  
  796.     for (i = 1; i <= 2; i++)
  797.     {
  798.         sprintf(buf, "/tmp/cxr.%d.%d", getpid(), i);
  799.         unlink(buf);
  800.     }
  801. }
  802.  
  803. /*
  804.  * now begins the nitty gritty work of forking and setting up pipes.
  805.  */
  806.  
  807. int level;    /* how many children down are we */
  808.  
  809. idens()        /* cross reference identifiers */
  810. {
  811.     int status;
  812.     int pid;
  813.     int ischild;
  814.     char buf[BUFSIZ];
  815.  
  816.     level = 0;    /* starting off as grandparent */
  817.  
  818.     ischild = ((pid = fork()) == 0);
  819.     
  820. retest:
  821.     switch (level) {
  822.     case 0:            /* first fork */
  823.         if (ischild)
  824.         {
  825.             level++;
  826.             do_pipe(pipe3);
  827.  
  828.             if (ischild = ((pid = fork()) == 0))
  829.                 goto retest;
  830.  
  831.             close(pipe3[1]);    /* doesn't need this */
  832.  
  833.             close (0);
  834.             dup(pipe3[0]);
  835.             close(pipe3[0]);
  836.             sprintf (buf, "%s/fmtxref", SRCDIR);
  837.             execv (buf, fmtxref);
  838.             fprintf (stderr, "couldn't exec '%s'\n", buf);
  839.             exit (1);
  840.         }
  841.         else
  842.             while (wait(&status) != pid)
  843.                 ;
  844.         break;
  845.     
  846.     case 1:            /* second fork */
  847.         level++;
  848.         close (pipe3[0]);
  849.  
  850.         close(1);
  851.         dup(pipe3[1]);
  852.         close(pipe3[1]);
  853.  
  854.         /* set up i/o for next child */
  855.         do_pipe(pipe2);
  856.  
  857.         if (ischild = ((pid = fork()) == 0))
  858.             goto retest;
  859.  
  860.         close (pipe2[1]);
  861.         close (0);
  862.         dup(pipe2[0]);
  863.         close (pipe2[0]);
  864.  
  865.         sprintf (buf, "%s/cxrfilt", SRCDIR);
  866.         execv (buf, cxrfilt);
  867.         fprintf (stderr, "couldn't exec '%s'\n", buf);
  868.         exit (1);
  869.         break;
  870.  
  871.     case 2:
  872.         level++;
  873.         close (pipe2[0]);
  874.  
  875.         close(1);
  876.         dup(pipe2[1]);
  877.         close(pipe2[1]);    /* now writes to parent */
  878.  
  879.         /* set up to read from next child */
  880.         do_pipe(pipe1);
  881.  
  882.         if (ischild = ((pid = fork()) == 0))
  883.             goto retest;
  884.  
  885.         close (pipe1[1]);
  886.  
  887.         close (0);
  888.         dup(pipe1[0]);
  889.         close (pipe1[0]);
  890.         execv (SORT, sort1);
  891.         fprintf (stderr, "couldn't exec '%s'\n", SORT);
  892.         exit (1);
  893.         break;
  894.  
  895.     case 3:
  896.         level++;
  897.         close (pipe1[0]);
  898.  
  899.         close(1);
  900.         dup(pipe1[1]);
  901.         close(pipe1[1]);    /* now writes to parent */
  902.  
  903.         sprintf(buf, "%s/docxref", SRCDIR);
  904.         execv (buf, docxref);
  905.         fprintf (stderr, "couldn't exec '%s'\n", buf);
  906.         exit (1);
  907.         break;
  908.  
  909.     default:
  910.         fprintf(stderr, "in cxref (idens): can't happen\n");
  911.         fflush(stderr);
  912.         break;
  913.     }
  914. }
  915.  
  916. #include <sys/types.h>
  917. #include <sys/stat.h>
  918.  
  919. integers()
  920. {
  921.     int status;
  922.     int pid;
  923.     int ischild;
  924.     char buf[BUFSIZ];
  925.     struct stat fbuf;
  926.  
  927.     sprintf(buf, "/tmp/cxr.%d.1", ancestor);
  928.     if (stat(buf, &fbuf) >= 0 && fbuf.st_size > 0)
  929.         ;    /* file is not empty */
  930.     else
  931.         return;
  932.  
  933.     level = 0;    /* starting off as grandparent */
  934.  
  935.     ischild = ((pid = fork()) == 0);
  936.     
  937. retest:
  938.     switch (level) {
  939.     case 0:            /* first fork */
  940.         if (ischild)
  941.         {
  942.             level++;
  943.             do_pipe(pipe2);
  944.  
  945.             if (ischild = ((pid = fork()) == 0))
  946.                 goto retest;
  947.  
  948.             close(pipe2[1]);    /* doesn't need this */
  949.  
  950.             close (0);
  951.             dup(pipe2[0]);
  952.             close(pipe2[0]);
  953.             sprintf (buf, "%s/fmtxref", SRCDIR);
  954.             execv (buf, fmtxref);
  955.             fprintf (stderr, "couldn't exec '%s'\n", buf);
  956.             exit (1);
  957.         }
  958.         else
  959.             while (wait(&status) != pid)
  960.                 ;
  961.         break;
  962.     
  963.     case 1:            /* second fork */
  964.         level++;
  965.         close (pipe2[0]);
  966.  
  967.         close(1);
  968.         dup(pipe2[1]);
  969.         close(pipe2[1]);
  970.  
  971.         /* set up i/o for next child */
  972.         do_pipe(pipe1);
  973.  
  974.         if (ischild = ((pid = fork()) == 0))
  975.             goto retest;
  976.  
  977.         close (pipe1[1]);
  978.         close (0);
  979.         dup(pipe1[0]);
  980.         close (pipe1[0]);
  981.  
  982.         cxrfilt[1] = "-i";
  983.         cxrfilt[2] = NULL;
  984.  
  985.         sprintf (buf, "%s/cxrfilt", SRCDIR);
  986.         execv (buf, cxrfilt);
  987.         fprintf (stderr, "couldn't exec '%s'\n", buf);
  988.         exit (1);
  989.         break;
  990.  
  991.     case 2:
  992.         level++;
  993.         close (pipe1[0]);
  994.  
  995.         close(1);
  996.         dup(pipe1[1]);
  997.         close(pipe1[1]);    /* now writes to parent */
  998.  
  999.         /* read from tempfile */
  1000.  
  1001.         close (0);
  1002.         sprintf (buf, "/tmp/cxr.%d.1", ancestor);
  1003.         open (buf, 0);        /* will be fd 0 */
  1004.  
  1005.         execv (SORT, sort2);
  1006.         fprintf (stderr, "couldn't exec '%s'\n", SORT);
  1007.         exit (1);
  1008.         break;
  1009.  
  1010.     default:
  1011.         fprintf(stderr, "in cxref(integers): can't happen\n");
  1012.         fflush(stderr);
  1013.         break;
  1014.     }
  1015. }
  1016.  
  1017. floats()
  1018. {
  1019.     int status;
  1020.     int pid;
  1021.     int ischild;
  1022.     char buf[BUFSIZ];
  1023.     struct stat fbuf;
  1024.  
  1025.     sprintf(buf, "/tmp/cxr.%d.2", ancestor);
  1026.     if (stat(buf, &fbuf) >= 0 && fbuf.st_size > 0)
  1027.         ;    /* file is not empty */
  1028.     else
  1029.         return;
  1030.  
  1031.     level = 0;    /* starting off as grandparent */
  1032.  
  1033.     ischild = ((pid = fork()) == 0);
  1034.     
  1035. retest:
  1036.     switch (level) {
  1037.     case 0:            /* first fork */
  1038.         if (ischild)
  1039.         {
  1040.             level++;
  1041.             do_pipe(pipe2);
  1042.  
  1043.             if (ischild = ((pid = fork()) == 0))
  1044.                 goto retest;
  1045.  
  1046.             close(pipe2[1]);    /* doesn't need this */
  1047.  
  1048.             close (0);
  1049.             dup(pipe2[0]);
  1050.             close(pipe2[0]);
  1051.             sprintf (buf, "%s/fmtxref", SRCDIR);
  1052.             execv (buf, fmtxref);
  1053.             fprintf (stderr, "couldn't exec '%s'\n", buf);
  1054.             exit (1);
  1055.         }
  1056.         else
  1057.             while (wait(&status) != pid)
  1058.                 ;
  1059.         break;
  1060.     
  1061.     case 1:            /* second fork */
  1062.         level++;
  1063.         close (pipe2[0]);
  1064.  
  1065.         close(1);
  1066.         dup(pipe2[1]);
  1067.         close(pipe2[1]);
  1068.  
  1069.         /* set up i/o for next child */
  1070.         do_pipe(pipe1);
  1071.  
  1072.         if (ischild = ((pid = fork()) == 0))
  1073.             goto retest;
  1074.  
  1075.         close (pipe1[1]);
  1076.         close (0);
  1077.         dup(pipe1[0]);
  1078.         close (pipe1[0]);
  1079.  
  1080.         cxrfilt[1] = "-f";
  1081.         cxrfilt[2] = NULL;
  1082.  
  1083.         sprintf (buf, "%s/cxrfilt", SRCDIR);
  1084.         execv (buf, cxrfilt);
  1085.         fprintf (stderr, "couldn't exec '%s'\n", buf);
  1086.         exit (1);
  1087.         break;
  1088.  
  1089.     case 2:
  1090.         level++;
  1091.         close (pipe1[0]);
  1092.  
  1093.         close(1);
  1094.         dup(pipe1[1]);
  1095.         close(pipe1[1]);    /* now writes to parent */
  1096.  
  1097.         /* read from tempfile */
  1098.  
  1099.         close (0);
  1100.         sprintf (buf, "/tmp/cxr.%d.2", ancestor);
  1101.         open (buf, 0);        /* will be fd 0 */
  1102.  
  1103.         execv (SORT, sort3);
  1104.         fprintf (stderr, "couldn't exec '%s'\n", SORT);
  1105.         exit (1);
  1106.         break;
  1107.  
  1108.     default:
  1109.         fprintf(stderr, "in cxref(floats): can't happen\n");
  1110.         fflush(stderr);
  1111.         break;
  1112.     }
  1113. }
  1114.  
  1115. usage()
  1116. {
  1117.     fprintf(stderr, "usage: %s [-SCcsif] [-w width] [files]\n", name);
  1118.     fflush(stderr);
  1119.     exit (1);
  1120. }
  1121.  
  1122. char *filename(fname)
  1123. char *fname;
  1124. {
  1125.     char *cp, *basename();
  1126.  
  1127.     cp = basename(fname);
  1128.  
  1129.     return ( strcmp(cp, "-") == 0 ? "stdin" : cp);
  1130. }
  1131.  
  1132. catchem()    /* simple signal catcher */
  1133. {
  1134.     signal(SIGQUIT, SIG_IGN);
  1135.     signal(SIGINT, SIG_IGN);
  1136.  
  1137.     deltemps();
  1138.  
  1139.     exit (0);
  1140. }
  1141.  
  1142. #include "basename.c"
  1143. End of cxref.c
  1144. echo 'extracting --- cxrfilt.c' 1>&2
  1145. cat > cxrfilt.c << 'End of cxrfilt.c'
  1146. /*
  1147. ** cxrfilt.c
  1148. **
  1149. ** if called with no flags, or with the -c or -s flags, it will
  1150. ** separate out integer and floating point constants into
  1151. ** their own files, pass char and string constants on through.
  1152. ** input: sorted output of docxref, contains identifiers and constants.
  1153. ** output: identifiers, char and string constants, depending on flags.
  1154. **      output goes to fmtxref. floats and ints to separate files for sorting.
  1155. **
  1156. ** if called with -i or -f option, behavior is to put sorted ints or floats
  1157. ** back into their original formats, and then pass the output to fmtxref.
  1158. **
  1159. ** originally, there was a separate program to do float and int, but these two
  1160. ** have been merged to reduce the total number of programs needed for cxref.
  1161. **
  1162. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  1163. **    gatech!arnold
  1164. ** Copyright (c) 1984 by Arnold Robbins
  1165. ** All rights reserved
  1166. ** This program may not be sold, but may be distributed
  1167. ** provided this header is included.
  1168. */
  1169.  
  1170. #include <stdio.h>
  1171. #include "constdefs.h"
  1172.  
  1173. #define MAXFILE        120
  1174. #define MAXLINE        120
  1175.  
  1176. FILE *fp1, *fp2;
  1177. int cflag = 0;
  1178. int sflag = 0;
  1179. char *name;
  1180. char *basename();
  1181.  
  1182. main(argc, argv)
  1183. int argc;
  1184. char **argv;
  1185. {
  1186.     char buf[BUFSIZ];
  1187.     char file1[MAXFILE], file2[MAXFILE];
  1188.     int i;
  1189.  
  1190.     name = basename(argv[0]);
  1191.  
  1192.     if (argc <= 1)
  1193.         usage();
  1194.  
  1195.     if(argv[1][0] == '-')
  1196.     {
  1197.         for (i = 1; argv[1][i] != '\0'; i++)
  1198.             switch (argv[1][i]) {
  1199.             case 'c':
  1200.                 cflag = 1;
  1201.                 break;
  1202.  
  1203.             case 's':
  1204.                 sflag = 1;
  1205.                 break;
  1206.  
  1207.             case 'i':
  1208.                 intfilter();
  1209.                 exit(0);
  1210.                 break;
  1211.             
  1212.             case 'f':
  1213.                 floatfilter();
  1214.                 exit(0);
  1215.                 break;
  1216.             
  1217.             default:    /* bad option given */
  1218.                 usage();
  1219.                 break;
  1220.             }
  1221.  
  1222.         /* if it gets to here, we were called only w/-c or -s */
  1223.         if (argc == 2)
  1224.             usage();
  1225.  
  1226.         argv++;
  1227.     }
  1228.  
  1229.     /* code for splitting constants off into separate files */
  1230.  
  1231.     sprintf(file1, "/tmp/cxr.%d.1", atoi(argv[1]));
  1232.     sprintf(file2, "/tmp/cxr.%d.2", atoi(argv[1]));
  1233.  
  1234.     if ((fp1 = fopen(file1, "w")) == NULL)
  1235.     {
  1236.         fprintf(stderr,"%s: couldn't create tempfile 1\n");
  1237.         exit (2);
  1238.     }
  1239.  
  1240.     if ((fp2 = fopen(file2, "w")) == NULL)
  1241.     {
  1242.         fprintf(stderr,"%s: couldn't create tempfile 2\n");
  1243.         exit (3);
  1244.     }
  1245.  
  1246.     while (gets(buf) != NULL)
  1247.     {
  1248.         if (buf[0] != '~')
  1249.             printf("%s\n", buf);
  1250.         else
  1251.             switch (buf[1]) {
  1252.             case CHAR:
  1253.                 if (! cflag)
  1254.                     printf("%s\n", &buf[2]);
  1255.                 break;
  1256.  
  1257.             case STRING:
  1258.                 if (! sflag)
  1259.                     printf("%s\n", &buf[2]);
  1260.                 break;
  1261.             
  1262.             case INT:
  1263.                 outint(buf);
  1264.                 break;
  1265.             
  1266.             case FLOAT:
  1267.                 outfloat(buf);
  1268.                 break;
  1269.             
  1270.             default:
  1271.                 fprintf(stderr,"%s: bad input line '%s'\n",
  1272.                     name, buf);
  1273.                 exit (4);
  1274.             }
  1275.     }
  1276.  
  1277.     fclose(fp1);
  1278.     fclose(fp2);
  1279.  
  1280.     exit(0);
  1281. }
  1282.  
  1283. #define OCTAL    1
  1284. #define HEX    2
  1285. #define DEC    3
  1286.  
  1287. outint(buf)
  1288. char *buf;
  1289. {
  1290.     char file[MAXLINE], line[MAXLINE];
  1291.     int val;
  1292.     int type = 0;
  1293.  
  1294.     buf += 2;        /* skip leading ~INT */
  1295.     file[0] = line[0] = '\0';
  1296.  
  1297.     if (buf[0] == '0')    /* octal or hex */
  1298.     {
  1299.         if (buf[1] == 'x' || buf[1] == 'X')    /* hex */
  1300.         {
  1301.             type = HEX;
  1302.             buf += 2;    /* skip leading 0x */
  1303.             sscanf(buf, "%x %s %s", &val, file, line);
  1304.         }
  1305.         else
  1306.         {
  1307.             type = OCTAL;
  1308.             sscanf(buf, "%o %s %s", &val, file, line);
  1309.         }
  1310.     }
  1311.     else
  1312.     {
  1313.         type = DEC;
  1314.         sscanf(buf, "%d %s %s", &val, file, line);    /* decimal */
  1315.     }
  1316.  
  1317.     /*
  1318.      * strategy is to convert to decimal for numeric sorting,
  1319.      * then have output filter convert back to right base.
  1320.      *
  1321.      * type is used to tell intfilter() what to turn it back into.
  1322.      */
  1323.  
  1324.     fprintf(fp1, "%d\t%s\t%s\t%d\n", val, file, line, type);
  1325. }
  1326.  
  1327. outfloat(buf)
  1328. char *buf;
  1329. {
  1330.     char file[MAXLINE], line[MAXLINE];
  1331.     char mantissa[MAXLINE], exponent[MAXLINE];
  1332.     char strval[MAXLINE];        /* character representation of float */
  1333.     char controlstr[MAXLINE];
  1334.     double val;
  1335.     int i, j;
  1336.  
  1337.     buf += 2;    /* skip ~FLOAT */
  1338.  
  1339.     mantissa[0] = exponent[0] = file[0] = line[0] = '\0';
  1340.  
  1341.     sscanf(buf, "%lf %s %s", &val, file, line);
  1342.  
  1343.     for (i = 0; buf[i] != '\t'; i++)
  1344.         if (buf[i] == '.')
  1345.             break;
  1346.  
  1347.     for (j = i + 1; buf[j] != 'E' && buf[j] != 'e' && buf[j] != '\t'; j++)
  1348.         ;
  1349.  
  1350.     j -= i - 1;    /* j is now num digits to right decimal point. */
  1351.     if (j < 6)
  1352.         j = 6;    /* default */
  1353.  
  1354.     sprintf(controlstr, "%%1.%dg", j);    /* make control string */
  1355.     sprintf(strval, controlstr, val);    /* make character string */
  1356.  
  1357.     /*
  1358.      * strategy is a follows:
  1359.      * 1) convert all floats to a common printed format (%g)
  1360.      * 2) split up mantissa and exponent into separate parts for sorting
  1361.      * 3) put them back together later when called w/-f option.
  1362.      */
  1363.  
  1364.     for(i = j = 0; strval[j] != 'e' && strval[j] != 'E' && strval[j] != '\0'; i++, j++)
  1365.         mantissa[i] = strval[j];
  1366.     mantissa[i] = '\0';
  1367.  
  1368.     if (strval[j] == 'e' || strval[j] == 'E')
  1369.     {
  1370.         j++;
  1371.         for(i = 0; strval[j] != '\0'; i++, j++)
  1372.             exponent[i] = strval[j];
  1373.         exponent[i] = '\0';
  1374.     }
  1375.     else
  1376.         exponent[0] = '\0';
  1377.     
  1378.     fprintf(fp2, "%s\t%s\t%s\t%s\n", mantissa,
  1379.         exponent[0] != '\0' ? exponent : "0", file, line);
  1380. }
  1381.  
  1382. usage()
  1383. {
  1384.     fprintf(stderr, "usage: %s [-csfi] pid\n", name);
  1385.     exit (1);
  1386. }
  1387.  
  1388.  
  1389. intfilter()    /* put sorted ints back into their original bases */
  1390. {
  1391.     char buf[BUFSIZ];
  1392.     char file[MAXLINE], number[MAXLINE];
  1393.     int val;
  1394.     int type;
  1395.  
  1396.     while (gets(buf) != NULL)
  1397.     {
  1398.         sscanf(buf, "%d %s %s %d", &val, file, number, &type);
  1399.  
  1400.         switch (type) {
  1401.         case OCTAL:
  1402.             if (val == 0)        /* don't print 00 */
  1403.                 printf("0\t%s\t%s\n", file, number);
  1404.             else
  1405.                 printf("0%o\t%s\t%s\n", val, file, number);
  1406.                 /* supply leading 0 */
  1407.             break;
  1408.  
  1409.         case DEC:
  1410.             printf("%d\t%s\t%s\n", val, file, number);
  1411.             break;
  1412.         
  1413.         case HEX:
  1414.             printf("0x%x\t%s\t%s\n", val, file, number);
  1415.             break;
  1416.         
  1417.         default:
  1418.             fprintf(stderr,"%s: bad input line '%s'\n", name, buf);
  1419.             exit (4);
  1420.         }
  1421.     }
  1422. }
  1423.  
  1424. floatfilter()    /* put sorted floats back together */
  1425. {
  1426.     char buf[BUFSIZ];
  1427.     char file[MAXLINE], number[MAXLINE];
  1428.     char mantissa[MAXLINE], exponent[MAXLINE];
  1429.  
  1430.     while (gets(buf) != NULL)
  1431.     {
  1432.         sscanf(buf, "%s %s %s %s", mantissa, exponent, file, number);
  1433.  
  1434.         if (strcmp(exponent, "0") == 0)
  1435.             printf("%s", mantissa);
  1436.         else
  1437.             printf("%sE%s", mantissa, exponent);
  1438.         
  1439.         printf("\t%s\t%s\n", file, number);
  1440.     }
  1441. }
  1442.  
  1443. #include "basename.c"
  1444. End of cxrfilt.c
  1445. echo 'extracting --- docxref.c' 1>&2
  1446. cat > docxref.c << 'End of docxref.c'
  1447. /*
  1448. ** docxref.c
  1449. **
  1450. ** Driver for lex based scanner.  Arranges for stdin to be each named
  1451. ** file in turn, so that yylex() never has to know about files.
  1452. ** Some of this code is not pretty, but it's not too bad.
  1453. **
  1454. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  1455. **    gatech!arnold
  1456. ** Copyright (c) 1984 by Arnold Robbins.
  1457. ** All rights reserved.
  1458. ** This program may not be sold, but may be distributed
  1459. ** provided this header is included.
  1460. */
  1461.  
  1462. #include <stdio.h>
  1463. #include <ctype.h>
  1464.  
  1465. #define TRUE    1
  1466. #define FALSE    0
  1467.  
  1468. extern char yytext[];
  1469. extern int yyleng;
  1470.  
  1471. int line_no = 1;    /* current line number */
  1472. char *fname = NULL;    /* current file name */
  1473.  
  1474. char *basename();    /* strips leading path of a file name */
  1475.  
  1476. main(argc,argv)
  1477. int argc;
  1478. char **argv;
  1479. {
  1480.     FILE saved_in, *fp;
  1481.     char *name;
  1482.     int more_input = FALSE;        /* more files to process */
  1483.     int read_stdin = FALSE;
  1484.  
  1485.     name = basename(argv[0]);    /* save command name */
  1486.     fname = "stdin";        /* assume stdin */
  1487.  
  1488.     if(argc == 1)
  1489.     {
  1490.         yylex();
  1491.         exit(0);
  1492.     }
  1493.  
  1494.     if(argv[1][0] == '-' && argv[1][1] != '\0')
  1495.             usage(argv[0]);    /* will exit */
  1496.  
  1497.     saved_in = *stdin;
  1498.     /* save stdin in case "-" is found in middle of command line */
  1499.  
  1500.     for(--argc, argv++; argc > 0; --argc, argv++)
  1501.     {
  1502.         if(fileno(stdin) != fileno((&saved_in)) || read_stdin)
  1503.             fclose(stdin);
  1504.         /* free unix file descriptors */
  1505.  
  1506.         if(strcmp(*argv, "-") == 0)
  1507.         {
  1508.             *stdin = saved_in;
  1509.             fname = "stdin";
  1510.             read_stdin = TRUE;
  1511.             more_input = (argc - 1 > 0);
  1512.         }
  1513.         else if((fp = fopen(*argv,"r")) == NULL)
  1514.         {
  1515.             fprintf(stderr,"%s: can't open %s\n", name, *argv);
  1516.             continue;
  1517.         }
  1518.         else
  1519.         {
  1520.             *stdin = *fp;
  1521.             /* do it this way so that yylex() */
  1522.             /* never knows about files etc. */
  1523.             more_input = (argc - 1 > 0);
  1524.             fname = *argv;
  1525.         }
  1526.  
  1527.         yylex();    /* do the work */
  1528.  
  1529.         if(more_input)
  1530.             line_no = 1;
  1531.     }
  1532. }
  1533.  
  1534. outid()
  1535. {
  1536.     char *basename();
  1537.  
  1538.     printf("%s\t%s\t%d\n", yytext, basename(fname), line_no);
  1539. }
  1540.  
  1541. usage(name)
  1542. char *name;
  1543. {
  1544.     fprintf(stderr,"usage: %s [files]\n", name);
  1545.     exit(1);
  1546. }
  1547.  
  1548. #include "basename.c"
  1549. End of docxref.c
  1550. echo 'extracting --- fmtxref.c' 1>&2
  1551. cat > fmtxref.c << 'End of fmtxref.c'
  1552. /*
  1553. ** fmtxref.c
  1554. **
  1555. ** format the output of the C cross referencer.
  1556. ** this program relies on the fact that its input
  1557. ** is sorted and uniq-ed.
  1558. **
  1559. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  1560. **    gatech!arnold
  1561. ** Copyright (c) 1984 by Arnold Robbins.
  1562. ** All rights reserved.
  1563. ** This program may not be sold, but may be distributed
  1564. ** provided this header is included.
  1565. */
  1566.  
  1567. #include <stdio.h>
  1568. #include <ctype.h>
  1569.  
  1570. #define TRUE    1
  1571. #define FALSE    0
  1572.  
  1573. #define MAXID    121    /* maximum lengths of identifiers, file names, etc. */
  1574. #define MAXFILE    15
  1575. #define MAXLINE    121
  1576. #define MAXNUM    7
  1577.  
  1578. #define ID    1    /* return codes to indicate what is new on input line */
  1579. #define NEWFILE    2
  1580. #define LINE    3
  1581. #define ERROR    4
  1582.  
  1583. #define WIDTH    80    /* default line output width */
  1584.  
  1585. int width = WIDTH;
  1586.  
  1587. char prev_id[MAXID] = "";
  1588. char prev_file[MAXFILE] = "";
  1589.  
  1590. char id[MAXID] = "";
  1591. char file[MAXFILE] = "";
  1592. char line[MAXNUM] = "";
  1593.  
  1594. char *name;
  1595. char *basename();    /* strips leading path name */
  1596.  
  1597. main(argc, argv)
  1598. int argc;
  1599. char **argv;
  1600. {
  1601.     char inline[BUFSIZ];
  1602.     char *gets();
  1603.     int val;
  1604.  
  1605.     name = basename(argv[0]);
  1606.  
  1607.     /*
  1608.      * since this program is ONLY called by the cxref driver,
  1609.      * we know that it will be called "fmtxref -w width"
  1610.      * so we don't have to do complicated argument parsing.
  1611.      * we also know that cxref makes sure we get a valid width.
  1612.      */
  1613.  
  1614.     if (argc > 1)
  1615.         if (argc == 3)
  1616.             if (strcmp(argv[1], "-w") == 0)
  1617.                 width = atoi(argv[2]);
  1618.             else
  1619.                 usage();
  1620.         else
  1621.             usage();
  1622.     /* else
  1623.         use default width */
  1624.  
  1625.     if(gets(inline) == NULL)
  1626.     {
  1627.         fprintf(stderr, "%s: standard input is empty.\n", name);
  1628.         exit(1);
  1629.     }
  1630.  
  1631.     if((val = breakup(inline)) == ERROR)
  1632.     {
  1633.         fprintf(stderr, "%s: malformed input '%s'\n", name, inline);
  1634.         exit(2);
  1635.     }
  1636.  
  1637.     output(val);        /* does proper formatting */
  1638.  
  1639.     while(gets(inline) != NULL && val != ERROR)
  1640.     {
  1641.         val = breakup(inline);
  1642.         output(val);
  1643.     }
  1644.  
  1645.     if(val == ERROR)
  1646.     {
  1647.         fprintf(stderr, "%s: malformed input '%s'\n", name, inline);
  1648.         exit(2);
  1649.     }
  1650.  
  1651.     putchar('\n');
  1652. }
  1653.  
  1654. breakup(text)
  1655. char *text;
  1656. {
  1657.     int retval;
  1658.     int i, j;
  1659.  
  1660.     if(text[0] == '"' || text[0] == '\'')
  1661.     {
  1662.         /* quoted stuff, break the line up by hand */
  1663.  
  1664.         i = 0;
  1665.         id[i++] = text[0];
  1666.  
  1667.         for(j = 1; text[j] != text[0]; i++, j++)
  1668.         {
  1669.             id[i] = text[j];
  1670.             if(id[i] == '\\')
  1671.                 id[++i] = text[++j];    /* e.g. \" */
  1672.         }
  1673.         id[i++] = text[0];
  1674.         id[i] = '\0';
  1675.         j++;    /* skip close quote */
  1676.  
  1677.         while(isspace(text[j]))
  1678.             j++;
  1679.         
  1680.         for(i = 0; !isspace(text[j]); i++, j++)
  1681.             file[i] = text[j];
  1682.         file[i] = '\0';
  1683.  
  1684.  
  1685.         while(isspace(text[j]))
  1686.             j++;
  1687.  
  1688.         for(i = 0; !isspace(text[j]) && text[j] != '\0'; i++, j++)
  1689.             line[i] = text[j];
  1690.         line[i] = '\0';
  1691.     }
  1692.     else
  1693.     {
  1694.         if(sscanf(text, "%s %s %s", id, file, line) != 3)
  1695.             return(ERROR);
  1696.     }
  1697.  
  1698.     /* now decide about return code for formatting */
  1699.  
  1700.     if(strcmp(prev_id, id) != 0)    /* different identifiers */
  1701.     {
  1702.         strcpy(prev_id, id);
  1703.         strcpy(prev_file, file);
  1704.         retval = ID;
  1705.     }
  1706.     else if(strcmp(prev_file, file) != 0)    /* different files */
  1707.     {
  1708.         strcpy(prev_file, file);
  1709.         retval = NEWFILE;
  1710.     }
  1711.     else
  1712.         retval = LINE;
  1713.  
  1714.     return(retval);
  1715. }
  1716.  
  1717. output(val)
  1718. int val;
  1719. {
  1720.     static int curpos = 1;
  1721.     static int first = TRUE;
  1722.     int line_len = strlen(line);
  1723.  
  1724.     switch(val) {
  1725.     case ID:
  1726.         if(! first)
  1727.             putchar('\n');    /* finish off last line of prev id */
  1728.         else
  1729.             first = FALSE;
  1730.  
  1731.         printf("%-20.20s\t%-14.14s\t%s", id, file, line);
  1732.         curpos = 40 + line_len;
  1733.         break;
  1734.  
  1735.     case NEWFILE:
  1736.         printf("\n\t\t\t%-14.14s\t%s", file, line);
  1737.         curpos = 40 + line_len;
  1738.         break;
  1739.  
  1740.     case LINE:
  1741.         if(curpos + line_len + 2 < width)
  1742.         {
  1743.             printf(", %s", line);    /* same output line */
  1744.             curpos += 2 + line_len;
  1745.         }
  1746.         else
  1747.         {
  1748.             printf(",\n\t\t\t\t\t%s", line);    /* new line */
  1749.             curpos = 40 + line_len;
  1750.         }
  1751.         break;
  1752.  
  1753.     case ERROR:
  1754.         /* shouldn't come to here */
  1755.         fprintf(stderr, "%s: internal error: output() called with %s\n",
  1756.             name, "a value of ERROR");
  1757.         fprintf(stderr, "%s: id == '%s'\tfile == '%s'\tline == '%s'\n",
  1758.             name, id, file, line);
  1759.         break;
  1760.  
  1761.     default:
  1762.         /* shouldn't come to here either */
  1763.         fprintf(stderr, "%s: internal error: output() called with %s %d\n",
  1764.             name, "the unknown value", val);
  1765.         fprintf(stderr, "%s: id == '%s'\tfile == '%s'\tline == '%s'\n",
  1766.             name, id, file, line);
  1767.         break;
  1768.     }
  1769. }
  1770.  
  1771. usage()
  1772. {
  1773.     char *basename();
  1774.  
  1775.     fprintf(stderr, "usage: %s [-w width]\n", basename(name));
  1776.     exit (1);
  1777. }
  1778.  
  1779. #include "basename.c"
  1780. End of fmtxref.c
  1781. echo 'extracting --- makefile' 1>&2
  1782. cat > makefile << 'End of makefile'
  1783. # makefile for cxref -- C cross referencing program
  1784. #
  1785. # Arnold Robbins, Information and Computer Science, Georgia Tech
  1786. #    gatech!arnold
  1787. # Copyright (c) 1985 by Arnold Robbins.
  1788. # All rights reserved.
  1789. # This program may not be sold, but may be distributed
  1790. # provided this header is included.
  1791.  
  1792. # some files are system dependant, e.g. where sort is.
  1793. # change the appropriate macro definitions and recompile.
  1794.  
  1795.  
  1796. ### definitions of files to compile and load, and other targets for make
  1797.  
  1798. SCANOBJS= docxref.o cscan.o
  1799. SCANSRCS= docxref.c cscan.l
  1800.  
  1801. CXREF = cxref
  1802. INCLS= constdefs.h basename.c
  1803. PROGS= docxref fmtxref cxrfilt $(CXREF)
  1804. SRCS=  $(SCANSRCS) fmtxref.c cxrfilt.c $(CXREF).c
  1805. DOCS=  README makefile cxref.1
  1806.  
  1807. PRINTS= $(INCLS) $(SRCS) $(DOCS)
  1808.  
  1809. CFLAGS= -O
  1810.  
  1811. ### system dependant definitions, change when you install cxref
  1812.  
  1813. # for my use during development, put in my bin, but see next few lines.
  1814. DESTDIR= $(BIN)
  1815. LIB= $(BIN)
  1816.  
  1817. # when installing, use the lines below; change DESTDIR to local bin of choice.
  1818. # DESTDIR=/ics/bin
  1819. # LIB=/usr/local/lib/cxref
  1820.  
  1821. # where to put the man page, use 1 instead of l if you don't have a manl.
  1822. MANSEC=l
  1823.  
  1824. # lex library, may be -lln on some systems
  1825. LEXLIB= -ll
  1826.  
  1827. # may be /bin/sort on some systems
  1828. SORT=/usr/bin/sort
  1829.  
  1830. # printer program, prt is for me, use pr on other systems
  1831. P=prt
  1832.  
  1833. # the owner and group of the installed program.  Both are 'admin' on our
  1834. # system, but they may different on yours.
  1835. OWNER= admin
  1836. GROUP= admin
  1837.  
  1838. all: $(PROGS)
  1839.     @echo "    all" done
  1840.  
  1841. docxref: $(SCANOBJS)
  1842.     $(CC) $(SCANOBJS) $(LEXLIB) -o $@
  1843.  
  1844. cscan.o docxref.o cxrfilt.o: $(INCLS)
  1845.  
  1846. fmtxref: fmtxref.c
  1847.     $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
  1848.  
  1849. cxrfilt: cxrfilt.c
  1850.     $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
  1851.  
  1852. $(CXREF): $(CXREF).c
  1853.     $(CC) $(CFLAGS) -DSRCDIR='"$(LIB)"' -DSORT='"$(SORT)"' $@.c $(LDFLAGS) -o $@
  1854.  
  1855. print:
  1856.     $(P) $(PRINTS) | lpr -b 'Cxref Source'
  1857.     touch print2
  1858.  
  1859. print2: $(PRINTS)
  1860.     $(P) $? | lpr -b 'Cxref New Source'
  1861.     touch print2
  1862.  
  1863. ### edit this before installing!!
  1864.  
  1865. install: $(PROGS)
  1866. # don't remove my bin!
  1867. #    rm -fr $(LIB)
  1868.     rm -f $(DESTDIR)/cxref
  1869. #    mkdir $(LIB)
  1870.     cp $(CXREF) $(DESTDIR)/$(CXREF)
  1871.     cp docxref  $(LIB)/docxref
  1872.     cp fmtxref  $(LIB)/fmtxref
  1873.     cp cxrfilt $(LIB)/cxrfilt
  1874. #    cp cxref.1 /usr/man/man$(MANSEC)/cxref.$(MANSEC)
  1875. #    cd $(DESTDIR); chmod 711 cxref; chown $(OWNER) cxref; chgrp $(GROUP) cxref
  1876. #    cd $(LIB); chmod 711 docxref fmtxref cxrfilt
  1877. #    cd $(LIB); chown $(OWNER) docxref fmtxref cxrfilt
  1878. #    cd $(LIB); chgrp $(GROUP) docxref fmtxref cxrfilt
  1879.  
  1880. clean:
  1881.     rm -f $(SCANOBJS)
  1882.  
  1883. clobber: clean
  1884.     rm -f $(PROGS) print2
  1885. End of makefile
  1886. echo 'extracting --- old.cxref.c' 1>&2
  1887. cat > old.cxref.c << 'End of old.cxref.c'
  1888. /*
  1889. ** cxref.c
  1890. **
  1891. ** C driver for Cxref program.
  1892. ** does argument handling, then builds the right
  1893. ** shell commands for passing to the system() routine.
  1894. **
  1895. ** A possible but difficult speed improvement would be to
  1896. ** set up the argument vectors ourselves, the i/o with a pipe()
  1897. ** call, and do all the forking and execing ourselves.
  1898. ** But, in keeping w/the philosophy of "Let someone else do
  1899. ** the hard part", we leave well enough alone and let the shell do it.
  1900. **
  1901. ** Arnold Robbins, Information and Computer Science, Georgia Tech
  1902. **    gatech!arnold
  1903. ** Copyright (c) 1984 by Arnold Robbins
  1904. ** All rights reserved
  1905. ** This program may not be sold, but may be distributed
  1906. ** provided this header is included.
  1907. */
  1908.  
  1909. #include <stdio.h>
  1910. #include <ctype.h>
  1911.  
  1912. #ifdef DEBUG
  1913. #define system(str)    printf("%s\n", str)
  1914. #endif
  1915.  
  1916. #ifdef TESTOUT
  1917. dosystem(str)
  1918. char *str;
  1919. {
  1920.     int pid;
  1921.  
  1922.     fprintf(stderr, "%s\n", str);
  1923.     system(str);
  1924. }
  1925.  
  1926. #define system(str)    dosystem(str)    /* takes effect after above routine */
  1927. #endif
  1928.  
  1929. #define TRUE    1
  1930. #define FALSE    0
  1931.  
  1932. char *name;        /* save command name */
  1933.  
  1934. int xargc;        /* make argc and argv available globally */
  1935. char **xargv;
  1936.  
  1937. int width = 0;        /* output width */
  1938.  
  1939. int sepflag = FALSE;    /* do each one separately */
  1940.  
  1941. int iflag = TRUE;    /* print out ints */
  1942. int fflag = TRUE;    /* print out floats */
  1943. int cflag = TRUE;    /* print out chars */
  1944. int sflag = TRUE;    /* print out strings */
  1945.  
  1946. char *filename();    /* turns "-" into "stdin" */
  1947.  
  1948. main(argc, argv)
  1949. int argc;
  1950. char **argv;
  1951. {
  1952.     int i;
  1953.     int extra_arg = FALSE;
  1954.  
  1955.     name = filename(argv[0]);
  1956.  
  1957.     for(argv++, argc--; argc > 0; argv++, argc--)
  1958.         if (argv[0][0] != '-')
  1959.             break;
  1960.         else if(argv[0][1] == '\0')    /* filename of "-" */
  1961.             break;
  1962.         else
  1963.             for(i = 1; argv[0][i] != '\0'; i++)
  1964.             {
  1965.                 switch(argv[0][i]) {
  1966.                 case 'S':
  1967.                     sepflag = TRUE;
  1968.                     break;
  1969.                 
  1970.                 case 'C':
  1971.                     /* leave out all constants */
  1972.                     cflag =
  1973.                     iflag =
  1974.                     fflag =
  1975.                     sflag = FALSE;
  1976.                     break;
  1977.  
  1978.                 case 'c':
  1979.                     cflag = FALSE;
  1980.                     break;
  1981.                 
  1982.                 case 'i':
  1983.                     iflag = FALSE;
  1984.                     break;
  1985.                 
  1986.                 case 'f':
  1987.                     fflag = FALSE;
  1988.                     break;
  1989.                 
  1990.                 case 's':
  1991.                     sflag = FALSE;
  1992.                     break;
  1993.                 
  1994.                 case 'w':
  1995.                     if (isdigit(argv[0][i+1]))
  1996.                     {
  1997.                         width = 0;
  1998.                         for(i++; isdigit(argv[0][i]); i++)
  1999.                             width = width * 10 + argv[0][i] - '0';
  2000.                         i--;
  2001.                     }
  2002.                     else
  2003.                     {
  2004.                         width = atoi(argv[1]);
  2005.                         extra_arg = TRUE;
  2006.                     }
  2007.                     break;
  2008.  
  2009.                 default:
  2010.                     usage();
  2011.                     break;
  2012.                 }
  2013.  
  2014.                 if (extra_arg)    /* skip column width */
  2015.                 {
  2016.                     extra_arg = FALSE;
  2017.                     /* do this only once */
  2018.                     /* inside the for loop */
  2019.                     argv++;
  2020.                     argc--;
  2021.                 }
  2022.             }
  2023.     
  2024.     if (width != 0)
  2025.         if (width < 51)
  2026.             width = 80;
  2027.         else if (width > 132)
  2028.             width = 132;
  2029.  
  2030.     xargc = argc;
  2031.     xargv = argv;
  2032.  
  2033.     runprogs();
  2034. }
  2035.  
  2036. char command[BUFSIZ * 10];    /* may need LOTS of room */
  2037. char com_buf[BUFSIZ * 10];    /* use short name for portability */
  2038.  
  2039. char *docxref();    /* functions to generate commands with args */
  2040. char *filter();
  2041. char *fmtxref();
  2042.  
  2043. #define ONLYONE        1
  2044. #define ALLOFTHEM    2
  2045.  
  2046. runprogs()        /* execute the programs */
  2047. {
  2048.     int i;
  2049.  
  2050.     if (sepflag)    /* do each file separately */
  2051.     {
  2052.         for (i = 0; i < xargc; i++)
  2053.         {
  2054.             printf("\tC Cross Refence Listing of %s\n\n",
  2055.                     filename(xargv[i]));
  2056.             fflush(stdout);
  2057.             /* send to ouput before commands start */
  2058.             sprintf(command,
  2059.                 "%s | sort -u +0b -2 +2n | %s | %s",
  2060.                 docxref(i, ONLYONE), filter(), fmtxref());
  2061.             system(command);
  2062.             if (iflag)
  2063.             {
  2064.                 sprintf(com_buf,
  2065.     "sort -u +0n -1 +1b -2 +2n < /tmp/cxr.%d.1 | %s/cxrfilt -i | %s",
  2066.                     getpid(), SRCDIR, fmtxref());
  2067.                 sprintf(command,
  2068.             "if test -s /tmp/cxr.%d.1 ; then %s ; fi",
  2069.                     getpid(), com_buf);
  2070.                 system(command);
  2071.             }
  2072.             if (fflag)
  2073.             {
  2074.                 sprintf(com_buf,
  2075. "sort -u +0n +1n -2 +2b -3 +3n < /tmp/cxr.%d.2 | %s/cxrfilt -f | %s",
  2076.                     getpid(), SRCDIR, fmtxref());
  2077.                 sprintf(command,
  2078.             "if test -s /tmp/cxr.%d.2 ; then %s ; fi",
  2079.                     getpid(), com_buf);
  2080.                 system(command);
  2081.             }
  2082.             fflush(stdout);
  2083.             if (! isatty(fileno(stdout)))
  2084.                 putchar('\f');
  2085.         }
  2086.     }
  2087.     else
  2088.     {
  2089.         if (xargc == 1)
  2090.             printf("\tC Cross Refence Listing of %s\n\n",
  2091.                     filename(xargv[0]));
  2092.         else
  2093.             printf("\tC Cross Reference Listing\n\n");
  2094.         fflush(stdout);
  2095.         sprintf(command, "%s | sort -u +0b -2 +2n | %s | %s",
  2096.             docxref(0, ALLOFTHEM), filter(), fmtxref());
  2097.         system (command);
  2098.         if (iflag)
  2099.         {
  2100.             sprintf(com_buf,
  2101.     "sort -u +0n -1 +1b -2 +2n < /tmp/cxr.%d.1 | %s/cxrfilt -i | %s",
  2102.                 getpid(), SRCDIR, fmtxref());
  2103.  
  2104.             sprintf(command,
  2105.                 "if test -s /tmp/cxr.%d.1 ; then %s ; fi",
  2106.                 getpid(), com_buf);
  2107.             system(command);
  2108.         }
  2109.         if (fflag)
  2110.         {
  2111.             sprintf(com_buf,
  2112. "sort -u +0n +1n -2 +2b -3 +3n < /tmp/cxr.%d.2 | %s/cxrfilt -f | %s",
  2113.                 getpid(), SRCDIR, fmtxref());
  2114.             sprintf(command,
  2115.                 "if test -s /tmp/cxr.%d.2 ; then %s ; fi",
  2116.                 getpid(), com_buf);
  2117.             system(command);
  2118.         }
  2119.         fflush(stdout);
  2120.         if (! isatty(fileno(stdout)))
  2121.             putchar('\f');
  2122.     }
  2123.  
  2124.     sprintf(command, "rm -f /tmp/cxr.%d.[12]", getpid());
  2125.     system(command);
  2126. }
  2127.  
  2128. char *docxref(index, howmany)
  2129. int index, howmany;
  2130. {
  2131.     static char buf[BUFSIZ * 10];
  2132.     int i, j;
  2133.  
  2134.     if (howmany == ONLYONE)
  2135.         sprintf(buf, "%s/docxref %s", SRCDIR, xargv[index]);
  2136.     else
  2137.     {
  2138.         /* put all the args on one command line */
  2139.         sprintf(buf, "%s/docxref ", SRCDIR);
  2140.  
  2141.         i = strlen(buf);
  2142.         for(; xargc > 0; xargc--, xargv++)
  2143.         {
  2144.             for(j = 0; xargv[0][j] != '\0'; j++)
  2145.                 buf[i++] = xargv[0][j];
  2146.             buf[i++] = ' ';
  2147.         }
  2148.         buf[i] = '\0';
  2149.     }
  2150.  
  2151.     return (buf);
  2152. }
  2153.  
  2154. char *filter()        /* command line for splitting off ints and floats */
  2155. {
  2156.     static char buf[40];
  2157.  
  2158.     if (! cflag && sflag)
  2159.         sprintf(buf, "%s/cxrfilt -c %d", SRCDIR, getpid());
  2160.     else if (cflag && ! sflag)
  2161.         sprintf(buf, "%s/cxrfilt -s %d", SRCDIR, getpid());
  2162.     else if (! cflag && ! sflag)
  2163.         sprintf(buf, "%s/cxrfilt -cs %d", SRCDIR, getpid());
  2164.     else
  2165.         sprintf(buf, "%s/cxrfilt %d", SRCDIR, getpid());
  2166.  
  2167.     return (buf);
  2168. }
  2169.  
  2170. char *fmtxref()
  2171. {
  2172.     static char buf[40];
  2173.  
  2174.     if (width != 0)
  2175.         sprintf(buf, "%s/fmtxref -w %d", SRCDIR, width);
  2176.     else
  2177.         sprintf(buf, "%s/fmtxref", SRCDIR);
  2178.     
  2179.     return(buf);
  2180. }
  2181.  
  2182. usage()
  2183. {
  2184.     fprintf(stderr, "usage: %s [-SCcsif] [-w width] [files]\n", name);
  2185.     exit (1);
  2186. }
  2187.  
  2188. char *filename(fname)
  2189. char *fname;
  2190. {
  2191.     char *cp, *basename();
  2192.  
  2193.     cp = basename(fname);
  2194.  
  2195.     return ( strcmp(cp, "-") == 0 ? "stdin" : cp);
  2196. }
  2197.  
  2198. #include "basename.c"
  2199. End of old.cxref.c
  2200.  
  2201.