home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 1 / GoldFishApril1994_CD1.img / d1xx / d103 / cref / cref.c < prev    next >
C/C++ Source or Header  |  1987-10-22  |  17KB  |  908 lines

  1. /*
  2. **   cref - C cross referencer
  3. **    This program reads its standard input or one or more files
  4. **    and prints the file plus an alphabetic list of word references
  5. **    by line number.
  6. **
  7. **    To run:
  8. **        cref [-q] [-lnnn] [-wnnn] [-hheading] [-tnnn] [-?] [file ...]
  9. **
  10. **    Options:
  11. **        q    - don't print normal input file listing.
  12. **        lnnn - set page length to n instead of the default 66.
  13. **        wnnn - set page width to n instead of the default 132.
  14. **        hccc - set page heading to 'ccc' rather than file names.
  15. **        tnnn - set tab spaces to n instead if the default 8.
  16. **      ?    - display this list.
  17. **
  18. **    Mike Edmonds - 5/81
  19. **--------------------------------------------------------------------
  20. **
  21. **  Amiga port by Joel Swank 9/87
  22. **
  23. **  Compiled under Manx:
  24. **  cc cref.c
  25. **  ln cref.o -lc
  26. **
  27. **  Changes besides porting:
  28. **
  29. **  + Deleted temporary file option because the Amiga sort command
  30. **      cannot sort files larger than memory.
  31. **  + Added -t option
  32. **  + Added -? option
  33. **  + Added Usage message and error msgs.
  34. **  + Rewrote case statments that overflowed compiler table
  35. */
  36.  
  37. #include <stdio.h>
  38. #include <ctype.h>
  39. #include <signal.h>
  40. #include <exec/types.h>
  41. #include <stat.h>
  42.  
  43. #define MAXWORD        15        /* maximum chars in word */
  44. #define MAXPAGLINES    9999    /* maximum posible lines in page */
  45. #define MINPAGLINES    4        /* minimum posible lines in page */
  46. #define MAXLINWIDTH    132        /* maximum posible chars in line */
  47. #define MINLINWIDTH    MAXWORD+12    /* minimum posible chars in line */
  48. #define MAXTABSIZE    132        /* maximum posible chars in tab */
  49. #define MINTABSIZE    1        /* minimum posible chars in tab */
  50.  
  51. #define igncase(c)    (isupper(c)? tolower(c) : (c))
  52.  
  53. #undef FALSE
  54. #undef TRUE
  55. #define FALSE    0
  56. #define TRUE    1
  57.  
  58. #ifdef    DEBUG
  59. #define debug(a,b)    fprintf(stderr,(a),(b))
  60. #else
  61. #define debug(a,b)
  62. #endif
  63.  
  64.  
  65.  
  66. /*
  67.  *  global structures
  68.  */
  69.  
  70. #define LINLIST    struct    _linlist
  71. #define WRDLIST    struct    _wrdlist
  72.  
  73. struct    _linlist {        /* line number list node */
  74.     long     ln_no ;      /* line number */
  75.     LINLIST    *ln_next ;      /* next element pointer (or NULL) */
  76. } ;
  77.  
  78. struct    _wrdlist {        /* word list node */
  79.     char    *wd_wd ;      /* pointer to word */
  80.     char    *wd_lwd ;      /* pointer to word (lower case) */
  81.     LINLIST     wd_ln ;      /* first element of line list */
  82.     WRDLIST    *wd_low ;      /* lower child */
  83.     WRDLIST    *wd_hi ;      /* higher child */
  84. } ;
  85.  
  86.  
  87.  
  88. /*
  89.  *  options
  90.  */
  91.  
  92. char    *Progname ;
  93. int     Quiet = FALSE ;    /* don't print input file listing? (-q) */
  94. int     Maxpaglines = 66 ;    /* maximum lines in page (-l) */
  95. int     Maxlinwidth = 132 ;    /* maximum chars in print line (-w) */
  96. int  Tabsize    = 8 ;    /* default length of tab */
  97.  
  98.  
  99.  
  100. /*
  101.  *  global variables
  102.  */
  103.  
  104. char     Crefhdr[MAXLINWIDTH+1] ;/* report header */
  105. char    *Filename ;        /* name of current input file */
  106. char     Date[30] ;        /* current or last file modify date */
  107. long     Hiline = 1L ;        /* current (and max.) input file line number */
  108. WRDLIST    *Wdtree = NULL ;    /* ptr to root node of binary word list */
  109.  
  110.  
  111.  
  112. /*
  113.  *  C language reserved keywords (in pseudo random order)
  114.  */
  115. char    *Ckeywords[] = {
  116.     "char",
  117.     "static",
  118.     "break",
  119.     "#define",
  120.     "#if",
  121.     "default",
  122.     "#ifdef",
  123.     "#ifndef",
  124.     "register",
  125.     "void",
  126.     "if",
  127.     "while",
  128.     "#line",
  129.     "union",
  130.     "switch",
  131.     "#else",
  132.     "asm",
  133.     "do",
  134.     "#include",
  135.     "#undef",
  136.     "#endif",
  137.     "long",
  138.     "continue",
  139.     "float",
  140.     "short",
  141.     "typedef",
  142.     "for",
  143.     "struct",
  144.     "case",
  145.     "else",
  146.     "unsigned",
  147.     "int",
  148.     "extern",
  149.     "auto",
  150.     "goto",
  151.     "entry",
  152.     "return",
  153.     "double",
  154.     "sizeof",
  155.     0
  156. } ;
  157.  
  158.  
  159.  
  160.  
  161. /*
  162.  *  main - Store C keywords.
  163.  *       Get program options and format heading lines.
  164.  *       Get words from input file (or files) and store in tree.
  165.  *       Retrieve and print in word sequence.
  166.  */
  167. main(argc, argv)
  168. int     argc ;
  169. char    *argv[] ;
  170. {
  171.     char    wordfilebuf[BUFSIZ] ;
  172.     register FILE    *filep ;
  173.     char    *getword(), *word ;
  174.     struct     stat    stbuf ;
  175.     long     time() ;
  176.     register cnt ;
  177.     int     files=0 ;
  178.  
  179.     Progname = *argv ;        /* get options */
  180.     getcmd(argc, argv) ;
  181.  
  182.  
  183.                     /* store C keywords */
  184.     for (cnt=0 ; Ckeywords[cnt] ; cnt++)
  185.         storword(Ckeywords[cnt], 0L) ;
  186.  
  187.  
  188.     listchr(-1);    /* clear output line */
  189.  
  190.                     /* read and store files */
  191.     for (cnt=1 ; cnt < argc ; cnt++)
  192.         if (*argv[cnt] != '-')
  193.         {    files++ ;
  194.             Filename = argv[cnt] ;
  195.             if ((filep = fopen(Filename, "r")) == NULL)
  196.                 fatal("can't open %s", Filename) ;
  197.             stat(Filename, &stbuf) ;
  198.             mkdate((long)stbuf.st_mtime) ;
  199.             while (word = getword(filep))
  200.                 storword(word, Hiline);
  201.             fclose(filep) ;
  202.         }
  203.  
  204.     if (!files)            /* no files - read stdin */
  205.     {    if (*Crefhdr)
  206.             Filename = Crefhdr ;
  207.         else
  208.             Filename = "stdin" ;
  209.         mkdate(time(0)) ;
  210.         while (word = getword(stdin))
  211.             storword(word, Hiline) ;
  212.     }
  213.  
  214.  
  215.     /*  print cross reference report */
  216.     cref(Wdtree) ;
  217.  
  218.     exit(0) ;
  219. }
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228. /*
  229.  *  getcmd - get arguments from command line & build page headings
  230.  */
  231. getcmd(argc, argv)
  232. register argc ;
  233. register char    *argv[] ;
  234. {
  235.     register cnt ;
  236.  
  237.     debug("GETCMD(%d", argc) ;
  238.     debug(", %s)\n", argv[0]) ;
  239.  
  240.     *Crefhdr = '\0' ;
  241.                     /* get command options */
  242.     for (cnt=1; cnt < argc; cnt++)
  243.     {    if (*argv[cnt] == '-')
  244.         {    switch(argv[cnt][1])
  245.             {  case 'q':
  246.                 Quiet = TRUE ;
  247.                 break ;
  248.  
  249.                case 'l':
  250.                 Maxpaglines = atoi(&argv[cnt][2]) ;
  251.                 if (Maxpaglines < MINPAGLINES
  252.                  || Maxpaglines > MAXPAGLINES)
  253.                     fatal("Bad -l value: %s", argv[cnt]) ;
  254.                 break ;
  255.  
  256.                case 'w':
  257.                 Maxlinwidth = atoi(&argv[cnt][2]) ;
  258.                 if (Maxlinwidth < MINLINWIDTH
  259.                  || Maxlinwidth > MAXLINWIDTH)
  260.                     fatal("Bad -w value: %s", argv[cnt]) ;
  261.                 break ;
  262.  
  263.                case 't':
  264.                 Tabsize = atoi(&argv[cnt][2]) ;
  265.                 if (Tabsize < MINTABSIZE
  266.                  || Tabsize > MAXTABSIZE)
  267.                     fatal("Bad -t value: %s", argv[cnt]) ;
  268.                 break ;
  269.  
  270.                case 'h':
  271.                 strncpy(Crefhdr, &argv[cnt][2], MAXLINWIDTH) ;
  272.                 Crefhdr[MAXLINWIDTH] = '\0' ;
  273.                 break ;
  274.  
  275.                case '?':                    /* help option */
  276.                  usage();
  277.                  printf(" Options:\n");
  278.                  printf(" q    - don't print normal input file listing\n");
  279.                  printf(" lnnn - set page length to n instead of the default 66.\n");
  280.                  printf(" wnnn - set page width to n instead of the default 132.\n");
  281.                  printf(" hccc - set page heading to 'ccc' rather than file names\n");
  282.                  printf(" tnnn - set tab spacing to n instead of the default 8\n");
  283.                  printf(" ?    - display this list.\n");
  284.                 exit(0);
  285.  
  286.                default:
  287.                  usage();
  288.                  exit(0);
  289.             }
  290.         }
  291.     }
  292.  
  293.                     /* insert file names in hdr */
  294.     if (!*Crefhdr)
  295.         for (cnt=1; cnt < argc; cnt++)
  296.             if (*argv[cnt] != '-')
  297.                 strjoin(Crefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
  298. }
  299.  
  300.  
  301.  
  302. usage()
  303. {
  304. printf("usage:cref [-q] [-lnnn] [-wnnn] [-hheading] [-tnnn] [-?] [file ...]\n");
  305. }
  306.  
  307.  
  308.  
  309.  
  310. /*
  311.  *  getword - read, print and return next word from file
  312.  */
  313. char *
  314. getword(filep)
  315. FILE    *filep ;
  316. {
  317.     static     char    wordbuf[MAXWORD+1] ;
  318.     register char    *wp = wordbuf ;
  319.     register maxw = sizeof(wordbuf) ;
  320.     register chr ;
  321.     int     inword=0, lastchr=0 ;
  322.     long     slineno ;
  323.  
  324. #define    _listchr(chr)    if (!Quiet) listchr(chr)
  325.  
  326. #define    _rtrnwrd(wp)             \
  327.     {    ungetc(chr, filep) ;    \
  328.         *(wp) = '\0' ;        \
  329.         return wordbuf ;    \
  330.     }
  331.  
  332.     while ((chr = getc(filep)) != EOF)
  333.     {    
  334.             /* normal char - add to current word */
  335.         if ((chr <= 'z' && chr >= 'a') || 
  336.             (chr <= 'Z' && chr >= 'A') || 
  337.              chr == '_' )
  338.             {
  339.             if (maxw-- <= 1)
  340.                 _rtrnwrd(wp) ;
  341.             *wp++ = chr ;
  342.             inword++ ;
  343.             _listchr(chr) ;
  344.             }
  345.  
  346.         else switch (chr)
  347.         {
  348.                     /* digit - can't be 1st char in word */
  349.            case '0': case '1': case '2': case '3': case '4':
  350.            case '5': case '6': case '7': case '8': case '9':
  351.             if (inword)
  352.             {    if (maxw-- <= 1)
  353.                     _rtrnwrd(wp) ;
  354.                 *wp++ = chr ;
  355.             }
  356.             _listchr(chr) ;
  357.             break ;
  358.  
  359.                     /* '#' - must be 1st char in word */
  360.            case '#':
  361.             if (inword)
  362.                 _rtrnwrd(wp) ;
  363.             *wp++ = chr ;
  364.             inword++ ;
  365.             _listchr(chr) ;
  366.             break ;
  367.  
  368.                     /* newline - end current word */
  369.            case '\n':
  370.             if (inword)
  371.                 _rtrnwrd(wp) ;
  372.             _listchr(chr) ;
  373.             Hiline++ ;
  374.             break ;
  375.  
  376.                     /* comments - print & bypass */
  377.            case '/':
  378.             if (inword)
  379.                 _rtrnwrd(wp) ;
  380.             _listchr(chr) ;
  381.             slineno = Hiline ;
  382.             if ((chr = getc(filep)) == '*')
  383.             {    _listchr(chr) ;
  384.                 while (chr != EOF)
  385.                 {    chr = getc(filep) ;
  386.                     _listchr(chr) ;
  387.                     if (chr == '\n')
  388.                         Hiline++ ;
  389.                     else if (chr == '*')
  390.                     {    chr = getc(filep) ;
  391.                         _listchr(chr) ;
  392.                         if (chr == '\n')
  393.                             Hiline++ ;
  394.                         else if (chr == '/')
  395.                             break ; ;
  396.                     }
  397.                 }
  398.                 if (chr == EOF)
  399.                     fatal("unterminated comment at %ld in %s", slineno, Filename) ;
  400.             }
  401.             else
  402.                 ungetc(chr, filep) ;
  403.             break ;
  404.  
  405.                     /* words in quotes - print & bypass */
  406.            case '"':
  407.             if (inword)
  408.                 _rtrnwrd(wp) ;
  409.             _listchr(chr) ;
  410.             slineno = Hiline ;
  411.             if (lastchr != '\\')
  412.             {    do
  413.                 {    if (chr == '\\' && lastchr == '\\')
  414.                         lastchr = '\0' ;
  415.                     else
  416.                         lastchr = chr ;
  417.                     if ((chr = getc(filep)) == EOF)
  418.                         fatal("unterminated quote at %ld in %s", slineno, Filename) ;
  419.                     _listchr(chr) ;
  420.                     if (chr == '\n')
  421.                         Hiline++ ;
  422.                 } while (chr != '"' || lastchr == '\\') ;
  423.             }
  424.             break ;
  425.  
  426.                     /* letters in quotes - print & bypass */
  427.            case '\'':
  428.             if (inword)
  429.                 _rtrnwrd(wp) ;
  430.             _listchr(chr) ;
  431.             if (isprint(chr = getc(filep)))
  432.             {    _listchr(chr) ;
  433.                 if (chr == '\\')
  434.                 {    if (!isprint(chr = getc(filep)))
  435.                         goto toofar ;
  436.                     _listchr(chr) ;
  437.                 }
  438.                 if ((chr = getc(filep)) != '\'')
  439.                     goto toofar ;
  440.                 _listchr(chr) ;
  441.             }
  442.             else
  443.                toofar:
  444.                 ungetc(chr, filep) ;
  445.             break ;
  446.  
  447.            default:
  448.             if (inword)
  449.                 _rtrnwrd(wp) ;
  450.             _listchr(chr) ;
  451.             break ;
  452.         }
  453.  
  454.         lastchr = chr ;
  455.     }
  456.  
  457.     if (inword)
  458.         _rtrnwrd(wp) ;
  459.     _listchr(EOF) ;
  460.     return NULL ;
  461. }
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470. /*
  471.  *  listchr - list the input files one character at a time
  472.  */
  473.  
  474. static    Listpage = 0 ;
  475. static    Listpline = MAXPAGLINES ;
  476.  
  477. listchr(chr)
  478. register chr ;
  479. {
  480.     static    char     linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
  481.     static    lastchr=0, linecnt=0 ;
  482.     int    remain;
  483.  
  484.     if (chr == -1)            /* clear line buffer */
  485.         {
  486.         setmem(linebuf,Maxlinwidth,' ');
  487.         return;
  488.         }
  489.  
  490.     if (chr == EOF)            /* EOF - print final line */
  491.     {    *lineptr = '\0' ;
  492.         listline(linebuf) ;
  493.         Listpage = 0 ;
  494.         Listpline = MAXPAGLINES ;
  495.         lineptr = linebuf ;
  496.         linecnt = 0 ;
  497.         return ;
  498.     }
  499.  
  500.     if (lineptr == linebuf)        /* new line - format line number */
  501.     {    ltoc(linebuf, Hiline, 6) ;
  502.         lineptr = linebuf+6 ;
  503.         *lineptr++ = ' ' ;
  504.         *lineptr++ = ' ' ;
  505.         linecnt = 8 ;
  506.     }
  507.  
  508. #define    _lineoflo(ctr, newctr)        \
  509.     if ((ctr) >= Maxlinwidth)    \
  510.     {    *lineptr = '\0' ;    \
  511.         listline(linebuf) ;    \
  512.         lineptr = &linebuf[8] ;    \
  513.         linecnt = (newctr) ;    \
  514.     }
  515.  
  516.     switch (chr)
  517.     {                /* newline - print last line */
  518.        case '\n':
  519.         if (lastchr != '\f')
  520.         {    *lineptr = '\0' ;
  521.             listline(linebuf) ;
  522.         }
  523.         lineptr = linebuf ;
  524.         linecnt = 0 ;
  525.         break ;
  526.  
  527.                      /* formfeed - print line and end page */
  528.        case '\f':
  529.         if (linecnt != 8)
  530.         {    *lineptr = '\0' ;
  531.             listline(linebuf) ;
  532.         }
  533.         Listpline = MAXPAGLINES ;
  534.         lineptr = linebuf ;
  535.         linecnt = 0 ;
  536.         break ;
  537.  
  538.                     /* tab - skip to next tab stop */
  539.        case '\t':
  540.         linecnt += Tabsize ;
  541.         remain =  linecnt % Tabsize ;
  542.         linecnt -= remain;
  543.         _lineoflo(linecnt, 8) ;
  544.         lineptr += Tabsize ;
  545.         lineptr -= remain;
  546.         break ;
  547.  
  548.                     /* backspace - print, but don't count */
  549.        case '\b':
  550.         *lineptr++ = chr ;
  551.         break ;
  552.  
  553.                     /* ctl-char - print as "^x" */
  554.              case 001: case 002: case 003:
  555.        case 004: case 005: case 006: case 007:
  556.                      case 013:
  557.                  case 015: case 016: case 017:
  558.        case 020: case 021: case 022: case 023:
  559.        case 024: case 025: case 026: case 027:
  560.        case 030: case 031: case 032: case 033:
  561.        case 034: case 035: case 036: case 037:
  562.         _lineoflo(linecnt+=2, 10) ;
  563.         *lineptr++ = '^' ;
  564.         *lineptr++ = ('A'-1) + chr ;
  565.         break ;
  566.  
  567.        default:
  568.         if (isprint(chr))
  569.         {    _lineoflo(++linecnt, 9) ;
  570.             *lineptr++ = chr ;
  571.         }
  572.  
  573.         else        /* non-ascii chars - print as "\nnn" */
  574.         {    _lineoflo(linecnt+=4, 12) ;
  575.             *lineptr++ = '\\' ;
  576.             *lineptr++ = '0' + ((chr & 0300) >> 6) ;
  577.             *lineptr++ = '0' + ((chr & 070) >> 3) ;
  578.             *lineptr++ = '0' + (chr & 07) ;
  579.         }
  580.         break ;
  581.     }
  582.     lastchr = chr ;
  583. }
  584.  
  585.             /* print a completed line from the input file */
  586. listline(line)
  587. register char    *line ;
  588. {
  589.     if (*line)
  590.     {    if (++Listpline >= (Maxpaglines-8))
  591.         {    putchar('\f') ;
  592.             printf("\n%s %s  Page %d\n\n",
  593.                 Date, Filename, ++Listpage) ;
  594.             Listpline = 0 ;
  595.         }
  596.         puts(line) ;
  597.         listchr(-1);    /* clear line buffer */
  598.     }
  599. }
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609. /*
  610.  *  storword - store word and line # in binary word tree or word file
  611.  */
  612.  
  613. storword(word, lineno)
  614. register char    *word ;
  615. long     lineno ;
  616. {
  617.     char     lword[MAXWORD+1] ;
  618.     register char    *cp1, *cp2 ;
  619.     WRDLIST    *addword() ;
  620.  
  621.                     /* convert word to lower case */
  622.     for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
  623.         ;
  624.  
  625.                     /* store words and lineno */
  626.     Wdtree = addword(Wdtree, word, lword, lineno) ;
  627. }
  628.  
  629.  
  630.  
  631. /*
  632.  *  addword - add word and line# to in-core word list
  633.  */
  634. WRDLIST *
  635. addword(wdp, word, lword, lineno)
  636. register WRDLIST *wdp ;
  637. char    *word, *lword ;
  638. long     lineno ;
  639. {
  640.     char    *malloc() ;
  641.     int     comp ;
  642.  
  643.                     /* insert new word into list */
  644.     if (wdp == NULL)
  645.     {    register wordlen = strlen(word) + 1 ;
  646.  
  647.         wdp = (WRDLIST *)malloc((wordlen * 2) + sizeof(WRDLIST)) ;
  648.         if (wdp == NULL)
  649.             goto nomemory ;
  650.  
  651.         wdp->wd_wd  = (char *)wdp + sizeof(WRDLIST) ;
  652.         wdp->wd_lwd = wdp->wd_wd + wordlen ;
  653.         strcpy(wdp->wd_wd,  word) ;
  654.         strcpy(wdp->wd_lwd, lword) ;
  655.  
  656.         wdp->wd_hi = wdp->wd_low = NULL ;
  657.         wdp->wd_ln.ln_no = lineno ;
  658.         wdp->wd_ln.ln_next = NULL ;
  659.     }
  660.  
  661.                     /* word matched in list? */
  662.     else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
  663.           && ((comp = strcmp(word,  wdp->wd_wd))  == 0))
  664.     {    register LINLIST *lnp, **lnpp ;
  665.  
  666.         if (wdp->wd_ln.ln_no)
  667.         {              /* add line# to linked list */
  668.             lnp = &wdp->wd_ln ;
  669.             do
  670.             {    if (lineno == lnp->ln_no)
  671.                     return wdp ;
  672.                 lnpp = &lnp->ln_next ;
  673.             } while ((lnp = *lnpp) != NULL) ;
  674.  
  675.             *lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
  676.             if ((lnp = *lnpp) == NULL)
  677.                 goto nomemory ;
  678.             lnp->ln_no = lineno ;
  679.             lnp->ln_next = NULL ;
  680.         }
  681.     }
  682.  
  683.     else if (comp < 0)        /* search for word in children */
  684.         wdp->wd_low = addword(wdp->wd_low, word, lword, lineno) ;
  685.     else
  686.         wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
  687.  
  688.     return wdp ;
  689.  
  690.  
  691.                     /* not enough memory - convert to -b */
  692. nomemory:
  693.     fatal("not enough memory for in-core word list") ;
  694. }
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701.  
  702. /*
  703.  *  cref - print cross reference report from internal word list
  704.  */
  705. #define MAXLNOS 2000        /* maximum line nos. for a word */
  706. long    Linenos[MAXLNOS] ;    /* list of line numbers for a word */
  707.  
  708. cref(wdtree)
  709. register WRDLIST *wdtree ;
  710. {
  711.     creftree(wdtree) ;
  712.     putchar('\f') ;
  713. }
  714.  
  715. creftree(wdp)            /* recursively print word tree nodes */
  716. register WRDLIST *wdp ;
  717. {
  718.     register LINLIST *lnp ;
  719.     register nos ;
  720.  
  721.     if (wdp != NULL)
  722.     {    creftree(wdp->wd_low) ;    /* print lower children */
  723.  
  724.         nos = 0 ;
  725.         if (Linenos[0] = wdp->wd_ln.ln_no)
  726.         {    lnp = &wdp->wd_ln ;
  727.             while ((lnp = lnp->ln_next) != NULL)
  728.                 if (nos < (MAXLNOS-2))
  729.                     Linenos[++nos] = lnp->ln_no ;
  730.             printword(wdp->wd_wd, nos) ;
  731.         }
  732.  
  733.         creftree(wdp->wd_hi) ;    /* print higher children */
  734.     }
  735. }
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743. /*
  744.  *  printword - print a word and all its line number references
  745.  */
  746. printword(word, nos)
  747. char    *word ;
  748. register nos ;
  749. {
  750.     static    firstime=TRUE, linecnt, maxlnos, lnosize ;
  751.     register cnt ;
  752.  
  753.     if (firstime)
  754.     {    firstime = FALSE ;
  755.         linecnt = Maxpaglines ;
  756.         for (lnosize=1 ; Hiline ; lnosize++)
  757.             Hiline /= 10L ;
  758.         maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
  759.     }
  760.  
  761.     if (linecnt >= (Maxpaglines - 8))
  762.     {    printheads() ;
  763.         linecnt = 5 ;
  764.     }
  765.  
  766.     printf("%-15s%5d  ", word, ++nos) ;
  767.     Linenos[nos] = 0 ;
  768.  
  769.     for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
  770.     {    if (++cnt > maxlnos)
  771.         {    cnt = 1 ;
  772.             if (linecnt++ >= (Maxpaglines - 2))
  773.             {    printheads() ;
  774.                 linecnt = 5 ;
  775.                 printf("%-15s(cont) ", word);
  776.             }
  777.             else
  778.                 printf("\n%22s", " ") ;
  779.         }
  780.         printf("%*ld", lnosize, Linenos[nos]) ;
  781.     }
  782.     putchar('\n') ;
  783.  
  784.     linecnt++ ;
  785. }
  786.  
  787.  
  788.  
  789. /*
  790.  *  printheads - print page headings
  791.  */
  792. printheads()
  793. {
  794.     static    page=0 ;
  795.     long    time() ;
  796.  
  797.     if (!page)
  798.         mkdate(time(0)) ;
  799.  
  800.     putchar('\f') ;
  801.     printf("\nCREF  %s %.*s  Page %d\n\n",
  802.         Date, (Maxlinwidth-36), Crefhdr, ++page) ;
  803.     printf("word             refs    line numbers\n\n") ;
  804. }
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813. /*
  814.  *  ltoc - store ASCII equivalent of long value in given field
  815.  */
  816. ltoc(fld, lval, len)
  817. register char    *fld ;
  818. register long    lval ;
  819. register len ;
  820. {
  821.     fld += len ;
  822.     while (len-->0)
  823.         if (lval)
  824.         {    *--fld = '0' + (lval%10L) ;
  825.             lval /= 10L ;
  826.         }
  827.         else
  828.             *--fld = ' ' ;
  829. }
  830.  
  831.  
  832.  
  833. /*
  834.  *  mkdate - build time/date for use in heading lines
  835.  */
  836. mkdate(atime)
  837. long    atime ;
  838. {
  839.     long    mtime ;
  840.     char    *cp, *ctime() ;
  841.  
  842.     debug("MKDATE(%ld)\n", atime) ;
  843.  
  844.     mtime = atime ;
  845.     cp = ctime(&mtime) ;
  846.     *(cp+24) = ' ' ;        /* clear newline */
  847.     strcpy(cp+16, cp+19) ;        /* shift over seconds */
  848.     strcpy(Date, cp+4) ;
  849. }
  850.  
  851.  
  852.  
  853. /*
  854.  *  strjoin - join "str1" to "str2" (separated by "sep")
  855.  *    Truncate if necessary to "max" chars.
  856.  */
  857. strjoin(str1, sep, str2, max)
  858. register char    *str1, *str2;
  859. char    sep ;
  860. register max ;
  861. {
  862.     if (*str2)
  863.     {    if (*str1)
  864.         {    while (*str1++)
  865.                 if (--max <= 0)
  866.                     goto oflo ;
  867.             max--, str1-- ;
  868.             *str1++ = sep ;
  869.         }
  870.         while (*str1++ = *str2++)
  871.             if (--max <= 0)
  872.                 goto oflo ;
  873.     }
  874.     return ;
  875.  
  876. oflo:
  877.     *--str1 = '\0' ;
  878.     return ;
  879. }
  880.  
  881.  
  882.  
  883.  
  884.  
  885.  
  886.  
  887. /*
  888.  *  error - print standard error msg
  889.  */
  890. error(ptrn, data1, data2)
  891. register char    *ptrn, *data1, *data2 ;
  892. {
  893.     fprintf(stderr, "%s: ", Progname) ;
  894.     fprintf(stderr, ptrn, data1, data2) ;
  895.     putc('\n', stderr) ;
  896. }
  897.  
  898.  
  899. /*
  900.  *  fatal - print standard error msg and halt process
  901.  */
  902. fatal(ptrn, data1, data2)
  903. register char    *ptrn, *data1, *data2 ;
  904. {
  905.     error(ptrn, data1, data2) ;
  906.     exit(1);
  907. }
  908.