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] */