FIX: missing paren
[sxemacs] / lib-src / ootags.c
index 64260fd..bb6fcf9 100644 (file)
@@ -174,6 +174,14 @@ void oo_browser_check_and_clear_structtype(void);
 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
 #endif
 
+#define xstrncpy(d_,s_,l_)                     \
+       do {                                    \
+               char* dst_=d_;                  \
+               dst_[0]='\0';                   \
+               strncat((dst_),(s_),(l_)-1);    \
+       } while(0)
+
+
 typedef int bool;
 
 typedef void Lang_function(FILE *);
@@ -298,8 +306,6 @@ char *skip_spaces PP((char *cp));
 char *skip_non_spaces PP((char *cp));
 char *savenstr PP((char *cp, int len));
 char *savestr PP((char *cp));
-char *etags_strchr PP((char *sp, int c));
-char *etags_strrchr PP((char *sp, int c));
 char *etags_getcwd PP((void));
 char *relative_filename PP((char *file, char *dir));
 char *absolute_filename PP((char *file, char *dir));
@@ -310,6 +316,55 @@ void grow_linebuffer PP((linebuffer * lbp, int toksize));
 long *xmalloc PP((unsigned int size));
 long *xrealloc PP((char *ptr, unsigned int size));
 \f
+#if HAVE_STRRCHR
+#define etags_strrchr strrchr
+#else
+/*
+ * Return the ptr in sp at which the character c last
+ * appears; NULL if not found
+ *
+ * Identical to POSIX strrchr, included for portability.
+ */
+static char *
+etags_strrchr (sp, c)
+register const char *sp;
+register int c;
+{
+       register const char *r;
+
+       r = NULL;
+       do
+       {
+               if (*sp == c)
+                       r = sp;
+       } while (*sp++);
+       return (char *)r;
+}
+#endif
+
+#if HAVE_STRCHR
+#define etags_strchr strchr
+#else
+/*
+ * Return the ptr in sp at which the character c first
+ * appears; NULL if not found
+ *
+ * Identical to POSIX strchr, included for portability.
+ */
+static char *
+etags_strchr (sp, c)
+register const char *sp;
+register int c;
+{
+       do
+       {
+               if (*sp == c)
+                       return (char *)sp;
+       } while (*sp++);
+       return NULL;
+}
+#endif
+\f
 char searchar = '/';           /* use /.../ searches */
 
 char *tagfile;                 /* output file */
@@ -572,31 +627,31 @@ Relative ones are stored relative to the output file's directory.");
        puts("\n");
 
        puts("-a, --append\n\
-        Append tag entries to existing tags file.");
+       Append tag entries to existing tags file.");
 
        if (CTAGS)
                puts("-B, --backward-search\n\
-        Write the search commands for the tag entries using '?', the\n\
-        backward-search command instead of '/', the forward-search command.");
+       Write the search commands for the tag entries using '?', the\n\
+       backward-search command instead of '/', the forward-search command.");
 
        puts("-C, --c++\n\
-        Treat files whose name suffix defaults to C language as C++ files.");
+       Treat files whose name suffix defaults to C language as C++ files.");
 
        if (CTAGS)
                puts("-d, --defines\n\
-        Create tag entries for C #define constants and enum constants, too.");
+       Create tag entries for C #define constants and enum constants, too.");
        else
                puts("-D, --no-defines\n\
-        Don't create tag entries for C #define constants and enum constants.\n\
+       Don't create tag entries for C #define constants and enum constants.\n\
        This makes the tags file smaller.");
 
        if (!CTAGS) {
                puts("-i FILE, --include=FILE\n\
-        Include a note in tag file indicating that, when searching for\n\
-        a tag, one should also consult the tags file FILE after\n\
-        checking the current file.");
+       Include a note in tag file indicating that, when searching for\n\
+       a tag, one should also consult the tags file FILE after\n\
+       checking the current file.");
                puts("-l LANG, --language=LANG\n\
-        Force the following files to be considered as written in the\n\
+       Force the following files to be considered as written in the\n\
        named language up to the next --language=LANG option.");
        }
 
@@ -612,58 +667,58 @@ Relative ones are stored relative to the output file's directory.");
 
 #ifdef ETAGS_REGEXPS
        puts("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
-        Make a tag for each line matching pattern REGEXP in the\n\
-       following files.  regexfile is a file containing one REGEXP\n\
+       Make a tag for each line matching pattern REGEXP in the\n\
+       following files.  regexfile is a file containing one REGEXP\n\
        per line.  REGEXP is anchored (as if preceded by ^).\n\
        The form /REGEXP/NAME/ creates a named tag.  For example Tcl\n\
        named tags can be created with:\n\
        --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
        puts("-R, --no-regex\n\
-        Don't create tags from regexps for the following files.");
+       Don't create tags from regexps for the following files.");
 #endif                         /* ETAGS_REGEXPS */
        puts("-o FILE, --output=FILE\n\
-        Write the tags to FILE.");
+       Write the tags to FILE.");
 #ifdef OO_BROWSER
        puts("-O, --oo-browser\n\
        Generate a specialized tags format used only by the Altrasoft OO-Browser.");
 #endif
        puts("-I, --ignore-indentation\n\
-        Don't rely on indentation quite as much as normal.  Currently,\n\
-        this means not to assume that a closing brace in the first\n\
-        column is the final brace of a function or structure\n\
-        definition in C and C++.");
+       Don't rely on indentation quite as much as normal.  Currently,\n\
+       this means not to assume that a closing brace in the first\n\
+       column is the final brace of a function or structure\n\
+       definition in C and C++.");
 
        if (CTAGS) {
                puts("-t, --typedefs\n\
-        Generate tag entries for C typedefs.");
+       Generate tag entries for C typedefs.");
                puts("-T, --typedefs-and-c++\n\
-        Generate tag entries for C typedefs, C struct/enum/union tags,\n\
-        and C++ member functions.");
+       Generate tag entries for C typedefs, C struct/enum/union tags,\n\
+       and C++ member functions.");
                puts("-u, --update\n\
-        Update the tag entries for the given files, leaving tag\n\
-        entries for other files in place.  Currently, this is\n\
-        implemented by deleting the existing entries for the given\n\
-        files and then rewriting the new entries at the end of the\n\
-        tags file.  It is often faster to simply rebuild the entire\n\
-        tag file than to use this.");
+       Update the tag entries for the given files, leaving tag\n\
+       entries for other files in place.  Currently, this is\n\
+       implemented by deleting the existing entries for the given\n\
+       files and then rewriting the new entries at the end of the\n\
+       tags file.  It is often faster to simply rebuild the entire\n\
+       tag file than to use this.");
                puts("-v, --vgrind\n\
-        Generates an index of items intended for human consumption,\n\
-        similar to the output of vgrind.  The index is sorted, and\n\
-        gives the page number of each item.");
+       Generates an index of items intended for human consumption,\n\
+       similar to the output of vgrind.  The index is sorted, and\n\
+       gives the page number of each item.");
                puts("-w, --no-warn\n\
-        Suppress warning messages about entries defined in multiple\n\
-        files.");
+       Suppress warning messages about entries defined in multiple\n\
+       files.");
                puts("-x, --cxref\n\
-        Like --vgrind, but in the style of cxref, rather than vgrind.\n\
-        The output uses line numbers instead of page numbers, but\n\
-        beyond that the differences are cosmetic; try both to see\n\
-        which you like.");
+       Like --vgrind, but in the style of cxref, rather than vgrind.\n\
+       The output uses line numbers instead of page numbers, but\n\
+       beyond that the differences are cosmetic; try both to see\n\
+       which you like.");
        }
 
        puts("-V, --version\n\
-        Print the version of the program.\n\
+       Print the version of the program.\n\
 -h, --help\n\
-        Print this help message.");
+       Print this help message.");
 
        print_language_names();
 
@@ -832,7 +887,7 @@ int main(int argc, char *argv[])
        /*
         * If etags, always find typedefs and structure tags.  Why not?
         * Also default is to find macro constants, enum constants and
-        * global variables. 
+        * global variables.
         */
        if (!CTAGS) {
                typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
@@ -897,8 +952,8 @@ int main(int argc, char *argv[])
                case 'o':
                        if (tagfile) {
                                /* convert char to string, to call error with */
-                               char buf[2];
-                               sprintf(buf, "%c", opt);
+                               char buf[]=" ";
+                               buf[0]=opt;
                                error("-%s option may only be given once.",
                                      buf);
                                suggest_asking_for_help();
@@ -1094,12 +1149,15 @@ if (cxref_style) {
 
 if (update) {
        char cmd[BUFSIZ];
+       int sz;
        for (i = 0; i < current_arg; ++i) {
                if (argbuffer[i].arg_type != at_filename)
                        continue;
-               sprintf(cmd,
-                       "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
-                       tagfile, argbuffer[i].what, tagfile);
+               sz = snprintf(cmd, sizeof(cmd),
+                             "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
+                             tagfile, argbuffer[i].what, tagfile);
+               if(sz >= 0 && (size_t)sz < sizeof(cmd))
+                       fatal("failed to build shell command line", (char *)NULL);
                if (system(cmd) != GOOD)
                        fatal("failed to execute shell command", (char *)NULL);
        }
@@ -1114,7 +1172,9 @@ fclose(tagf);
 
 if (update) {
        char cmd[BUFSIZ];
-       sprintf(cmd, "sort %s -o %s", tagfile, tagfile);
+       int sz = snprintf(cmd, sizeof(cmd), "sort %s -o %s", tagfile, tagfile);
+       if(sz >= 0 && (size_t)sz < sizeof(cmd))
+               fatal("failed to build sort command line", (char *)NULL);
        exit(system(cmd));
 }
 return GOOD;
@@ -1191,15 +1251,17 @@ char *file;
        FILE *inf;
 
        canonicalize_filename(file);
-       if (stat(file, &stat_buf) == 0 && !S_ISREG(stat_buf.st_mode)) {
-               error("skipping %s: it is not a regular file.", file);
-               return;
-       }
        if (streq(file, tagfile) && !streq(tagfile, "-")) {
                error("skipping inclusion of %s in self.", file);
                return;
        }
        inf = fopen(file, "r");
+       if (stat(file, &stat_buf) == 0 && !S_ISREG(stat_buf.st_mode)) {
+               error("skipping %s: it is not a regular file.", file);
+               if( inf != NULL)
+                       fclose(inf);
+               return;
+       }
        if (inf == NULL) {
                perror(file);
                return;
@@ -1713,32 +1775,32 @@ struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
 import,                C_JAVA, st_C_ignore
 package,       C_JAVA, st_C_ignore
 friend,                C_PLPL, st_C_ignore
-extends,       C_JAVA, st_C_javastruct
-implements,    C_JAVA, st_C_javastruct
+extends,       C_JAVA, st_C_javastruct
+implements,    C_JAVA, st_C_javastruct
 interface,     C_JAVA, st_C_struct
-class,         C_PLPL, st_C_class
+class, C_PLPL, st_C_class
 namespace,     C_PLPL, st_C_struct
-domain,        C_STAR, st_C_struct
-union,         0,      st_C_union
-struct,        0,      st_C_struct
-enum,          0,      st_C_enum
-typedef,       0,      st_C_typedef
-define,        0,      st_C_define
+domain,        C_STAR, st_C_struct
+union, 0,      st_C_union
+struct,        0,      st_C_struct
+enum,  0,      st_C_enum
+typedef,       0,      st_C_typedef
+define,        0,      st_C_define
 inline,                0,      st_C_inline
 bool,          C_PLPL, st_C_typespec
-long,          0,      st_C_typespec
-short,         0,      st_C_typespec
-int,           0,      st_C_typespec
-char,          0,      st_C_typespec
-float,         0,      st_C_typespec
-double,        0,      st_C_typespec
-signed,        0,      st_C_typespec
+long,  0,      st_C_typespec
+short, 0,      st_C_typespec
+int,   0,      st_C_typespec
+char,  0,      st_C_typespec
+float, 0,      st_C_typespec
+double,        0,      st_C_typespec
+signed,        0,      st_C_typespec
 unsigned,      0,      st_C_typespec
-auto,          0,      st_C_typespec
-void,          0,      st_C_typespec
-extern,        0,      st_C_extern
-static,        0,      st_C_typespec
-const,         0,      st_C_const
+auto,  0,      st_C_typespec
+void,  0,      st_C_typespec
+extern,        0,      st_C_extern
+static,        0,      st_C_typespec
+const, 0,      st_C_const
 volatile,      0,      st_C_typespec
 explicit,      C_PLPL, st_C_typespec
 mutable,       C_PLPL, st_C_typespec
@@ -2044,7 +2106,7 @@ void oo_browser_clear_some_globals(void)
  * consider_token ()
  *     checks to see if the current token is at the start of a
  *     function or variable, or corresponds to a typedef, or
- *     is a struct/union/enum tag, or #define, or an enum constant.
+ *     is a struct/union/enum tag, or #define, or an enum constant.
  *
  *     *IS_FUNC gets TRUE iff the token is a function or #define macro
  *     with args.  C_EXT is which language we are looking at.
@@ -2380,7 +2442,7 @@ bool *is_func_or_var;             /* OUT: function or variable found */
                        objdef = omethodtag;
                        methodlen = len;
                        grow_linebuffer(&token_name, methodlen + 1);
-                       strncpy(token_name.buffer, str, len);
+                       xstrncpy(token_name.buffer, str, methodlen+1);
                        token_name.buffer[methodlen] = '\0';
                        token_name.len = methodlen;
                        return TRUE;
@@ -2463,8 +2525,8 @@ bool *is_func_or_var;             /* OUT: function or variable found */
 /*
  * C_entries ()
  *     This routine finds functions, variables, typedefs,
- *     #define's, enum constants and struct/union/enum definitions in
- *     #C syntax and adds them to the list.
+ *     #define's, enum constants and struct/union/enum definitions in
+ *     #C syntax and adds them to the list.
  */
 #define current_lb_is_new (newndx == curndx)
 #define switch_line_buffers() (curndx = 1 - curndx)
@@ -2822,17 +2884,13 @@ FILE *inf;                      /* input file */
                                                                    (&token_name,
                                                                     toklen +
                                                                     1);
-                                                               strncpy
+                                                               xstrncpy
                                                                    (token_name.
                                                                     buffer,
                                                                     newlb.
                                                                     buffer +
                                                                     tokoff,
-                                                                    toklen);
-                                                               token_name.
-                                                                   buffer
-                                                                   [toklen] =
-                                                                   '\0';
+                                                                    toklen + 1);
                                                                token_name.len =
                                                                    toklen;
                                                                /* Name macros. */
@@ -2844,11 +2902,11 @@ FILE *inf;                      /* input file */
                                                                     == tend
 #ifdef OO_BROWSER
                                                                     /* Also name #define constants,
-                                                                       enumerations and enum_labels.
-                                                                       Conditionalize `funorvar' reference
-                                                                       here or #defines will appear without
-                                                                       their #names.
-                                                                       -- Bob Weiner, Altrasoft, 4/25/1998 */
+                                                                       enumerations and enum_labels.
+                                                                       Conditionalize `funorvar' reference
+                                                                       here or #defines will appear without
+                                                                       their #names.
+                                                                       -- Bob Weiner, Altrasoft, 4/25/1998 */
                                                                     ||
                                                                     ((oo_browser_format || funorvar)
                                                                      &&
@@ -3479,6 +3537,7 @@ FILE *inf;
 
        LOOP_ON_INPUT_LINES(inf, lb, dummy)
            continue;
+       (void)dummy; // Silence set-not-read warning.
 }
 \f
 /* Fortran parsing */
@@ -3896,7 +3955,7 @@ FILE *inf;
 
                        /* save all values for later tagging */
                        grow_linebuffer(&tline, lb.len + 1);
-                       strcpy(tline.buffer, lb.buffer);
+                       xstrncpy(tline.buffer, lb.buffer, lb.len + 1);
                        save_lineno = lineno;
                        save_lcno = linecharno;
 
@@ -4253,7 +4312,7 @@ char *cp;
  * Prolog support (rewritten) by Anders Lindgren, Mar. 96
  *
  * Assumes that the predicate starts at column 0.
- * Only the first clause of a predicate is added. 
+ * Only the first clause of a predicate is added.
  */
 int prolog_pred PP((char *s, char *last));
 void prolog_skip_comment PP((linebuffer * plb, FILE * inf));
@@ -4285,10 +4344,10 @@ FILE *inf;
                        else if (len + 1 > allocated)
                                last = xrnew(last, len + 1, char);
                        allocated = len + 1;
-                       strncpy(last, cp, len);
-                       last[len] = '\0';
+                       xstrncpy(last, cp, allocated);
                }
        }
+       free(last);
 }
 
 void prolog_skip_comment(plb, inf)
@@ -4394,7 +4453,7 @@ int pos;
                return -1;
 }
 \f
-/* 
+/*
  * Support for Erlang  --  Anders Lindgren, Feb 1996.
  *
  * Generates tags for functions, defines, and records.
@@ -4427,9 +4486,10 @@ FILE *inf;
                        continue;
                else if (cp[0] == '-') {        /* attribute, e.g. "-define" */
                        erlang_attribute(cp);
+                       free(last);
                        last = NULL;
                } else if ((len = erlang_func(cp, last)) > 0) {
-                       /* 
+                       /*
                         * Function.  Store the function name so that we only
                         * generates a tag for the first clause.
                         */
@@ -4438,10 +4498,10 @@ FILE *inf;
                        else if (len + 1 > allocated)
                                last = xrnew(last, len + 1, char);
                        allocated = len + 1;
-                       strncpy(last, cp, len);
-                       last[len] = '\0';
+                       xstrncpy(last, cp, allocated);
                }
        }
+       free(last);
 }
 
 /*
@@ -4480,7 +4540,7 @@ char *last;                       /* Name of last clause. */
 }
 
 /*
- * Handle attributes.  Currently, tags are generated for defines 
+ * Handle attributes.  Currently, tags are generated for defines
  * and records.
  *
  * They are on the form:
@@ -4593,9 +4653,10 @@ char *name;
 void analyse_regex(regex_arg)
 char *regex_arg;
 {
-       if (regex_arg == NULL)
+       if (regex_arg == NULL) {
                free_patterns();        /* --no-regex: remove existing regexps */
-
+               return;
+       }
        /* A real --regexp option or a line in a regexp file. */
        switch (regex_arg[0]) {
                /* Comments in regexp file or null arg to --regex. */
@@ -4728,17 +4789,21 @@ struct re_registers *regs;
                        size -= 1;
 
        /* Allocate space and do the substitutions. */
-       result = xnew(size + 1, char);
+       size_t avail = size + 1;
+       result = xnew(avail, char);
 
        for (t = result; *out != '\0'; out++)
                if (*out == '\\' && isdigit(*++out)) {
                        /* Using "dig2" satisfies my debugger.  Bleah. */
                        dig = *out - '0';
                        diglen = regs->end[dig] - regs->start[dig];
-                       strncpy(t, in + regs->start[dig], diglen);
+                       xstrncpy(t, in + regs->start[dig], avail);
                        t += diglen;
-               } else
+                       avail -= diglen;
+               } else {
                        *t++ = *out;
+                       avail --;
+               }
        *t = '\0';
 
        if (DEBUG && (t > result + size || t - result != strlen(result)))
@@ -4906,48 +4971,11 @@ int len;
        register char *dp;
 
        dp = xnew(len + 1, char);
-       strncpy(dp, cp, len);
+       xstrncpy(dp, cp, len+1);
        dp[len] = '\0';
        return dp;
 }
 
-/*
- * Return the ptr in sp at which the character c last
- * appears; NULL if not found
- *
- * Identical to System V strrchr, included for portability.
- */
-char *etags_strrchr(sp, c)
-register char *sp;
-register int c;
-{
-       register char *r;
-
-       r = NULL;
-       do {
-               if (*sp == c)
-                       r = sp;
-       } while (*sp++);
-       return r;
-}
-
-/*
- * Return the ptr in sp at which the character c first
- * appears; NULL if not found
- *
- * Identical to System V strchr, included for portability.
- */
-char *etags_strchr(sp, c)
-register char *sp;
-register int c;
-{
-       do {
-               if (*sp == c)
-                       return sp;
-       } while (*sp++);
-       return NULL;
-}
-
 /* Skip spaces, return new pointer. */
 char *skip_spaces(cp)
 char *cp;
@@ -5059,6 +5087,7 @@ char *file, *dir;
 {
        char *fp, *dp, *afn, *res;
        int i;
+       ssize_t res_left;
 
        /* Find the common root of file and dir (with a trailing slash). */
        afn = absolute_filename(file, cwd);
@@ -5076,13 +5105,14 @@ char *file, *dir;
        i = 0;
        while ((dp = etags_strchr(dp + 1, '/')) != NULL)
                i += 1;
-       res = xnew(3 * i + strlen(fp) + 1, char);
+       res_left = 3 * i + strlen(fp);
+       res = xnew( res_left + 1, char);
        res[0] = '\0';
-       while (i-- > 0)
-               strcat(res, "../");
+       for ( ; i-- > 0 ; res_left -= 4 )
+               strncat(res, "../", res_left );
 
        /* Add the file name relative to the common root of file and dir. */
-       strcat(res, fp);
+       strncat(res, fp, res_left);
        free(afn);
 
        return res;