"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.

    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 }