"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/calltree/calltree.c" (20 Aug 2021, 22025 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "calltree.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 2021-08-14_vs_2021-09-18 or 2021-07-29_vs_2021-09-18.

    1 /* @(#)calltree.c   1.50 21/08/20 Copyright 1985, 1999-2021 J. Schilling */
    2 #include <schily/mconfig.h>
    3 #ifndef lint
    4 static  UConst char sccsid[] =
    5     "@(#)calltree.c 1.50 21/08/20 Copyright 1985, 1999-2021 J. Schilling";
    6 #endif
    7 /*
    8  *  A program to produce a static calltree for C-functions
    9  *
   10  *  Copyright (c) 1985, 1999-2021 J. Schilling
   11  */
   12 /*
   13  * The contents of this file are subject to the terms of the
   14  * Common Development and Distribution License, Version 1.0 only
   15  * (the "License").  You may not use this file except in compliance
   16  * with the License.
   17  *
   18  * See the file CDDL.Schily.txt in this distribution for details.
   19  * A copy of the CDDL is also available via the Internet at
   20  * http://www.opensource.org/licenses/cddl1.txt
   21  *
   22  * When distributing Covered Code, include this CDDL HEADER in each
   23  * file and include the License file CDDL.Schily.txt from this distribution.
   24  */
   25 
   26 #include <schily/stdio.h>       /* Includes popen()/pclose()    */
   27 #include <schily/standard.h>
   28 #include <schily/stdlib.h>
   29 #include <schily/unistd.h>
   30 #include <schily/string.h>
   31 #define GT_COMERR       /* #define comerr gtcomerr */
   32 #define GT_ERROR        /* #define error gterror   */
   33 #include <schily/schily.h>
   34 #define VMS_VFORK_OK
   35 #include <schily/vfork.h>
   36 #include <schily/nlsdefs.h>
   37 #include "strsubs.h"
   38 #include "sym.h"
   39 #include "clex.h"
   40 #include "version.h"
   41 
   42 #ifdef  HAVE_FORK
   43 #   include <schily/wait.h>
   44 #   define  Pwait(f)    { wait(0); fclose(f); }
   45 #else
   46 #   define  Pwait(f)    pclose(f)
   47 #endif
   48 
   49 LOCAL   char    ct_version[] = VERSION;
   50 
   51 BOOL    bflag   = FALSE;        /* -b: print vertical bar for indent */
   52 BOOL    rflag   = FALSE;        /* -r: inverted output print callers */
   53 BOOL    fflag   = FALSE;        /* -f: flat output (summary per func)*/
   54 BOOL    gflag   = FALSE;        /* -g: print filename of definition  */
   55 BOOL    mflag   = FALSE;        /* -m: list 'main' only (like l=main)*/
   56 BOOL    npflag  = FALSE;        /* -np: don't call preprocessor     */
   57 BOOL    pflag   = TRUE;         /* -p: call preprocessor (default)   */
   58 BOOL    uflag   = FALSE;        /* -u: print funcs unused from 'main'*/
   59 BOOL    eflag   = FALSE;        /* -e: print funcs unused completely */
   60 BOOL    xflag   = FALSE;        /* -x: detect external functions    */
   61 BOOL    vflag   = FALSE;        /* -v: be verbose           */
   62 BOOL    debug   = FALSE;        /* -debug: print debugging messages */
   63 BOOL    xvcg    = FALSE;        /* -xvcg: format output for xvcg    */
   64 BOOL    dot = FALSE;        /* -dot: format output for graphviz */
   65 
   66 #define DEFDEPTH    32000
   67 
   68 int depth   = DEFDEPTH;     /* Stop at this call nesting depth  */
   69 int indents = 4;            /* default indentation per nest depth*/
   70 char    indent[256];            /* This is the indent string        */
   71 
   72 int nestlevel;          /* for {} nesting, used by parser   */
   73 sym_t   *funcs;             /* global function table        */
   74 sym_t   *fnames;            /* global filename table        */
   75 sym_t   *listfuncs;         /* table of functions to list       */
   76 sym_t   *ignorefuncs;           /* table of functions to ignore     */
   77 char    *curfname;
   78 
   79 #define MAXARGS     32
   80 
   81 #ifdef  _MSC_VER
   82 int Argc = 2;
   83 char    *Argv [MAXARGS] = { "cl.exe", "-E" };
   84 #else
   85 #ifndef HAVE_FORK
   86 int Argc = 2;
   87 char    *Argv [MAXARGS] = { "cc", "-E" };
   88 #else
   89 int Argc = 2;
   90 char    *Argv [MAXARGS] = { "cpp", "-I/usr/include" };
   91 #endif  /* HAVE_FORK */
   92 #endif  /* _MSC_VER */
   93 #ifdef  __EMX__
   94 char    *Env[2] = { "PATH=/lib;/usr/ccs/lib;/usr/bin;/bin", 0 };
   95 #else
   96 char    *Env[2] = { "PATH=/lib:/usr/ccs/lib:/usr/bin:/bin", 0 };
   97 #endif
   98 
   99 LOCAL   void    usage       __PR((int exitcode));
  100 EXPORT  int main        __PR((int ac, char **av));
  101 LOCAL   FILE    *mkcpppipe  __PR((FILE *f, char *fname));
  102 LOCAL   void    printfuncs  __PR((sym_t *table));
  103 LOCAL   void    printafunc  __PR((sym_t *sym));
  104 LOCAL   void    printusage  __PR((int indt, sym_t *tab));
  105 LOCAL   void    printflatusage  __PR((sym_t *tab));
  106 LOCAL   void    printxvcgusage  __PR((sym_t *caller, sym_t *tab));
  107 LOCAL   void    printdotusage   __PR((sym_t *caller, sym_t *tab));
  108 LOCAL   void    cleartree   __PR((sym_t *sym));
  109 LOCAL   void    flattree    __PR((sym_t *tab));
  110 LOCAL   BOOL    findclose   __PR((FILE *fp));
  111 LOCAL   void    findfname   __PR((FILE *fp, char *fname));
  112 LOCAL   int checkfunc   __PR((FILE *fp, int *ftype));
  113 LOCAL   int findfunc    __PR((FILE *fp, char *name, char *fname));
  114 LOCAL   void    nesterror   __PR((void));
  115 LOCAL   void    parsefile   __PR((FILE *fp, char *filename));
  116 LOCAL   int readfuncs   __PR((char *filename, sym_t **tab));
  117 LOCAL   int got_cpp_arg __PR((char *name, char *type));
  118 
  119 LOCAL void
  120 usage(exitcode)
  121     int exitcode;
  122 {
  123     error("Usage:   calltree [calltree_options] [cpp_options] file1..filen\n");
  124     error("Options:\n");
  125     error("\t-b\t\tPrint a vertial Bar at each tab stop.\n");
  126     error("\t-r\t\tInvert the structure of the tree.\n");
  127     error("\t-f\t\tFlattened (cumulative) tree.\n");
  128     error("\t-g\t\tPrint file names past procedure names.\n");
  129     error("\t-m\t\tCall structure for main only.\n");
  130     error("\t-p\t\tUse C Preprocessor (default).\n");
  131     error("\t-np\t\tDon't use C Preprocessor.\n");
  132     error("\t-u\t\tList all functions not called via 'main'.\n");
  133     error("\t-e\t\tList all functions not called.\n");
  134     error("\t-x\t\tList all external functions.\n");
  135     error("\t-xvcg\t\tFormat output for xvcg.\n");
  136     error("\t-dot\t\tFormat output for graphviz.\n");
  137     error("\t-v\t\tBe verbose.\n");
  138     error("\t-help\t\tPrint this help.\n");
  139     error("\t-version\tPrint version number.\n");
  140     error("\tigorefile=file\tDon't list functions found in 'file'.\n");
  141     error("\tlistfile=file\tList only functions found in 'file'.\n");
  142     error("\tlist=name\tProduce call graph only for function 'name'.\n");
  143     error("\tdepth=#\t\tSet the maximum printed nesting depth to #.\n");
  144     error("\ts=#\t\tSet indentation to #.\n");
  145     error("ignorefile=, listfile= and depth= may be abbreviated by first letter.\n");
  146     error("list= may be abbreviated by lf=.\n");
  147     exit(exitcode);
  148 }
  149 
  150 LOCAL   char    *opts = "b,r,f,g,m,p,np,u,e,x,dot,xvcg,v,ignorefile&,i&,listfile&,l&,list*,lf*,depth#,d#,s#,help,version,debug+,db+,I&,D&,U&";
  151 
  152 EXPORT int
  153 main(ac, av)
  154     int ac;
  155     char    *av[];
  156 {
  157     FILE    *f;
  158     int i;
  159     int help = 0;
  160     int version = 0;
  161     char    *thisname = 0;
  162     int cac;
  163     char *const * cav;
  164 
  165     save_args(ac, av);
  166 
  167     (void) setlocale(LC_ALL, "");
  168 
  169 #ifdef  USE_NLS
  170 #if !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
  171 #define TEXT_DOMAIN "calltree"  /* Use this only if it weren't */
  172 #endif
  173     { char  *dir;
  174     dir = searchfileinpath("share/locale", F_OK,
  175                     SIP_ANY_FILE|SIP_NO_PATH, NULL);
  176     if (dir)
  177         (void) bindtextdomain(TEXT_DOMAIN, dir);
  178     else
  179 #if defined(PROTOTYPES) && defined(INS_BASE)
  180     (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
  181 #else
  182     (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
  183 #endif
  184     (void) textdomain(TEXT_DOMAIN);
  185     }
  186 #endif  /* USE_NLS */
  187 
  188     cac = --ac;
  189     cav = ++av;
  190 
  191     /*
  192      * the argument order it's important and it must be the same of opts
  193      */
  194     if (getallargs(&cac, &cav, opts, &bflag, &rflag, &fflag, &gflag,
  195             &mflag, &pflag, &npflag, &uflag, &eflag,
  196             &xflag,
  197             &dot,
  198             &xvcg,
  199             &vflag,
  200             readfuncs, &ignorefuncs,
  201             readfuncs, &ignorefuncs,
  202             readfuncs, &listfuncs,
  203             readfuncs, &listfuncs,
  204             &thisname, &thisname,
  205             &depth, &depth,
  206             &indents, &help, &version,
  207             &debug, &debug,
  208             got_cpp_arg, "-I",
  209             got_cpp_arg, "-D",
  210             got_cpp_arg, "-U") < 0) {
  211         errmsgno(EX_BAD, "Bad Option: %s.\n", cav[0]);
  212         usage(EX_BAD);
  213     }
  214     if (help)
  215         usage(0);
  216     if (version) {
  217         gtprintf("Calltree release %s %s (%s-%s-%s) Copyright (C) 1985, 88-90, 95-99, 2000-2021 %s\n",
  218                 ct_version, VERSION_DATE,
  219                 HOST_CPU, HOST_VENDOR, HOST_OS,
  220                 _("Jörg Schilling"));
  221         exit(0);
  222     }
  223 
  224     if (npflag)
  225         pflag = FALSE;
  226     if (depth <= 0)
  227         depth = DEFDEPTH;
  228     if (uflag)
  229         mflag = fflag = TRUE;
  230     if (eflag)
  231         uflag = rflag = TRUE;
  232     if (xflag) {
  233         eflag = TRUE;  rflag = FALSE;
  234     }
  235     if (thisname)
  236         mflag = TRUE;
  237     if (thisname == 0)
  238         thisname = "main";
  239 
  240     if (indents > sizeof (indent)-1) {
  241         indents = sizeof (indent)-1;
  242         errmsgno(EX_BAD, "Cannot indent more than %d spaces.\n", indents);
  243     }
  244     for (i = 0; i < indents; i++)
  245         indent[i] = ' ';
  246     if (bflag)
  247         indent[0] = '|';
  248     indent[indents] = '\0';
  249 
  250     initkeyw();
  251 
  252     cac = ac;
  253     cav = av;
  254     if (getfiles(&cac, &cav, opts) <= 0) {
  255         errmsgno(EX_BAD, "No input files.\n");
  256         usage(EX_BAD);
  257     }
  258 
  259     if (vflag)
  260         error("Generating names ...\n");
  261 
  262     for (; getfiles(&cac, &cav, opts); cac--, cav++) {
  263         if ((f = fileopen(cav[0], "r")) == (FILE *) NULL)
  264             comerr("Cannot open '%s'.\n", cav[0]);
  265 
  266         if (pflag)
  267             f = mkcpppipe(f, cav[0]);
  268 
  269         parsefile(f, cav[0]);
  270 
  271         if (pflag) {
  272             Pwait(f);
  273         } else {
  274             fclose(f);
  275         }
  276     }
  277 
  278     if (vflag)
  279         error("Generating tree ...\n");
  280 
  281     if (xvcg) {
  282         /*
  283          * Print header for xvcg.
  284          */
  285         mflag = FALSE;
  286         printf("graph: {\norientation: left_to_right\n");
  287     }
  288     if (dot) {
  289         /*
  290          * Print header for graphviz.
  291          */
  292         mflag = FALSE;
  293         printf("digraph function_map {\nrankdir=LR;\nratio=fill;\nnode [style=filled]\n");
  294     }
  295     if (mflag) {
  296         /*
  297          * Either -m or -r name, do one function only.
  298          */
  299         sym_t   *this;
  300 
  301         if ((this = lookup(thisname, &funcs, L_LOOK)) == NULL) {
  302             comerrno(EX_BAD, "Function '%s' not found.\n", thisname);
  303         } else {
  304             cleartree(funcs);
  305             if (uflag)
  306                 this->s_flags |= S_USED;
  307             printafunc(this);
  308         }
  309     } else {
  310         /*
  311          * Print all functions.
  312          */
  313         printfuncs(funcs);
  314     }
  315     if (xvcg) {
  316         /*
  317          * Print trailer for xvcg.
  318          */
  319         printf("}\n");
  320     }
  321     if (dot) {
  322         /*
  323          * Print trailer for graphviz.
  324          */
  325         printf("}\n");
  326     }
  327     exit(0);
  328     /* NOTREACHED */
  329     return (0); /* Keep lint happy */
  330 }
  331 
  332 LOCAL FILE *
  333 mkcpppipe(f, fname)
  334     FILE    *f;
  335     char    *fname;
  336 {
  337 #ifdef  HAVE_FORK
  338     FILE    *fpp[2];
  339     int i;
  340 
  341     if (debug) {
  342         error("CPP args: ");
  343         for (i = 0; i < Argc; i++)
  344             error("'%s' ", Argv[i]);
  345         error("\n");
  346     }
  347     if (fpipe(fpp) == 0)
  348         comerr("Can not make pipe to C-preprocessor.\n");
  349 
  350     if ((i = vfork()) == 0) {   /* child */
  351 #ifdef  F_SETFD
  352         fcntl(fileno(pfd[0]), F_SETFD, FD_CLOEXEC);
  353 #endif
  354         fexecve(Argv[0], f, fpp[1], stderr,
  355             Argv, Env);
  356         errmsg("Cannot execute '%s'.\n", Argv[0]);
  357 #ifdef  HAVE_VFORK
  358         _exit(geterrno());
  359 #else
  360         exit(geterrno());
  361 #endif
  362     }
  363     if (i < 0)
  364         comerr("Fork failed.\n");
  365 
  366     /*
  367      * parent
  368      */
  369     fclose(f);          /* don't need it here*/
  370     fclose(fpp[1]);
  371     return (fpp[0]);
  372 #else                   /* No fork(), try popen() */
  373     FILE    *fp;
  374     int i;
  375     char    cmd[8192];
  376     char    *p;
  377 
  378     if (debug) {
  379         error("CPP args: ");
  380         for (i = 0; i < Argc; i++)
  381             error("'%s' ", Argv[i]);
  382         error("\n");
  383     }
  384     cmd[0] = '\0';
  385     for (i = 0; i < Argc; i++) {
  386         p = cmd + strlen(cmd);
  387         js_snprintf(p, sizeof (cmd) + cmd - p,
  388             "%s ", Argv[i]);
  389     }   
  390     p = cmd + strlen(cmd);
  391     js_snprintf(p, sizeof (cmd) + cmd - p,
  392         "%s ", fname);
  393     fp = popen(cmd, "r");
  394     fclose(f);
  395     return (fp);
  396 #endif
  397 }
  398 
  399 /*
  400  * Print the known information for all functions
  401  */
  402 LOCAL void
  403 printfuncs(tab)
  404     sym_t   *tab;
  405 {
  406     if (tab) {
  407         printfuncs(tab->s_left);
  408         cleartree(funcs);
  409         printafunc(tab);
  410         printfuncs(tab->s_right);
  411     }
  412 }
  413 
  414 /*
  415  * Print the known information for one function
  416  */
  417 LOCAL void
  418 printafunc(sym)
  419     sym_t   *sym;
  420 {
  421     if (listfuncs && !lookup(sym->s_name, &listfuncs, L_LOOK))
  422         return;
  423 
  424     if (xvcg) {
  425         if (!eflag && !sym->s_uses)
  426             return;
  427         printf("node: { title: \"%s\" ", sym->s_name);
  428         if (gflag && sym->s_filename)
  429             printf("label: \"%s [%s:%d]\" ",
  430                 sym->s_name, sym->s_filename, sym->s_lineno);
  431         if ((sym->s_flags & S_DEF) == 0)
  432             printf("shape: ellipse textcolor: lightgrey bordercolor: lightgrey ");
  433         printf("}\n");
  434         printxvcgusage(sym, sym->s_uses);
  435     } else if (dot) {
  436         if (!eflag && !sym->s_uses)
  437             return;
  438         printf(" %s [ shape=box ", sym->s_name);
  439         if (gflag && sym->s_filename)
  440             printf("label = \"%s [%s:%d]\" ",
  441                 sym->s_name, sym->s_filename, sym->s_lineno);
  442         if ((sym->s_flags & S_DEF) == 0)
  443             printf("shape = ellipse, fontcolor = lightgrey ");
  444         printf("];\n");
  445         printdotusage(sym, sym->s_uses);
  446     } else if ((sym->s_flags & S_DEF) == 0) {
  447         printf("%s", sym->s_name);
  448         if (gflag && sym->s_filename) {
  449             printf(" [%s:%d]",
  450                 sym->s_filename, sym->s_lineno);
  451         }
  452         if (eflag) {
  453             printf("\n");
  454         } else if (rflag) {
  455             printf(":\n%sNOT CALLED\n", indent);
  456         } else {
  457             printf(":\n%sEXTERNAL ROUTINE\n", indent);
  458         }
  459     } else if (!eflag) {
  460         printf("%s", sym->s_name);
  461         if (gflag && sym->s_filename) {
  462             printf(" [%s:%d]:\n",
  463                     sym->s_filename,
  464                     sym->s_lineno);
  465         } else {
  466             printf(":\n");
  467         }
  468         if (fflag) {
  469             flattree(sym->s_uses);
  470             printflatusage(funcs);
  471         } else {
  472             sym->s_flags |= S_RECURSE;
  473             printusage(1, sym->s_uses);
  474             sym->s_flags &= ~S_RECURSE;
  475         }
  476     }
  477 }
  478 
  479 /*
  480  * Print the known caller/callee information for one function.
  481  */
  482 LOCAL void
  483 printusage(indt, tab)
  484     int indt;
  485     sym_t   *tab;
  486 {
  487     int i;
  488     sym_t   *sym;
  489     BOOL    isrecurse = FALSE;
  490 
  491     if (tab == NULL)
  492         return;
  493 
  494     printusage(indt, tab->s_left);
  495     for (i = 0; i < indt; i++)
  496         printf("%s", indent);
  497 
  498     if (tab->s_sym == NULL) {   /* Darf eigentlich nicht vorkommen */
  499         printf("FAKED CALL\n");
  500         return;
  501     }
  502     sym = tab->s_sym;
  503 
  504     printf("%s", sym->s_name);
  505     if (gflag && sym->s_filename)
  506         printf(" [%s:%d]", sym->s_filename, sym->s_lineno);
  507     if ((sym->s_flags & S_RECURSE) != 0) {
  508         isrecurse = TRUE;
  509         printf(" ....\n");
  510     } else
  511         printf("\n");
  512     if ((--depth > 0) && sym != 0 && !isrecurse && !rflag) {
  513         sym->s_flags |= S_RECURSE;
  514         printusage(indt+1, sym->s_uses);
  515         sym->s_flags &= ~S_RECURSE;
  516     }
  517     depth++;
  518 
  519     printusage(indt, tab->s_right);
  520 }
  521 
  522 /*
  523  * Print the known caller/callee information for one function in flat form.
  524  */
  525 LOCAL void
  526 printflatusage(tab)
  527     sym_t   *tab;
  528 {
  529     if (tab) {
  530         printflatusage(tab->s_left);
  531         if (((tab->s_flags & S_USED) != 0 && !uflag) ||
  532             ((tab->s_flags & S_USED) == 0 && uflag)) {
  533             printf("%s%s", indent, tab->s_name);
  534             if (gflag && tab->s_filename) {
  535                 printf(" [%s:%d]\n",
  536                     tab->s_filename, tab->s_lineno);
  537             } else {
  538                 printf("\n");
  539             }
  540         }
  541         printflatusage(tab->s_right);
  542     }
  543 }
  544 
  545 /*
  546  * Print the known caller/callee information formatted for xvcg.
  547  */
  548 LOCAL void
  549 printxvcgusage(caller, tab)
  550     sym_t   *caller;
  551     sym_t   *tab;
  552 {
  553     if (tab) {
  554         sym_t   *called;
  555 
  556         printxvcgusage(caller, tab->s_left);
  557         if (eflag ||
  558             ((called = lookup(tab->s_name, &funcs, L_LOOK)) != NULL &&
  559             called->s_uses))
  560             printf("edge: { sourcename: \"%s\" targetname: \"%s\" }\n",
  561                     caller->s_name, tab->s_name);
  562         printxvcgusage(caller, tab->s_right);
  563     }
  564 }
  565 
  566 LOCAL void
  567 printdotusage(caller, tab)
  568     sym_t   *caller;
  569     sym_t   *tab;
  570 {
  571     if (tab) {
  572         sym_t   *called;
  573 
  574         printdotusage(caller, tab->s_left);
  575         if (eflag ||
  576             ((called = lookup(tab->s_name, &funcs, L_LOOK)) != NULL &&
  577             called->s_uses))
  578             printf("%s  -> %s;\n",
  579                 caller->s_name, tab->s_name);
  580         printdotusage(caller, tab->s_right);
  581     }
  582 }
  583 /*
  584  * Clear all markers in the symbol tree
  585  */
  586 LOCAL void
  587 cleartree(sym)
  588     sym_t   *sym;
  589 {
  590     if (sym) {
  591         cleartree(sym->s_left);
  592         sym->s_flags &= ~(S_USED|S_RECURSE);
  593         cleartree(sym->s_right);
  594     }
  595 }
  596 
  597 /*
  598  * Prepare a tree for flat (cumulative) printing.
  599  */
  600 LOCAL void
  601 flattree(tab)
  602     sym_t   *tab;
  603 {
  604     sym_t   *sym;
  605 
  606     if (tab) {
  607         flattree(tab->s_left);
  608         if (((sym = tab->s_sym)->s_flags & S_USED) == 0) {
  609             sym->s_flags |= S_USED;
  610             flattree(sym->s_uses);
  611         }
  612         flattree(tab->s_right);
  613     }
  614 }
  615 
  616 /*
  617  * Find a matching close bracket ')'.
  618  */
  619 LOCAL BOOL
  620 findclose(fp)
  621     FILE    *fp;
  622 {
  623     register int    n = 1;
  624     register int    tktype;
  625 
  626     while ((tktype = clex(fp)) != T_EOF) {
  627         switch (tktype) {
  628 
  629         case T_LCURLY:
  630         case T_RCURLY:
  631             return (FALSE);
  632 
  633         case T_OPEN:
  634             n++; break;
  635 
  636         case T_CLOSE:
  637             n--; break;
  638         }
  639         if (n == 0)
  640             return (TRUE);
  641     }
  642     return (FALSE);
  643 }
  644 
  645 /*
  646  * Parse a lineno/filename directive from the C-preprocessor.
  647  */
  648 LOCAL void
  649 findfname(fp, fname)
  650     FILE    *fp;
  651     char    *fname;
  652 {
  653     register int    tktype;
  654         char    *p;
  655         int line;
  656 
  657     if ((tktype = clex(fp)) == T_EOF)
  658         return;
  659 
  660     switch (tktype) {
  661 
  662     case T_ALPHA:
  663         if (strcmp((char *)lexbuf, "line") != 0)
  664             return;
  665         if ((tktype = clex(fp)) == T_EOF)
  666             return;
  667         if (tktype != T_NUMBER)
  668             return;
  669         /* FALLTHROUGH */
  670     case T_NUMBER:
  671         astoi((char *)lexbuf, &line);
  672         lexline = line-1;
  673         if ((tktype = clex(fp)) == T_EOF)
  674             return;
  675         if (tktype == T_STRING) {
  676             p = (char *)lexbuf;
  677             p++;
  678             p[strlen(p)-1] = '\0';
  679             strcpy(fname, p);
  680 
  681             /*
  682              * The new GNU cpp v3.2 prints <stdin> for filename.
  683              * For example the hash line in GNU cpp v2.96 (worked):
  684              *
  685              *  # 40 ""
  686              *
  687              * With GNU cpp v3.2 (fails without the fix below):
  688              *
  689              *  # 40 "<stdin>"
  690              *
  691              * The "<stdin>" string should be treated as a blank
  692              * string instead of a filename.
  693              */
  694             if (strcmp(fname, "<stdin>") == 0)
  695                 fname[0] = '\0';
  696 
  697             if (fname[0] != '\0')
  698                 lexfile = fname;
  699             else
  700                 lexfile = curfname;
  701         }
  702     }
  703 }
  704 
  705 #define FUNC_DEF    1
  706 #define FUNC_CALL   0
  707 
  708 /*
  709  * Check for function call/definition.
  710  */
  711 LOCAL int
  712 checkfunc(fp, ftypep)
  713     FILE    *fp;
  714     int *ftypep;
  715 {
  716     register int    tktype = T_NONE;
  717 
  718     /*
  719      * We come here if we found a T_ALPHA followed by T_OPEN
  720      * e.g. 'testfunc ('
  721      */
  722     if (nestlevel == 0) {               /* not in function */
  723 
  724         if (!findclose(fp))
  725             return (-1);            /* maybe var def */
  726         tktype = clex(fp);
  727 
  728         if (tktype != T_SEMI &&
  729             tktype != T_COMMA) {        /* no external def */
  730 
  731             if (tktype == T_LCURLY) {
  732                 nestlevel++;
  733             } else if (tktype == T_RCURLY &&
  734                     --nestlevel < 0) {
  735                 /*
  736                  * Bad syntax or rotten parser.
  737                  */
  738                 nesterror();
  739             }
  740             *ftypep = FUNC_DEF;     /* func definition */
  741             return (tktype);
  742         }
  743         *ftypep = -1;               /* maybe a var def */
  744         return (tktype);
  745 
  746     } else {                    /* in function */
  747 
  748 #ifdef  nonono /* Hier wird Func call im Argument nicht erkannt */
  749         if (!findclose(fp))
  750             return (-1);            /* maybe var usage */
  751         if ((tktype = clex(fp)) == T_OPEN) {
  752             error("No func: '%s' ('%s') on line %d\n", name, lexbuf, lexline);
  753             return (-1);
  754         }
  755 #endif
  756         *ftypep = FUNC_CALL;            /* func call */
  757         return (tktype);
  758     }
  759 }
  760 
  761 /*
  762  * Find functions in C-syntax.
  763  */
  764 LOCAL int
  765 findfunc(fp, name, fname)
  766     FILE    *fp;
  767     char    *name;
  768     char    *fname;
  769 {
  770     register int    tktype;
  771         int ftype = 0;      /* init to make GCC quiet */
  772 
  773     while ((tktype = clex(fp)) != T_EOF) {
  774 recheck:
  775         if (debug) {
  776             error("%s:%d{%d} %s: %s\n",
  777                 lexfile, lexline, nestlevel, lextnames[tktype], lexbuf);
  778         }
  779         switch (tktype) {
  780 
  781         case T_LCURLY:
  782             nestlevel++;
  783             break;
  784 
  785         case T_RCURLY:
  786             if (--nestlevel < 0)
  787                 nesterror();
  788             break;
  789 
  790         case T_HASH:
  791             findfname(fp, fname);
  792             break;
  793 
  794         case T_ALPHA:
  795             strcpy(name, (char *)lexbuf);
  796             if ((tktype = clex(fp)) == T_OPEN) {
  797                 tktype = checkfunc(fp, &ftype);
  798                 if (ftype < 0)
  799                     goto recheck;
  800                 return (ftype);
  801             }
  802             goto recheck;
  803 
  804         default:
  805             break;
  806         }
  807     }
  808     return (-1);                    /* EOF */
  809 }
  810 
  811 /*
  812  * Warn about a {} nesting error and reset nestlevel.
  813  */
  814 LOCAL void
  815 nesterror()
  816 {
  817     error("Found '}' without open on line %d.\n", lexline);
  818     if (debug)
  819         error("lexbuf from line %d: %s\n", lexline, lexbuf);
  820     nestlevel = 0;
  821 }
  822 
  823 /*
  824  * Zuerst wird eine Funktionsdefinition gefunden und deren Wert in 'dfunc'
  825  * gemerkt. Alle Funktionsaufrufe innerhalb dieser Funktion bekommen
  826  * dann 'dfunc' als rufende Funktion vermerkt.
  827  *
  828  * Problem:
  829  * Es gibt Struct Definitionen, bei denen calltree 'denkt' dasz ein
  830  * Funktionsaufruf vorliegt, ohne dasz vorher eine Funktionsdefinition
  831  * gefunden wurde. Dann ist der Zeiger auf die Rufende Funktion ein
  832  * NULL Pointer.
  833  * Richtige Abhilfe:
  834  * Funktionsdecoder verbessern.
  835  *
  836  * Standard tree:
  837  *
  838  * <funcs (tree)> ... -> <sym_t 'name' caller> -> <list of callees (tree)>
  839  *    ^                         |
  840  *    |_________________________________________________|
  841  *  Backpointer to adjacent callee pointer in main tree
  842  *
  843  *
  844  * Reversed tree:
  845  *
  846  * <funcs (tree)> ... -> <sym_t 'name' callee> -> <list of callers (tree)>
  847  *    ^                         |
  848  *    |_________________________________________________|
  849  *  Backpointer to adjacent caller pointer in main tree
  850  *
  851  */
  852 LOCAL void
  853 parsefile(fp, filename)
  854     FILE    *fp;
  855     char    *filename;
  856 {
  857     char    name[LEXBSIZE];
  858     char    fname[LEXBSIZE];
  859     int ft;
  860     sym_t   *dsym = (sym_t *)0; /* defined function */
  861     sym_t   *csym;          /* called function */
  862     sym_t   *usym;          /* this function from uses list */
  863 
  864     if (vflag)
  865         error("%s\n", filename);
  866 
  867     clexinit();
  868     fname[0] = '\0';
  869     lexfile = curfname = filename;
  870 
  871     for (;;) {
  872         if ((ft = findfunc(fp, name, fname)) == FUNC_DEF) {
  873             if (lookup(name, &ignorefuncs, L_LOOK))
  874                 continue;
  875             if (debug)
  876                 error("define func '%s'\n", name);
  877 
  878             dsym = lookup(name, &funcs, L_CREATE);
  879             if (fname[0] != '\0') {
  880                 usym = lookup(fname, &fnames, L_CREATE);
  881                 dsym->s_filename = usym->s_name;
  882             } else {
  883                 dsym->s_filename = filename;
  884             }
  885             dsym->s_lineno = lexline;
  886             if ((dsym->s_flags & S_DEF) != 0) {
  887                 /*
  888                  * Static functions of the same name
  889                  * are not yet handled.
  890                  */
  891                 if ((dsym->s_flags & S_WARN) == 0)
  892                     errmsgno(EX_BAD,
  893                         "Warning: function: %s already defined\n", name);
  894                 dsym->s_flags |= S_WARN;
  895             }
  896             dsym->s_flags |= S_DEF;
  897         } else if (ft == FUNC_CALL) {
  898             if (lookup(name, &ignorefuncs, L_LOOK))
  899                 continue;
  900             if (debug)
  901                 error("call func '%s'\n", name);
  902             if (dsym == (sym_t *)0) {   /* Not in Function */
  903                 if (debug)
  904                     error("Bad call: '%s'\n", name);
  905                 continue;
  906             }
  907 
  908             csym = lookup(name, &funcs, L_CREATE);
  909             if (rflag) {
  910                 /*
  911                  * Insert the calling function into the
  912                  * function list of (this) called function.
  913                  */
  914                 usym = lookup(dsym->s_name, &(csym->s_uses), funcs);
  915                 usym->s_sym = dsym; /* Back ptr to caller */
  916                             /* in main funcs tree */
  917             } else {
  918                 /*
  919                  * Insert (this) called function into the
  920                  * function list of the caller.
  921                  */
  922                 usym = lookup(name, &(dsym->s_uses), funcs);
  923                 usym->s_sym = csym; /* Back ptr to callee */
  924                             /* in main funcs tree */
  925             }
  926         } else {
  927             if (debug)
  928                 error("EOF '%s'\n", name);
  929             break;
  930         }
  931     }
  932 }
  933 
  934 /*
  935  * Read a file containung a list of function names.
  936  */
  937 LOCAL int
  938 readfuncs(filename, tab)
  939     char    *filename;
  940     sym_t   **tab;
  941 {
  942     FILE    *fp;
  943     char    fname[LEXBSIZE];
  944 
  945     if ((fp = fileopen(filename, "r")) == NULL)
  946         comerr("Cannot open file %s\n", filename);
  947 
  948     while (fgetline(fp, fname, sizeof (fname)) >= 0)
  949         lookup(fname, tab, L_CREATE);
  950 
  951     return (1);
  952 }
  953 
  954 /*
  955  * Handle CPP command line options.
  956  */
  957 LOCAL int
  958 got_cpp_arg(name, type)
  959     char    *name;
  960     char    *type;
  961 {
  962     if (debug)
  963         error("Got CPP arg: %s %s\n", type, name);
  964 
  965     if (Argc >= MAXARGS) {
  966         errmsgno(EX_BAD, "Too many Preprocessor options.\n");
  967         return (-2);
  968     }
  969     Argv[Argc++] = concat(type, name, (char *)NULL);
  970     return (1);
  971 }