home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fchek284.zip / pgsymtab.c.orig < prev    next >
Text File  |  1995-06-02  |  68KB  |  2,456 lines

  1. /* pgsymtab.c:
  2.  
  3.         Routines associated with printing of global symbol table info
  4.  
  5.     Copyright (C) 1993 by Robert K. Moniot.
  6.     This program is free software.  Permission is granted to
  7.     modify it and/or redistribute it, retaining this notice.
  8.     No guarantees accompany this software.
  9.  
  10.     Shared functions defined:
  11.  
  12.         arg_array_cmp()   Compares subprogram calls with defns.
  13.         check_arglists()  Scans global symbol table for subprograms
  14.                   and finds subprogram defn if it exists.
  15.         check_comlists()  Scans global symbol table for common blocks.
  16.         check_com_usage() Checks usage status of common blocks & vars
  17.  
  18.  
  19.     Private functions defined:
  20.         arg_array_cmp()      Compares arg lists of subprog calls/defns
  21.         com_cmp_lax()      Compares common blocks at strictness 1,2
  22.         com_cmp_strict()  Compares common blocks at strictness 3
  23.         com_element_usage() Checks set/used status of common variables
  24.         com_block_usage() Checks for dead common blocks & variables
  25.         print_modules()      Prints names from a list of gsymt pointers.
  26.         sort_gsymbols()      Sorts the list of gsymt names.
  27.         swap_gsymptrs()      Swaps a pair of pointers.
  28.         visit_child()      Recursively visits callees of module,
  29.                   printing call tree as it goes.
  30.         visit_child_reflist() Recursively visits callees of module,
  31.                   printing reference list as it goes.
  32.         print_crossrefs() Prints list of callers of module.
  33.         toposort()      Topological sort of call tree.
  34.         sort_child_list() Sorts linked list of callees.
  35. */
  36.  
  37. #include <stdio.h>
  38. #include <ctype.h>
  39. #include <string.h>
  40. #include "ftnchek.h"
  41. #define PGSYMTAB
  42. #include "symtab.h"
  43.  
  44.  
  45. PRIVATE void
  46. com_cmp_lax(),com_cmp_strict(), arg_array_cmp(),
  47. visit_child(),visit_child_reflist(),sort_child_list();
  48. #ifdef VCG_SUPPORT
  49. PRIVATE void visit_child_vcg();
  50. #endif
  51.  
  52. PRIVATE void
  53. print_crossrefs(),sort_gsymbols(),swap_gsymptrs();
  54.  
  55. PRIVATE int
  56. toposort();
  57.  
  58. PRIVATE void
  59. com_element_usage(), com_block_usage(), print_modules();
  60.  
  61.  
  62.         /* Macro for testing whether an arglist or comlist header is
  63.            irrelevant for purposes of error checking: i.e. it comes
  64.            from an unvisited library module. */
  65. #define irrelevant(list) ((list)->module->library_module &&\
  66.                 !(list)->module->visited_somewhere)
  67.  
  68. #define pluralize(n) ((n)==1? "":"s")    /* singular/plural suffix for n */
  69.  
  70. #define CMP_ERR_LIMIT 3    /* stop printing errors after this many */
  71.  
  72.  
  73. PRIVATE int cmp_error_count;
  74. PRIVATE int
  75. cmp_error_head(name,message)
  76.      char *name,*message;
  77.     /* Increment error count, and if it is 1, print header for arg
  78.        mismatch error messages.  If it is past limit, print "etc"
  79.        and return TRUE, otherwise return FALSE.
  80.        */
  81. {
  82.         /* stop after limit: probably a cascade */
  83.     if(++cmp_error_count > CMP_ERR_LIMIT) {
  84.       (void)fprintf(list_fd,"\n etc...");
  85.       return TRUE;
  86.     }
  87.     if(cmp_error_count == 1)
  88.       (void)fprintf(list_fd,"\nSubprogram %s: %s",name,message);
  89.     return FALSE;
  90. }
  91. PRIVATE void
  92. arg_error_locate(alh)    /* Gives module, line, filename for error messages */
  93.      ArgListHeader *alh;
  94. {
  95.   if(novice_help) {        /* oldstyle messages */
  96.     (void)fprintf(list_fd," in module %s line %u file %s",
  97.             alh->module->name,
  98.             alh->line_num,
  99.             alh->filename);
  100.     if(alh->filename != alh->topfile) /* Track include filename */
  101.       (void)fprintf(list_fd," (included at line %u in %s)",
  102.             alh->top_line_num,
  103.             alh->topfile);
  104.   }
  105.   else {            /* lint-style messages */
  106.     (void)fprintf(list_fd," in module %s of \"%s\", line %u",
  107.             alh->module->name,
  108.             alh->filename,
  109.             alh->line_num);
  110.     if(alh->filename != alh->topfile) /* Track include filename */
  111.       (void)fprintf(list_fd," (\"%s\", line %u)",
  112.             alh->topfile,
  113.             alh->top_line_num);
  114.   }
  115. }
  116.  
  117. PRIVATE void
  118. com_error_locate(clh)    /* Gives module, line, filename for error messages */
  119.      ComListHeader *clh;
  120. {
  121.   if(novice_help) {        /* oldstyle messages */
  122.     (void)fprintf(list_fd," in module %s line %u file %s",
  123.             clh->module->name,
  124.             clh->line_num,
  125.             clh->filename);
  126.     if(clh->filename != clh->topfile) /* Track include filename */
  127.       (void)fprintf(list_fd," (included at line %u in %s)",
  128.             clh->top_line_num,
  129.             clh->topfile);
  130.   }
  131.   else    {            /* lint-style messages */
  132.     (void)fprintf(list_fd," in module %s of \"%s\", line %u",
  133.             clh->module->name,
  134.             clh->filename,
  135.             clh->line_num);
  136.     if(clh->filename != clh->topfile) /* Track include filename */
  137.       (void)fprintf(list_fd," (\"%s\", line %u)",
  138.             clh->topfile,
  139.             clh->top_line_num);
  140.   }
  141. }
  142.  
  143. PRIVATE void
  144. arg_array_cmp(name,args1,args2)
  145.              /* Compares subprogram calls with definition */
  146.     char *name;
  147.     ArgListHeader *args1, *args2;
  148. {
  149.     int i;
  150.     int  n,
  151.          n1 = args1->numargs,
  152.          n2 = args2->numargs;
  153.     ArgListElement *a1 = args1->arg_array,
  154.                *a2 = args2->arg_array;
  155.  
  156.     n = (n1 > n2) ? n2: n1;        /* n = min(n1,n2) */
  157.  
  158.     if (check_args_number && n1 != n2){
  159.       cmp_error_count = 0;
  160.       (void) cmp_error_head(name,"varying number of arguments:");
  161.  
  162.       (void)fprintf(list_fd,"\n    %s with %d argument%s",
  163.             args1->is_defn? "Defined":"Invoked",
  164.                 n1,pluralize(n1));
  165.       arg_error_locate(args1);
  166.  
  167.       (void)fprintf(list_fd,"\n    %s with %d argument%s",
  168.             args2->is_defn? "Defined":"Invoked",
  169.             n2,pluralize(n2));
  170.       arg_error_locate(args2);
  171.     }
  172.  
  173.     if(check_args_type)
  174.     {    /* Look for type mismatches */
  175.         cmp_error_count = 0;
  176.         for (i=0; i<n; i++) {
  177.           int c1 = storage_class_of(a1[i].type),
  178.               c2 = storage_class_of(a2[i].type),
  179.           t1 = datatype_of(a1[i].type),
  180.               t2 = datatype_of(a2[i].type),
  181.           s1 = a1[i].size,
  182.           s2 = a2[i].size,
  183.           defsize1 = (s1==size_DEFAULT),
  184.           defsize2 = (s2==size_DEFAULT);
  185.                 /* cmptype is type to use for mismatch test.
  186.                    Basically cmptype=type but DP matches
  187.                    REAL, DCPX matches CPLX, and hollerith
  188.                    matches any numeric or logical type
  189.                    but not  character.  The single/double
  190.                    match will be deferred to size check. */
  191.           int cmptype1= (t1==type_HOLLERITH && t2!=type_STRING)?
  192.                 t2:type_category[t1];
  193.           int cmptype2= (t2==type_HOLLERITH && t1!=type_STRING)?
  194.                 t1:type_category[t2];
  195.  
  196.         /* If -portability, do not translate default sizes so
  197.            they will never match explicit sizes. */
  198.           if(!(port_check || local_wordsize==0)) {
  199.         if(defsize1)
  200.           s1 = type_size[t1];
  201.         if(defsize2)
  202.           s2 = type_size[t2];
  203.           }
  204.  
  205.           if(s1 < 0 || s2 < 0) { /* char size_ADJUSTABLE or UNKNOWN */
  206.         s1 = s2 = size_DEFAULT;    /* suppress warnings on size */
  207.         defsize1 = defsize2 = TRUE;
  208.           }
  209.  
  210.              /* Require exact match between storage classes and
  211.                 compatible data type.  If that is OK, then for
  212.                 non-char args require exact size match.  For char
  213.                 and hollerith defer size check to other section.
  214.               */
  215.         if( (c1 != c2) || (cmptype1 != cmptype2) || ( (s1 != s2) &&
  216.             is_num_log_type(t1) && is_num_log_type(t2) ) ) {
  217.  
  218.         if(cmp_error_head(name," argument data type mismatch"))
  219.           break;
  220.  
  221.         (void)fprintf(list_fd, "\n  at position %d:", i+1);
  222. #ifdef KEEP_ARG_NAMES
  223.         (void)fprintf(list_fd,"\n    %s arg %s is type %s",
  224.                 args1->is_defn? "Dummy": "Actual",
  225.                 a1[i].name,
  226.                 type_name[t1]);
  227. #else
  228.         (void)fprintf(list_fd,"\n    %s type %s",
  229.                 args1->is_defn? "Dummy": "Actual",
  230.                 type_name[t1]);
  231. #endif
  232.         if(!defsize1)
  233.           (void)fprintf(list_fd,"*%d",s1);
  234.         (void)fprintf(list_fd," %s",
  235.             class_name[storage_class_of(a1[i].type)]);
  236.         arg_error_locate(args1);
  237.  
  238. #ifdef KEEP_ARG_NAMES
  239.         (void)fprintf(list_fd,"\n    %s arg %s is type %s",
  240.                 args2->is_defn? "Dummy": "Actual",
  241.                 a2[i].name,
  242.                 type_name[t2]);
  243. #else
  244.         (void)fprintf(list_fd,"\n    %s type %s",
  245.                 args2->is_defn? "Dummy": "Actual",
  246.                 type_name[t2]);
  247. #endif
  248.         if(!defsize2)
  249.           (void)fprintf(list_fd,"*%d",s2);
  250.         (void)fprintf(list_fd," %s",
  251.             class_name[storage_class_of(a2[i].type)]);
  252.         arg_error_locate(args2);
  253.  
  254.         if(args1->is_defn
  255.             && storage_class_of(a1[i].type) == class_SUBPROGRAM
  256.             && storage_class_of(a2[i].type) != class_SUBPROGRAM
  257.             && datatype_of(a1[i].type) != type_SUBROUTINE
  258.             && ! a1[i].declared_external )
  259.           (void)fprintf(list_fd,
  260.              "\n    (possibly it is an array which was not declared)");
  261.           }
  262.                 /* If no class/type/elementsize clash,
  263.                    and if comparing dummy vs. actual,
  264.                    check character and hollerith sizes */
  265.           else if(args1->is_defn) {
  266.                 /* Character: check size but skip *(*)
  267.                    and dummy array vs. actual array element.
  268.                  */
  269.         if(t1 == type_STRING && s1 > 0 && s2 > 0 &&
  270.           !(a1[i].array_var && a2[i].array_element)) {
  271.             unsigned long
  272.               dims1,dims2,size1,size2;
  273.  
  274.             if(a1[i].array_var) {
  275.               dims1 = array_dims(a1[i].info.array_dim);
  276.               size1 = array_size(a1[i].info.array_dim);
  277.             }
  278.             else {
  279.               dims1 = 0;
  280.               size1 = 1;
  281.             }
  282.             if(a2[i].array_var && !a2[i].array_element) {
  283.               dims2 = array_dims(a2[i].info.array_dim);
  284.               size2 = array_size(a2[i].info.array_dim);
  285.             }
  286.             else {
  287.               dims2 = 0;
  288.               size2 = 1;
  289.             }
  290.  
  291.                 /* standard requires dummy <= actual size.
  292.                      */
  293.           if( (s1*size1 > s2*size2 &&
  294.               (dims1==0 || size1>1) && (dims2==0 || size2>1)) ) {
  295.  
  296.             if(cmp_error_head(name," argument mismatch"))
  297.                 break;
  298.  
  299.             (void)fprintf(list_fd, "\n  at position %d:", i+1);
  300. #ifdef KEEP_ARG_NAMES
  301.             (void)fprintf(list_fd,"\n    Dummy arg %s is type %s*%d",
  302.                 a1[i].name,
  303.                 type_name[t1],s1);
  304. #else
  305.             (void)fprintf(list_fd,"\n    Dummy type %s*%d",
  306.                 type_name[t1],s1);
  307. #endif
  308.             if(dims1 > 0)
  309.               (void)fprintf(list_fd,"(%lu)",size1);
  310.             arg_error_locate(args1);
  311.  
  312. #ifdef KEEP_ARG_NAMES
  313.             (void)fprintf(list_fd,"\n    Actual arg %s is type %s*%d",
  314.                 a2[i].name,
  315.                 type_name[t2],s2);
  316. #else
  317.             (void)fprintf(list_fd,"\n    Actual type %s*%d",
  318.                 type_name[t2],s2);
  319. #endif
  320.             if(dims2 > 0)
  321.               (void)fprintf(list_fd,"(%lu)",size2);
  322.             arg_error_locate(args2);
  323.           }/*end if char size mismatch*/
  324.         }/*end if type==char*/
  325.  
  326.         else if(t2 == type_HOLLERITH) {
  327.             /* Allow hollerith to match any noncharacter type of
  328.                at least equal aggregate size.  */
  329.             unsigned long dims1,size1;
  330.             if(a1[i].array_var) {
  331.               dims1 = array_dims(a1[i].info.array_dim);
  332.               size1 = array_size(a1[i].info.array_dim);
  333.             }
  334.             else {
  335.               dims1 = 0;
  336.               size1 = 1;
  337.             }
  338.             if(s2 > s1*size1 && (dims1==0 || size1>1)) {
  339.  
  340.               if(cmp_error_head(name," argument mismatch"))
  341.                 break;
  342.  
  343.               (void)fprintf(list_fd, "\n  at position %d:", i+1);
  344. #ifdef KEEP_ARG_NAMES
  345.               (void)fprintf(list_fd,"\n    Dummy arg %s is type %s",
  346.                 a1[i].name,
  347.                 type_name[t1]);
  348. #else
  349.               (void)fprintf(list_fd,"\n    Dummy type %s",
  350.                 type_name[t1]);
  351. #endif
  352.               if(!defsize1)
  353.             (void)fprintf(list_fd,"*%d",s1);
  354.               if(dims1 > 0)
  355.             (void)fprintf(list_fd,"(%lu)",size1);
  356.               arg_error_locate(args1);
  357.  
  358. #ifdef KEEP_ARG_NAMES
  359.               (void)fprintf(list_fd,"\n    Actual arg %s is type %s*%d",
  360.                 a2[i].name,
  361.                 type_name[t2],s2);
  362. #else
  363.               (void)fprintf(list_fd,"\n    Actual type %s*%d",
  364.                 type_name[t2],s2);
  365. #endif
  366.               arg_error_locate(args2);
  367.             }/*end if holl size mismatch*/
  368.         }/*end if type==holl*/
  369.           }
  370.         }/*end for i*/
  371.     }/* end look for type && size mismatches */
  372.  
  373.  
  374.          /* Check arrayness of args only if defn exists */
  375.     if(check_args_type && args1->is_defn ) {
  376.         cmp_error_count = 0;
  377.         for (i=0; i<n; i++) {
  378.             /* Skip if class or datatype mismatch.  This
  379.                also skips holleriths which were checked above.
  380.                Do not process externals.
  381.              */
  382.           if(datatype_of(a2[i].type) != type_HOLLERITH &&
  383.          storage_class_of(a1[i].type) == class_VAR &&
  384.          storage_class_of(a2[i].type) == class_VAR) {
  385.  
  386.         if( a1[i].array_var ) {    /* I. Dummy arg is array */
  387.             if( a2[i].array_var ) {
  388.             if( a2[i].array_element ) {
  389.                     /*   A. Actual arg is array elt */
  390.                     /*    Warn on check_array_dims. */
  391.                 if(check_array_dims) {
  392.  
  393.                   if(cmp_error_head(
  394.                       name," argument arrayness mismatch"))
  395.                 break;
  396.  
  397.                   (void)fprintf(list_fd,"\n  at position %d:", i+1);
  398.  
  399. #ifdef KEEP_ARG_NAMES
  400.                   (void)fprintf(list_fd,
  401.                      "\n    Dummy arg %s is whole array",
  402.                      a1[i].name);
  403. #else
  404.                   (void)fprintf(list_fd,"\n    Dummy arg is whole array");
  405. #endif
  406.                   arg_error_locate(args1);
  407.  
  408. #ifdef KEEP_ARG_NAMES
  409.                   (void)fprintf(list_fd,
  410.                     "\n    Actual arg %s is array element",
  411.                     a2[i].name);
  412. #else
  413.                   (void)fprintf(list_fd,"\n    Actual arg is array element");
  414. #endif
  415.                   arg_error_locate(args2);
  416.                 }
  417.             }/* end case I.A. */
  418.  
  419.             else {
  420.                     /*   B. Actual arg is whole array */
  421.                     /*    Warn if dims or sizes differ */
  422.               unsigned long
  423.                 diminfo1,diminfo2,dims1,dims2,size1,size2,
  424.                 cmpsize1,cmpsize2;
  425.               diminfo1 = a1[i].info.array_dim;
  426.               diminfo2 = a2[i].info.array_dim;
  427.               dims1 = array_dims(diminfo1);
  428.               dims2 = array_dims(diminfo2);
  429.               cmpsize1 = size1 = array_size(diminfo1);
  430.               cmpsize2 = size2 = array_size(diminfo2);
  431.                 /* For char arrays relevant size is no. of
  432.                    elements times element size. But use
  433.                    no. of elements if *(*) involved. */
  434.               if(datatype_of(a1[i].type) == type_STRING
  435.                  && a1[i].size > 0 && a2[i].size > 0) {
  436.                 cmpsize1 *= a1[i].size;
  437.                 cmpsize2 *= a2[i].size;
  438.               }
  439.  
  440.             /* size = 0 or 1 means variable-dim: OK to differ */
  441.               if( (check_array_size &&
  442.                   (size1>1 && size2>1 && cmpsize1 != cmpsize2))
  443.                  || (check_array_dims &&
  444.                   (dims1 != dims2)) ) {
  445.  
  446.  
  447.                 if(cmp_error_head(
  448.                     name," argument arrayness mismatch"))
  449.                       break;
  450.  
  451.                 (void)fprintf(list_fd,"\n  at position %d:", i+1);
  452.  
  453. #ifdef KEEP_ARG_NAMES
  454.                 (void)fprintf(list_fd,
  455.                     "\n    Dummy arg %s has %ld dim%s size %ld",
  456.                     a1[i].name,
  457.                     dims1,pluralize(dims1),
  458.                     size1);
  459. #else
  460.                 (void)fprintf(list_fd,
  461.                     "\n    Dummy arg %ld dim%s size %ld",
  462.                     dims1,pluralize(dims1),
  463.                     size1);
  464. #endif
  465.                 if(datatype_of(a1[i].type) == type_STRING &&
  466.                    a1[i].size > 0)
  467.                   (void)fprintf(list_fd,"*%ld",a1[i].size);
  468.                 arg_error_locate(args1);
  469.  
  470. #ifdef KEEP_ARG_NAMES
  471.                 (void)fprintf(list_fd,
  472.                     "\n    Actual arg %s has %ld dim%s size %ld",
  473.                     a2[i].name,
  474.                     dims2,pluralize(dims2),
  475.                     size2);
  476. #else
  477.                 (void)fprintf(list_fd,
  478.                     "\n    Actual arg %ld dim%s size %ld",
  479.                     dims2,pluralize(dims2),
  480.                     size2);
  481. #endif
  482.                 if(datatype_of(a2[i].type) == type_STRING
  483.                    && a2[i].size > 0)
  484.                   (void)fprintf(list_fd,"*%ld",a2[i].size);
  485.                 arg_error_locate(args2);
  486.               }/* end if size mismatch */
  487.             }/* end case I.B. */
  488.             }
  489.             else {
  490.                     /*   C. Actual arg is scalar */
  491.                     /*    Warn in all cases */
  492.  
  493.                   if(cmp_error_head(
  494.                 name," argument arrayness mismatch"))
  495.               break;
  496.  
  497.             (void)fprintf(list_fd,"\n  at position %d:", i+1);
  498.  
  499. #ifdef KEEP_ARG_NAMES
  500.             (void)fprintf(list_fd,"\n    Dummy arg %s is array",
  501.                       a1[i].name);
  502. #else
  503.             (void)fprintf(list_fd,"\n    Dummy arg is array");
  504. #endif
  505.             arg_error_locate(args1);
  506.  
  507. #ifdef KEEP_ARG_NAMES
  508.             (void)fprintf(list_fd,"\n    Actual arg %s is scalar",
  509.                       a2[i].name);
  510. #else
  511.             (void)fprintf(list_fd,"\n    Actual arg is scalar");
  512. #endif
  513.             arg_error_locate(args2);
  514.             }/* end case I.C. */
  515.         } /* end dummy is array, case I. */
  516.  
  517.         else {            /* II. Dummy arg is scalar */
  518.             if( a2[i].array_var ) {
  519.             if( a2[i].array_element ) {
  520.                     /*   A. Actual arg is array elt */
  521.                     /*    OK */
  522.             }
  523.             else {
  524.                     /*   B. Actual arg is whole array */
  525.                     /*    Warn in all cases */
  526.  
  527.               if(cmp_error_head(
  528.                    name," argument arrayness mismatch"))
  529.                 break;
  530.  
  531.               (void)fprintf(list_fd,"\n  at position %d:", i+1);
  532.  
  533. #ifdef KEEP_ARG_NAMES
  534.               (void)fprintf(list_fd,
  535.                   "\n    Dummy arg %s is scalar",
  536.                   a1[i].name);
  537. #else
  538.               (void)fprintf(list_fd,"\n    Dummy arg is scalar");
  539. #endif
  540.               arg_error_locate(args1);
  541.  
  542. #ifdef KEEP_ARG_NAMES
  543.               (void)fprintf(list_fd,
  544.                   "\n    Actual arg %s is whole array",
  545.                    a2[i].name);
  546. #else
  547.               (void)fprintf(list_fd,"\n    Actual arg is whole array");
  548. #endif
  549.               arg_error_locate(args2);
  550.  
  551.             }/* end case II.B. */
  552.             }
  553.             else {
  554.                     /*   C. Actual arg is scalar */
  555.                     /*    OK */
  556.             }
  557.  
  558.         } /* end dummy is scalar, case II */
  559.  
  560.           } /* end if class_VAR */
  561.         }/* end for (i=0; i<n; i++) */
  562.     }/* if( args1->is_defn ) */
  563.  
  564.  
  565.          /* Check usage of args only if defn exists */
  566.     if(check_set_used && args1->is_defn) {
  567.  
  568.         cmp_error_count = 0;
  569.         for (i=0; i<n; i++) {
  570.           if(storage_class_of(a1[i].type) == class_VAR &&
  571.          storage_class_of(a2[i].type) == class_VAR ) {
  572.         int nonlvalue_out = (a1[i].assigned_flag && !a2[i].is_lvalue),
  573.             nonset_in = (a1[i].used_before_set && !a2[i].set_flag);
  574.  
  575. #if DEBUG_PGSYMTAB
  576. if(debug_latest) {
  577. (void)fprintf(list_fd,
  578. "\nUsage check: %s[%d] dummy asgnd %d ubs %d  actual lvalue %d set %d",
  579. args1->module->name,
  580. i+1,
  581. a1[i].assigned_flag,
  582. a1[i].used_before_set,
  583. a2[i].is_lvalue,
  584. a2[i].set_flag);
  585. }
  586. #endif
  587.  
  588.         if(nonlvalue_out || nonset_in) {
  589.  
  590.           if(cmp_error_head(name," argument usage mismatch"))
  591.              break;
  592.  
  593.           (void)fprintf(list_fd,"\n  at position %d:", i+1);
  594.  
  595.           if(nonlvalue_out) {
  596. #ifdef KEEP_ARG_NAMES
  597.             (void)fprintf(list_fd,"\n    Dummy arg %s is modified",
  598.                   a1[i].name);
  599. #else
  600.             (void)fprintf(list_fd,"\n    Dummy arg is modified");
  601. #endif
  602.             arg_error_locate(args1);
  603.  
  604. #ifdef KEEP_ARG_NAMES
  605.             (void)fprintf(list_fd,"\n    Actual arg %s is const or expr",
  606.                   a2[i].name);
  607. #else
  608.             (void)fprintf(list_fd,"\n    Actual arg is const or expr");
  609. #endif
  610.             arg_error_locate(args2);
  611.           }
  612.           else if(nonset_in) {
  613.  
  614. #ifdef KEEP_ARG_NAMES
  615.             (void)fprintf(list_fd,"\n    Dummy arg %s used before set",
  616.                   a1[i].name);
  617. #else
  618.             (void)fprintf(list_fd,"\n    Dummy arg used before set");
  619. #endif
  620.             arg_error_locate(args1);
  621.  
  622. #ifdef KEEP_ARG_NAMES
  623.             (void)fprintf(list_fd,"\n    Actual arg %s not set",
  624.                   a2[i].name);
  625. #else
  626.             (void)fprintf(list_fd,"\n    Actual arg not set");
  627. #endif
  628.             arg_error_locate(args2);
  629.           }
  630.         }
  631.           }
  632.         }
  633.     }/*end if(check_set_used && args->is_defn) */
  634.  
  635. }/* arg_array_cmp */
  636.  
  637.  
  638.  
  639. void
  640. check_arglists()    /* Scans global symbol table for subprograms */
  641. {                       /* and finds subprogram defn if it exists */
  642.     unsigned i;
  643.     ArgListHeader *defn_list, *alist;
  644.  
  645.     for (i=0; i<glob_symtab_top; i++){
  646.  
  647.                 /* Skip common blocks */
  648.         if(storage_class_of(glob_symtab[i].type) != class_SUBPROGRAM)
  649.         continue;
  650.  
  651.                 /* Skip unvisited library modules */
  652.         if(glob_symtab[i].library_module && !glob_symtab[i].visited)
  653.         continue;
  654.  
  655.  
  656.         if((alist=glob_symtab[i].info.arglist) == NULL){
  657.           oops_message(OOPS_NONFATAL,NO_LINE_NUM,NO_COL_NUM,
  658.               "global symbol has no argument lists:");
  659.           oops_tail(glob_symtab[i].name);
  660.         }
  661.         else{    /* alist != NULL */
  662.         int num_defns= 0;
  663.         ArgListHeader *list_item;
  664.  
  665.             /* use 1st invocation instead of defn if no defn */
  666.         defn_list = alist;
  667.  
  668.                 /* Find a definition in the linked list of
  669.                    usages.  Count how many defns found. */
  670.         list_item = alist;
  671.         while(list_item != NULL){
  672.             if(list_item->is_defn){
  673.             if(ext_def_check && num_defns > 0) {/* multiple defn */
  674.                 if(num_defns == 1) {
  675.                   (void)fprintf(list_fd,
  676.                       "\nSubprogram %s multiply defined:\n    ",
  677.                       glob_symtab[i].name);
  678.                   arg_error_locate(defn_list);
  679.                 }
  680.                 (void)fprintf(list_fd,"\n    ");
  681.                 arg_error_locate(list_item);
  682.             }
  683.             ++num_defns;
  684.             defn_list = list_item;    /* Use last defn found */
  685.             }
  686.             else { /* ! list_item->is_defn */
  687.                 /* Here treat use as actual arg like call */
  688.             if(list_item->is_call || list_item->actual_arg){
  689.                  /* Use last call by a visited or nonlibrary
  690.                     module as defn if no defn found */
  691.               if(!defn_list->is_defn
  692.                  && !irrelevant(list_item) )
  693.                 defn_list = list_item;
  694.                 }
  695.             }
  696.  
  697.             list_item = list_item->next;
  698.         }
  699.         if(num_defns == 0){
  700.                 /* If no defn found, and all calls are
  701.                    from unvisited library modules, skip. */
  702.           if(irrelevant(defn_list))
  703.             continue;
  704.                 /* If no definitions found, report error
  705.                    unless -noext is given */
  706.            if(ext_def_check) {
  707.              (void)fprintf(list_fd,
  708.                  "\nSubprogram %s never defined",
  709.                  glob_symtab[i].name);
  710.              if(!glob_symtab[i].used_flag)
  711.                (void)fprintf(list_fd," nor invoked");
  712.  
  713.              (void)fprintf(list_fd, "\n    %s",
  714.                  (defn_list->external_decl)?"declared":"invoked");
  715.              arg_error_locate(defn_list);
  716.  
  717.             /* Warn if it seems it may just be an array they
  718.                forgot to declare */
  719.               if(defn_list->numargs != 0
  720.              && datatype_of(defn_list->type) != type_SUBROUTINE
  721.              && ! glob_symtab[i].declared_external) {
  722.             if(novice_help)
  723.               (void)fprintf(list_fd,
  724.         "\n    (possibly it is an array which was not declared)");
  725.               }
  726.            }
  727.         }
  728.                 /* If definition is found but module is
  729.                    not in call tree, report it unless -lib */
  730.         else{    /* num_defns != 0 */
  731.             if(!glob_symtab[i].visited
  732.                && datatype_of(glob_symtab[i].type) != type_BLOCK_DATA
  733.                && !glob_symtab[i].library_module) {
  734.             (void)fprintf(list_fd,"\nSubprogram %s never invoked",
  735.                 glob_symtab[i].name);
  736.             (void)fprintf(list_fd, "\n    defined");
  737.             arg_error_locate(defn_list);
  738.             }
  739.         }
  740.  
  741.             /* Now check defns/invocations for consistency.  If
  742.                no defn, 1st invocation will serve. Here treat
  743.                use as actual arg like call.  Ignore calls & defns
  744.                in unvisited library modules. */
  745.         if( check_args_type &&
  746.            (defn_list->is_defn || !defn_list->external_decl)) {
  747.           while(alist != NULL){
  748.             int typerrs = 0;
  749.             if(alist != defn_list && !alist->external_decl
  750.                && !irrelevant(alist)) {
  751.               int t1 = datatype_of(defn_list->type),
  752.                   t2 = datatype_of(alist->type),
  753.                   s1 = defn_list->size,
  754.                   s2 = alist->size,
  755.                   defsize1 = (s1 == size_DEFAULT),
  756.                   defsize2 = (s2 == size_DEFAULT);
  757.         /* If -portability, do not translate default sizes so
  758.            they will never match explicit sizes. */
  759.               if(!(port_check || local_wordsize==0)) {
  760.                 if(defsize1)
  761.                   s1 = type_size[t1];
  762.                 if(defsize2)
  763.                   s2 = type_size[t2];
  764.               }
  765.  
  766.               if(s1 < 0 || s2 < 0){ /*size_ADJUSTABLE or UNKNOWN*/
  767.                 s1 = s2 = size_DEFAULT;/* suppress size warnings */
  768.                 defsize1 = defsize2 = TRUE;
  769.               }
  770.                 /* Check class, type, and size */
  771.               if(defn_list->type != alist->type ||
  772.                  ( (s1 != s2) &&
  773.                 /*exclude char size-only mismatch betw calls */
  774.                   (t1 != type_STRING ||
  775.                     defn_list->is_defn || alist->is_defn )) ){
  776.  
  777.                     if(typerrs++ == 0){
  778.                   (void)fprintf(list_fd,
  779.                     "\nSubprogram %s invoked inconsistently:",
  780.                      glob_symtab[i].name);
  781.                   (void)fprintf(list_fd,
  782.                     "\n    %s type %s",
  783.                     defn_list->is_defn? "Defined":"Invoked",
  784.                     type_name[t1]);
  785.                   if(!defsize1)
  786.                     (void)fprintf(list_fd,"*%d",s1);
  787.                   arg_error_locate(defn_list);
  788.                 }
  789.                 (void)fprintf(list_fd,
  790.                     "\n    %s type %s",
  791.                     alist->is_defn? "Defined":"Invoked",
  792.                     type_name[t2]);
  793.                 if(!defsize2)
  794.                   (void)fprintf(list_fd,"*%d",s2);
  795.                 arg_error_locate(alist);
  796.               }
  797.             }
  798.             alist = alist->next;
  799.  
  800.           }/* end while(alist != NULL) */
  801.             }/* end if(defn) */
  802.  
  803.         alist = glob_symtab[i].info.arglist;
  804.         while(alist != NULL){
  805.           /* Here we require true call, not use as actual arg.
  806.              Also, do not compare multiple defns against each
  807.              other. */
  808.             if(alist != defn_list &&
  809.                (defn_list->is_defn || defn_list->is_call) &&
  810.                (alist->is_call && !irrelevant(alist)) ){
  811.                 arg_array_cmp(glob_symtab[i].name,defn_list,alist);
  812.             }
  813.             alist = alist->next;
  814.  
  815.         }/* end while(alist != NULL) */
  816.         }/* end else <alist != NULL> */
  817.     }/* end for (i=0; i<glob_symtab_top; i++) */
  818. }
  819.  
  820.  
  821.  
  822. void
  823. check_comlists()        /* Scans global symbol table for common blocks */
  824. {
  825.     unsigned i, model_n;
  826.     ComListHeader *first_list, *model, *clist;
  827.  
  828.     if(check_com_off)
  829.         return;
  830.  
  831.     for (i=0; i<glob_symtab_top; i++){
  832.  
  833.         if (storage_class_of(glob_symtab[i].type) != class_COMMON_BLOCK)
  834.         continue;
  835.  
  836.         if((first_list=glob_symtab[i].info.comlist) == NULL){
  837.         (void)fprintf(list_fd,"\nCommon block %s never defined",
  838.             glob_symtab[i].name);
  839.         }
  840.         else {
  841.               /* Find instance with most variables to use as model */
  842.         model=first_list;
  843.         model_n = first_list->numargs;
  844.         clist = model;
  845.         while( (clist=clist->next) != NULL ){
  846.             if(clist->numargs >= model_n /* if tie, use earlier */
  847.             /* also if model is from an unvisited library
  848.                module, take another */
  849.                || irrelevant(model) ) {
  850.             model = clist;
  851.             model_n = clist->numargs;
  852.             }
  853.         }
  854.  
  855.         if( irrelevant(model) )
  856.           continue;    /* skip if irrelevant */
  857.  
  858.             /* Check consistent SAVEing of block:
  859.                If SAVEd in one module, must be SAVEd in all.
  860.                Main prog is an exception: SAVE ignored there. */
  861.           {
  862.         ComListHeader *saved_list, *unsaved_list;
  863.         saved_list = unsaved_list = (ComListHeader *)NULL;
  864.         clist = first_list;
  865.         while( clist != NULL ){
  866.  
  867.             if(!irrelevant(clist) && clist->module->type !=
  868.                type_byte(class_SUBPROGRAM,type_PROGRAM) ) {
  869.  
  870.               if(clist->saved)
  871.             saved_list = clist;
  872.               else
  873.             unsaved_list = clist;
  874.             }
  875.             clist = clist->next;
  876.         }
  877.         if(saved_list != (ComListHeader *)NULL &&
  878.            unsaved_list != (ComListHeader *)NULL) {
  879.               (void)fprintf(list_fd,
  880.                 "\nCommon block %s not SAVED consistently",
  881.                 glob_symtab[i].name);
  882.               (void)fprintf(list_fd,
  883.                   "\n    is SAVED");
  884.               com_error_locate(saved_list);
  885.               (void)fprintf(list_fd,
  886.                   "\n    is not SAVED");
  887.               com_error_locate(unsaved_list);
  888.         }
  889.           }
  890.  
  891.  
  892.                 /* Now check agreement of common lists */
  893.         clist = first_list;
  894.         while( clist != NULL ){
  895.             if(clist != model && !irrelevant(clist)) {
  896.  
  897.             if(check_com_byname)
  898.               com_cmp_strict(glob_symtab[i].name,model,clist);
  899.             else
  900.               com_cmp_lax(glob_symtab[i].name,model,clist);
  901.             }
  902.             clist = clist->next;
  903.         }
  904.         }
  905.     }
  906. } /* check_comlists */
  907.  
  908.  
  909.  
  910. PRIVATE void
  911. com_cmp_lax(name,c1,c2)        /* Common-list check at levels 1 & 2 */
  912.      char *name;
  913.      ComListHeader *c1,*c2;
  914. {
  915.     int i1,i2,            /* count of common variables in each block */
  916.     done1,done2,        /* true when end of block reached */
  917.     type1,type2;        /* type of variable presently in scan */
  918.     unsigned long
  919.     len1,len2,        /* length of variable remaining */
  920.         size1,size2,        /* unit size of variable */
  921.     word1,word2,        /* number of "words" scanned */
  922.     words1,words2,        /* number of "words" in block */
  923.         defsize1,defsize2,    /* default size used? */
  924.     jump;            /* number of words to skip next in scan */
  925.     int byte_oriented=FALSE,    /* character vs numeric block */
  926.         type_clash;        /* flag for catching clashes */
  927.     int n1=c1->numargs,n2=c2->numargs; /* variable count for each block */
  928.     int numerrs;
  929.     ComListElement *a1=c1->com_list_array, *a2=c2->com_list_array;
  930.  
  931.                 /* Count words in each list */
  932.     words1=words2=0;
  933.     for(i1=0; i1<n1; i1++) {
  934.       size1 = a1[i1].size;
  935.       if(size1 == size_DEFAULT)
  936.     size1 = type_size[a1[i1].type];
  937.       else
  938.     byte_oriented = TRUE;
  939.       words1 += array_size(a1[i1].dimen_info)*size1;
  940.     }
  941.     for(i2=0; i2<n2; i2++) {
  942.       size2 = a2[i2].size;
  943.       if(size2 == size_DEFAULT)
  944.     size2 = type_size[a2[i2].type];
  945.       else
  946.     byte_oriented = TRUE;
  947.       words2 += array_size(a2[i2].dimen_info)*size2;
  948.     }
  949.     /* If not byte oriented, then sizes are all multiples of
  950.        BpW and can be reported as words according to F77 std. */
  951.     if(!byte_oriented) {
  952.       words1 /= BpW;
  953.       words2 /= BpW;
  954.     }
  955.     if(check_com_lengths && words1 != words2) {
  956.       (void)fprintf(list_fd,
  957.           "\nCommon block %s: varying length:", name);
  958.       (void)fprintf(list_fd,
  959.           "\n    Has %ld %s%s",
  960.         words1,
  961.         byte_oriented? "byte":"word",
  962.         pluralize(words1));
  963.       com_error_locate(c1);
  964.       (void)fprintf(list_fd,
  965.           "\n    Has %ld %s%s",
  966.         words2,
  967.         byte_oriented? "byte":"word",
  968.         pluralize(words2));
  969.       com_error_locate(c2);
  970.     }
  971.  
  972.                 /* Now check type matches */
  973.     done1=done2=FALSE;
  974.     i1=i2=0;
  975.     len1=len2=0;
  976.     word1=word2=1;
  977.     numerrs=0;
  978.     for(;;) {
  979.     if(len1 == 0) {        /* move to next variable in list 1 */
  980.         if(i1 == n1) {
  981.         done1 = TRUE;
  982.         }
  983.         else {
  984.         type1 = a1[i1].type;
  985.         size1 = a1[i1].size;
  986.         defsize1 = (size1 == size_DEFAULT);
  987.         if(defsize1)
  988.           size1 = type_size[type1];
  989.         if(!byte_oriented)
  990.           size1 /= BpW;    /* convert bytes to words */
  991.         len1 = array_size(a1[i1].dimen_info)*size1;
  992.         ++i1;
  993.         }
  994.     }
  995.     if(len2 == 0) {        /* move to next variable in list 2 */
  996.         if(i2 == n2) {
  997.         done2 = TRUE;
  998.         }
  999.         else {
  1000.         type2 = a2[i2].type;
  1001.         size2 = a2[i2].size;
  1002.         defsize2 = (size2 == size_DEFAULT);
  1003.         if(defsize2)
  1004.           size2 = type_size[type2];
  1005.         if(!byte_oriented)
  1006.           size2 /= BpW;
  1007.         len2 = array_size(a2[i2].dimen_info)*size2;
  1008.         ++i2;
  1009.         }
  1010.     }
  1011.  
  1012.     if(done1 || done2){    /* either list exhausted? */
  1013.         break;        /* then stop checking */
  1014.     }
  1015.  
  1016.         /* Look for type clash.  Allow explicitly sized real to
  1017.            match double of equal size.
  1018.            Allow real to match complex whose parts are of equal size.
  1019.            Within same type category, size diff counts as clash
  1020.            except with char.
  1021.            Also issue warning under -portability or -nowordsize
  1022.            if an explicit size is matched to an implicit size. */
  1023.     type_clash = FALSE;
  1024.     if( (type_category[type1] == type_category[type2]) ) {
  1025.       if( type1 != type_STRING &&
  1026.           (size1 != size2
  1027.            || ((port_check||local_wordsize==0) && defsize1 != defsize2))) {
  1028.         type_clash = TRUE;
  1029.       }
  1030.     }
  1031.     else /* different type categories */ {
  1032.                 /* Equiv_type matches complex to real */
  1033.       if(equiv_type[type1] != equiv_type[type2]) {
  1034.         type_clash = TRUE;
  1035.       }
  1036.       else {
  1037.         if( type_category[type1] == type_COMPLEX ) {
  1038.           type_clash = (size1 != 2*size2);
  1039.         }
  1040.         else {
  1041.                 /* 2nd block has complex */
  1042.           type_clash = (size2 != 2*size1);
  1043.         }
  1044.                   /* Give warning anyway if default size
  1045.                    is matched to explicit. */
  1046.         if( (port_check||local_wordsize==0) && defsize1 != defsize2 )
  1047.           type_clash = TRUE;
  1048.       }
  1049.     }
  1050.  
  1051.     if(type_clash) {
  1052.          if(++numerrs > 3) {
  1053.            (void)fprintf(list_fd,"\netc...");
  1054.            break;        /* stop checking after third mismatch */
  1055.          }
  1056.          if(numerrs == 1)
  1057.            (void)fprintf(list_fd,
  1058.                "\nCommon block %s: data type mismatch",
  1059.                name);
  1060.          (void)fprintf(list_fd,"\n    %s %ld is type %s",
  1061.              byte_oriented?"Byte":"Word",
  1062.              word1,
  1063.              type_name[type1]);
  1064.          if(!defsize1)
  1065.            (void)fprintf(list_fd,"*%lu",
  1066.                size1);
  1067.          com_error_locate(c1);
  1068.  
  1069.          (void)fprintf(list_fd,"\n    %s %ld is type %s",
  1070.              byte_oriented?"Byte":"Word",
  1071.              word2,
  1072.              type_name[type2]);
  1073.          if(!defsize2)
  1074.            (void)fprintf(list_fd,"*%lu",
  1075.                size2);
  1076.          com_error_locate(c2);
  1077.     }
  1078.  
  1079.             /* Advance along list by largest possible
  1080.                step that does not cross a variable boundary.
  1081.                If matching complex to real, only advance
  1082.                the real part.
  1083.              */
  1084.     jump = len1 < len2? len1: len2;    /* min(len1,len2) */
  1085.     len1 -= jump;
  1086.     len2 -= jump;
  1087.     word1 += jump;
  1088.     word2 += jump;
  1089.     }/* end for(;;) */
  1090. }
  1091.  
  1092. PRIVATE void
  1093. com_cmp_strict(name,c1,c2)    /* Common-list check at level 3 */
  1094.     char *name;
  1095.     ComListHeader *c1, *c2;
  1096. {
  1097.     int i,
  1098.         typerr,        /* count of type/size mismatches */
  1099.         dimerr;        /* count of array dim/size mismatches */
  1100.     short n,
  1101.           n1 = c1->numargs,
  1102.           n2 = c2->numargs;
  1103.     ComListElement *a1 = c1->com_list_array,
  1104.                *a2 = c2->com_list_array;
  1105.  
  1106.     n = (n1 > n2) ? n2: n1;
  1107.     if(n1 != n2){
  1108.       (void)fprintf(list_fd,
  1109.           "\nCommon block %s: varying length:", name);
  1110.       (void)fprintf(list_fd,
  1111.           "\n    Has %d variable%s",
  1112.           n1,pluralize(n1));
  1113.       com_error_locate(c1);
  1114.  
  1115.       (void)fprintf(list_fd,
  1116.           "\n    Has %d variable%s",
  1117.           n2,pluralize(n2));
  1118.       com_error_locate(c2);
  1119.         }
  1120. #if DEBUG_PGSYMTAB
  1121. if(debug_latest){
  1122. (void)fprintf(list_fd,"block %s",name);
  1123. (void)fprintf(list_fd,"\n\t1=in module %s line %u file %s (%s)",
  1124.             c1->module->name,
  1125.             c1->line_num,
  1126.             c1->topfile
  1127.                 c1->filename);
  1128. (void)fprintf(list_fd,"\n\t2=in module %s line %u file %s (%s)",
  1129.             c2->module->name,
  1130.             c2->line_num,
  1131.             c2->topfile,
  1132.                 c2->filename);
  1133. }
  1134. #endif
  1135.     typerr = 0;
  1136.     for (i=0; i<n; i++) {
  1137.       int t1 = datatype_of(a1[i].type),
  1138.           t2 = datatype_of(a2[i].type),
  1139.           s1 = a1[i].size,
  1140.           s2 = a2[i].size,
  1141.           defsize1 = (s1==size_DEFAULT),
  1142.           defsize2 = (s2==size_DEFAULT);
  1143.         /* If -portability, do not translate default sizes so
  1144.            they will never match explicit sizes. */
  1145.      if(!(port_check || local_wordsize==0)) {
  1146.        if(defsize1)
  1147.          s1 = type_size[t1];
  1148.        if(defsize2)
  1149.          s2 = type_size[t2];
  1150.      }
  1151.  
  1152.         if( t1 != t2 || s1 != s2 ) {
  1153.                 /* stop after limit: probably a cascade */
  1154.             if(++typerr > CMP_ERR_LIMIT) {
  1155.                 (void)fprintf(list_fd,"\n etc...");
  1156.                 break;
  1157.             }
  1158.  
  1159.                 if(typerr == 1)
  1160.               (void)fprintf(list_fd,
  1161.                   "\nCommon block %s: data type mismatch",
  1162.                   name);
  1163.             (void)fprintf(list_fd, "\n  at position %d:", i+1);
  1164.  
  1165.             (void)fprintf(list_fd,
  1166.                 "\n    Variable %s has type %s",
  1167.                 a1[i].name,
  1168.                 type_name[t1]);
  1169.             if(!defsize1)
  1170.               (void)fprintf(list_fd,"*%d",s1);
  1171.             com_error_locate(c1);
  1172.  
  1173.             (void)fprintf(list_fd,
  1174.                 "\n    Variable %s has type %s",
  1175.                 a2[i].name,
  1176.                  type_name[t2]);
  1177.             if(!defsize2)
  1178.               (void)fprintf(list_fd,"*%d",s2);
  1179.             com_error_locate(c2);
  1180.  
  1181.         }/*end if(type or size mismatch)*/
  1182.     }/*end for(i=0; i<n; i++)*/
  1183.  
  1184.  
  1185.     dimerr = 0;
  1186.     for (i=0; i<n; i++){
  1187.         unsigned long d1, d2, s1, s2;
  1188.  
  1189.         if((d1=array_dims(a1[i].dimen_info)) !=
  1190.             (d2=array_dims(a2[i].dimen_info))){
  1191.  
  1192.                 /* stop after limit: probably a cascade */
  1193.             if(++dimerr > CMP_ERR_LIMIT) {
  1194.                 (void)fprintf(list_fd,"\n etc...");
  1195.                 break;
  1196.             }
  1197.             if(dimerr == 1)
  1198.               (void)fprintf(list_fd,
  1199.                   "\nCommon block %s: array dimen/size mismatch",
  1200.                   name);
  1201.             (void)fprintf(list_fd, "\nat position %d:", i+1);
  1202.  
  1203.             (void)fprintf(list_fd,
  1204.                 "\n    Variable %s has %ld dimension%s",
  1205.                 a1[i].name,
  1206.                 d1,pluralize(d1));
  1207.             com_error_locate(c1);
  1208.  
  1209.             (void)fprintf(list_fd,
  1210.                 "\n    Variable %s has %ld dimension%s",
  1211.                 a2[i].name,
  1212.                 d2,pluralize(d2));
  1213.             com_error_locate(c2);
  1214.         }/*end if(num dims mismatch)*/
  1215.  
  1216.         if((s1=array_size(a1[i].dimen_info)) !=
  1217.             (s2=array_size(a2[i].dimen_info))){
  1218.  
  1219.                 /* stop after limit: probably a cascade */
  1220.             if(++dimerr > CMP_ERR_LIMIT) {
  1221.                 (void)fprintf(list_fd,"\n etc...");
  1222.                 break;
  1223.             }
  1224.             if(dimerr == 1)
  1225.               (void)fprintf(list_fd,
  1226.                   "\nCommon block %s: array dimen/size mismatch",
  1227.                   name);
  1228.             (void)fprintf(list_fd,
  1229.                 "\nat position %d:", i+1);
  1230.  
  1231.             (void)fprintf(list_fd,
  1232.                 "\n    Variable %s has size %ld",
  1233.                 a1[i].name,
  1234.                 s1);
  1235.             com_error_locate(c1);
  1236.  
  1237.             (void)fprintf(list_fd,
  1238.                 "\n    Variable %s has size %ld",
  1239.                 a2[i].name,
  1240.                 s2);
  1241.             com_error_locate(c2);
  1242.  
  1243.         }/*end if(array size mismatch)*/
  1244.     }/*end for(i=0; i<n; i++)*/
  1245.  
  1246. }/*com_cmp_strict*/
  1247.  
  1248.  
  1249. /**  Common block and common variable usage checks.  Implemented
  1250.  **  by John Quinn, Jan-May 1993.  Some modifications made by RKM.
  1251.  **/
  1252.  
  1253. void
  1254. check_com_usage()
  1255. {
  1256. #ifdef DYNAMIC_TABLES        /* tables will be mallocked at runtime */
  1257.     Gsymtab  **gsymlist;
  1258. #else
  1259.     Gsymtab  *gsymlist[GLOBSYMTABSZ];
  1260. #endif
  1261.     int  i,numentries,numblocks;
  1262.     ComListHeader  *cmlist;
  1263.  
  1264. #ifdef DYNAMIC_TABLES
  1265.       if( (gsymlist=(Gsymtab **)calloc(glob_symtab_top,sizeof(Gsymtab *)))
  1266.      == (Gsymtab **)NULL) {
  1267.       oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
  1268.                "Cannot malloc space for common block list");
  1269.       }
  1270. #endif
  1271.  
  1272.                 /* Print cross-reference list */
  1273.     if(print_xref_list) {
  1274.     for(i=numblocks=0;i<glob_symtab_top;i++){ /* loop thru global table */
  1275.        if (storage_class_of(glob_symtab[i].type) == class_COMMON_BLOCK){
  1276.  
  1277.          cmlist = glob_symtab[i].info.comlist;
  1278.          numentries=0;
  1279.  
  1280. #ifdef DEBUG_COM_USAGE
  1281.          (void)fprintf(list_fd, "\n Common Block %s:\n",glob_symtab[i].name );
  1282. #endif
  1283.  
  1284.          while (cmlist != NULL){ /* loop thru declarations */
  1285.  
  1286.              if(! irrelevant(cmlist)  &&
  1287.             (cmlist->any_used || cmlist->any_set))
  1288.            gsymlist[numentries++] = cmlist->module;
  1289. #ifdef DEBUG_COM_USAGE
  1290.          print_comvar_usage(cmlist);
  1291. #endif
  1292.          cmlist = cmlist->next;
  1293.  
  1294.           }  /* end of while */
  1295.  
  1296.          if (numentries >0){ /* print modules that declare this block*/
  1297.  
  1298.            if(numblocks++ == 0)
  1299.          (void)fprintf(list_fd,
  1300.                "\n        Common block cross-reference list:\n");
  1301.  
  1302.            (void)fprintf(list_fd, "\nCommon Block %s used in:\n" ,
  1303.             glob_symtab[i].name );
  1304.  
  1305.            sort_gsymbols(gsymlist,numentries);
  1306.  
  1307.            print_modules((unsigned)numentries,gsymlist);
  1308.  
  1309.          }  /* end of if */
  1310.  
  1311.  
  1312.        } /* end of if */
  1313.  
  1314.     } /* end of for */
  1315.  
  1316.     if(numblocks > 0)
  1317.       (void)fprintf(list_fd,"\n");
  1318.  
  1319.     }/* end if print_xref_list */
  1320.  
  1321.                 /* Print out usage info */
  1322.     if(usage_check > 0) {
  1323.     for(i=0;i<glob_symtab_top;i++){ /* loop thru global table */
  1324.        if (storage_class_of(glob_symtab[i].type) == class_COMMON_BLOCK){
  1325.  
  1326.            com_block_usage(glob_symtab[i].name,
  1327.                  glob_symtab[i].info.comlist );
  1328.        }
  1329.     }
  1330.     }
  1331. #ifdef DYNAMIC_TABLES
  1332.     (void) cfree(gsymlist);
  1333. #endif
  1334. }
  1335.  
  1336. PRIVATE void
  1337. print_modules(n,list)    /* formatting of module names */
  1338.     unsigned n;
  1339.     Gsymtab *list[];
  1340. {
  1341.     unsigned col=0,len,j;
  1342.  
  1343.         for (j=0;j<n;j++){
  1344.       if(list[j]->internal_entry) {
  1345.          len=strlen(list[j]->link.module->name);
  1346.          col+= len= (len<=10? 10:len) +9;
  1347.          if (col >78){
  1348.             fprintf(list_fd, "\n");
  1349.             col = len;
  1350.          } /* end of if */
  1351.          fprintf(list_fd,"   %10s entry",list[j]->link.module->name);
  1352.          len=strlen(list[j]->name)+1;
  1353.          col+= len;
  1354.          if (col >78){
  1355.             fprintf(list_fd, "\n");
  1356.             col = len;
  1357.          } /* end of if */
  1358.          fprintf(list_fd," %s",list[j]->name);
  1359.        }
  1360.        else {
  1361.          len=strlen(list[j]->name);
  1362.          col+= len= (len<=10? 10:len) +3;
  1363.          if (col >78){
  1364.             (void)fprintf(list_fd, "\n");
  1365.             col = len;
  1366.          } /* end of if */
  1367.  
  1368.          (void)fprintf(list_fd,"   %10s",list[j]->name);
  1369.        }
  1370.  
  1371.  
  1372.      } /* end of for */
  1373. }
  1374.  
  1375.  
  1376.  
  1377. #ifdef DEBUG_COM_USAGE
  1378.  
  1379. print_comvar_usage(comlist)
  1380.  
  1381.     ComListHeader *comlist;
  1382. {
  1383.         int i, count;
  1384.       ComListElement *c;
  1385.  
  1386.       count = comlist->numargs;
  1387.       c = comlist->com_list_array;
  1388.  
  1389. /* prints out caller module and any_used, any_set flags in CLhead */
  1390.  
  1391.     (void)fprintf(list_fd, "\nModule %s  any_used %u any_set %u\n",
  1392.                 comlist->module->name, comlist->any_used, comlist->any_set);
  1393.  
  1394.         if((comlist->any_used || comlist-> any_set||1) ){
  1395.            for (i=0; i<count; i++){
  1396.  
  1397. /* prints out all four flags for each element in array */
  1398.  
  1399.               (void)fprintf(list_fd,
  1400.         "\n Element %d (%s) used %u set %u used bf set %u asgnd %u\n"
  1401.               , i+1
  1402.               , c[i].name
  1403.               , c[i].used
  1404.               , c[i].set
  1405.               , c[i].used_before_set
  1406.               , c[i].assigned);
  1407.        } /* end of for */
  1408.  
  1409.         } /* end of if */
  1410. }
  1411. #endif
  1412.  
  1413.     /* Check used, set status of common block.  First it looks for
  1414.        whether the block is totally unused, and if so prints a warning
  1415.        and returns.  Otherwise, if block is unused by some modules,
  1416.        it says which ones.  Meanwhile, it finds the declaration with
  1417.        the most elements to use as reference.  If common strictness
  1418.        is 3 (variable by variable) then it OR's the usage flags of
  1419.        each block variable among different declarations, saving the
  1420.        result in reference list.  Passes off to com_element_usage
  1421.        to print usage of individual common variables.
  1422.        */
  1423. PRIVATE int any_com_warning;
  1424. #define IDENTIFY_COMBLOCK if(any_com_warning++ == 0) \
  1425.         (void)fprintf(list_fd,"\nCommon block %s:",name)
  1426.  
  1427. PRIVATE void
  1428. com_block_usage(name,cl1)
  1429.      char *name;
  1430.      ComListHeader *cl1;
  1431. {
  1432.      ComListHeader *ref_cl,    /* reference decl: has most elements */
  1433.          *cur_cl;        /* running cursor thru decls  */
  1434.      int j,n,ref_n;
  1435.      int block_any_used, block_any_set;
  1436.      int block_unused_somewhere;
  1437.      ComListElement *ref_list, *c;
  1438.  
  1439.     any_com_warning = 0; /* used to print block name once only */
  1440.  
  1441.         block_any_used = block_any_set = FALSE;
  1442.     block_unused_somewhere = FALSE;
  1443.     ref_n = cl1->numargs;
  1444.         ref_cl= cl1;
  1445.     cur_cl = cl1;
  1446.     while (cur_cl!=NULL){  /* traverses CLheads */
  1447.       if(! irrelevant(cur_cl) ) {
  1448.  
  1449.             if (cur_cl->any_used){  /* stores TRUE if any are TRUE */
  1450.         block_any_used = TRUE;
  1451.             }
  1452.         if (cur_cl->any_set){   /* stores TRUE if any are TRUE */
  1453.         block_any_set = TRUE;
  1454.         }
  1455.         if( ! (cur_cl->any_used || cur_cl->any_set) &&
  1456.         ! cur_cl->module->defined_in_include ) {
  1457.           block_unused_somewhere = TRUE;
  1458.         }
  1459.    /* if any_set and any_used false after this loop block never used */
  1460.  
  1461.         if (cur_cl->numargs > ref_n){ /* find largest array */
  1462.         ref_cl = cur_cl;
  1463.         ref_n = cur_cl->numargs;
  1464.             } /* end of if */
  1465.       }/* end if not irrelevant */
  1466.       cur_cl = cur_cl->next;
  1467.     }
  1468.  
  1469.         if(irrelevant(ref_cl))    /* Block not declared by modules in calltree */
  1470.       return;
  1471.  
  1472.      if(! (block_any_used || block_any_set) ) {    /* Totally unused */
  1473.        if(check_unused) {
  1474.      IDENTIFY_COMBLOCK;
  1475.      (void)fprintf(list_fd," unused");
  1476.        }
  1477.      }
  1478.      else {
  1479.                 /* If block used somewhere but not everywhere,
  1480.                    report it. */
  1481.         if(block_unused_somewhere && check_unused) {
  1482.       IDENTIFY_COMBLOCK;
  1483.       (void)fprintf(list_fd," unused");
  1484.       cur_cl = cl1;
  1485.       while (cur_cl!=NULL){  /* traverses CLheads */
  1486.         if(! irrelevant(cur_cl) ) {
  1487.           if( ! (cur_cl->any_used || cur_cl->any_set) &&
  1488.           ! cur_cl->module->defined_in_include ) {
  1489.         (void)fprintf(list_fd,"\n  ");
  1490.         com_error_locate(cur_cl);
  1491.           }
  1492.         }
  1493.         cur_cl = cur_cl->next;
  1494.       }
  1495.     }/* end if block_unused_somewhere */
  1496.  
  1497.     if(! check_com_byname) {
  1498.                 /* If not variablewise checking, just
  1499.                    give general warnings. */
  1500.       if (!block_any_set){
  1501.         if(check_set_used) {
  1502.           IDENTIFY_COMBLOCK;
  1503.           (void)fprintf (list_fd," No elements are set, but some are used.");
  1504.         }
  1505.       }
  1506.       if (!block_any_used){
  1507.         if(check_set_used) {
  1508.           IDENTIFY_COMBLOCK;
  1509.           (void)fprintf (list_fd," No elements are used, but some are set.");
  1510.         }
  1511.       }
  1512.         }
  1513.     else {    /* strictness == 3 */
  1514.                 /* Now go thru the details for each element */
  1515.       ref_list = ref_cl->com_list_array;
  1516.       ref_cl->any_used = block_any_used;
  1517.       ref_cl->any_set = block_any_set;
  1518.  
  1519. /* traversing elements in arrays and storing OR'd values in largest array*/
  1520.  
  1521.       cur_cl = cl1;
  1522.       while (cur_cl!=NULL){
  1523.         if(! irrelevant(cur_cl) ) {
  1524.           c = cur_cl->com_list_array;
  1525.           n = cur_cl->numargs;
  1526.           for (j=0; j<n; j++){
  1527.         if (c[j].used) {
  1528.           ref_list[j].used = TRUE;
  1529.         }
  1530.         if (c[j].set){
  1531.           ref_list[j].set = TRUE;
  1532.         }
  1533.         if (c[j].used_before_set){
  1534.           ref_list[j].used_before_set = TRUE;
  1535.         }
  1536.         if (c[j].assigned){
  1537.           ref_list[j].assigned = TRUE;
  1538.         }
  1539.           }
  1540.         }
  1541.         cur_cl = cur_cl->next;
  1542.       }
  1543.       com_element_usage(name, ref_cl, ref_list, ref_n);
  1544.     }
  1545.      }
  1546. }
  1547.  
  1548.  
  1549. PRIVATE void
  1550. com_element_usage(name,  r_cl, r_list, r_num)
  1551.  
  1552.     char *name;
  1553.     ComListHeader *r_cl;
  1554.         ComListElement  *r_list;
  1555.     int r_num;
  1556.  
  1557. {
  1558.     int i,col, warnings;
  1559.  
  1560.      if (r_cl->any_used || r_cl->any_set){  /* if false block not used */
  1561.  
  1562.         if(check_set_used) {
  1563.           warnings = 0;
  1564.           for (i=0; i<r_num; i++){ /* Count used-not-set cases */
  1565.         if (r_list[i].used && !r_list[i].set){
  1566.           warnings++;
  1567.         }
  1568.           }
  1569.           if(warnings > 0) {
  1570.         IDENTIFY_COMBLOCK;
  1571.         (void)fprintf (list_fd,
  1572.              "\n  Elements used but never set:");
  1573.         if(warnings == r_num) {
  1574.           (void)fprintf(list_fd," all");
  1575.         }
  1576.         else {
  1577.           for (i=0,col=30; i<r_num; i++){
  1578.             if (r_list[i].used && !r_list[i].set){
  1579.               if( (col += 1+(int)strlen(r_list[i].name)) > 78 ) {
  1580.             (void)fprintf(list_fd,"\n");
  1581.             col = 6;
  1582.               }
  1583.               (void)fprintf(list_fd, " %s",
  1584.                     r_list[i].name);
  1585.             }
  1586.           }
  1587.             }
  1588.           }
  1589.         }
  1590.  
  1591.         if(check_unused) {
  1592.           warnings = 0;
  1593.           for (i=0; i<r_num; i++){ /* Count set-not-used cases */
  1594.         if (r_list[i].set && !r_list[i].used){
  1595.           warnings++;
  1596.         }
  1597.           }
  1598.           if(warnings > 0) {
  1599.         IDENTIFY_COMBLOCK;
  1600.         (void)fprintf (list_fd,
  1601.              "\n  Elements set but never used:");
  1602.         if(warnings == r_num) {
  1603.           (void)fprintf(list_fd," all");
  1604.         }
  1605.         else {
  1606.           for (i=0,col=30; i<r_num; i++){
  1607.             if (r_list[i].set && !r_list[i].used){
  1608.               if( (col += 1+(int)strlen(r_list[i].name)) > 78 ) {
  1609.             (void)fprintf(list_fd,"\n");
  1610.             col = 6;
  1611.               }
  1612.               (void)fprintf (list_fd, " %s",
  1613.                      r_list[i].name);
  1614.             }
  1615.               }
  1616.             }
  1617.           }
  1618.         }
  1619.  
  1620.         warnings = 0;
  1621.         for (i=0,col=30; i<r_num; i++){
  1622.           if(!r_list[i].set && !r_list[i].used &&
  1623.          !r_list[i].used_before_set){
  1624.             if(check_unused) {
  1625.               IDENTIFY_COMBLOCK;
  1626.               if (warnings++ == 0 ){
  1627.             (void)fprintf (list_fd,
  1628.                  "\n  Elements never used, never set:");
  1629.               }
  1630.               if( (col += 1+(int)strlen(r_list[i].name)) > 78 ) {
  1631.             (void)fprintf(list_fd,"\n");
  1632.             col = 6;
  1633.               }
  1634.               (void)fprintf (list_fd, " %s",
  1635.                      r_list[i].name);
  1636.             }
  1637.         }
  1638.         }
  1639.     }
  1640.     else{    /* This cannot be reached if called only when block is used */
  1641.       if(check_unused) {
  1642.         IDENTIFY_COMBLOCK;
  1643.         (void)fprintf (list_fd," not used.");
  1644.       }
  1645.     }            /* any_used and any_set are both false */
  1646.  
  1647.  
  1648.  
  1649. }
  1650. /** End of common block and variable usage checks **/
  1651.  
  1652.                 /* Things used for common undef check */
  1653. PRIVATE int com_tree_error;
  1654. PRIVATE int block_is_volatile();
  1655. PRIVATE ComListHeader *com_tree_check(), *com_declared_by();
  1656. PRIVATE int numvisited;
  1657.  
  1658. void
  1659. visit_children()
  1660. {
  1661.   int i,
  1662.     num_mains,        /* number of main programs */
  1663.     num_roots;        /* number of uncalled nonlibrary modules */
  1664.   Gsymtab* main_module;
  1665.  
  1666.   num_roots =  0;
  1667.   for(i=0; i<glob_symtab_top; i++) {
  1668.     if(storage_class_of(glob_symtab[i].type) == class_SUBPROGRAM
  1669.        && ! glob_symtab[i].internal_entry) {
  1670.       sort_child_list(glob_symtab[i].link.child_list);
  1671.             /* Count uncalled non-library modules for use later */
  1672.       if(!glob_symtab[i].used_flag && !glob_symtab[i].library_module)
  1673.       ++num_roots;    /* Count tree roots for use if no mains */
  1674.     }
  1675.   }
  1676.  
  1677.   if(print_ref_list)
  1678.     (void)fprintf(list_fd,"\nList of subprogram references:");
  1679. #ifdef VCG_SUPPORT
  1680.   else if(print_vcg_list)
  1681.     (void)fprintf(list_fd,"\nVCG description of call graph:");
  1682. #endif
  1683.   else if(print_call_tree)
  1684.     (void)fprintf(list_fd,"\nTree of subprogram calls:");
  1685.  
  1686.                 /* Visit children of all main progs */
  1687.   for(i=0,num_mains=0; i<glob_symtab_top; i++) {
  1688.     if(glob_symtab[i].type == type_byte(class_SUBPROGRAM,type_PROGRAM)) {
  1689.       main_module = &glob_symtab[i];
  1690.       if(print_ref_list)
  1691.     visit_child_reflist(main_module);
  1692. #ifdef VCG_SUPPORT
  1693.       else if(print_vcg_list)
  1694.     visit_child_vcg(main_module,1);
  1695. #endif
  1696.       else
  1697.     visit_child(main_module,0);
  1698.       ++num_mains;
  1699.     }
  1700.   }
  1701.                 /* If no main program found, give
  1702.                    warning unless -noextern was set */
  1703.   if(num_mains == 0) {
  1704.     if(print_call_tree || print_ref_list
  1705. #ifdef VCG_SUPPORT
  1706.        || print_vcg_list
  1707. #endif
  1708.        ) {
  1709.       (void)fprintf(list_fd,"\n  (no main program found)");
  1710.     }
  1711.     else if(ext_def_check) {
  1712.       (void)fprintf(list_fd,
  1713.     "\nNo main program found");
  1714.     }
  1715.         /* If no main, visit trees rooted at uncalled
  1716.            nonlibrary routines, as the next best thing.
  1717.            If there are no uncalled nonlib modules, use
  1718.            uncalled library routines.  If there are no uncalled
  1719.            routines, then there is a cycle!
  1720.          */
  1721.     for(i=0; i<glob_symtab_top; i++) {
  1722.       if(storage_class_of(glob_symtab[i].type) == class_SUBPROGRAM
  1723.     && !glob_symtab[i].used_flag &&
  1724.      (num_roots == 0 || !glob_symtab[i].library_module) ) {
  1725.     if(print_ref_list)
  1726.       visit_child_reflist(&glob_symtab[i]);
  1727. #ifdef VCG_SUPPORT
  1728.     else if(print_vcg_list)
  1729.       visit_child_vcg(main_module,1);
  1730. #endif
  1731.     else
  1732.       visit_child(&glob_symtab[i],1); /* indent all trees one level */
  1733.       }
  1734.     }
  1735.   }
  1736.   if(print_call_tree || print_ref_list)
  1737.     (void)fprintf(list_fd,"\n");
  1738. #ifdef VCG_SUPPORT
  1739.   if(print_vcg_list)
  1740.     (void)fprintf(list_fd,"\nEnd of VCG description\n");
  1741. #endif
  1742.  
  1743.  
  1744.             /* Print list of callers of all visited
  1745.                or non-library modules, if -crossref
  1746.                flag given. */
  1747.   if(print_xref_list) {
  1748.     print_crossrefs();
  1749.   }
  1750.  
  1751.             /* Print linkage-order list of modules. */
  1752.   if( print_topo_sort ) {
  1753.     (void) toposort(glob_symtab,(int)glob_symtab_top);
  1754.   }
  1755.  
  1756.             /* Check that common blocks retain definition
  1757.                status between uses. */
  1758.   if(check_com_tree || check_volatile_com){
  1759.     if(num_mains != 1) {
  1760.       if(check_com_tree)
  1761.     (void)fprintf(list_fd,
  1762.         "\nCommon definition check requires single main program");
  1763.       if(check_volatile_com)
  1764.     (void)fprintf(list_fd,
  1765.         "\nCommon volatility check requires single main program");
  1766.     }
  1767.     else {
  1768.       numvisited = 0;        /* need headcount in case of cycle */
  1769.       for(i=0; i<glob_symtab_top; i++) {
  1770.     if(glob_symtab[i].visited_somewhere)
  1771.       numvisited++;
  1772.       }
  1773.       for(i=0; i<glob_symtab_top; i++) {
  1774.     if(storage_class_of(glob_symtab[i].type) == class_COMMON_BLOCK) {
  1775.       if( block_is_volatile(glob_symtab[i].info.comlist,main_module) ) {
  1776.         if(check_volatile_com) {
  1777.           (void)fprintf(list_fd,
  1778.            "\nCommon block %s is volatile",
  1779.            glob_symtab[i].name);
  1780.         }
  1781.         if(check_com_tree) {
  1782.           com_tree_error=0;
  1783.           (void)com_tree_check(&glob_symtab[i],main_module,0);
  1784.         }
  1785.       }
  1786.     }
  1787.       }
  1788.     }
  1789.   }
  1790. }
  1791.  
  1792.     /* Returns TRUE unless block is SAVED by any module, or declared by
  1793.        the actual main program or in a BLOCK DATA subprogram. */
  1794. PRIVATE int
  1795. block_is_volatile(clist,main_module)
  1796.      ComListHeader *clist;
  1797.      Gsymtab *main_module;
  1798. {
  1799.   int t;
  1800.   while(clist != NULL) {
  1801.     if( clist->saved ||
  1802.        (t=datatype_of(clist->module->type)) == type_BLOCK_DATA
  1803.        || (t == type_PROGRAM && clist->module == main_module)) {
  1804.       return FALSE;
  1805.     }
  1806.     clist = clist->next;
  1807.   }
  1808.   return TRUE;
  1809. }
  1810.  
  1811.  /* If block declared by module, returns pointer to the comlist
  1812.     header which describes it.  Otherwise returns NULL. */
  1813. PRIVATE ComListHeader *
  1814. com_declared_by(comblock,module)
  1815.      Gsymtab *comblock,*module;
  1816. {
  1817.   ComListHeader *clist=comblock->info.comlist;
  1818.   while(clist != NULL) {
  1819.     if(clist->module == module) {
  1820.       if(clist->saved) {
  1821.     com_tree_error = TRUE;    /* not so, but causes bailout */
  1822.       }
  1823.       return clist;
  1824.     }
  1825.     clist = clist->next;
  1826.   }
  1827.   return NULL;
  1828. }
  1829.  
  1830.  
  1831.         /* Checks whether common block can become undefined
  1832.            between activations of some module that declares it.
  1833.            Should only be done for blocks that are volatile, i.e.
  1834.            that are not SAVED or declared in main or block_data.
  1835.            Rules used are:
  1836.              (1) Block is declared in two subtrees whose roots
  1837.                  are called by a given module, and not in
  1838.              the given module itself or above.
  1839.              (2) Block is declared and elements accessed in a module
  1840.                  called by a given module, and not declared in the
  1841.              module itself or above.  (Module that declares it but
  1842.              does not access elements, can be holding the
  1843.              block active for its children.)
  1844.            Since Rule 2 is likely to be wrong often due to Ftnchek's
  1845.            lack of knowledge about whether a routine is invoked
  1846.            more than once, it is suppressed for now.
  1847.         */
  1848. PRIVATE ComListHeader *
  1849. com_tree_check(comblock,module,level)
  1850.      Gsymtab *comblock,*module;
  1851.      int level;
  1852. {
  1853.   ComListHeader *clist;
  1854.  
  1855.     /* The following only protects against recursion.  It is not
  1856.        a full-fledged cycle detector just a stopper. */
  1857.   if(level > numvisited) {
  1858.     (void)fprintf(list_fd,
  1859.         "\nWarning: Call tree has a cycle containing module %s\n",
  1860.         module->name);
  1861.     com_tree_error = TRUE;
  1862.     return NULL;
  1863.   }
  1864.  
  1865.         /* If this module declares the block, return its clist */
  1866.   if( (clist=com_declared_by(comblock,module)) != NULL) {
  1867. #ifdef DEBUG_SAVE
  1868.       (void)fprintf(list_fd,"\n%s declared by %s",comblock->name,module->name);
  1869. #endif
  1870.     return clist;
  1871.   }
  1872.   else {    /* Otherwise see if it is declared in subtree */
  1873.     int any_child_declares_it;
  1874.     ComListHeader *declaring_clist, *this_clist;
  1875.     ChildList *child_list;
  1876.  
  1877.     any_child_declares_it=FALSE;
  1878.     declaring_clist=NULL;
  1879.                 /* Scan list of children */
  1880.     child_list = (module->internal_entry?module->link.module:module)
  1881.            ->link.child_list;
  1882.     while(child_list != NULL) {
  1883.       this_clist = com_tree_check(comblock,child_list->child,level+1);
  1884.                 /* Error was detected below: bail out */
  1885.       if(com_tree_error) {
  1886.     return NULL;
  1887.       }
  1888.       else if(this_clist != NULL) {
  1889.                 /* Subtree contains the block */
  1890.     if(any_child_declares_it               /* Rule 1 */
  1891. #ifdef COMTREE_RULE_2
  1892.        || (this_clist->any_used || this_clist->any_set) /* Rule 2 */
  1893. #endif
  1894.     ){
  1895.       (void)fprintf(list_fd,
  1896.     "\nWarning: Common block %s may become undefined between activations",
  1897.         comblock->name);
  1898.       (void)fprintf(list_fd,"\n    ");
  1899.       com_error_locate(this_clist);
  1900.       if(declaring_clist != NULL && declaring_clist != this_clist) {
  1901.         (void)fprintf(list_fd,"\n    ");
  1902.         com_error_locate(declaring_clist);
  1903.       }
  1904.       (void)fprintf(list_fd,"\n        ");
  1905.       (void)fprintf(list_fd,
  1906.           "during activation of module %s",
  1907.           module->name);
  1908.       com_tree_error = TRUE;
  1909.       return NULL;
  1910.     }
  1911.     else {
  1912.       any_child_declares_it = TRUE;
  1913.       declaring_clist = this_clist;
  1914.     }
  1915.       }
  1916.  
  1917.       child_list = child_list->next;
  1918.     }
  1919.         /* If any subtree declares it, say so */
  1920.     return declaring_clist;
  1921.   }
  1922. }
  1923.  
  1924.  
  1925.  
  1926.                 /* Depth-first search of call tree */
  1927. PRIVATE void
  1928. visit_child(gsymt,level)
  1929.      Gsymtab *gsymt;
  1930.      int level;
  1931. {
  1932.   static char fmt[]="%000s";    /* Variable format for indenting names */
  1933.   ChildList *child_list;
  1934.  
  1935.  
  1936.   if(print_call_tree) {
  1937.     (void)fprintf(list_fd,"\n");
  1938.     if(level > 0) {
  1939.       (void)sprintf(fmt,"%%%ds",level*4); /* indent 4 spaces per nesting level */
  1940.       (void)fprintf(list_fd,fmt,"");
  1941.     }
  1942.     if(gsymt->internal_entry)
  1943.       (void)fprintf(list_fd,"%s entry ",gsymt->link.module->name);
  1944.     (void)fprintf(list_fd,"%s",gsymt->name);
  1945.   }
  1946.  
  1947.  
  1948.  
  1949.                 /* Visit its unvisited children.  Note
  1950.                    that children of internal entry are
  1951.                    taken as those of its superior module.
  1952.                  */
  1953.   child_list = (gsymt->internal_entry?gsymt->link.module:gsymt)
  1954.            ->link.child_list;
  1955.  
  1956.                 /* If already visited, do not visit its
  1957.                    children, but give note to reader if it
  1958.                    has some. */
  1959.   if(gsymt->visited) {
  1960.     if(print_call_tree && child_list != NULL)
  1961.       (void)fprintf(list_fd," (see above)");
  1962.   }
  1963.   else {
  1964.                 /* Mark node as visited */
  1965.     gsymt->visited = TRUE;
  1966.                 /* Record that containing module
  1967.                    is visited via this entry point*/
  1968.     if(gsymt->internal_entry)
  1969.       gsymt->link.module->visited_somewhere = TRUE;
  1970.     else
  1971.       gsymt->visited_somewhere = TRUE;
  1972.  
  1973.     ++level;            /* move to next level */
  1974.     while(child_list != NULL) {
  1975.       visit_child(child_list->child,level);
  1976.       child_list = child_list->next;
  1977.     }
  1978.   }
  1979. }
  1980.  
  1981. /*** visit_child_reflist
  1982.  
  1983. Same as visit_child, except it does a breadth-first search of the call
  1984. tree, and prints the results in the form of a who-calls-who list.
  1985.  
  1986. Contributed by: Gerome Emmanuel : Esial Troisieme annee
  1987.         Projet commun Esial / Ecole des mines
  1988.         INERIS
  1989.         E-mail: gerome@mines.u-nancy.fr
  1990. Date received: 20-APR-1993
  1991. Modified slightly to make it compatible as alternative to call-tree and
  1992. to make output format consistent.
  1993. ***/
  1994.  
  1995. PRIVATE void
  1996. visit_child_reflist(gsymt)
  1997.      Gsymtab *gsymt;
  1998. {
  1999.   ChildList *child_list;
  2000.  
  2001.   child_list = (gsymt->internal_entry?gsymt->link.module:gsymt)
  2002.                    ->link.child_list;
  2003.  
  2004.                                 /* If already visited, do not visit its
  2005.                                    children, but give note to reader if it
  2006.                                    has some. */
  2007.   if(!gsymt->visited) {
  2008.                                 /* Mark node as visited */
  2009.     gsymt->visited = TRUE;
  2010.                                 /* Record that containing module
  2011.                                    is visited via this entry point*/
  2012.     if(gsymt->internal_entry)
  2013.       gsymt->link.module->visited_somewhere = TRUE;
  2014.     else
  2015.       gsymt->visited_somewhere = TRUE;
  2016.  
  2017.     if(print_ref_list)        /* Print callees neatly if desired */
  2018.     {
  2019. #ifdef DYNAMIC_TABLES        /* tables will be mallocked at runtime */
  2020.       Gsymtab  **gsymlist;
  2021. #else
  2022.       Gsymtab  *gsymlist[GLOBSYMTABSZ];
  2023. #endif
  2024.       ChildList *child_list2;
  2025.       unsigned numcalls;
  2026.  
  2027. #ifdef DYNAMIC_TABLES
  2028.       if( (gsymlist=(Gsymtab **)calloc(glob_symtab_top,sizeof(Gsymtab *)))
  2029.      == (Gsymtab **)NULL) {
  2030.       oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
  2031.                "Cannot malloc space for reference list");
  2032.       }
  2033. #endif
  2034.  
  2035.       (void)fprintf(list_fd,"\n%s calls:",gsymt->name);
  2036.  
  2037.       numcalls = 0;
  2038.       child_list2 = child_list;
  2039.       while(child_list2 != NULL)
  2040.       {
  2041.         gsymlist[numcalls++] = child_list2->child;
  2042.         child_list2 = child_list2->next;
  2043.       }
  2044.  
  2045.       if(numcalls == (unsigned)0)
  2046.         (void)fprintf(list_fd," none");
  2047.       else {
  2048.         (void)fprintf(list_fd,"\n");
  2049.         print_modules(numcalls,gsymlist);
  2050.       }
  2051. #ifdef DYNAMIC_TABLES
  2052.       (void) cfree(gsymlist);
  2053. #endif
  2054.     }
  2055.  
  2056.     while(child_list != NULL) {
  2057.       visit_child_reflist(child_list->child);
  2058.       child_list = child_list->next;
  2059.     }
  2060.   }
  2061. }
  2062.  
  2063. /* visit_child_vcg:
  2064.   
  2065.   Same as visit_child_reflist except it provides output suitable for
  2066.   visualisation of the call graph, using the vcg graph visualisation
  2067.   program.  VCG is freely available from ftp.cs.uni-sb.de and
  2068.   elsewhere. It was written by G. Sander of the University of
  2069.   Saarland, Germany.
  2070.  
  2071.   Contributed by:  P.A.Rubini@cranfield.ac.uk
  2072.   Date: 3-APR-1995
  2073. */
  2074.  
  2075. #ifdef VCG_SUPPORT
  2076. PRIVATE void
  2077. visit_child_vcg(gsymt,level)
  2078.      Gsymtab *gsymt;
  2079.      int level;
  2080. {
  2081.   ArgListHeader *arglist;
  2082.   ChildList *child_list;
  2083.  
  2084.   child_list = (gsymt->internal_entry?gsymt->link.module:gsymt)
  2085.                    ->link.child_list;
  2086.  
  2087.                                 /* If already visited, do not visit its
  2088.                                    children, but give note to reader if it
  2089.                                    has some. */
  2090.   if(!gsymt->visited) {
  2091.                                 /* Mark node as visited */
  2092.     gsymt->visited = TRUE;
  2093.                                 /* Record that containing module
  2094.                                    is visited via this entry point*/
  2095.     if(gsymt->internal_entry)
  2096.       gsymt->link.module->visited_somewhere = TRUE;
  2097.     else
  2098.       gsymt->visited_somewhere = TRUE;
  2099.  
  2100.     if(print_vcg_list)        /* Print callees neatly if desired */
  2101.     {
  2102. #ifdef DYNAMIC_TABLES        /* tables will be mallocked at runtime */
  2103.       Gsymtab  **gsymlist;
  2104. #else
  2105.       Gsymtab  *gsymlist[GLOBSYMTABSZ];
  2106. #endif
  2107.       ChildList *child_list2;
  2108.       int j;
  2109.       unsigned numcalls;
  2110.  
  2111. #ifdef DYNAMIC_TABLES
  2112.       if( (gsymlist=(Gsymtab **)calloc(glob_symtab_top,sizeof(Gsymtab *)))
  2113.      == (Gsymtab **)NULL) {
  2114.       oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
  2115.                "Cannot malloc space for reference list");
  2116.       }
  2117. #endif
  2118.  
  2119.     numcalls = 0;
  2120.     child_list2 = child_list;
  2121.     while(child_list2 != NULL)
  2122.       {
  2123.         gsymlist[numcalls++] = child_list2->child;
  2124.         child_list2 = child_list2->next;
  2125.       }
  2126.  
  2127.     arglist = gsymt->info.arglist;
  2128.     while(arglist != NULL) {
  2129.       if ( arglist->is_defn ) {
  2130.  
  2131.          (void)fprintf(list_fd,"\n\ngraph: {\ntitle:\"[%s]\"\n",gsymt->name);
  2132.          (void)fprintf(list_fd,"node: { title: \"%s\" label: \"%s \\n (%s)\" info1:\"%d\" }\n",
  2133.                     gsymt->name,gsymt->name,
  2134.                     arglist->filename,
  2135.                     level );
  2136.  
  2137.  
  2138.       if(numcalls != (unsigned)0) {
  2139.         for (j=0;j<numcalls;j++){
  2140.            arglist = gsymlist[j]->info.arglist;
  2141.            while(arglist != NULL) {
  2142.              if ( arglist->is_defn ) {
  2143.             (void)fprintf(list_fd,"edge: { sourcename: \"%s\" targetname: \"%s\" class:%d} \n",
  2144.                 gsymt->name,gsymlist[j]->name,
  2145.                             level );
  2146.             break ;
  2147.              }
  2148.                      arglist = arglist->next;
  2149.            }
  2150.         }
  2151.       }
  2152.           break;
  2153.       }
  2154.       arglist = arglist->next;
  2155.     }
  2156. #ifdef DYNAMIC_TABLES
  2157.       (void) cfree(gsymlist);
  2158. #endif
  2159.  
  2160.     ++level;            /* move to next level */
  2161.  
  2162. /*  while(child_list != NULL) {
  2163.       visit_child_vcg(child_list->child,level);
  2164.       child_list = child_list->next;
  2165.     } */
  2166.  
  2167.     for (j=0;j<numcalls;j++){
  2168.        arglist = gsymlist[j]->info.arglist;
  2169.        while(arglist != NULL) {
  2170.           if ( arglist->is_defn ) {
  2171.              visit_child_vcg(gsymlist[j],level);
  2172.              break ;
  2173.           }
  2174.           arglist = arglist->next;
  2175.        }
  2176.     }
  2177.     (void)fprintf(list_fd,"}\n");
  2178.     }
  2179.   }
  2180. }
  2181.  
  2182. #endif /* VCG_SUPPORT */
  2183.  
  2184.  
  2185. PRIVATE void
  2186. print_crossrefs()
  2187. {
  2188. #ifdef DYNAMIC_TABLES        /* tables will be mallocked at runtime */
  2189.       Gsymtab  **gsymlist, **modulelist;
  2190. #else
  2191.   Gsymtab  *gsymlist[GLOBSYMTABSZ], *modulelist[GLOBSYMTABSZ];
  2192. #endif
  2193.   ArgListHeader *args;
  2194.   int  i,numentries;
  2195.   unsigned numcalls;
  2196.  
  2197. #ifdef DYNAMIC_TABLES
  2198.       if( (gsymlist=(Gsymtab **)calloc(glob_symtab_top,sizeof(Gsymtab *)))
  2199.      == (Gsymtab **)NULL ||
  2200.      (modulelist=(Gsymtab **)calloc(glob_symtab_top,sizeof(Gsymtab *)))
  2201.      == (Gsymtab **)NULL) {
  2202.       oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
  2203.                "Cannot malloc space for crossref list");
  2204.       }
  2205. #endif
  2206.  
  2207.                 /* Gather up all relevant subprograms */
  2208.   for(i=0,numentries=0; i<glob_symtab_top; i++) {
  2209.     if(storage_class_of(glob_symtab[i].type) == class_SUBPROGRAM
  2210.        && (glob_symtab[i].visited || !glob_symtab[i].library_module)) {
  2211.       gsymlist[numentries++] = &glob_symtab[i];
  2212.     }
  2213.   }
  2214.  
  2215.   if(numentries > 0) {
  2216.     (void)fprintf(list_fd,"\n\n        Cross-reference list:\n");
  2217.  
  2218.                 /* Sort the subprograms */
  2219.     sort_gsymbols(gsymlist,numentries);
  2220.  
  2221.                 /* Print their callers */
  2222.     for(i=0; i<numentries; i++) {
  2223.       (void)fprintf(list_fd,"\n");
  2224.       if(gsymlist[i]->internal_entry)
  2225.     (void)fprintf(list_fd,"%s entry ",gsymlist[i]->link.module->name);
  2226.       (void)fprintf(list_fd,"%s",gsymlist[i]->name);
  2227.  
  2228.       numcalls=0;
  2229.       args = gsymlist[i]->info.arglist;
  2230.       while(args != NULL) {        /* Gather up callers */
  2231.     if(!args->is_defn) {
  2232.                 /* (eliminate duplicates) */
  2233.       if(numcalls==(unsigned) 0 || args->module != modulelist[numcalls-1])
  2234.         modulelist[numcalls++] = args->module;
  2235.     }
  2236.     args = args->next;
  2237.       }
  2238.  
  2239.       if(numcalls == (unsigned) 0)
  2240.     (void)fprintf(list_fd," not called");
  2241.       else {
  2242.     (void)fprintf(list_fd," called by:\n");
  2243.     sort_gsymbols(modulelist,(int)numcalls); /* Sort the callers */
  2244.     print_modules(numcalls,modulelist);
  2245.       }
  2246.     }
  2247.     (void)fprintf(list_fd,"\n");
  2248.   }
  2249. #ifdef DYNAMIC_TABLES
  2250.       (void) cfree(gsymlist);
  2251.       (void) cfree(modulelist);
  2252. #endif
  2253. }
  2254.  
  2255.  
  2256.     /* Topological sort of the call tree.  Based closely on algorithm
  2257.        on page 314 of Horowitz and Sahni, Fundamentals of Data
  2258.        Structures.  Returns TRUE if successful, FALSE if failed
  2259.        due to a cycle being detected.
  2260.      */
  2261. PRIVATE void print_cycle_nodes(); /* Routine for error diagnostics */
  2262.  
  2263. PRIVATE int
  2264. toposort(gsymt,nsym)
  2265.      Gsymtab gsymt[];
  2266.      int nsym;
  2267. {
  2268.   int i,num_nodes, node_count;
  2269.   ChildList *child_list;
  2270.   Gsymtab *child_module;    /* Called module's top entry point */
  2271. #ifdef DYNAMIC_TABLES        /* tables will be mallocked at runtime */
  2272.   int *parent_count;
  2273.   Gsymtab **node_list;
  2274. #else
  2275.   int parent_count[GLOBSYMTABSZ];
  2276.   Gsymtab *node_list[GLOBSYMTABSZ];
  2277. #endif
  2278.  
  2279. #ifdef DYNAMIC_TABLES
  2280.       if( (parent_count=(int *)calloc(glob_symtab_top,sizeof(int)))
  2281.      == (int *)NULL ||
  2282.      (node_list=(Gsymtab **)calloc(glob_symtab_top,sizeof(Gsymtab *)))
  2283.      == (Gsymtab **)NULL) {
  2284.       oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
  2285.                "Cannot malloc space for module sort");
  2286.       }
  2287. #endif
  2288.             /* Initialize array of links/counts */
  2289.   for(i=0; i<nsym; i++)
  2290.     parent_count[i] = 0;    /* In-order of module as node */
  2291.  
  2292.             /* Traverse child lists, incrementing their
  2293.                parent counts.
  2294.              */
  2295.   for(i=0,num_nodes=0; i<nsym; i++) {
  2296.     if(gsymt[i].visited_somewhere) { /* skip entry pts and com blocks */
  2297.       ++num_nodes;
  2298.       child_list = gsymt[i].link.child_list;
  2299.       while(child_list != NULL) {
  2300.                 /* If child is an internal entry, substitute
  2301.                    top entry point of its subprogram unit. */
  2302.     if( (child_module=child_list->child)->internal_entry )
  2303.       child_module = child_module->link.module;
  2304.     ++parent_count[child_module - gsymt]; /* index into table */
  2305.     child_list = child_list->next;
  2306.       }
  2307.     }
  2308.   }
  2309.  
  2310.   {                /* Start of the sort */
  2311.     int top=0;
  2312.     int j,k;
  2313.  
  2314.     for(i=0; i<nsym; i++) {
  2315.       if(gsymt[i].visited_somewhere && parent_count[i] == 0) {
  2316.     parent_count[i] = top;    /* Link now-parentless module into stack */
  2317.     top = i+1;
  2318.       }
  2319.     }
  2320.     for(i=0,node_count=0; i<num_nodes; i++) {
  2321.       if(top == 0) {
  2322.     if(print_topo_sort) {
  2323.       (void)fprintf(list_fd,"\nCall tree has a cycle");
  2324.       print_cycle_nodes(gsymt,nsym,node_list,node_count,parent_count);
  2325.     }
  2326.     break;
  2327.       }
  2328.       j = top-1;
  2329.       top = parent_count[j];    /* Recover the link */
  2330.  
  2331.                 /* Print the next module */
  2332.       if(print_topo_sort) {
  2333.     node_list[node_count++] = &gsymt[j];
  2334.     parent_count[j] = -1;
  2335.       }
  2336.             /* Decrease parent count of its children */
  2337.       child_list = gsymt[j].link.child_list;
  2338.       while(child_list != NULL) {
  2339.     if( (child_module=child_list->child)->internal_entry )
  2340.       child_module = child_module->link.module;
  2341.     k = child_module - gsymt;
  2342.     if(--parent_count[k] == 0) { /* Now parentless? Stack it*/
  2343.       parent_count[k] = top;
  2344.       top = k+1;
  2345.     }
  2346.     child_list = child_list->next;
  2347.       }
  2348.     }
  2349.   }/*end sort*/
  2350.  
  2351.   if(print_topo_sort && node_count > 0) {
  2352.     (void)fprintf(list_fd,"\nList of called modules in prerequisite order:\n");
  2353.     print_modules(node_count,node_list);
  2354.     (void)fprintf(list_fd,"\n");
  2355.   }
  2356.  
  2357. #ifdef DYNAMIC_TABLES
  2358.   (void) cfree(parent_count);
  2359.   (void) cfree(node_list);
  2360. #endif
  2361.  
  2362.   return (node_count==num_nodes);    /* Success = TRUE */
  2363. }
  2364.  
  2365.         /* Traces back to find nodes not listed in topological
  2366.            sort.  They are the cycle nodes and their descendants.
  2367.          */
  2368. PRIVATE void
  2369. print_cycle_nodes(gsymt,nsym,node_list,node_count,parent_count)
  2370.      Gsymtab gsymt[];
  2371.      int nsym;
  2372.      Gsymtab *node_list[];
  2373.      int node_count;
  2374.      int parent_count[];
  2375. {
  2376.   int i;
  2377.   int k=node_count;
  2378.   for(i=0; i<nsym; i++) {
  2379.     if(gsymt[i].visited_somewhere) {
  2380.       if(parent_count[i] != -1)    /* Not tagged */
  2381.     node_list[k++] = &gsymt[i];
  2382.     }
  2383.   }
  2384.   if(k > node_count)
  2385.     (void)fprintf(list_fd," containing some of the following modules:\n");
  2386.   print_modules(k-node_count,node_list+node_count);
  2387. }
  2388.  
  2389.  
  2390.                 /* Insertion sort of child list.
  2391.                    Also removes duplicates which
  2392.                    can be introduced via multiple
  2393.                    defns or via project files. */
  2394. PRIVATE void
  2395. sort_child_list(child_list)
  2396.      ChildList *child_list;
  2397. {
  2398.   ChildList *front,*prev,*next;
  2399.   Gsymtab *temp;
  2400.   prev = NULL;
  2401.  
  2402.   while(child_list != NULL) {
  2403.             /* Scan thru list for lexicographically lowest name */
  2404.     front=child_list;
  2405.     for(next=child_list->next; next != NULL; next = next->next) {
  2406.       if(strcmp(front->child->name,next->child->name) > 0) {
  2407.     front = next;
  2408.       }
  2409.     }
  2410.             /* Swap child pointers so front is first */
  2411.     if(front != child_list) {
  2412.       temp = front->child;
  2413.       front->child = child_list->child;
  2414.       child_list->child = temp;
  2415.     }
  2416.             /* If duplicate, remove from list */
  2417.     if(prev != NULL && prev->child == child_list->child)
  2418.       prev->next = child_list->next;
  2419.     else
  2420.       prev = child_list;
  2421.     child_list = child_list->next;
  2422.   }
  2423. }
  2424.  
  2425.  
  2426.  
  2427. PRIVATE void
  2428. sort_gsymbols ( glist,n )   /* bubble sort, same as sort_symbols */
  2429.     Gsymtab *glist[];
  2430.     int n;
  2431. {
  2432.     int i,j,swaps;
  2433.  
  2434.     for (i=0; i<n; i++ ){
  2435.         swaps = 0;
  2436.         for  (j=n-1; j>=i+1; j--){
  2437.         if ((strcmp (glist[j-1]->name, glist[j]->name)) >0) {
  2438.             swap_gsymptrs(&glist[j-1], &glist[j] );
  2439.             swaps++;
  2440.         }
  2441.         }
  2442.         if (swaps == 0) break;
  2443.     }
  2444.  
  2445.  
  2446. }
  2447.  
  2448. PRIVATE void
  2449. swap_gsymptrs (x_ptr, y_ptr)    /* swap pointers */
  2450.     Gsymtab **x_ptr,**y_ptr;
  2451. {
  2452.     Gsymtab *temp = *x_ptr;
  2453.     *x_ptr = *y_ptr;
  2454.     *y_ptr = temp;
  2455. }
  2456.