## root/libutil/conf.c(171.html)

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

## DEFINITIONS

This source file includes following definitions.

1. trim
2. readrecord
3. includelabel
4. configpath
5. openconf
6. getconfn
7. getconfs
8. getconfb
9. getconfline
10. closeconf

    /*
     * Copyright (c) 1998, 1999, 2000, 2001, 2002, 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
    #include <assert.h>
    #include <ctype.h>
    #ifdef STDC_HEADERS
    #include <stdlib.h>
    #endif
    #ifdef HAVE_STRING_H
    #include <string.h>
    #else
    #include <strings.h>
    #endif

    #include "gparam.h"
    #include "checkalloc.h"
    #include "conf.h"
    #include "die.h"
    #include "env.h"
    #include "langmap.h"
    #include "locatestring.h"
    #include "makepath.h"
    #include "path.h"
    #include "strbuf.h"
    #include "strlimcpy.h"
    #include "strmake.h"
    #include "test.h"
    #include "usable.h"

    static FILE *fp;
    static STRBUF *ib;
    static char *confline;
    /*
     * 8 level nested tc= or include= is allowed.
     */
    static int allowed_nest_level = 8;
    static int opened;

    static void trim(char *);
    static const char *readrecord(const char *);
    static void includelabel(STRBUF *, const char *, int);

    #ifndef isblank
    #define isblank(c)      ((c) == ' ' || (c) == '\t')
    #endif

    /*
     * trim: trim string.
     *
     * : var1=a b :
     *      |
     *      v
     * :var1=a b :
     */
    static void
    trim(char *l)
    {
            char *f, *b;
            int colon = 0;

            /*
             * delete blanks.
             */
            for (f = b = l; *f; f++) {
                    if (colon && isblank(*f))
                            continue;
                    colon = 0;
                    if ((*b++ = *f) == ':')
                            colon = 1;
            }
            *b = 0;
            /*
             * delete duplicate semi colons.
             */
            for (f = b = l; *f;) {
                    if ((*b++ = *f++) == ':') {
                            while (*f == ':')
                                    f++;
                    }
            }
            *b = 0;
    }
    /*
     * readrecord: read recoed indexed by label.
     *
     *      i)      label   label in config file
     *      r)              record
     *
     * Jobs:
     * o skip comment.
     * o append following line.
     * o format check.
     */
    static const char *
    readrecord(const char *label)
    {
            char *p;
            int flag = STRBUF_NOCRLF;
            int count = 0;

            rewind(fp);
            while ((p = strbuf_fgets(ib, fp, flag)) != NULL) {
                    count++;
                    /*
                     * ignore \<new line>.
                     */
                    flag &= ~STRBUF_APPEND;
                    if (*p == '#' || *p == '\0')
                            continue;
                    if (strbuf_unputc(ib, '\\')) {
                            flag |= STRBUF_APPEND;
                            continue;
                    }
                    trim(p);
                    for (;;) {
                            const char *candidate;
                            /*
                             * pick up candidate.
                             */
                            if ((candidate = strmake(p, "|:")) == NULL)
                                    die("invalid config file format (line %d).", count);
                            if (!strcmp(label, candidate)) {
                                    if (!(p = locatestring(p, ":", MATCH_FIRST)))
                                            die("invalid config file format (line %d).", count);
                                    return check_strdup(p);
                            }
                            /*
                             * locate next candidate.
                             */
                            p += strlen(candidate);
                            if (*p == ':')
                                    break;
                            else if (*p == '|')
                                    p++;
                            else
                                    die("invalid config file format (line %d).", count);
                    }
            }
            /*
             * config line not found.
             */
            return NULL;
    }
    /*
     * includelabel: procedure for tc= (or include=)
     *
     *      o)      sb      string buffer
     *      i)      label   record label
     *      i)      level   nest level for check
     */
    static void
    includelabel(STRBUF *sb, const char *label, int level)
    {
            const char *savep, *p, *q;

            if (++level > allowed_nest_level)
                    die("nested include= (or tc=) over flow.");
            if (!(savep = p = readrecord(label)))
                    die("label '%s' not found.", label);
            while ((q = locatestring(p, ":include=", MATCH_FIRST)) || (q = locatestring(p, ":tc=", MATCH_FIRST))) {
                    STRBUF *inc = strbuf_open(0);

                    strbuf_nputs(sb, p, q - p);
                    q = locatestring(q, "=", MATCH_FIRST) + 1;
                    for (; *q && *q != ':'; q++)
                            strbuf_putc(inc, *q);
                    includelabel(sb, strbuf_value(inc), level);
                    p = q;
                    strbuf_close(inc);
            }
            strbuf_puts(sb, p);
            free((void *)savep);
    }
    /*
     * configpath: get path of configuration file.
     */
    static char *
    configpath(void)
    {
            STATIC_STRBUF(sb);
            const char *p;

            strbuf_clear(sb);
            /*
             * at first, check environment variable GTAGSCONF.
             */
            if (getenv("GTAGSCONF") != NULL)
                    strbuf_puts(sb, getenv("GTAGSCONF"));
            /*
             * if GTAGSCONF not set then check standard config files.
             */
            else if ((p = get_home_directory()) && test("r", makepath(p, GTAGSRC, NULL)))
                    strbuf_puts(sb, makepath(p, GTAGSRC, NULL));
    #ifdef __DJGPP__
            else if ((p = get_home_directory()) && test("r", makepath(p, DOS_GTAGSRC, NULL)))
                    strbuf_puts(sb, makepath(p, DOS_GTAGSRC, NULL));
    #endif
            else if (test("r", GTAGSCONF))
                    strbuf_puts(sb, GTAGSCONF);
            else if (test("r", OLD_GTAGSCONF))
                    strbuf_puts(sb, OLD_GTAGSCONF);
            else if (test("r", DEBIANCONF))
                    strbuf_puts(sb, DEBIANCONF);
            else if (test("r", OLD_DEBIANCONF))
                    strbuf_puts(sb, OLD_DEBIANCONF);
            else
                    return NULL;
            return strbuf_value(sb);
    }
    /*
     * openconf: load configuration file.
     *
     *      go)     line    specified entry
     */
    void
    openconf(void)
    {
            STRBUF *sb;
            const char *config;
            extern int vflag;

            assert(opened == 0);
            opened = 1;

            /*
             * if config file not found then return default value.
             */
            if (!(config = configpath())) {
                    if (vflag)
                            fprintf(stderr, " Using default configuration.\n");
                    confline = check_strdup("");
            }
            /*
             * if it is not an absolute path then assumed config value itself.
             */
            else if (!isabspath(config)) {
                    confline = check_strdup(config);
                    if (!locatestring(confline, ":", MATCH_FIRST))
                            die("GTAGSCONF must be absolute path name.");
            }
            /*
             * else load value from config file.
             */
            else {
                    const char *label;

                    if (test("d", config))
                            die("config file '%s' is a directory.", config);
                    if (!test("f", config))
                            die("config file '%s' not found.", config);
                    if (!test("r", config))
                            die("config file '%s' is not readable.", config);
                    if ((label = getenv("GTAGSLABEL")) == NULL)
                            label = "default";

                    if (!(fp = fopen(config, "r")))
                            die("cannot open '%s'.", config);
                    if (vflag)
                            fprintf(stderr, " Using config file '%s'.\n", config);
                    ib = strbuf_open(MAXBUFLEN);
                    sb = strbuf_open(0);
                    includelabel(sb, label, 0);
                    confline = check_strdup(strbuf_value(sb));
                    strbuf_close(ib);
                    strbuf_close(sb);
                    fclose(fp);
            }
            /*
             * make up lacked variables.
             */
            sb = strbuf_open(0);
            strbuf_puts(sb, confline);
            strbuf_unputc(sb, ':');

            if (!getconfs("suffixes", NULL)) {
                    STRBUF *tmp = strbuf_open(0);
                    const char *langmap = NULL;

                    /*
                     * Variable 'suffixes' is obsoleted. But it is generated
                     * internally from the value of variable 'langmap'.
                     */
                    if (getconfs("langmap", tmp))
                            langmap = strbuf_value(tmp);
                    else
                            langmap = DEFAULTLANGMAP;
                    strbuf_puts(sb, ":suffixes=");
                    make_suffixes(langmap, sb);
                    strbuf_close(tmp);
            }
            if (!getconfs("skip", NULL)) {
                    strbuf_puts(sb, ":skip=");
                    strbuf_puts(sb, DEFAULTSKIP);
            }
            /*
             * GTAGS, GRTAGS and GSYMS have no default values but non of them
             * specified then use default values.
             * (Otherwise, nothing to do for gtags.)
             */
            if (!getconfs("GTAGS", NULL) && !getconfs("GRTAGS", NULL) && !getconfs("GSYMS", NULL)) {
                    const char *path;

                    /*
                     * usable search in BINDIR at first.
                     */
    #if defined(_WIN32)
                    path = "gtags-parser.exe";
    #elif defined(__DJGPP__)
                    path = usable("gtags-parser") ? "gtags-parser.exe" : "gtags-~1.exe";
    #else
                    path = usable("gtags-parser");
                    if (!path)
                            path = "gtags-parser";
    #endif /* _WIN32 */
                    strbuf_puts(sb, ":GTAGS=");
                    strbuf_puts(sb, path);
                    strbuf_puts(sb, " %s");
                    strbuf_puts(sb, ":GRTAGS=");
                    strbuf_puts(sb, path);
                    strbuf_puts(sb, " -r %s");
                    strbuf_puts(sb, ":GSYMS=");
                    strbuf_puts(sb, path);
                    strbuf_puts(sb, " -s %s");
            }
            strbuf_unputc(sb, ':');
            strbuf_putc(sb, ':');
            confline = check_strdup(strbuf_value(sb));
            strbuf_close(sb);
            trim(confline);
            return;
    }
    /*
     * getconfn: get property number
     *
     *      i)      name    property name
     *      o)      num     value (if not NULL)
     *      r)              1: found, 0: not found
     */
    int
    getconfn(const char *name, int *num)
    {
            const char *p;
            char buf[MAXPROPLEN+1];

            if (!opened)
                    openconf();
            snprintf(buf, sizeof(buf), ":%s#", name);
            if ((p = locatestring(confline, buf, MATCH_FIRST)) != NULL) {
                    p += strlen(buf);
                    if (num != NULL)
                            *num = atoi(p);
                    return 1;
            }
            return 0;
    }
    /*
     * getconfs: get property string
     *
     *      i)      name    property name
     *      o)      sb      string buffer (if not NULL)
     *      r)              1: found, 0: not found
     */
    int
    getconfs(const char *name, STRBUF *sb)
    {
            const char *p;
            char buf[MAXPROPLEN+1];
            int all = 0;
            int exist = 0;

            if (!opened)
                    openconf();
            if (!strcmp(name, "suffixes") || !strcmp(name, "skip"))
                    all = 1;
            snprintf(buf, sizeof(buf), ":%s=", name);
            p = confline;
            while ((p = locatestring(p, buf, MATCH_FIRST)) != NULL) {
                    if (exist && sb)
                            strbuf_putc(sb, ',');
                    exist = 1;
                    for (p += strlen(buf); *p && *p != ':'; p++) {
                            if (*p == '\\') /* quoted character */
                                    p++;
                            if (sb)
                                    strbuf_putc(sb, *p);
                    }
                    if (!all)
                            break;
            }
            /*
             * If 'bindir' and 'datadir' are not defined then
             * return system configuration value.
             */
            if (!exist) {
                    if (!strcmp(name, "bindir")) {
                            strbuf_puts(sb, BINDIR);
                            exist = 1;
                    } else if (!strcmp(name, "datadir")) {
                            strbuf_puts(sb, DATADIR);
                            exist = 1;
                    }
            }
            return exist;
    }
    /*
     * getconfb: get property bool value
     *
     *      i)      name    property name
     *      r)              1: TRUE, 0: FALSE
     */
    int
    getconfb(const char *name)
    {
            char buf[MAXPROPLEN+1];

            if (!opened)
                    openconf();
            snprintf(buf, sizeof(buf), ":%s:", name);
            if (locatestring(confline, buf, MATCH_FIRST) != NULL)
                    return 1;
            return 0;
    }
    /*
     * getconfline: print loaded config entry.
     */
    const char *
    getconfline(void)
    {
            if (!opened)
                    openconf();
            return confline;
    }
    void
    closeconf(void)
    {
            if (!opened)
                    return;
            free(confline);
            confline = NULL;
            opened = 0;
    }

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