home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / clarion / showtree.zip / SHOWTREE.C < prev    next >
Text File  |  1989-04-13  |  20KB  |  717 lines

  1. /*****************************************************************************
  2.  
  3.     Program Name    │ ShowTree
  4.     Version            │ 1.0
  5.                         │
  6.     Created            │ 89/04/02 - Mike Hanson
  7.     Revised            │
  8.                   │
  9.     Company            │ BoxSoft Development
  10.                         │ Computer Information Management Ltd.
  11.                         │ White City, SK
  12.                         │ S0G 5B0  CANADA  (306)781-2554
  13.                         │
  14.     Purpose            │ Print calling tree based on Clarion XRF file.
  15.                         │
  16.     Usage                │ ShowTree <appname>
  17.                         │
  18.                         │ The <appname> must NOT include an extension.
  19.                         │ The XRF and CLA files must be in the current directory.
  20.  
  21. *****************************************************************************/
  22.  
  23. /****************
  24.     header files
  25.  ****************/
  26.  
  27. #include    <string.h>
  28. #include <stdio.h>
  29. #include <ctype.h>
  30. #include    <alloc.h>
  31. #include    <math.h>
  32.  
  33. /***********
  34.     defines
  35.  ***********/
  36.  
  37. #define    MAX_CALLS_ON_LINE    (9)                        /*  max calls on XRF line    */
  38. #define    MAX_CALLS    (10*52*MAX_CALLS_ON_LINE)    /*  max calls in XRF file    */
  39. #define    MAX_PROCS    (10*52)                            /*  max procs in app            */
  40. #define    MAX_DEPTH    (100)                                /*  max calling depth        */
  41. #define    FORMFEED        (12)
  42. #define    ESC            (27)
  43.  
  44. /************
  45.     typedefs
  46.  ************/
  47.  
  48. typedef     char  PROC[12];            /*  procedure type    */
  49. typedef     char  MODULE[8];            /*  module type        */
  50. typedef     char  LINE[5];            /*  line # type        */
  51. typedef     char  FILL;                /*  fill (waste)        */
  52.  
  53. typedef struct _CALL_TABLE {        /*  pointer to call table entry    */
  54.     MODULE    calling_module;
  55.     LINE        calling_line;
  56.     PROC        calling_proc;
  57.     PROC        called_proc;
  58. } CALL_TABLE;
  59.  
  60. typedef struct _PROC_TABLE {        /*  pointer to procedure table entry    */
  61.     MODULE    module;
  62.     LINE        line;
  63.     PROC        name;
  64. } PROC_TABLE;
  65.  
  66. /********************
  67.     global variables
  68.  ********************/
  69.  
  70. struct _XRF_LINE {                    /*  XRF line    */
  71.     PROC        called_proc;
  72.     FILL        fill_1[13];
  73.     MODULE    declared_in_module;
  74.     LINE        declared_in_line;
  75.     FILL        fill_3[3];
  76.     MODULE    calling_module;
  77.     LINE        calling_line[MAX_CALLS_ON_LINE];
  78. } line;
  79.  
  80. PROC_TABLE    *proc[MAX_PROCS];        /*  procedure table    */
  81. CALL_TABLE    *call[MAX_CALLS];        /*  call table            */
  82. char            link[MAX_DEPTH];        /*  vertical line    flags (see build_table)    */
  83. int            nprocs=0;                /*  procs counter        */
  84. int            ncalls=0;                /*  call counter        */
  85.  
  86. /***********************
  87.     function prototypes
  88.  ***********************/
  89.  
  90. void    main                                (    int            argc,
  91.                                                 char            *argv[]        );
  92. void    check_parms                        (    int            argc,
  93.                                                 char            *argv[]        );
  94. void    bad_parms                        (                                    );
  95. void    scan_xrf_file                    (    char            *appname        );
  96. void    get_first_app_line            (    char            *appname,
  97.                                                 LINE            *l                );
  98. void    get_line                            (    FILE            *file            );
  99. void    no_memory                        (                                    );
  100. void    finish_call_table                (                                    );
  101. int    find_proc_proc_by_module    (    CALL_TABLE    *c                );
  102. void    output_tree                        (    char            *appname        );
  103. int    find_proc_start                (    PROC            procname        );
  104. void    build_tree                        (    int            first_call,
  105.                                                 int            level            );
  106. void    make_output_str                (    CALL_TABLE    *c,
  107.                                                 char            *text            );
  108. int    lookup_proc_proc                (    PROC            p                );
  109. void    sort                                (     void            *arr[],
  110.                                                 size_t        n,
  111.                                                 int            (*comp)()    );
  112. int    comp_proc_module_line        (    PROC_TABLE    *proc1,
  113.                                                 PROC_TABLE    *proc2        );
  114. int    comp_call_module_line        (    CALL_TABLE    *call1,
  115.                                                 CALL_TABLE    *call2        );
  116. int    comp_call_proc_line            (    CALL_TABLE    *call1,
  117.                                                 CALL_TABLE    *call2        );
  118. int    comp_call_calling_proc        (    CALL_TABLE    *call1,
  119.                                                 CALL_TABLE    *call2        );
  120.  
  121. /*****************************************************************************
  122.     main() - calls major code sections
  123. *****************************************************************************/
  124.  
  125. void main (    int    argc,
  126.                 char    *argv[] )
  127. {
  128.     printf("ShowTree 1.0  -  Mike Hanson, BoxSoft Development\n\n");
  129.  
  130.     printf("Checking parameters...\n");
  131.     check_parms(argc, argv);
  132.  
  133.     printf("Scanning XRF file...\n");
  134.     scan_xrf_file(argv[1]);
  135.  
  136.     printf("Finishing call table...\n");
  137.     finish_call_table();
  138.  
  139.     printf("Generating tree...\n");
  140.     output_tree(argv[1]);
  141. }
  142.  
  143. /*****************************************************************************
  144.     check_parms() - checks for valid command line parameters
  145. *****************************************************************************/
  146.  
  147. void check_parms (    int    argc,
  148.                             char    *argv[] )
  149. {
  150.     char    fname[13];
  151.  
  152.     if    (argc != 2)    bad_parms();
  153.     strupr(argv[1]);
  154.     if (strchr(argv[1], '.')) bad_parms();
  155.  
  156.     strcat(strcpy(fname,argv[1]),".XRF");
  157.     if (!fopen(fname,"rt")) {
  158.         printf("Cannot access XRF file!\x07\n");
  159.         bad_parms();
  160.     }
  161.  
  162.     strcat(strcpy(fname,argv[1]),".CLA");
  163.     if (!fopen(fname,"rt")) {
  164.         printf("Cannot access CLA file!\x07\n");
  165.         bad_parms();
  166.     }
  167.  
  168.     fcloseall();
  169. }
  170.  
  171. /*****************************************************************************
  172.     bad_parms() - called if command line parameters are bad
  173. *****************************************************************************/
  174.  
  175. void bad_parms()
  176. {
  177.     printf("\nUsage:  ShowTree <AppName> <MainProc>\n\n");
  178.     printf("Do NOT include a file extension!\n\n");
  179.     exit(1);
  180. }
  181.  
  182. /*****************************************************************************
  183.     scan_xrf_file() - reads XRF file, builds proc and call tables
  184. *****************************************************************************/
  185.  
  186. void  scan_xrf_file ( char *appname )        /*  appname is argv[1]    */
  187. {
  188.     PROC        current_proc ;
  189.     MODULE    current_module ;
  190.     char        fname[13] ;
  191.     FILE        *xrf_file ;
  192.     int        x ;
  193.     char        t[80];
  194.     LINE        first_app_line;
  195.     PROC        main_proc;
  196.  
  197.     strcat(strcpy(fname, appname), ".XRF");
  198.     xrf_file = fopen(fname, "rt");
  199.  
  200.     get_first_app_line(appname, &first_app_line);
  201.     memset(main_proc, ' ', sizeof(PROC));
  202.     memcpy(main_proc, appname, strlen(appname));
  203.  
  204.     for (;;) {
  205.  
  206.         while (!feof(xrf_file) && line.called_proc[0] != FORMFEED)
  207.             get_line(xrf_file);
  208.  
  209.         if (feof(xrf_file))
  210.             break;
  211.         else {
  212.             get_line(xrf_file);
  213.             get_line(xrf_file);
  214.             if (!memcmp(&line, "PROCEDURES", 10))
  215.                 for (x=0; x<4; x++) get_line(xrf_file);
  216.              else
  217.                 continue;
  218.         }
  219.  
  220.         while (!feof(xrf_file)) {
  221.  
  222.             get_line(xrf_file);
  223.  
  224.             if (strlen((char*) &line) < sizeof(PROC))
  225.                 break;
  226.  
  227.              if (isalpha(line.called_proc[0])) {
  228.  
  229.                 memcpy(current_proc,
  230.                         line.called_proc,
  231.                         sizeof(PROC));
  232.  
  233.                 proc[nprocs] = (PROC_TABLE*) malloc(sizeof(PROC_TABLE));
  234.                 if (!proc[nprocs]) no_memory();
  235.  
  236.                 memcpy(proc[nprocs]->name,
  237.                         line.called_proc,
  238.                         sizeof(PROC));
  239.                 if (memcmp(proc[nprocs]->name, main_proc, sizeof(PROC))) {
  240.  
  241.                     memcpy(proc[nprocs]->module,
  242.                             line.declared_in_module,
  243.                             sizeof(PROC));
  244.                     memcpy(proc[nprocs]->line,
  245.                             line.declared_in_line,
  246.                             sizeof(LINE));
  247.                 } else {
  248.  
  249.                     memcpy(proc[nprocs]->module,
  250.                             line.calling_module,
  251.                             sizeof(MODULE));
  252.                     memcpy(proc[nprocs]->line,
  253.                             line.calling_line[0],
  254.                             sizeof(LINE));
  255.                 }
  256.  
  257.                 ++nprocs;
  258.             }
  259.  
  260.             if (isalpha(line.calling_module[0]))
  261.                 memcpy(current_module,
  262.                         line.calling_module,
  263.                         sizeof(MODULE));
  264.  
  265.             for (    x = 0 ;                                            /*  start at 0            */
  266.                     line.calling_line[x][0] != '\n'
  267.                     && x < MAX_CALLS_ON_LINE;
  268.                     x++ ) {                                            /*  increment count    */
  269.  
  270.                 if ( memcmp(line.calling_module,
  271.                             main_proc,
  272.                             sizeof(MODULE)) == 0
  273.                         && memcmp(line.calling_line[x],
  274.                             first_app_line,
  275.                             sizeof(LINE)) < 0 )
  276.                     continue;
  277.  
  278.                 call[ncalls] = (CALL_TABLE *)
  279.                         malloc(sizeof(CALL_TABLE));            /*  allocate memory    */
  280.                 if (!call[ncalls]) no_memory();
  281.                 memset(call[ncalls], ' ', sizeof(CALL_TABLE));
  282.  
  283.                 memcpy(call[ncalls]->calling_module,        /*  get module            */
  284.                         current_module,
  285.                         sizeof(MODULE));
  286.                 memcpy(call[ncalls]->calling_line,            /*  get line            */
  287.                         line.calling_line[x],
  288.                         sizeof(LINE));
  289.                 memcpy(call[ncalls]->called_proc,            /*  get called proc    */
  290.                         current_proc,
  291.                         sizeof(PROC));
  292.  
  293.                 ++ncalls;                                            /*  inc call counter    */
  294.             }
  295.         }
  296.     }
  297.     fclose(xrf_file);
  298. }
  299.  
  300. /*****************************************************************************
  301.     get_first_app_line() - scans CLA file for first line after map
  302.                                   (XRF file includes map declarations as calls)
  303.                                   The determined line is placed into the LINE
  304.                                   parameter.
  305. *****************************************************************************/
  306.  
  307. void get_first_app_line (    char    *appname,        /*  argv[1]                    */
  308.                                     LINE    *l            )        /*  pointer to LINE var    */
  309. {
  310.     char    fname[13];
  311.     FILE    *cla_file;
  312.     char    buf[255];
  313.     int    within_map = 0;
  314.     char    *ptr;
  315.     int    pos = 0;
  316.  
  317.     strcat(strcpy(fname, appname), ".CLA");
  318.     cla_file = fopen(fname, "rt");
  319.  
  320.     while (!feof(cla_file)) {
  321.  
  322.         fgets(buf, sizeof(buf), cla_file);
  323.         ++pos ;
  324.  
  325.         if (!within_map && (ptr = strstr(buf, "MAP")))
  326.             within_map = ptr - buf ;
  327.  
  328.         if (    within_map && (ptr = strchr(buf, '.'))
  329.                 && ptr - buf == within_map )
  330.             break;
  331.     }
  332.     sprintf(buf, "%*d", sizeof(LINE), pos);
  333.     memcpy(l, buf, sizeof(LINE));
  334. }
  335.  
  336. /*****************************************************************************
  337.     get_line() - reads a line from XRF file and puts it in variable "line"
  338. *****************************************************************************/
  339.  
  340. void get_line ( FILE *file )        /*  file is the XRF file stream        */
  341. {
  342.     char    ln[255];
  343.  
  344.     if (!feof(file)) {
  345.         fgets(ln, sizeof(ln), file);
  346.         memcpy(&line, ln, sizeof(line));
  347.     }
  348. }
  349.  
  350. /*****************************************************************************
  351.     no_memory() - called if too many procs and/or calls
  352. *****************************************************************************/
  353.  
  354. void no_memory()
  355. {
  356.     printf("Out of memory!\007\n");
  357.     exit(1);
  358. }
  359.  
  360. /*****************************************************************************
  361.     finish_call_table() - looks-up calling_proc in proc table for each call
  362.                                  (calling_proc is not included in XRF file)
  363. *****************************************************************************/
  364.  
  365. void finish_call_table()
  366. {
  367.     int    x, y ;
  368.  
  369.     sort((void*) proc, nprocs, comp_proc_module_line);
  370.     sort((void*) call, ncalls, comp_call_module_line);
  371.  
  372.     for (x=0; x < ncalls; x++)
  373.         if ((y = find_proc_proc_by_module(call[x])) != -1)
  374.             memcpy(call[x]->calling_proc, proc[y]->name, sizeof(PROC));
  375. }
  376.  
  377. /*****************************************************************************
  378.     find_proc_proc_by_module() - Search the proc table using module name and
  379.                                           line number to find a calling_proc for the
  380.                                           specified call
  381. *****************************************************************************/
  382.  
  383. find_proc_proc_by_module ( CALL_TABLE *c )    /*  "c" is a pointer to the    */
  384. {                                                            /*  call containing the module*/
  385.     int x, flag=0, module_match;                    /*  name and line number        */
  386.  
  387.     for (x=0; x < nprocs; x++) {
  388.         module_match = !memcmp( proc[x]->module,
  389.                 c->calling_module,
  390.                 sizeof(MODULE));
  391.         if (module_match) flag = 1;
  392.         if (flag && (!module_match
  393.                 || (module_match
  394.                 && memcmp( proc[x]->line,
  395.                     c->calling_line,
  396.                     sizeof(LINE)) > 0 )))
  397.             break;
  398.     }
  399.     if ( memcmp( proc[x-1]->module,
  400.             c->calling_module,
  401.             sizeof(MODULE)) == 0 )
  402.         return(x-1);
  403.     else
  404.         return(-1);
  405. }
  406.  
  407. /*****************************************************************************
  408.     output_tree() - This procedure creates the tree for the application.  It
  409.                          opens the output file and calls build_tree to recurse
  410.                          through the call table.
  411. *****************************************************************************/
  412.  
  413. FILE    *outfile;
  414.  
  415. void output_tree ( char *appname )        /*  appname is argv[1]    */
  416. {
  417.     char    fname[13];
  418.     PROC    mainproc;
  419.     int    start;
  420.  
  421.     strcat(strcpy(fname, appname), ".XRT");
  422.     outfile = fopen(fname, "wt");
  423.  
  424.     sort((void*) call, ncalls, comp_call_proc_line);
  425.  
  426.     memset(mainproc, ' ', sizeof(PROC));
  427.     memcpy(mainproc, appname, strlen(appname));
  428.     fprintf(outfile, "%.*s\n", sizeof(PROC), mainproc);
  429.     printf("%.*s\n", sizeof(PROC), mainproc);
  430.  
  431.     start = find_proc_start(mainproc);
  432.    if (start != -1) build_tree(start, 0);
  433.  
  434.     fclose(outfile);
  435. }
  436.  
  437. /*****************************************************************************
  438.     find_proc_start() - finds the start of calls made from a given proc.  If
  439.                               the specified proc has no calls, -1 is returned.
  440. *****************************************************************************/
  441.  
  442. int find_proc_start ( PROC procname )    /*  procname is the desired proc        */
  443. {
  444.     int    x;
  445.  
  446.     for (x=0; x < ncalls; x++)
  447.         if (!memcmp(call[x]->calling_proc, procname, sizeof(PROC)))
  448.             break;
  449.  
  450.     if (x == ncalls)
  451.         return (-1);
  452.     else
  453.         return (x);
  454. }
  455.  
  456. /*****************************************************************************
  457.     build_tree() - this function is recursive.  It is continually called for
  458.                         each level of procedure calls.  When it calls it self, it
  459.                         sets "link" which is used to determine which vertical bars
  460.                         are continued (printed).
  461. *****************************************************************************/
  462.  
  463. void build_tree (    int    first_call,            /*  first call for calling_proc    */
  464.                         int    level            )        /*  recursion depth                    */
  465. {
  466.     int    s = first_call;
  467.     int    l, x;
  468.     char    text[sizeof(PROC)+sizeof(MODULE)+4];
  469.     int    start, more=1;
  470.  
  471.     for (    s = first_call;
  472.             comp_call_calling_proc(call[first_call], call[s]) == 0
  473.             && more;
  474.             s++ ) {
  475.  
  476.         if ( !memcmp ( call[s]->called_proc,
  477.                 "CHKERR      ",
  478.                 sizeof(PROC)))
  479.             continue;
  480.         else {
  481.             for (x = s-1; x >= first_call; x--)
  482.                 if (memcmp(call[x]->called_proc,
  483.                         call[s]->called_proc,
  484.                         sizeof(PROC)) == 0 )
  485.                     break;
  486.          if (x >= first_call) continue;
  487.         }
  488.  
  489.         for (l=0; l<level; l++)
  490.             if (link[l]) {
  491.                 fprintf(outfile, "│ ");
  492.                 printf("│ ");
  493.             } else {
  494.                 fprintf(outfile, "  ");
  495.                 printf("  ");
  496.             }
  497.  
  498.         if (more = more_calls(first_call, s)) {
  499.             fprintf(outfile, "├─");
  500.             printf("├─");
  501.         } else {
  502.             fprintf(outfile, "└─");
  503.             printf("└─");
  504.         }
  505.  
  506.         make_output_str(call[s], text);
  507.         fprintf(outfile, "%s\n", text);
  508.         printf("%s\n", text);
  509.  
  510.         start = find_proc_start(call[s]->called_proc);
  511.         if (start != -1) {
  512.             link[level] = more;
  513.             build_tree(start, l+1);
  514.         }
  515.     }
  516. }
  517.  
  518. /*****************************************************************************
  519.     more_calls() - checks for additional calls from current proc that are not
  520.                         duplicates or CHKERR.
  521. *****************************************************************************/
  522.  
  523. int more_calls (    int    first,        /*  first call for the calling_proc        */
  524.                         int    current )    /*  current call (after first)            */
  525. {
  526.     int    flag = 0;
  527.     int    x;
  528.  
  529.     for (    ++current;
  530.             comp_call_calling_proc ( call[first], call[current] ) == 0;
  531.             ++current ) {
  532.         if ( memcmp ( call[current]->called_proc,
  533.                 "CHKERR      ",
  534.                 sizeof(PROC)) != 0 ) {
  535.  
  536.             for (x=current-1; x>=first; x--)
  537.  
  538.                 if (memcmp(call[x]->called_proc,
  539.                         call[current]->called_proc,
  540.                         sizeof(PROC)) == 0 )
  541.                     break;
  542.  
  543.          if (x<first) {
  544.                 flag=1;
  545.                 break;
  546.             }
  547.         }
  548.     }
  549.     return (flag);
  550. }
  551.  
  552. /****************************************************************************
  553.     make_output_str() - creates output string with proc name and module with
  554.                               the format "PROCNAME (MODULE)"
  555. *****************************************************************************/
  556.  
  557. void make_output_str (    CALL_TABLE    *c,        /*  pointer to call                */
  558.                                 char            *text )    /*  buffer for output text        */
  559. {
  560.     char    *p ;
  561.     int    x ;
  562.  
  563.    memset(text, ' ', sizeof(PROC)+sizeof(MODULE)+4);
  564.  
  565.     memcpy(text, c->called_proc, sizeof(PROC));
  566.  
  567.     p = strchr(text, ' ') + 1 ;
  568.     *(p++) = '(' ;
  569.  
  570.     x = lookup_proc_proc(c->called_proc);
  571.     memcpy(p, proc[x]->module, sizeof(MODULE));
  572.  
  573.     p = strchr(p, ' ') ;
  574.     *(p++) = ')' ;
  575.     *p = NULL ;
  576. }
  577.  
  578. /*****************************************************************************
  579.     lookup_proc_proc() - used to find a proc's module name using the proc name
  580. *****************************************************************************/
  581.  
  582. int lookup_proc_proc ( PROC p )        /*  p contains name to be looked-up        */
  583. {
  584.     int    x ;
  585.  
  586.     for (x=0; x < nprocs; x++)
  587.         if (!memcmp(proc[x]->name, p, sizeof(PROC)))
  588.             break;
  589.  
  590.     return (x);
  591. }
  592.  
  593. /*****************************************************************************
  594.     sort() - sorts pointers to calls/procs using specified compare function.
  595.                 This is a SHELL sort taken from Numerical Recipes in C (page 245)
  596. *****************************************************************************/
  597.  
  598. #define    ALN2I    1.442695022
  599. #define    TINY    1.0e-5
  600.  
  601. void sort (     void        *arr[],            /*  pointer to an array of pointers    */
  602.                     size_t    n,                    /*  number of elements in array        */
  603.                     int        (*comp)())        /*  pointer to comparison function    */
  604. {
  605.     int    nn,m,j,i,lognb2;
  606.     void    *t;
  607.  
  608.     lognb2=(log((double) n)*ALN2I+TINY);
  609.     m=n;
  610.     for (nn=1; nn<=lognb2; nn++) {
  611.         m >>= 1;
  612.         for (j=m+1; j<=n; j++) {
  613.             i=j-m;
  614.             t=arr[j-1];
  615.             while (i >= 1 && comp(arr[i-1], t) > 0) {
  616.                 arr[i+m-1]=arr[i-1];
  617.                 i -= m;
  618.             }
  619.             arr[i+m-1]=t;
  620.         }
  621.     }
  622. }
  623.  
  624. /*****************************************************************************
  625.     comp_proc_module_line() - compare module+line for two procs
  626. *****************************************************************************/
  627.  
  628. int comp_proc_module_line (    PROC_TABLE    *proc1,        /*  pointer to proc    */
  629.                                         PROC_TABLE    *proc2  )    /*  pointer to proc    */
  630. {
  631.     int x;
  632.  
  633.     if (x = memcmp (    proc1->module,
  634.                             proc2->module,
  635.                             sizeof(MODULE) ))
  636.         return (x);
  637.     else
  638.         return ( memcmp (    proc1->line,
  639.                                 proc2->line,
  640.                                 sizeof(LINE) ));
  641. }
  642.  
  643. /*****************************************************************************
  644.     comp_call_module_line() - compare module+line for two calls
  645. *****************************************************************************/
  646.  
  647. int comp_call_module_line (    CALL_TABLE    *call1,        /*  pointer to call    */
  648.                                         CALL_TABLE    *call2  )    /*  pointer to call    */
  649. {
  650.     int x;
  651.  
  652.     if (x = memcmp (    call1->calling_module,
  653.                             call2->calling_module,
  654.                             sizeof(MODULE) ))
  655.         return (x);
  656.     else
  657.         return ( memcmp (    call1->calling_line,
  658.                                 call2->calling_line,
  659.                                 sizeof(LINE) ));
  660. }
  661.  
  662. /*****************************************************************************
  663.     comp_call_proc_line() - compare proc+line for two calls
  664. *****************************************************************************/
  665.  
  666. int comp_call_proc_line (    CALL_TABLE *call1,        /*  pointer to call    */
  667.                                     CALL_TABLE *call2  )        /*  pointer to call    */
  668. {
  669.     int    x ;
  670.  
  671.     if ( x = memcmp (    call1->calling_proc,
  672.                             call2->calling_proc,
  673.                             sizeof(PROC) ))
  674.         return(x);
  675.     else
  676.         return ( memcmp (    call1->calling_line,
  677.                                 call2->calling_line,
  678.                                 sizeof(LINE) ));
  679. }
  680.  
  681. /*****************************************************************************
  682.     comp_call_calling_proc() = compare calling_proc for two calls
  683. *****************************************************************************/
  684.  
  685. int comp_call_calling_proc (    CALL_TABLE *call1,        /*  pointer to call    */
  686.                                         CALL_TABLE *call2  )        /*  pointer to call    */
  687. {
  688.     return (memcmp (    call1->calling_proc,
  689.                             call2->calling_proc,
  690.                             sizeof(PROC) ));
  691. }
  692.  
  693. /*****************************************************************************
  694.     show() - used for debugging.  Shows call or proc table, 20 lines at a time
  695.                 This funtion is not normally called if the program is working.
  696.                 (Yes folks, it's wasted space!)
  697. *****************************************************************************/
  698.  
  699. show (    char    type,            /*  'p' = proc table,  'c' = call table            */
  700.             int    point )        /*  extra number to show source file position    */
  701. {
  702.     int x=0, y;
  703.  
  704.     printf("%c/%d  nprocs=%d  ncalls=%d\n", type, point, nprocs, ncalls);
  705.     for (y=0; y < ((type == 'c') ? ncalls : nprocs); y++) {
  706.         printf("%4d│%.*s\n", y,
  707.                 ((type=='c')?sizeof(CALL_TABLE):sizeof(PROC_TABLE))-1,
  708.                 (type == 'c') ? (char*) call[y] : (char *) proc[y]);
  709.         if (++x == 20) {
  710.             if (getch() == ESC) exit(0);
  711.             x = 0;
  712.         }
  713.     }
  714.     if (getch() == ESC) exit(0);
  715.     return(0);
  716. }
  717.