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