home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / PROGRAM / C / CFLOW / CFLOWX.C < prev    next >
Text File  |  1993-12-01  |  24KB  |  1,079 lines

  1. /*    CFLOWX.C: cflow cross-reference utility for function/macro calls
  2. **
  3. **    Copyright (c) 1985 by:
  4. **
  5. **        Lawrence R. Steeger
  6. **        1009 North Jackson
  7. **        Milwaukee, Wisconsin 53202
  8. **        414-277-8149
  9. */
  10.  
  11. #include <stdio.h>            /* CI-C86 header        */
  12.  
  13. #define    VOID int
  14.  
  15. /*    external functions        */
  16.  
  17. extern    VOID abort();
  18. extern    char *alloc();
  19. extern    VOID exit();
  20. extern    int fclose();
  21. extern    char *fgets();
  22. extern    FILE *fopen();
  23. extern    VOID fprintf();
  24. extern    VOID free();
  25. extern    char *lower();
  26. extern    VOID printf();
  27. extern    VOID qsort();
  28. extern    char *realloc();
  29. extern    VOID sprintf();
  30. extern    int sscanf();
  31. extern    char *strcat();
  32. extern    int strcmp();
  33. extern    char *strcpy();
  34. extern    int strlen();
  35. extern    int strncmp();
  36. extern    int tolower();
  37.  
  38. #include "cflowx.h"            /* CFLOW/CFLOWX header        */
  39.  
  40. #define    VERSION    85
  41. #define    RELEASE    06
  42. #define    MODIFIC    20
  43.  
  44. #define    outinfo(S) fputs(S, stdout)
  45.  
  46. outlogo()
  47. {
  48.     fprintf(stdout, "\n%s V%02d.%02d.%02d - %s",
  49.         "CFLOWX",
  50.         VERSION, RELEASE, MODIFIC,
  51.         "cflow cross-reference generator");
  52.     outinfo("\nCopyright (c) 1985 by Lawrence R. Steeger\n");
  53. }
  54.  
  55. outhelp()
  56. {
  57.     outinfo("\nusage: cflowx [-[efimr]] infile [>outfile]");
  58.     outinfo("\n note: infile is created by the");
  59.     outinfo(" CFLOW utility using the -x flag\n");
  60.     outinfo("\nreports: -e    function/macro external definition report");
  61.     outinfo("\n         -f    path\\file name report");
  62.     outinfo("\n         -i    function/macro internal definition report");
  63.     outinfo("\n         -m    macro name cross-reference report");
  64.     outinfo("\n         -r    function name cross-reference report");
  65.     outinfo("\n   note: The order of the specified [efimr] flags will");
  66.     outinfo("\n         be the order that the reports will generated in.");
  67. }
  68.  
  69. #define    OUTHDR    0            /* start output header        */
  70. #define    OUTUPD    1            /* update output array        */
  71. #define    OUTFLSH    2            /* flush output line        */
  72. #define    OUTCLR    3            /* clear output line        */
  73.  
  74. typedef    struct _xref {            /* cross-reference record    */
  75.  
  76.     struct _xref *_related;        /* related XREF chain        */
  77.  
  78.     unsigned char _dup;        /* duplicate entry flag        */
  79.  
  80.     int _fnmbr,            /* file name number        */
  81.         _level,            /* {...} nest level number    */
  82.         _line;            /* line number            */
  83.  
  84.     unsigned int _str;        /* record data string offset    */
  85.  
  86.     } XREF;
  87.  
  88. static    XREF *xref = NULL,        /* XREF element pointers    */
  89.          *xref1 = NULL,
  90.          *xref2 = NULL,
  91.          *xref3 = NULL,
  92.          *xref4 = NULL,
  93.          *xchain = NULL;
  94.  
  95. /*    useability macros for XREF    */
  96.  
  97. #define    related xref->_related
  98. #define    dup xref->_dup
  99. #define    fnmbr xref->_fnmbr
  100. #define    level xref->_level
  101. #define    line xref->_line
  102. #define    str xref->_str
  103.  
  104. #define    related1 xref1->_related
  105. #define    dup1 xref1->_dup
  106. #define    fnmbr1 xref1->_fnmbr
  107. #define    level1 xref1->_level
  108. #define    line1 xref1->_line
  109. #define    str1 xref1->_str
  110.  
  111. #define    related2 xref2->_related
  112. #define    dup2 xref2->_dup
  113. #define    fnmbr2 xref2->_fnmbr
  114. #define    level2 xref2->_level
  115. #define    line2 xref2->_line
  116. #define    str2 xref2->_str
  117.  
  118. #define    related3 xref3->_related
  119. #define    dup3 xref3->_dup
  120. #define    fnmbr3 xref3->_fnmbr
  121. #define    level3 xref3->_level
  122. #define    line3 xref3->_line
  123. #define    str3 xref3->_str
  124.  
  125. #define    related4 xref4->_related
  126. #define    dup4 xref4->_dup
  127. #define    fnmbr4 xref4->_fnmbr
  128. #define    level4 xref4->_level
  129. #define    line4 xref4->_line
  130. #define    str4 xref4->_str
  131.  
  132. #define    relxc xchain->_related
  133. #define    dupxc xchain->_dup
  134. #define    fnmbrxc xchain->_fnmbr
  135. #define    levelxc xchain->_level
  136. #define    linexc xchain->_line
  137. #define    strxc xchain->_str
  138.  
  139. typedef    struct _rqueue {        /* xref record queue header    */
  140.  
  141.     XREF **__xref;            /* XREF record queue pointer    */
  142.     unsigned char _sorted;        /* sorted queue flag        */
  143.     unsigned int _total,        /* offset counter        */
  144.              _index;        /* offset index            */
  145.  
  146.     } RQUEUE;
  147.  
  148. static    RQUEUE rqueue[HIGHKEY];        /* xref record queue headers    */
  149.  
  150. static    int rkey = 0,            /* xref record queue keys    */
  151.         rkey1 = 0,
  152.         rkey2 = 0;
  153.  
  154. /*    useability macros for RQUEUE    */
  155.  
  156. #define    pxref rqueue[rkey].__xref
  157. #define    sorted rqueue[rkey]._sorted
  158. #define    total rqueue[rkey]._total
  159. #define    index rqueue[rkey]._index
  160.  
  161. #define    pxref1 rqueue[rkey1].__xref
  162. #define    sorted1 rqueue[rkey1]._sorted
  163. #define    total1 rqueue[rkey1]._total
  164. #define    index1 rqueue[rkey1]._index
  165.  
  166. #define    pxref2 rqueue[rkey2].__xref
  167. #define    sorted2 rqueue[rkey2]._sorted
  168. #define    total2 rqueue[rkey2]._total
  169. #define    index2 rqueue[rkey2]._index
  170.  
  171. static    unsigned char *strings = NULL;    /* character strings buffer    */
  172. static    unsigned int stringl = 0;    /* character strings length    */
  173.  
  174. static    char *invrec =            /* standard input error format    */
  175.          "invalid record %s- %d: \"%s";
  176.  
  177. static    int reportc = 0;        /* report function counter    */
  178. static    PFI *(reports) = NULL;        /* report function pointers    */
  179.  
  180. /*    mainline            */
  181.  
  182. main(argc, argv)
  183. int argc;
  184. unsigned char **argv;
  185. {
  186.     int i, j;
  187.  
  188.     outlogo();            /* display utility logo        */
  189.  
  190.     if (argc < 2) {            /* too few arguments        */
  191.         outhelp();
  192.         exit(1);        /* exit abnormal        */
  193.     }
  194.  
  195.     for (rkey = 0; rkey < HIGHKEY; rkey++) { /* reset queue headers    */
  196.         pxref  = NULL;
  197.         sorted = FALSE;
  198.         total  = 0;
  199.         index  = 0;
  200.     }
  201.  
  202.     for (i = 1; i < argc; i++) {    /* process -flags        */
  203.         if (*argv[i] == '-') {
  204.             flags(argv[i]);
  205.             for (j = i--, --argc; j < argc; j++)
  206.                 argv[j] = argv[j+1];
  207.         }
  208.     }
  209.  
  210.     if (argc < 2) {            /* no filename specified !    */
  211.         outhelp();
  212.         exit(1);        /* exit abnormal        */
  213.     }
  214.  
  215.     buildq(argv[1]);        /* build CFLOWX record queues    */
  216.  
  217.     dupfile();            /* detect duplicate files    */
  218.  
  219.     for (i = 0; i < reportc; i++)    /* generate CFLOWX reports    */
  220.         (*(reports[i]))();
  221.  
  222.     exit(0);            /* exit normal            */
  223. }
  224.  
  225. /*    process command line flags                    */
  226.  
  227. flags(flag)
  228. unsigned char *flag;
  229. {
  230.     int i;
  231.  
  232.     PFI function;
  233.  
  234.     int reporte(),            /* function/macro external    */
  235.         reportf(),            /* path\file name        */
  236.         reporti(),            /* function/macro internal    */
  237.         reportm(),            /* macro cross_reference    */
  238.         reportr();            /* function cross_reference    */
  239.  
  240.     for (i = 0; flag[++i];) {        /* scan all characters    */
  241.  
  242.         function = NULL;
  243.  
  244.         switch (tolower(flag[i])) {    /* set any valid flag    */
  245.  
  246.         case 'e':        /* function/macro external    */
  247.             function = reporte;
  248.             break;
  249.  
  250.         case 'f':        /* path\file name        */
  251.             function = reportf;
  252.             break;
  253.  
  254.         case 'i':        /* function/macro internal    */
  255.             function = reporti;
  256.             break;
  257.  
  258.         case 'm':        /* macro cross_reference    */
  259.             function = reportm;
  260.             break;
  261.  
  262.         case 'r':        /* function cross_reference    */
  263.             function = reportr;
  264.             break;
  265.  
  266.         default:
  267.             abort("Unknown flag: '%c'\n", flag[i]);
  268.             break;
  269.         }
  270.  
  271.         if (function != NULL) {
  272.             reports = realloc(reports, (sizeof(PFI)*(reportc+1)));
  273.             if (reports == NULL)
  274.                 abort("REALLOC - reports");
  275.             reports[reportc++] = function;
  276.         }
  277.     }
  278.  
  279.     flag[0] = EOS;                /* terminate flag    */
  280. }
  281.  
  282. /*    build CFLOWX record queues                    */
  283.  
  284. buildq(filename)
  285. unsigned char *filename;
  286. {
  287.     unsigned char *cp,
  288.               string[MAXBUF];
  289.  
  290.     unsigned int stradd();        /* add string to char buffer    */
  291.  
  292.     int currec,            /* current input record        */
  293.         crelxkey,            /* current related base key    */
  294.         i,
  295.         j;
  296.  
  297.     FILE *fptr;            /* input file pointer        */
  298.  
  299.     XREF *crelated;            /* related XREF base pointer    */
  300.  
  301.     if ((fptr = fopen(filename, "r+")) == NULL) /* open input file    */
  302.         abort("FOPEN - %s\n", filename);
  303.  
  304.     currec = 0;            /* start record counter        */
  305.     crelated = NULL;        /* clear related chain base    */
  306.  
  307.     while (1) {            /* scan XREF input        */
  308.  
  309.         if (fgets(string,MAXBUF,fptr)==FALSE) /* get record    */
  310.             break;
  311.  
  312.         xref = alloc(sizeof(XREF));    /* next XREF element    */
  313.  
  314.         ++currec;            /* update line count    */
  315.  
  316.         /*    scan for standard fields             */
  317.  
  318.         if ((i=sscanf(string,
  319.                 cxref((MAXFLDS-1)),
  320.                 &rkey,
  321.                 &fnmbr,
  322.                 &level,
  323.                 &line)
  324.             ) != ((MAXFLDS-1)*2)) {
  325.             printf("sscanf(%d)\n", i);
  326.             abort(invrec, "sscanf ", currec, string);
  327.         }
  328.  
  329.         if (rkey >= HIGHKEY)        /* validate record key    */
  330.             abort(invrec, "type ", currec, string);
  331.  
  332.         /*    skip over standard fields            */
  333.  
  334.         for (i=j=0; j != (MAXFLDS-1) && string[i] != RS; i++)
  335.             if (string[i] == US) ++j;
  336.  
  337.         cp = &string[i];        /* save data position    */
  338.  
  339.         /*    find trailing RS                */
  340.  
  341.         for (; string[i] && string[i] != RS; i++);
  342.  
  343.         string[i] = EOS;        /* truncate at RS    */
  344.  
  345.         str = stradd(cp);        /* add string to buffer    */
  346.  
  347.         pxref = realloc(pxref, (sizeof(XREF *) * (index+1)));
  348.  
  349.         if (pxref == NULL) abort("REALLOC - XREC");
  350.  
  351.         pxref[index++] = xref;
  352.         total++;
  353.  
  354.         switch (rkey) {        /* build record relationships    */
  355.  
  356.         /*    related record base keys            */
  357.  
  358.         case WILDPTH:            /* wildcard path    */
  359.         case FILEPTH:            /* C source path    */
  360.         case FUNCNME:            /* function name    */
  361.         case MACNME:            /* macro name        */
  362.             crelated = xref;    /* set new base record    */
  363.             crelxkey = rkey;    /* set new base key    */
  364.             break;
  365.  
  366.         /*    related record keys                */
  367.  
  368.         case WILDNME:            /* wildcard name    */
  369.             checkrel(WILDPTH,crelxkey,currec,string);
  370.             goto relation;
  371.  
  372.         case FILENME:            /* C source name    */
  373.             checkrel(FILEPTH,crelxkey,currec,string);
  374.             goto relation;
  375.  
  376.         case FUNCDCL:            /* function declaration    */
  377.             checkrel(FUNCNME,crelxkey,currec,string);
  378.             goto relation;
  379.  
  380.         case FUNCARG:            /* function argument    */
  381.             if (crelxkey == FUNCARG)
  382.                 goto relation;
  383.             checkrel(FUNCDCL,crelxkey,currec,string);
  384.             goto relation;
  385.  
  386.         case MACDCL:            /* macro declaration    */
  387.             checkrel(MACNME,crelxkey,currec,string);
  388.             goto relation;
  389.  
  390.         case MACEQU:            /* macro equate        */
  391.             checkrel(MACDCL,crelxkey,currec,string);
  392.  
  393.         relation:
  394.             if (crelated == NULL)
  395.                 abort(invrec,
  396.                 "has missing relationship ", currec, string);
  397.             crelated->_related=xref;/* chain related XREFs    */
  398.             crelated = xref;    /* update chain base    */
  399.             crelxkey = rkey;    /* update related key    */
  400.             break;
  401.  
  402.         default:
  403.             crelated = NULL;    /* break related chain    */
  404.             crelxkey = NOFUNC;    /* reset related key    */
  405.             break;
  406.         }
  407.     }
  408.  
  409.     fclose(fptr);
  410.     return;
  411. }
  412.  
  413. /*    detect duplicate file names                    */
  414.  
  415. dupfile()
  416. {
  417.     char tfile[MAXPATH],
  418.          tfile1[MAXPATH];
  419.  
  420.     int sindex;
  421.  
  422.     for (rkey = FILEPTH, index = 0; index < total; index++) {
  423.  
  424.         xref = pxref[index];
  425.         strcpy(tfile, &strings[str]);
  426.  
  427.         for (xchain = related;
  428.              xchain != NULL;
  429.              xchain = relxc
  430.             )
  431.             strcat(tfile, &strings[strxc]);
  432.  
  433.         lower(tfile);
  434.  
  435.         sindex = index;
  436.  
  437.         for (rkey1 = FILEPTH, index1 = index + 1;
  438.              index1 < total1;
  439.              index1++
  440.             ) {
  441.  
  442.             xref1 = pxref1[index1];
  443.             strcpy(tfile1, &strings[str1]);
  444.  
  445.             for (xchain = related1;
  446.                  xchain != NULL;
  447.                  xchain = relxc
  448.                 )
  449.                 strcat(tfile1, &strings[strxc]);
  450.  
  451.             lower(tfile1);
  452.  
  453.             if (strcmp(tfile, tfile1) == 0) {
  454.                 dup1 = TRUE;
  455.  
  456.                 for (xchain = related1;
  457.                      xchain != NULL;
  458.                      xchain = relxc
  459.                     )
  460.                     dupxc = TRUE;
  461.             }
  462.         }
  463.  
  464.         index = sindex;
  465.     }
  466. }
  467.  
  468. /*    generate funcation/macro external report            */
  469.  
  470. reporte()
  471. {
  472.     int xrefcmp();            /* compare XREF queue elements    */
  473.  
  474.     xsort(FUNCREF, xrefcmp);    /* sort function ref queue    */
  475.  
  476.     xsort(FUNCNME, xrefcmp);    /* sort function name queue    */
  477.  
  478.     xsort(MACNME, xrefcmp);        /* sort macro name queue    */
  479.  
  480.     /*    report external functions/macros            */
  481.  
  482.     _reporte(FUNCREF,
  483.          FILENME,
  484.          FUNCNME,
  485.          MACNME,
  486.          "\nFUNCTION/MACRO EXTERNAL REFERENCES:\n",
  487.          "\n(no external functions/macros)\n"
  488.         );
  489. }
  490.  
  491. /*    generate header/wildcard/file names listing            */
  492.  
  493. reportf()
  494. {
  495.     int _reportf();
  496.  
  497.     /*    report any -hsystem[,project] specifications        */
  498.  
  499.     rkey = HDRSYST;            /* -hsystem specification    */
  500.  
  501.     for (index = 0; index < total; index++) {
  502.         xref = pxref[index];
  503.         fprintf(stdout, "\nSYSTEM HEADER: %s", &strings[str]);
  504.     }
  505.  
  506.     if (total) fprintf(stdout, "\n");
  507.  
  508.     rkey = HDRPROJ;            /* -h[,project] specification    */
  509.  
  510.     for (index = 0; index < total; index++) {
  511.         xref = pxref[index];
  512.         fprintf(stdout, "\nPROJECT HEADER: %s", &strings[str]);
  513.     }
  514.  
  515.     if (total) fprintf(stdout, "\n");
  516.  
  517.     /*    report any wildcard path\file names            */
  518.  
  519.     if (_reportf(WILDPTH,
  520.         "\nWILDCARD PATH\\FILE NAMES:\n",
  521.         "\n(no wildcard names)\n")
  522.        )
  523.         fprintf(stdout,
  524.         "\n\t\"# \" before a wildcard indicates no files found\n");
  525.  
  526.     /*    report all other path\file names            */
  527.  
  528.     if (_reportf(FILEPTH,
  529.         "\nC SOURCE PATH\\FILE NAMES:\n",
  530.         "\n(no C source names)\n")
  531.        )
  532.         fprintf(stdout,
  533.         "\n\t\"* \" before a file name indicates an open error\n");
  534. }
  535.  
  536. /*    generate function/macro internal report                */
  537.  
  538. reporti()
  539. {
  540.     int xrefcmp();            /* compare XREF queue elements    */
  541.  
  542.     xsort(FUNCNME, xrefcmp);    /* sort function name queue    */
  543.  
  544.     /*    report FUNCNME internal queue                */
  545.  
  546.     _reporti(FUNCNME,
  547.          FILENME,
  548.          -1,
  549.          "\nFUNCTION INTERNAL DECLARATIONS:\n",
  550.          "\n(no functions)\n"
  551.         );
  552.  
  553.     xsort(MACNME, xrefcmp);        /* sort macro name queue    */
  554.  
  555.     /*    report MACNME internal queue                */
  556.  
  557.     _reporti(MACNME,
  558.          FILENME,
  559.          -1,
  560.          "\nMACRO INTERNAL DECLARATIONS:\n",
  561.          "\n(no macros)\n"
  562.         );
  563. }
  564.  
  565. /*    generate macro cross-reference report                */
  566.  
  567. reportm()
  568. {
  569.     int xrefcmp();            /* compare XREF queue elements    */
  570.  
  571.     xsort(MACNME, xrefcmp);        /* sort macro name queue    */
  572.  
  573.     xsort(FUNCREF, xrefcmp);    /* sort function reference queue*/
  574.  
  575.     /*    report MACNME queue                    */
  576.  
  577.     _reporti(MACNME,
  578.          FILENME,
  579.          FUNCREF,
  580.          "\nMACRO CROSS_REFERENCE:\n",
  581.          "\n(no macros)\n"
  582.         );
  583. }
  584.  
  585. /*    generate function cross-reference report            */
  586.  
  587. reportr()
  588. {
  589.     int xrefcmp();            /* compare XREF queue elements    */
  590.  
  591.     xsort(FUNCNME, xrefcmp);    /* sort function name queue    */
  592.  
  593.     xsort(FUNCREF, xrefcmp);    /* sort function reference queue*/
  594.  
  595.     /*    report FUNCNME queue                    */
  596.  
  597.     _reporti(FUNCNME,
  598.          FILENME,
  599.          FUNCREF,
  600.          "\nFUNCTION CROSS_REFERENCE:\n",
  601.          "\n(no functions)\n"
  602.         );
  603. }
  604.  
  605. /*    function/macro external reporter                */
  606.  
  607. int _reporte(qkey, qkey1, qkey2, qkey3, title, noreport)
  608. unsigned char *title, *noreport;
  609. int qkey, qkey1, qkey2, qkey3;
  610. {
  611.     char outfnme[MAXPATH];        /* output path\file name string    */
  612.  
  613.     int curfile,            /* current FILENME queue number    */
  614.         tcount,            /* total reference count    */
  615.         _reportr();            /* reference reporter/counter    */
  616.  
  617.     fprintf(stdout, title);        /* display report title        */
  618.  
  619.     rkey = qkey;            /* function/macro ref queue    */
  620.  
  621.     for (tcount = index = 0; index < total;) {
  622.  
  623.         xref = pxref[index];    /* function/macro ref queue ptr    */
  624.  
  625.         if (dup
  626.         || _reportr(qkey2, FALSE)    /* function dcl found    */
  627.         || _reportr(qkey3, FALSE)    /* macro dcl found    */
  628.            ) {
  629.             ++index;
  630.             continue;        /* not external name    */
  631.         }
  632.  
  633.         tcount++;        /* increment external count    */
  634.  
  635.         /*    report function/macro external name        */
  636.  
  637.         fprintf(stdout, "\n%s:", &strings[str]);
  638.  
  639.         for (rkey2 = qkey, index2 = index, curfile = -1;
  640.              index2 < total2;
  641.              index2++
  642.             ) {
  643.             xref2 = pxref2[index2];    /* reference queue ptr    */
  644.  
  645.             if (strcmp(&strings[str], &strings[str2]) != 0) {
  646.                 index = index2;
  647.                 break;
  648.             }
  649.  
  650.             if (curfile != fnmbr2) {    /* new filename    */
  651.                 fmtout(OUTFLSH);
  652.                 xref1 = pxref1[(curfile = fnmbr2)];
  653.                 strcpy(outfnme, &strings[str1]);
  654.  
  655.                 for (xchain = related1;
  656.                     xchain != NULL;
  657.                     xchain = relxc
  658.                     )
  659.                     strcat(outfnme, &strings[strxc]);
  660.  
  661.                 fmtout(OUTHDR, 0, outfnme);
  662.             }
  663.  
  664.             if (dup1) {
  665.                 fmtout(OUTCLR);
  666.                 continue;    /* skip duplicate files    */
  667.             }
  668.  
  669.             fmtout(OUTUPD, line2);    /* update output array    */
  670.         }
  671.  
  672.         fmtout(OUTFLSH);        /* flush format output    */
  673.     }
  674.  
  675.     if (tcount)
  676.         fprintf(stdout, "\n");
  677.     else    fprintf(stdout, noreport);
  678.  
  679.     fmtout(OUTCLR);
  680.  
  681.     return (tcount);
  682. }
  683.  
  684. /*    path\file name reporter                        */
  685.  
  686. int _reportf(qkey, title, noreport)
  687. unsigned char *title, *noreport;
  688. int qkey;
  689. {
  690.     int filerr;
  691.  
  692.     filerr = 0;
  693.  
  694.     fprintf(stdout, title);        /* report title            */
  695.  
  696.     rkey = qkey;            /* report queue = qkey        */
  697.  
  698.     for (index = 0; index < total; index++) {
  699.  
  700.         xref = pxref[index];    /* queue XREF pointer        */
  701.  
  702.         fprintf(stdout,        /* report number/pathname    */
  703.             "\n%d: %s",
  704.             (fnmbr+1),
  705.             &strings[str]
  706.                );
  707.  
  708.         if (strncmp(&strings[str], "* ", 2) == 0
  709.         ||  strncmp(&strings[str], "# ", 2) == 0)
  710.             filerr++;
  711.  
  712.         for (xchain = related; xchain != NULL; xchain = relxc) {
  713.             fprintf(stdout, "%s", &strings[strxc]);
  714.             if (strncmp(&strings[strxc], "* ", 2) == 0
  715.             ||  strncmp(&strings[strxc], "# ", 2) == 0)
  716.                 filerr++;
  717.         }
  718.     }
  719.  
  720.     if (total)
  721.         fprintf(stdout, "\n");
  722.     else    fprintf(stdout, noreport);
  723.  
  724.     return (filerr);
  725. }
  726.  
  727. /*    function/macro internal reporter                */
  728.  
  729. int _reporti(qkey, qkey1, qkey2, title, noreport)
  730. unsigned char *title, *noreport;
  731. int qkey, qkey1, qkey2;
  732. {
  733.     char *cid;
  734.  
  735.     int tcount;
  736.  
  737.     fprintf(stdout, title);        /* display report title        */
  738.  
  739.     rkey = qkey;            /* function/macro queue        */
  740.     rkey1 = qkey1;            /* path\file name queue        */
  741.  
  742.     for (tcount = index = 0; index < total; index++, tcount++) {
  743.  
  744.         xref = pxref[index];    /* function/macro queue ptr    */
  745.         xref1 = pxref1[fnmbr];    /* path\file name queue ptr    */
  746.  
  747.         if (dup && qkey2 != -1)
  748.             continue;        /* ignore duplicates    */
  749.  
  750.         /*    report function/macro & 1st path\file segment    */
  751.  
  752.         fprintf(stdout, "\n%s:\t%s (%d)",
  753.             &strings[str],        /* function/macro name    */
  754.             &strings[str1],        /* 1st pathfile segment    */
  755.             line            /* line where declared    */
  756.                );
  757.  
  758.         /*    report path\file name related chain        */
  759.  
  760.         for (xchain = related1; xchain != NULL; xchain = relxc)
  761.             fprintf(stdout, "%s", &strings[strxc]);
  762.  
  763.         fprintf(stdout, "\n");
  764.  
  765.         /*    report function/macro related chain        */
  766.  
  767.         for (xchain = related, cid = "**";
  768.              xchain != NULL;
  769.              xchain = relxc, cid = " *"
  770.             )
  771.             fprintf(stdout, "\n\t%s %s", cid, &strings[strxc]);
  772.  
  773.         if (related != NULL) fprintf(stdout, "\n");
  774.  
  775.         if (qkey2 != -1)
  776.             _reportr(qkey2, TRUE);    /* reference report    */
  777.         else    fprintf(stdout, "\n");
  778.     }
  779.  
  780.     if (tcount)
  781.         fprintf(stdout, "\n");
  782.     else    fprintf(stdout, noreport);
  783.  
  784.     return (tcount);
  785. }
  786.  
  787. /*    cross_reference reporter                    */
  788.  
  789. int _reportr(qkey2, display)
  790. int qkey2, display;
  791. {
  792.     char outfnme[MAXPATH];        /* output path\file name string    */
  793.  
  794.     int curfile,
  795.         tcount;
  796.  
  797.     tcount = 0;
  798.     rkey2 = qkey2;            /* reference queue        */
  799.  
  800.     /*    search reference queue for a matching reference        */
  801.  
  802.     for (index2 = 0; index2 < total2; index2++) {
  803.  
  804.         xref2 = pxref2[index2];    /* reference queue ptr        */
  805.  
  806.         if (strcmp(&strings[str], &strings[str2]) == 0)
  807.             break;
  808.     }
  809.  
  810.     if (!(index2 < total2))
  811.         if (display) fprintf(stdout, "\n\t(no references)");
  812.  
  813.     /*    count/report references                    */
  814.  
  815.     for (curfile = -1; index2 < total2; tcount++, index2++) {
  816.  
  817.         xref2 = pxref2[index2];    /* reference queue ptr        */
  818.  
  819.         if (strcmp(&strings[str], &strings[str2]) != 0)
  820.             break;
  821.  
  822.         if (display) {
  823.             if (curfile != fnmbr2) {    /* new filename    */
  824.                 fmtout(OUTFLSH);
  825.                 xref1 = pxref1[(curfile = fnmbr2)];
  826.                 strcpy(outfnme, &strings[str1]);
  827.  
  828.                 for (xchain = related1;
  829.                     xchain != NULL;
  830.                     xchain = relxc
  831.                     )
  832.                     strcat(outfnme, &strings[strxc]);
  833.  
  834.                 fmtout(OUTHDR, 0, outfnme);
  835.             }
  836.  
  837.             fmtout(OUTUPD, line2);    /* add to detail line    */
  838.         }
  839.     }
  840.  
  841.     if (display) {
  842.         fmtout(OUTFLSH);    /* flush final pending line    */
  843.         fmtout(OUTCLR);        /* clear all output        */
  844.         fprintf(stdout, "\n");
  845.     }
  846.  
  847.     return (tcount);
  848. }
  849.  
  850. /*    check key relationship, abort on a bad relationship        */
  851.  
  852. checkrel(rkey, xkey, currec, string)
  853. int rkey, xkey, currec;
  854. unsigned char *string;
  855. {
  856.     if (rkey != xkey)
  857.         abort(invrec, "relationship ", currec, string);
  858. }
  859.  
  860. /*    formatted reference output                    */
  861.  
  862. fmtout(mode, outval, outfnme)
  863. int mode, outval;
  864. char *outfnme;
  865. {
  866.     static    char *outfmt = NULL,    /* output format string        */
  867.              *outhdr = NULL,    /* output format header        */
  868.              *fmthdr = NULL,    /* format header string        */
  869.              *fmtdet = NULL;    /* format detail string        */
  870.  
  871.     static    int outcnt = 0,        /* output reference count    */
  872.             outhdrl = 0,    /* output header length        */
  873.             outlim = 0,        /* output reference maximum    */
  874.             outint[8] =        /* output reference array    */
  875.             {0,0,0,0,0,0,0,0};
  876.  
  877.     int outlen;
  878.  
  879.     switch (mode) {            /* select output mode        */
  880.  
  881.     case OUTHDR:            /* start format heading        */
  882.  
  883.         if (outfmt == NULL) {        /* 1st time thru only    */
  884.             outfmt = alloc((MAXPATH * 2));
  885.             outhdr = alloc(MAXPATH);
  886.             fmthdr = alloc(16);
  887.             fmtdet = alloc(8);
  888.         }
  889.  
  890.         strcpy(fmthdr, "  %*s   ");    /* fprintf() formats    */
  891.         fmthdr[0] = '\n';
  892.         fmthdr[1] = '\t';
  893.         strcpy(fmtdet, "%8d");
  894.  
  895.         strcpy(outhdr, outfnme);    /* build format heading    */
  896.         outhdrl = strlen(outhdr);
  897.         strcpy(outfmt, fmthdr);
  898.         outlen = (80 - (outhdrl + 11));
  899.         for (outlim = 0;
  900.              outlim < 8 && outlen > 8;
  901.              outlen -= 8, outlim++
  902.             )
  903.             strcat(outfmt, fmtdet);
  904.  
  905.         outcnt = 0;            /* restart array    */
  906.         break;
  907.  
  908.     case OUTUPD:            /* update formatted array    */
  909.  
  910.         if (outfmt == NULL) break;
  911.  
  912.         outint[outcnt++] = outval;
  913.  
  914.         if (outcnt < outlim);
  915.         else {            /* format line full - flush    */
  916.             fprintf(stdout,
  917.                 outfmt, outhdrl, outhdr,
  918.                 outint[0], outint[1], outint[2],
  919.                 outint[3], outint[4], outint[5],
  920.                 outint[6], outint[7]
  921.                    );
  922.             strcpy(outhdr, " ");
  923.             outcnt = 0;
  924.         }
  925.         break;
  926.  
  927.     case OUTFLSH:            /* flush formatted output line    */
  928.  
  929.         if (outfmt == NULL) break;
  930.  
  931.         if (outcnt) {
  932.             outfmt[(strlen(fmthdr)+(strlen(fmtdet)*outcnt))] = EOS;
  933.             strcat(outfmt, "\n");
  934.             fprintf(stdout,
  935.                 outfmt, outhdrl, outhdr,
  936.                 outint[0], outint[1], outint[2], outint[3],
  937.                 outint[4], outint[5], outint[6], outint[7]
  938.                    );
  939.         }
  940.         else    fprintf(stdout, "\n");
  941.  
  942.         free(outfmt);
  943.         free(outhdr);
  944.         free(fmthdr);
  945.         free(fmtdet);
  946.         outfmt = outhdr = fmthdr = fmtdet = NULL;
  947.         outcnt = 0;
  948.         break;
  949.  
  950.     case OUTCLR:            /* clear current format        */
  951.  
  952.         if (outfmt == NULL) break;
  953.  
  954.         free(outfmt);
  955.         free(outhdr);
  956.         free(fmthdr);
  957.         free(fmtdet);
  958.         outfmt = outhdr = fmthdr = fmtdet = NULL;
  959.         outcnt = 0;
  960.         break;
  961.  
  962.     default:    
  963.         break;
  964.     }
  965. }
  966.  
  967. /*    add string to character string buffer                */
  968.  
  969. unsigned int stradd(string)
  970. unsigned char *string;
  971. {
  972.     unsigned int sp,            /* string offset    */
  973.              strfind();            /* search char buffer    */
  974.  
  975.     if ((sp = strfind(string)) != -1)
  976.         return (sp);        /* existing string found    */
  977.  
  978.     strings = realloc(strings, (stringl + strlen(string) + 1));
  979.     if (strings == NULL) abort("REALLOC - STRINGS");
  980.  
  981.     sp = stringl;
  982.  
  983.     strcpy(&strings[stringl], string);
  984.     stringl += (strlen(string) + 1);
  985.  
  986.     return (sp);
  987. }
  988.  
  989. /*    search string buffer for matching string
  990.  
  991.     returns:    unsigned int    string buffer offset if found
  992.             -1        string not found
  993. */
  994.  
  995. unsigned int strfind(string)
  996. unsigned char *string;
  997. {
  998.     unsigned int sp;
  999.  
  1000.     for (sp = 0;
  1001.          sp < stringl;
  1002.          sp += (strlen(&strings[sp]) + 1)
  1003.         )
  1004.         if (strcmp(&strings[sp], string) == 0)
  1005.              return (sp);        /* match found        */
  1006.  
  1007.     return (-1);                /* no match found    */
  1008. }
  1009.  
  1010. /*    XREF qsort() routine                        */
  1011.  
  1012. xsort(key,compare)
  1013. int key;
  1014. PFI compare;
  1015. {
  1016.     rkey = key;
  1017.  
  1018.     if (sorted == FALSE) {
  1019.  
  1020.         qsort((char *)pxref,        /* 1st XREF pointer    */
  1021.               (unsigned)total,        /* XREF pointer count    */
  1022.               (unsigned)sizeof(XREF *),    /* size of XREF element    */
  1023.               compare            /* XREF comparison    */
  1024.              );
  1025.  
  1026.         rkey = key;
  1027.         sorted = TRUE;            /* set sort completed    */
  1028.     }
  1029. }
  1030.  
  1031. /*    qsort() XREF comparison routine                    */
  1032.  
  1033. int xrefcmp(rec1, rec2)
  1034. XREF **rec1, **rec2;
  1035. {
  1036.     unsigned char *rstring;
  1037.  
  1038.     int result;
  1039.  
  1040.     xref1 = *rec1;            /* 1st element pointer        */
  1041.     xref2 = *rec2;            /* 2nd element pointer        */
  1042.  
  1043.     rkey1 = FILENME;        /* file name queue header    */
  1044.     xref3 = pxref1[fnmbr1];        /* 1st element file name    */
  1045.     xref4 = pxref1[fnmbr2];        /* 2nd element file name    */
  1046.  
  1047.     if ((result = strcmp(&strings[str1], &strings[str2])) == 0) {
  1048.  
  1049.         /*    element names match                */
  1050.  
  1051.         if ((result = strcmp(&strings[str3], &strings[str4])) == 0) {
  1052.  
  1053.             /*    file names match            */
  1054.  
  1055.             if (line1 == line2)
  1056.  
  1057.                 /*    line numbers match        */
  1058.  
  1059.                 result = 0;
  1060.             else {
  1061.                 if (line1 > line2)
  1062.                     result = 1;
  1063.                 else    result = -1;
  1064.             }
  1065.         }
  1066.     }
  1067.  
  1068.     if (result == 0 && !dup1 && !dup2 && (line1 != line2))
  1069.         dup2 = TRUE;        /* flag duplicate entries    */
  1070.  
  1071.     if (result == 0 && !dup1 && dup2)
  1072.         result = -1;        /* a non-duplicate is lower    */
  1073.  
  1074.     return (result);
  1075. }
  1076.  
  1077. /*    end of cflowx.c            */
  1078.  
  1079.