LCOV - code coverage report
Current view: top level - src - main.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 175 313 55.9 %
Date: 2015-04-20 Functions: 10 14 71.4 %

          Line data    Source code
       1             : /* This file is part of GNU cflow
       2             :    Copyright (C) 1997, 2005, 2007, 2009, 2010, 2011 Sergey Poznyakoff
       3             :  
       4             :    GNU cflow is free software; you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation; either version 3 of the License, or
       7             :    (at your option) any later version.
       8             :  
       9             :    GNU cflow is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public
      15             :    License along with GNU cflow; if not, write to the Free Software
      16             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      17             :    MA 02110-1301 USA */
      18             : 
      19             : #include <cflow.h>
      20             : #include <argp.h>
      21             : #include <argp-version-etc.h>
      22             : #include <progname.h>
      23             : #include <stdarg.h>
      24             : #include <parser.h>
      25             : #include <version-etc.h>
      26             : 
      27             : const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
      28             : static char doc[] = N_("generate a program flowgraph")
      29             : "\v"
      30             : N_("* The effect of each option marked with an asterisk is reversed if the option's long name is prefixed with `no-'. For example, --no-cpp cancels --cpp.");
      31             : const char *program_authors[] = {
      32             :      "Sergey Poznyakoff",
      33             :      NULL
      34             : };
      35             : 
      36             : enum option_code {
      37             :      OPT_DEFINES = 256,
      38             :      OPT_LEVEL_INDENT,
      39             :      OPT_DEBUG,
      40             :      OPT_PREPROCESS,
      41             :      OPT_NO_PREPROCESS,
      42             :      OPT_EMACS,
      43             :      OPT_NO_USE_INDENTATION,
      44             :      OPT_NO_ANSI,
      45             :      OPT_NO_TREE,
      46             :      OPT_NO_BRIEF,
      47             :      OPT_NO_EMACS,
      48             :      OPT_NO_VERBOSE,
      49             :      OPT_NO_NUMBER,
      50             :      OPT_NO_PRINT_LEVEL,
      51             :      OPT_NO_REVERSE,
      52             :      OPT_OMIT_ARGUMENTS,
      53             :      OPT_NO_OMIT_ARGUMENTS,
      54             :      OPT_OMIT_SYMBOL_NAMES,
      55             :      OPT_NO_OMIT_SYMBOL_NAMES
      56             : };
      57             : 
      58             : static struct argp_option options[] = {
      59             : #define GROUP_ID 0
      60             :      { NULL, 0, NULL, 0,
      61             :        N_("General options:"), GROUP_ID },
      62             :      { "depth", 'd', N_("NUMBER"), 0,
      63             :        N_("Set the depth at which the flowgraph is cut off"), GROUP_ID+1 },
      64             :      { "include", 'i', N_("CLASSES"), 0,
      65             :        N_("Include specified classes of symbols (see below). Prepend CLASSES with ^ or - to exclude them from the output"), GROUP_ID+1 },
      66             :      { "format", 'f', N_("NAME"), 0,
      67             :        N_("Use given output format NAME. Valid names are `gnu' (default) and `posix'"),
      68             :        GROUP_ID+1 },
      69             :      { "reverse", 'r', NULL, 0,
      70             :        N_("* Print reverse call tree"), GROUP_ID+1 },
      71             :      { "xref", 'x', NULL, 0,
      72             :        N_("Produce cross-reference listing only"), GROUP_ID+1 },
      73             :      { "print", 'P', N_("OPT"), OPTION_HIDDEN,
      74             :        N_("Set printing option to OPT. Valid OPT values are: xref (or cross-ref), tree. Any unambiguous abbreviation of the above is also accepted"),
      75             :        GROUP_ID+1 },
      76             :      { "output", 'o', N_("FILE"), 0,
      77             :        N_("Set output file name (default -, meaning stdout)"),
      78             :        GROUP_ID+1 },
      79             : 
      80             :      { NULL, 0, NULL, 0, N_("Symbols classes for --include argument"), GROUP_ID+2 },
      81             :      {"  x", 0, NULL, OPTION_DOC|OPTION_NO_TRANS,
      82             :       N_("all data symbols, both external and static"), GROUP_ID+3 },
      83             :      {"  _",  0, NULL, OPTION_DOC|OPTION_NO_TRANS,
      84             :       N_("symbols whose names begin with an underscore"), GROUP_ID+3 },
      85             :      {"  s",  0, NULL, OPTION_DOC|OPTION_NO_TRANS,
      86             :       N_("static symbols"), GROUP_ID+3 },
      87             :      {"  t",  0, NULL, OPTION_DOC|OPTION_NO_TRANS,
      88             :       N_("typedefs (for cross-references only)"), GROUP_ID+3 },
      89             : 
      90             :      
      91             : #undef GROUP_ID
      92             : #define GROUP_ID 10     
      93             :      { NULL, 0, NULL, 0,
      94             :        N_("Parser control:"), GROUP_ID },
      95             :      { "use-indentation", 'S', NULL, 0,
      96             :        N_("* Rely on indentation"), GROUP_ID+1 },
      97             :      { "no-use-indentation", OPT_NO_USE_INDENTATION, NULL, OPTION_HIDDEN,
      98             :        "", GROUP_ID+1 },
      99             :      { "ansi", 'a', NULL, 0,
     100             :        N_("* Accept only sources in ANSI C"), GROUP_ID+1 },
     101             :      { "no-ansi", OPT_NO_ANSI, NULL, OPTION_HIDDEN,
     102             :        "", GROUP_ID+1 },
     103             :      { "pushdown", 'p', N_("NUMBER"), 0,
     104             :        N_("Set initial token stack size to NUMBER"), GROUP_ID+1 },
     105             :      { "symbol", 's', N_("SYMBOL:[=]TYPE"), 0,
     106             :        N_("Register SYMBOL with given TYPE, or define an alias (if := is used). Valid types are: keyword (or kw), modifier, qualifier, identifier, type, wrapper. Any unambiguous abbreviation of the above is also accepted"), GROUP_ID+1 },
     107             :      { "main", 'm', N_("NAME"), 0,
     108             :        N_("Assume main function to be called NAME"), GROUP_ID+1 },
     109             :      { "define", 'D', N_("NAME[=DEFN]"), 0,
     110             :        N_("Predefine NAME as a macro"), GROUP_ID+1 },
     111             :      { "undefine", 'U', N_("NAME"), 0,
     112             :        N_("Cancel any previous definition of NAME"), GROUP_ID+1 },
     113             :      { "include-dir", 'I', N_("DIR"), 0,
     114             :        N_("Add the directory DIR to the list of directories to be searched for header files."), GROUP_ID+1 },
     115             :      { "preprocess", OPT_PREPROCESS, N_("COMMAND"), OPTION_ARG_OPTIONAL,
     116             :        N_("* Run the specified preprocessor command"), GROUP_ID+1 },
     117             :      { "cpp", 0, NULL, OPTION_ALIAS, NULL, GROUP_ID+1 },
     118             :      { "no-preprocess", OPT_NO_PREPROCESS, NULL, OPTION_HIDDEN,
     119             :        "", GROUP_ID+1 },
     120             :      { "no-cpp", 0, NULL, OPTION_ALIAS|OPTION_HIDDEN, NULL, GROUP_ID+1 },
     121             : #undef GROUP_ID
     122             : #define GROUP_ID 20          
     123             :      { NULL, 0, NULL, 0,
     124             :        N_("Output control:"), GROUP_ID },
     125             :      { "number", 'n', NULL, 0,
     126             :        N_("* Print line numbers"), GROUP_ID+1 },
     127             :      { "no-number", OPT_NO_NUMBER, NULL, OPTION_HIDDEN,
     128             :        "", GROUP_ID+1 },
     129             :      { "print-level", 'l', NULL, 0,
     130             :        N_("* Print nesting level along with the call tree"), GROUP_ID+1 },
     131             :      { "no-print-level", OPT_NO_PRINT_LEVEL, NULL, OPTION_HIDDEN,
     132             :        "", GROUP_ID+1 },
     133             :      { "level-indent", OPT_LEVEL_INDENT, "ELEMENT", 0,
     134             :        N_("Control graph appearance"), GROUP_ID+1 },
     135             :      { "tree", 'T', NULL, 0,
     136             :        N_("* Draw ASCII art tree"), GROUP_ID+1 },
     137             :      { "no-tree", OPT_NO_TREE, NULL, OPTION_HIDDEN,
     138             :        "", GROUP_ID+1 },
     139             :      { "brief", 'b', NULL, 0,
     140             :        N_("* Brief output"), GROUP_ID+1 },
     141             :      { "no-brief", OPT_NO_BRIEF, NULL, OPTION_HIDDEN,
     142             :        "", GROUP_ID+1 },
     143             :      { "emacs", OPT_EMACS, NULL, 0,
     144             :        N_("* Additionally format output for use with GNU Emacs"), GROUP_ID+1 },
     145             :      { "no-emacs", OPT_NO_EMACS, NULL, OPTION_HIDDEN,
     146             :        "", GROUP_ID+1 },
     147             :      { "omit-arguments", OPT_OMIT_ARGUMENTS, NULL, 0,
     148             :        N_("* Do not print argument lists in function declarations"), GROUP_ID+1 },
     149             :      { "no-ignore-arguments", OPT_NO_OMIT_ARGUMENTS, NULL, OPTION_HIDDEN,
     150             :        "", GROUP_ID+1 },
     151             :      { "omit-symbol-names", OPT_OMIT_SYMBOL_NAMES, NULL, 0,
     152             :        N_("* Do not print symbol names in declaration strings"), GROUP_ID+1 },
     153             :      { "no-omit-symbol-names", OPT_NO_OMIT_SYMBOL_NAMES, NULL, OPTION_HIDDEN,
     154             :        "", GROUP_ID+1 },
     155             : #undef GROUP_ID
     156             : #define GROUP_ID 30                 
     157             :      { NULL, 0, NULL, 0,
     158             :        N_("Informational options:"), GROUP_ID },
     159             :      { "verbose", 'v', NULL, 0,
     160             :        N_("* Verbose error diagnostics"), GROUP_ID+1 },
     161             :      { "no-verbose", OPT_NO_VERBOSE, NULL, OPTION_HIDDEN,
     162             :        "", GROUP_ID+1 },
     163             :      { "debug", OPT_DEBUG, "NUMBER", OPTION_ARG_OPTIONAL,
     164             :        N_("Set debugging level"), GROUP_ID+1 },
     165             : #undef GROUP_ID     
     166             :      { 0, }
     167             : };
     168             : 
     169             : /* Structure representing various arguments of command line options */
     170             : struct option_type {
     171             :     char *str;           /* optarg value */
     172             :     int min_match;       /* minimal number of characters to match */
     173             :     int type;            /* data associated with the arg */
     174             : };
     175             : 
     176             : int debug;              /* debug level */
     177             : char *outname = "-";    /* default output file name */
     178             : int print_option = 0;   /* what to print. */
     179             : int verbose;            /* be verbose on output */
     180             : int use_indentation;    /* Rely on indentation,
     181             :                          * i.e. suppose the function body
     182             :                          * is necessarily surrounded by the curly braces
     183             :                          * in the first column
     184             :                          */
     185             : int record_defines;     /* Record macro definitions */
     186             : int strict_ansi;        /* Assume sources to be written in ANSI C */
     187             : int print_line_numbers; /* Print line numbers */
     188             : int print_levels;       /* Print level number near every branch */
     189             : int print_as_tree;      /* Print as tree */
     190             : int brief_listing;      /* Produce short listing */
     191             : int reverse_tree;       /* Generate reverse tree */
     192             : int max_depth;          /* The depth at which the flowgraph is cut off */
     193             : int emacs_option;       /* Format and check for use with Emacs cflow-mode */ 
     194             : int omit_arguments_option;    /* Omit arguments from function declaration string */
     195             : int omit_symbol_names_option; /* Omit symbol name from symbol declaration string */
     196             : 
     197             : #define SM_FUNCTIONS   0x0001
     198             : #define SM_DATA        0x0002
     199             : #define SM_STATIC      0x0004
     200             : #define SM_UNDERSCORE  0x0008
     201             : #define SM_TYPEDEF     0x0010
     202             : #define SM_UNDEFINED   0x0020
     203             : 
     204             : #define CHAR_TO_SM(c) ((c)=='x' ? SM_DATA : \
     205             :                         (c)=='_' ? SM_UNDERSCORE : \
     206             :                          (c)=='s' ? SM_STATIC : \
     207             :                           (c)=='t' ? SM_TYPEDEF : \
     208             :                            (c)=='u' ? SM_UNDEFINED : 0)
     209             : #define SYMBOL_INCLUDE(c) (symbol_map |= CHAR_TO_SM(c))
     210             : #define SYMBOL_EXCLUDE(c) (symbol_map &= ~CHAR_TO_SM(c))
     211             : int symbol_map;  /* A bitmap of symbols included in the graph. */
     212             : 
     213             : char *level_indent[] = { NULL, NULL };
     214             : char *level_end[] = { "", "" };
     215             : char *level_begin = "";
     216             : 
     217             : int preprocess_option = 0; /* Do they want to preprocess sources? */
     218             : 
     219             : char *start_name = "main"; /* Name of start symbol */
     220             : 
     221             : struct linked_list *arglist;        /* List of command line arguments */
     222             : 
     223             : /* Given the option_type array and (possibly abbreviated) option argument
     224             :  * find the type corresponding to that argument.
     225             :  * Return 0 if the argument does not match any one of OPTYPE entries
     226             :  */
     227             : static int
     228          33 : find_option_type(struct option_type *optype, const char *str, int len)
     229             : {
     230          33 :      if (len == 0)
     231           5 :           len = strlen(str);
     232         131 :      for ( ; optype->str; optype++) {
     233         262 :           if (len >= optype->min_match &&
     234         131 :               memcmp(str, optype->str, len) == 0) {
     235          33 :                return optype->type;
     236             :           }
     237             :      }
     238           0 :      return 0;
     239             : }
     240             : 
     241             : /* Args for --symbol option */
     242             : static struct option_type symbol_optype[] = {
     243             :      { "keyword", 2, WORD },
     244             :      { "kw", 2, WORD },
     245             :      { "modifier", 1, MODIFIER },
     246             :      { "identifier", 1, IDENTIFIER },
     247             :      { "type", 1, TYPE },
     248             :      { "wrapper", 1, PARM_WRAPPER },
     249             :      { "qualifier", 1, QUALIFIER },
     250             :      { 0 },
     251             : };
     252             : 
     253             : /* Parse the string STR and store the symbol in the temporary symbol table.
     254             :  * STR is the string of form: NAME:TYPE
     255             :  * NAME means symbol name, TYPE means symbol type (possibly abbreviated)
     256             :  */
     257             : static void
     258           5 : symbol_override(const char *str)
     259             : {
     260             :      const char *ptr;
     261             :      char *name;
     262             :      Symbol *sp;
     263             :      
     264           5 :      ptr = strchr(str, ':');
     265           5 :      if (!ptr) {
     266           0 :           error(0, 0, _("%s: no symbol type supplied"), str);
     267           0 :           return;
     268             :      } else {
     269           5 :           name = strndup(str, ptr - str);
     270           5 :           if (ptr[1] == '=') {
     271           0 :                Symbol *alias = lookup(ptr+2);
     272           0 :                if (!alias) {
     273           0 :                     alias = install(xstrdup(ptr+2), INSTALL_OVERWRITE);
     274           0 :                     alias->type = SymToken;
     275           0 :                     alias->token_type = 0;
     276           0 :                     alias->source = NULL;
     277           0 :                     alias->def_line = -1;
     278           0 :                     alias->ref_line = NULL;
     279             :                }
     280           0 :                sp = install(name, INSTALL_OVERWRITE);
     281           0 :                sp->type = SymToken;
     282           0 :                sp->alias = alias;
     283           0 :                sp->flag = symbol_alias;
     284             :           } else {
     285           5 :                int type = find_option_type(symbol_optype, ptr+1, 0);
     286           5 :                if (type == 0) {
     287           0 :                     error(0, 0, _("unknown symbol type: %s"), ptr+1);
     288           0 :                     return;
     289             :                }
     290           5 :                sp = install(name, INSTALL_OVERWRITE);
     291           5 :                sp->type = SymToken;
     292           5 :                sp->token_type = type;
     293             :           }
     294           5 :           sp->source = NULL;
     295           5 :           sp->def_line = -1;
     296           5 :           sp->ref_line = NULL;
     297             :      }
     298             : }
     299             : 
     300             : /* Args for --print option */
     301             : static struct option_type print_optype[] = {
     302             :      { "xref", 1, PRINT_XREF },
     303             :      { "cross-ref", 1, PRINT_XREF },
     304             :      { "tree", 1, PRINT_TREE },
     305             :      { 0 },
     306             : };
     307             : 
     308             : static void
     309           0 : set_print_option(char *str)
     310             : {
     311             :      int opt;
     312             :      
     313           0 :      opt = find_option_type(print_optype, str, 0);
     314           0 :      if (opt == 0) {
     315           0 :           error(0, 0, _("unknown print option: %s"), str);
     316           0 :           return;
     317             :      }
     318           0 :      print_option |= opt;
     319             : }
     320             : 
     321             : /* Convert first COUNT bytes of the string pointed to by STR_PTR
     322             :  * to integer using BASE. Move STR_PTR to the point where the
     323             :  * conversion stopped.
     324             :  * Return the number obtained.
     325             :  */
     326             : static int
     327           0 : number(const char **str_ptr, int base, int count)
     328             : {
     329             :      int  c, n;
     330             :      unsigned i;
     331           0 :      const char *str = *str_ptr;
     332             :      
     333           0 :      for (n = 0; *str && count; count--) {
     334           0 :           c = *str++;
     335           0 :           if (isdigit(c))
     336           0 :                i = c - '0';
     337             :           else
     338           0 :                i = toupper(c) - 'A' + 10;
     339           0 :           if (i > base) {
     340           0 :                break;
     341             :           }
     342           0 :           n = n * base + i;
     343             :      }
     344           0 :      *str_ptr = str - 1;
     345           0 :      return n;
     346             : }
     347             : 
     348             : /* Processing for --level option
     349             :  * The option syntax is
     350             :  *    --level NUMBER
     351             :  * or
     352             :  *    --level KEYWORD=STR
     353             :  * where
     354             :  *    KEYWORD is one of "begin", "0", ", "1", "end0", "end1",
     355             :  *    or an abbreviation thereof,
     356             :  *    STR is the value to be assigned to the parameter.
     357             :  *  
     358             :  * STR can contain usual C escape sequences plus \e meaning '\033'.
     359             :  * Apart from this any character followed by xN suffix (where N is
     360             :  * a decimal number) is expanded to the sequence of N such characters.
     361             :  * 'x' looses its special meaning at the start of the string.
     362             :  */
     363             : #define MAXLEVELINDENT 216
     364             : #define LEVEL_BEGIN 1
     365             : #define LEVEL_INDENT0 2
     366             : #define LEVEL_INDENT1 3
     367             : #define LEVEL_END0 4
     368             : #define LEVEL_END1 5
     369             : 
     370             : static struct option_type level_indent_optype[] = {
     371             :      { "begin", 1, LEVEL_BEGIN },
     372             :      { "start", 1, LEVEL_BEGIN },
     373             :      { "0", 1, LEVEL_INDENT0 },
     374             :      { "1", 1, LEVEL_INDENT1 },
     375             :      { "end0", 4, LEVEL_END0 },
     376             :      { "end1", 4, LEVEL_END1 },
     377             : };
     378             : 
     379             : static void
     380          28 : parse_level_string(const char *str, char **return_ptr)
     381             : {
     382             :      static char text[MAXLEVELINDENT];
     383             :      char *p;
     384             :      int i, c, num;
     385             :     
     386          28 :      p = text;
     387          28 :      memset(text, ' ', sizeof(text));
     388          28 :      text[sizeof(text)-1] = 0;
     389             :      
     390         112 :      while (*str) {
     391          56 :           switch (*str) {
     392             :           case '\\':
     393           7 :                switch (*++str) {
     394             :                case 'a':
     395           0 :                     *p++ = '\a';
     396           0 :                     break;
     397             :                case 'b':
     398           0 :                     *p++ = '\b';
     399           0 :                     break;
     400             :                case 'e':
     401           0 :                     *p++ = '\033';
     402           0 :                     break;
     403             :                case 'f':
     404           0 :                     *p++ = '\f';
     405           0 :                     break;
     406             :                case 'n':
     407           0 :                     *p++ = '\n';
     408           0 :                     break;
     409             :                case 'r':
     410           0 :                     *p++ = '\r';
     411           0 :                     break;
     412             :                case 't':
     413           0 :                     *p++ = '\t';
     414           0 :                     break;
     415             :                case 'x':
     416             :                case 'X':
     417           0 :                     ++str;
     418           0 :                     *p++ = number(&str,16,2);
     419           0 :                     break;
     420             :                case '0':
     421           0 :                     ++str;
     422           0 :                     *p++ = number(&str,8,3);
     423           0 :                     break;
     424             :                default:
     425           7 :                     *p++ = *str;
     426             :                }
     427           7 :                ++str;
     428           7 :                break;
     429             :           case 'x':
     430           0 :                if (p == text) {
     431           0 :                     goto copy;
     432             :                }
     433           0 :                num = strtol(str+1, (char**)&str, 10);
     434           0 :                c = p[-1];
     435           0 :                for (i = 1; i < num; i++) {
     436           0 :                     *p++ = c;
     437           0 :                     if (*p == 0) {
     438           0 :                          error(1, 0, _("level indent string is too long"));
     439           0 :                          return;
     440             :                     }
     441             :                }
     442           0 :                break;
     443             :           default:
     444             :           copy:
     445          49 :                *p++ = *str++;
     446          49 :                if (*p == 0) {
     447           0 :                     error(1, 0, _("level indent string is too long"));
     448           0 :                     return;
     449             :                }
     450             :           }
     451             :      }
     452          28 :      *p = 0;
     453          28 :      *return_ptr = strdup(text);
     454             : }
     455             : 
     456             : static void
     457          43 : set_level_indent(const char *str)
     458             : {
     459             :      long n;
     460             :      const char *p;
     461             :      char *q;
     462             :      
     463          43 :      n = strtol(str, &q, 0);
     464          43 :      if (*q == 0 && n > 0) {
     465          15 :           char *s = xmalloc(n+1);
     466          15 :           memset(s, ' ', n-1);
     467          15 :           s[n-1] = 0;
     468          15 :           level_indent[0] = level_indent[1] = s;
     469          30 :           return;
     470             :      }
     471             :      
     472          28 :      p = str;
     473         126 :      while (*p != '=') {
     474          70 :           if (*p == 0) {
     475           0 :                error(1, 0, _("level-indent syntax"));
     476           0 :                return;
     477             :           }
     478          70 :           p++;
     479             :      }
     480          28 :      ++p;
     481             :     
     482          28 :      switch (find_option_type(level_indent_optype, str, p - str - 1)) {
     483             :      case LEVEL_BEGIN:
     484           0 :           parse_level_string(p, &level_begin);
     485           0 :           break;
     486             :      case LEVEL_INDENT0:
     487           7 :           parse_level_string(p, &level_indent[0]);
     488           7 :           break;
     489             :      case LEVEL_INDENT1:
     490           7 :           parse_level_string(p, &level_indent[1]);
     491           7 :           break;
     492             :      case LEVEL_END0:
     493           7 :           parse_level_string(p, &level_end[0]);
     494           7 :           break;
     495             :      case LEVEL_END1:
     496           7 :           parse_level_string(p, &level_end[1]);
     497           7 :           break;
     498             :      default:
     499           0 :           error(1, 0, _("unknown level indent option: %s"), str);
     500             :      }
     501             : }
     502             : 
     503             : static void
     504         229 : add_name(const char *name)
     505             : {
     506         229 :      linked_list_append(&arglist, (void*) name);
     507         229 : }
     508             : 
     509             : static void
     510           0 : add_preproc_option(int key, const char *arg)
     511             : {
     512           0 :      char *opt = xmalloc(3 + strlen(arg));
     513           0 :      sprintf(opt, "-%c%s", key, arg);
     514           0 :      add_name(opt);
     515           0 :      preprocess_option = 1;
     516           0 : }
     517             : 
     518             : static error_t
     519         552 : parse_opt (int key, char *arg, struct argp_state *state)
     520             : {
     521             :      int num;
     522             :      
     523         552 :      switch (key) {
     524             :      case 'a':
     525          15 :           strict_ansi = 1;
     526          15 :           break;
     527             :      case OPT_NO_ANSI:
     528           0 :           strict_ansi = 0;
     529           0 :           break;
     530             :      case OPT_DEBUG:
     531          15 :           debug = arg ? atoi(arg) : 1;
     532          15 :           break;
     533             :      case 'P':
     534           0 :           set_print_option(arg);
     535           0 :           break;
     536             :      case 'S':
     537           6 :           use_indentation = 1;
     538           6 :           break;
     539             :      case OPT_NO_USE_INDENTATION:
     540           0 :           use_indentation = 0;
     541           0 :           break;
     542             :      case 'T':
     543           7 :           print_as_tree = 1;
     544           7 :           set_level_indent("0=  "); /* two spaces */
     545           7 :           set_level_indent("1=| ");
     546           7 :           set_level_indent("end0=+-");
     547           7 :           set_level_indent("end1=\\\\-");
     548           7 :           break;
     549             :      case OPT_NO_TREE:
     550           0 :           print_as_tree = 0;
     551           0 :           level_indent[0] = level_indent[1] = NULL;
     552           0 :           level_end[0] = level_end[0] = NULL;
     553           0 :           break;
     554             :      case 'b':
     555          15 :           brief_listing = 1;
     556          15 :           break;
     557             :      case OPT_NO_BRIEF:
     558           0 :           brief_listing = 0;
     559           0 :           break;
     560             :      case 'd':
     561          15 :           max_depth = atoi(arg);
     562          15 :           if (max_depth < 0)
     563           0 :                max_depth = 0;
     564          15 :           break;
     565             :      case OPT_DEFINES: /* FIXME: Not used. */
     566           0 :           record_defines = 1;
     567           0 :           break;
     568             :      case OPT_EMACS:
     569           1 :           emacs_option = 1;
     570           1 :           break;
     571             :      case OPT_NO_EMACS:
     572           0 :           emacs_option = 0;
     573           0 :           break;
     574             :      case 'f':
     575          15 :           if (select_output_driver(arg))
     576           0 :                argp_error(state, _("%s: No such output driver"), optarg);
     577          15 :           output_init();
     578          15 :           break;
     579             :      case OPT_LEVEL_INDENT:
     580          15 :           set_level_indent(arg);
     581          15 :           break;
     582             :      case 'i':
     583          52 :           num = 1;
     584         104 :           for (; *arg; arg++) 
     585          52 :                switch (*arg) {
     586             :                case '-':
     587             :                case '^':
     588           0 :                     num = 0;
     589           0 :                     break;
     590             :                case '+':
     591           0 :                     num = 1;
     592           0 :                     break;
     593             :                case 'x':
     594             :                case '_':
     595             :                case 's':
     596             :                case 't':
     597             :                case 'u':
     598          52 :                     if (num)
     599          52 :                          SYMBOL_INCLUDE(*arg);
     600             :                     else
     601           0 :                          SYMBOL_EXCLUDE(*arg);
     602          52 :                     break;
     603             :                default:
     604           0 :                     argp_error(state, _("Unknown symbol class: %c"), *arg);
     605             :                }
     606          52 :           break;
     607             :      case OPT_OMIT_ARGUMENTS:
     608           9 :           omit_arguments_option = 1;
     609           9 :           break;
     610             :      case OPT_NO_OMIT_ARGUMENTS:
     611           0 :           omit_arguments_option = 0;
     612           0 :           break;
     613             :      case OPT_OMIT_SYMBOL_NAMES:
     614           8 :           omit_symbol_names_option = 1;
     615           8 :           break;
     616             :      case OPT_NO_OMIT_SYMBOL_NAMES:
     617           0 :           omit_symbol_names_option = 0;
     618           0 :           break;
     619             :      case 'l':
     620           4 :           print_levels = 1;
     621           4 :           break;
     622             :      case OPT_NO_PRINT_LEVEL:
     623           0 :           print_levels = 0;
     624           0 :           break;
     625             :      case 'm':
     626          11 :           start_name = strdup(arg);
     627          11 :           break;
     628             :      case 'n':
     629          10 :           print_line_numbers = 1;
     630          10 :           break;
     631             :      case OPT_NO_NUMBER:
     632           0 :           print_line_numbers = 0;
     633           0 :           break;
     634             :      case 'o':
     635          20 :           outname = strdup(arg);
     636          20 :           break;
     637             :      case 'p':
     638           7 :           num = atoi(arg);
     639           7 :           if (num > 0)
     640           7 :                token_stack_length = num;
     641           7 :           break;
     642             :      case 'r':
     643           0 :           reverse_tree = 1;
     644           0 :           break;
     645             :      case OPT_NO_REVERSE:
     646           0 :           reverse_tree = 0;
     647           0 :           break;
     648             :      case 's':
     649           5 :           symbol_override(arg);
     650           5 :           break;
     651             :      case 'v':
     652           2 :           verbose = 1;
     653           2 :           break;
     654             :      case OPT_NO_VERBOSE:
     655           0 :           verbose = 0;
     656           0 :           break;
     657             :      case 'x':
     658           5 :           print_option = PRINT_XREF;
     659           5 :           break;
     660             :      case OPT_PREPROCESS:
     661           0 :           preprocess_option = 1;
     662           0 :           set_preprocessor(arg ? arg : CFLOW_PREPROC);
     663           0 :           break;
     664             :      case OPT_NO_PREPROCESS:
     665           0 :           preprocess_option = 0;
     666           0 :           break;
     667             :      case ARGP_KEY_ARG:
     668         229 :           add_name(arg);
     669         229 :           break;
     670             :      case 'I':
     671             :      case 'D':
     672             :      case 'U':
     673           0 :           add_preproc_option(key, arg);
     674           0 :           break;
     675             :      default:
     676          86 :           return ARGP_ERR_UNKNOWN;
     677             :      }
     678         466 :      return 0;
     679             : }
     680             : 
     681             : static struct argp argp = {
     682             :      options,
     683             :      parse_opt,
     684             :      N_("[FILE]..."),
     685             :      doc,
     686             :      NULL,
     687             :      NULL,
     688             :      NULL
     689             : };
     690             : 
     691             : int
     692        5333 : globals_only()
     693             : {
     694        5333 :      return !(symbol_map & SM_STATIC);
     695             : }
     696             : 
     697             : int
     698       74172 : include_symbol(Symbol *sym)
     699             : {
     700       74172 :      int type = 0;
     701             :      
     702       74172 :      if (!sym)
     703           0 :           return 0;
     704             :      
     705       74172 :      if (sym->type == SymIdentifier) {
     706       72983 :           if (sym->name[0] == '_' && !(symbol_map & SM_UNDERSCORE))
     707        1186 :                return 0;
     708             : 
     709       71797 :           if (sym->storage == StaticStorage)
     710        4167 :                type |= SM_STATIC;
     711       71797 :           if (sym->arity == -1 && sym->storage != AutoStorage)
     712       47447 :                type |= SM_DATA;
     713       24350 :           else if (sym->arity >= 0)
     714       24350 :                type |= SM_FUNCTIONS;
     715             : 
     716       71797 :           if (!sym->source)
     717       47308 :                type |= SM_UNDEFINED;
     718             :           
     719        1189 :      } else if (sym->type == SymToken) {
     720        1189 :           if (sym->token_type == TYPE && sym->source)
     721           0 :                type |= SM_TYPEDEF;
     722             :           else
     723        1189 :                return 0;
     724             :      }
     725       71797 :      return (symbol_map & type) == type;
     726             : }
     727             : 
     728             : void
     729           0 : xalloc_die(void)
     730             : {
     731           0 :      error(1, ENOMEM, _("Exiting"));
     732           0 : }
     733             : 
     734             : void
     735          21 : init()
     736             : {
     737          21 :      if (level_indent[0] == NULL) 
     738           3 :           level_indent[0] = "    "; /* 4 spaces */
     739          21 :      if (level_indent[1] == NULL)
     740           3 :           level_indent[1] = level_indent[0];
     741          21 :      if (level_end[0] == NULL)
     742           0 :           level_end[0] = "";
     743          21 :      if (level_end[1] == NULL)
     744           0 :           level_end[1] = "";
     745             :      
     746          21 :      init_lex(debug > 1);
     747          21 :      init_parse();
     748          21 : }
     749             : 
     750             : const char version_etc_copyright[] =
     751             :   /* Do *not* mark this string for translation.  %s is a copyright
     752             :      symbol suitable for this locale, and %d is the copyright
     753             :      year.  */
     754             :   "Copyright %s 2005, 2006, 2009, 2010, 2011 %d Sergey Poznyakoff";
     755             : 
     756             : int
     757          23 : main(int argc, char **argv)
     758             : {
     759             :      int index;
     760             : 
     761          23 :      set_program_name(argv[0]);
     762          23 :      argp_version_setup("cflow", program_authors);
     763             :      
     764          23 :      setlocale(LC_ALL, "");
     765          23 :      bindtextdomain(PACKAGE, LOCALEDIR);
     766          23 :      textdomain(PACKAGE);
     767             :      
     768          23 :      register_output("gnu", gnu_output_handler, NULL);
     769          23 :      register_output("posix", posix_output_handler, NULL);
     770             : 
     771          23 :      symbol_map = SM_FUNCTIONS|SM_STATIC|SM_UNDEFINED;
     772             : 
     773          23 :      if (getenv("POSIXLY_CORRECT")) {
     774           0 :           if (select_output_driver("posix"))
     775           0 :                error(1, 0, _("%s: No such output driver"), "posix");
     776           0 :           output_init();
     777             :      }
     778             :      
     779          23 :      sourcerc(&argc, &argv);
     780          23 :      if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &index, NULL))
     781           0 :           exit(1);
     782             : 
     783          21 :      if (print_option == 0)
     784          16 :           print_option = PRINT_TREE;
     785             : 
     786          21 :      init();
     787             : 
     788          21 :      if (arglist) {
     789             :           struct linked_list_entry *p;
     790             : 
     791         250 :           for (p = arglist->head; p; p = p->next) {
     792         229 :                char *s = (char*)p->data;
     793         229 :                if (s[0] == '-')
     794           0 :                     pp_option(s);
     795         229 :                else if (source(s) == 0)
     796         229 :                     yyparse();
     797             :           }
     798             :      }
     799             :      
     800          21 :      argc -= index;
     801          21 :      argv += index;
     802             : 
     803          42 :      while (argc--) {
     804           0 :           if (source(*argv++) == 0)
     805           0 :                yyparse();
     806             :      }
     807             : 
     808          21 :      if (input_file_count == 0)
     809           0 :              error(1, 0, _("no input files"));
     810             : 
     811          21 :      output();
     812          21 :      return 0;
     813             : }
     814             : 
     815             : 
     816             : 
     817             : 
     818             : 
     819             : 
     820             : 

Generated by: LCOV version 1.10