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