## root/gtags-parser/gctags.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. get_lang_entry
2. usage
3. help
4. main
5. cmp
6. isnotfunction
7. dbg_print

    /*
     * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003, 2005
     *      Tama Communications Corporation
     *
     * This file is part of GNU GLOBAL.
     *
     * This program is free software: you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     */

    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #ifdef HAVE_LIMITS_H
    #include <limits.h>
    #endif
    #include <stdio.h>
    #ifdef STDC_HEADERS
    #include <stdlib.h>
    #endif
    #ifdef HAVE_STRING_H
    #include <string.h>
    #else
    #include <strings.h>
    #endif
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #include "getopt.h"

    #include "global.h"
    #include "gctags.h"
    #include "const.h"

    int main(int, char **);
    static void usage(void);
    static void help(void);

    struct words {
            const char *name;
            int val;
    };
    struct words *words;
    static int tablesize;

    static char *langmap;

    int bflag;                      /* -b: force level 1 block start */
    int eflag;                      /* -e: force level 1 block end */
    int nflag;                      /* -n: doen't print tag */
    int qflag;                      /* -q: quiet mode */
    int rflag;                      /* -r: function reference */
    int sflag;                      /* -s: collect symbols */
    int wflag;                      /* -w: warning message */
    int vflag;                      /* -v: verbose mode */
    int show_version;
    int show_help;
    int debug;

    /*----------------------------------------------------------------------*/
    /* Parser switch                                                        */
    /*----------------------------------------------------------------------*/
    /*
     * This is the linkage section of each parsers.
     * If you want to support new language, you must define parser procedure
     * which requires file name as an argument.
     */
    struct lang_entry {
            const char *lang_name;
            void (*parser)(const char *);           /* parser procedure */
    };

    /*
     * The first entry is default language.
     */
    static struct lang_entry lang_switch[] = {
            /* lang_name    parser_proc     */
            {"c",           C},                     /* DEFAULT */
            {"yacc",        yacc},
            {"cpp",         Cpp},
            {"java",        java},
            {"php",         php},
            {"asm",         assembly}
    };
    #define DEFAULT_ENTRY &lang_switch[0]
    /*
     * get language entry.
     *
     *      i)      lang    language name (NULL means 'not specified'.)
     *      r)              language entry
     */
    static struct lang_entry *
    get_lang_entry(const char *lang)
    {
            int i, size = sizeof(lang_switch) / sizeof(struct lang_entry);

            /*
             * if language not specified, it assumes default language.
             */
            if (lang == NULL)
                    return DEFAULT_ENTRY;
            for (i = 0; i < size; i++)
                    if (!strcmp(lang, lang_switch[i].lang_name))
                            return &lang_switch[i];
            /*
             * if specified language not found, it assumes default language.
             */
            return DEFAULT_ENTRY;
    }

    static void
    usage(void)
    {
            fputs(usage_const, stderr);
            exit(2);
    }
    static void
    help(void)
    {
            fputs(usage_const, stdout);
            fputs(help_const, stdout);
            exit(0);
    }
    /*
     * Though the -d(--define) and -t(--typedef) option was removed,
     * the entries have been left not to bring error messages.
     */
    static struct option const long_options[] = {
            {"begin-block", no_argument, NULL, 'b'},
            {"define", no_argument, NULL, 'd'},
            {"end-block", no_argument, NULL, 'e'},
            {"no-tags", no_argument, NULL, 'n'},
            {"quiet", no_argument, NULL, 'q'},
            {"reference", no_argument, NULL, 'r'},
            {"symbol", no_argument, NULL, 's'},
            {"typedef", no_argument, NULL, 't'},
            {"verbose", no_argument, NULL, 'v'},
            {"warning", no_argument, NULL, 'w'},

            /* long name only */
            {"debug", no_argument, &debug, 1},
            {"langmap", required_argument, NULL, 0},
            {"version", no_argument, &show_version, 1},
            {"help", no_argument, &show_help, 1},
            { 0 }
    };

    int
    main(int argc, char **argv)
    {
            char *p;
            int optchar;
            int option_index = 0;

            while ((optchar = getopt_long(argc, argv, "bdenqrstvw", long_options, &option_index)) != EOF) {
                    switch(optchar) {
                    case 0:
                            p = (char *)long_options[option_index].name;
                            if (!strcmp(p, "langmap"))
                                    langmap = optarg;
                            break;
                    case 'b':
                            bflag++;
                            break;
                    case 'd':
                            break;
                    case 'e':
                            eflag++;
                            break;
                    case 'n':
                            nflag++;
                            break;
                    case 'q':
                            qflag++;
                            break;
                    case 'r':
                            rflag++;
                            sflag = 0;
                            break;
                    case 's':
                            sflag++;
                            rflag = 0;
                            break;
                    case 't':
                            break;
                    case 'v':
                            vflag++;
                            break;
                    case 'w':
                            wflag++;
                            break;
                    default:
                            usage();
                            /* NOTREACHED */
                    }
            }
            if (show_version)
                    version(NULL, vflag);
            else if (show_help)
                    help();
            /*
             * If langmap is not passed as argument, environment variable
             * GTAGSLANGMAP should be checked. Gtags(1) call gtags-parser
             * in this method.
             */
            if (langmap == NULL)
                    langmap = getenv("GTAGSLANGMAP");
            if (langmap == NULL)
                    langmap = DEFAULTLANGMAP;
            setup_langmap(langmap);

            argc -= optind;
            argv += optind;

            if (argc < 1)
                    usage();
            if (getenv("GTAGSWARNING"))
                    wflag++;
            /*
             * This is a hack for FreeBSD.
             * In the near future, it will be removed.
             */
    #ifdef __DJGPP__
            if (test("r", NOTFUNCTION) || test("r", DOS_NOTFUNCTION))
    #else
            if (test("r", NOTFUNCTION))
    #endif
            {
                    FILE *ip;
                    STRBUF *sb = strbuf_open(0);
                    STRBUF *ib = strbuf_open(0);
                    char *p;
                    int i;

                    if ((ip = fopen(NOTFUNCTION, "r")) == 0)
    #ifdef __DJGPP__
                            if ((ip = fopen(DOS_NOTFUNCTION, "r")) == 0)
    #endif
                            die("'%s' cannot read.", NOTFUNCTION);
                    for (tablesize = 0; (p = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL; tablesize++)
                            strbuf_puts0(sb, p);
                    fclose(ip);
                    words = (struct words *)check_malloc(sizeof(struct words) * tablesize);
                    /*
                     * Don't free *p.
                     */
                    p = (char *)check_malloc(strbuf_getlen(sb) + 1);
                    memcpy(p, strbuf_value(sb), strbuf_getlen(sb) + 1);
                    for (i = 0; i < tablesize; i++) {
                            words[i].name = p;
                            p += strlen(p) + 1;
                    }
                    qsort(words, tablesize, sizeof(struct words), cmp);
                    strbuf_close(sb);
                    strbuf_close(ib);
            }

            /*
             * pick up files and parse them.
             */
            for (; argc > 0; argv++, argc--) {
                    const char *lang, *suffix;
                    struct lang_entry *ent;

                    /* get suffix of the path. */
                    suffix = locatestring(argv[0], ".", MATCH_LAST);
                    if (!suffix)
                            continue;
                    lang = decide_lang(suffix);
                    if (lang == NULL)
                            continue;
                    if (vflag)
                            fprintf(stderr, "suffix '%s' assumed language '%s'.\n", suffix, lang);
                    /*
                     * Select parser.
                     * If lang == NULL then default parser is selected.
                     */
                    ent = get_lang_entry(lang);
                    /*
                     * call language specific parser.
                     */
                    ent->parser(argv[0]);
            }
            return 0;
    }

    int
    cmp(const void *s1, const void *s2)
    {
            return strcmp(((struct words *)s1)->name, ((struct words *)s2)->name);
    }

    int
    isnotfunction(char *name)
    {
            struct words tmp;
            struct words *result;

            if (words == NULL)
                    return 0;
            tmp.name = name;
            result = (struct words *)bsearch(&tmp, words, tablesize, sizeof(struct words), cmp);
            return (result != NULL) ? 1 : 0;
    }

    void
    dbg_print(int level, const char *s)
    {
            if (!debug)
                    return;
            fprintf(stderr, "[%04d]", lineno);
            for (; level > 0; level--)
                    fprintf(stderr, "    ");
            fprintf(stderr, "%s\n", s);
    }

/* [<][>][^][v][top][bottom][index][help] */