root/libutil/conf.c

/* [previous][next][first][last][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

   1 /*
   2  * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2005, 2010, 2011
   3  *      Tama Communications Corporation
   4  *
   5  * This file is part of GNU GLOBAL.
   6  *
   7  * This program is free software: you can redistribute it and/or modify
   8  * it under the terms of the GNU General Public License as published by
   9  * the Free Software Foundation, either version 3 of the License, or
  10  * (at your option) any later version.
  11  * 
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  * 
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19  */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include <config.h>
  23 #endif
  24 #include <assert.h>
  25 #include <ctype.h>
  26 #ifdef STDC_HEADERS
  27 #include <stdlib.h>
  28 #endif
  29 #ifdef HAVE_STRING_H
  30 #include <string.h>
  31 #else
  32 #include <strings.h>
  33 #endif
  34 
  35 #include "gparam.h"
  36 #include "char.h"
  37 #include "checkalloc.h"
  38 #include "conf.h"
  39 #include "die.h"
  40 #include "env.h"
  41 #include "langmap.h"
  42 #include "locatestring.h"
  43 #include "makepath.h"
  44 #include "path.h"
  45 #include "strbuf.h"
  46 #include "strlimcpy.h"
  47 #include "strmake.h"
  48 #include "test.h"
  49 #include "usable.h"
  50 
  51 static FILE *fp;
  52 static STRBUF *ib;
  53 static char *confline;
  54 /**
  55  * 32 level nested @CODE{tc=} or @CODE{include=} is allowed.
  56  */
  57 static int allowed_nest_level = 32;
  58 static int opened;
  59 
  60 static void trim(char *);
  61 static const char *readrecord(const char *);
  62 static void includelabel(STRBUF *, const char *, int);
  63 
  64 #ifndef isblank
  65 #define isblank(c)      ((c) == ' ' || (c) == '\t')
  66 #endif
  67 
  68 /**
  69  * trim: trim string.
  70  *
  71  * @code
  72  * : var1=a b :
  73  *      |
  74  *      v
  75  * :var1=a b :
  76  * @endcode
  77  */
  78 static void
  79 trim(char *l)
  80 {
  81         char *f, *b;
  82         int colon = 0;
  83 
  84         /*
  85          * delete blanks.
  86          */
  87         for (f = b = l; *f; f++) {
  88                 if (colon && isblank(*f))
  89                         continue;
  90                 colon = 0;
  91                 if ((*b++ = *f) == ':')
  92                         colon = 1;
  93         }
  94         *b = 0;
  95         /*
  96          * delete duplicate semi colons.
  97          */
  98         for (f = b = l; *f;) {
  99                 if ((*b++ = *f++) == ':') {
 100                         while (*f == ':')
 101                                 f++;
 102                 }
 103         }
 104         *b = 0;
 105 }
 106 /**
 107  * readrecord: read recoed indexed by label.
 108  *
 109  *      @param[in]      label   label in config file
 110  *      @return         record
 111  *
 112  * @par Jobs:
 113  * - skip comment.
 114  * - append following line.
 115  * - format check.
 116  */
 117 static const char *
 118 readrecord(const char *label)
 119 {
 120         char *p;
 121         int flag = STRBUF_NOCRLF|STRBUF_SHARPSKIP;
 122         int count = 0;
 123 
 124         rewind(fp);
 125         while ((p = strbuf_fgets(ib, fp, flag)) != NULL) {
 126                 count++;
 127                 /*
 128                  * ignore \<new line>.
 129                  */
 130                 flag &= ~STRBUF_APPEND;
 131                 if (*p == '\0')
 132                         continue;
 133                 if (strbuf_unputc(ib, '\\')) {
 134                         flag |= STRBUF_APPEND;
 135                         continue;
 136                 }
 137                 trim(p);
 138                 for (;;) {
 139                         const char *candidate;
 140                         /*
 141                          * pick up candidate.
 142                          */
 143                         if ((candidate = strmake(p, "|:")) == NULL)
 144                                 die("invalid config file format (line %d).", count);
 145                         if (!strcmp(label, candidate)) {
 146                                 if (!(p = locatestring(p, ":", MATCH_FIRST)))
 147                                         die("invalid config file format (line %d).", count);
 148                                 return check_strdup(p);
 149                         }
 150                         /*
 151                          * locate next candidate.
 152                          */
 153                         p += strlen(candidate);
 154                         if (*p == ':')
 155                                 break;
 156                         else if (*p == '|')
 157                                 p++;
 158                         else
 159                                 die("invalid config file format (line %d).", count);
 160                 }
 161         }
 162         /*
 163          * config line not found.
 164          */
 165         return NULL;
 166 }
 167 /**
 168  * includelabel: procedure for @CODE{tc=} (or @CODE{include=})
 169  *
 170  *      @param[out]     sb      string buffer
 171  *      @param[in]      label   record label
 172  *      @param[in]      level   nest level for check
 173  */
 174 static void
 175 includelabel(STRBUF *sb, const char *label, int level)
 176 {
 177         const char *savep, *p, *q;
 178 
 179         if (++level > allowed_nest_level)
 180                 die("nested include= (or tc=) over flow.");
 181         if (!(savep = p = readrecord(label)))
 182                 die("label '%s' not found.", label);
 183         while ((q = locatestring(p, ":include=", MATCH_FIRST)) || (q = locatestring(p, ":tc=", MATCH_FIRST))) {
 184                 STRBUF *inc = strbuf_open(0);
 185 
 186                 strbuf_nputs(sb, p, q - p);
 187                 q = locatestring(q, "=", MATCH_FIRST) + 1;
 188                 for (; *q && *q != ':'; q++)
 189                         strbuf_putc(inc, *q);
 190                 includelabel(sb, strbuf_value(inc), level);
 191                 p = q;
 192                 strbuf_close(inc);
 193         }
 194         strbuf_puts(sb, p);
 195         free((void *)savep);
 196 }
 197 /**
 198  * configpath: get path of configuration file.
 199  */
 200 static char *
 201 configpath(void)
 202 {
 203         STATIC_STRBUF(sb);
 204         const char *p;
 205 
 206         strbuf_clear(sb);
 207         /*
 208          * at first, check environment variable GTAGSCONF.
 209          */
 210         if (getenv("GTAGSCONF") != NULL)
 211                 strbuf_puts(sb, getenv("GTAGSCONF"));
 212         /*
 213          * if GTAGSCONF not set then check standard config files.
 214          */
 215         else if ((p = get_home_directory()) && test("r", makepath(p, GTAGSRC, NULL)))
 216                 strbuf_puts(sb, makepath(p, GTAGSRC, NULL));
 217 #ifdef __DJGPP__
 218         else if ((p = get_home_directory()) && test("r", makepath(p, DOS_GTAGSRC, NULL)))
 219                 strbuf_puts(sb, makepath(p, DOS_GTAGSRC, NULL));
 220 #endif
 221         else if (test("r", GTAGSCONF))
 222                 strbuf_puts(sb, GTAGSCONF);
 223         else if (test("r", OLD_GTAGSCONF))
 224                 strbuf_puts(sb, OLD_GTAGSCONF);
 225         else if (test("r", DEBIANCONF))
 226                 strbuf_puts(sb, DEBIANCONF);
 227         else if (test("r", OLD_DEBIANCONF))
 228                 strbuf_puts(sb, OLD_DEBIANCONF);
 229         else if (test("r", makepath(SYSCONFDIR, "gtags.conf", NULL)))
 230                 strbuf_puts(sb, makepath(SYSCONFDIR, "gtags.conf", NULL));
 231         else
 232                 return NULL;
 233         return strbuf_value(sb);
 234 }
 235 /**
 236  * openconf: load configuration file.
 237  *
 238  * @par Globals used (output):
 239  *      #confline:       specified entry
 240  */
 241 void
 242 openconf(void)
 243 {
 244         STRBUF *sb;
 245         const char *config;
 246         extern int vflag;
 247 
 248         assert(opened == 0);
 249         opened = 1;
 250 
 251         /*
 252          * if config file not found then return default value.
 253          */
 254         if (!(config = configpath())) {
 255                 if (vflag)
 256                         fprintf(stderr, " Using default configuration.\n");
 257                 confline = check_strdup("");
 258         }
 259         /*
 260          * if it is not an absolute path then assumed config value itself.
 261          */
 262         else if (!isabspath(config)) {
 263                 confline = check_strdup(config);
 264                 if (!locatestring(confline, ":", MATCH_FIRST))
 265                         die("GTAGSCONF must be absolute path name.");
 266         }
 267         /*
 268          * else load value from config file.
 269          */
 270         else {
 271                 const char *label;
 272 
 273                 if (test("d", config))
 274                         die("config file '%s' is a directory.", config);
 275                 if (!test("f", config))
 276                         die("config file '%s' not found.", config);
 277                 if (!test("r", config))
 278                         die("config file '%s' is not readable.", config);
 279                 if ((label = getenv("GTAGSLABEL")) == NULL)
 280                         label = "default";
 281         
 282                 if (!(fp = fopen(config, "r")))
 283                         die("cannot open '%s'.", config);
 284                 if (vflag)
 285                         fprintf(stderr, " Using config file '%s'.\n", config);
 286                 ib = strbuf_open(MAXBUFLEN);
 287                 sb = strbuf_open(0);
 288                 includelabel(sb, label, 0);
 289                 confline = check_strdup(strbuf_value(sb));
 290                 strbuf_close(ib);
 291                 strbuf_close(sb);
 292                 fclose(fp);
 293         }
 294         /*
 295          * make up required variables.
 296          */
 297         sb = strbuf_open(0);
 298         strbuf_puts(sb, confline);
 299         strbuf_unputc(sb, ':');
 300 
 301         if (!getconfs("langmap", NULL)) {
 302                 strbuf_puts(sb, ":langmap=");
 303                 strbuf_puts(sb, quote_chars(DEFAULTLANGMAP, ':'));
 304         }
 305         if (!getconfs("skip", NULL)) {
 306                 strbuf_puts(sb, ":skip=");
 307                 strbuf_puts(sb, DEFAULTSKIP);
 308         }
 309         strbuf_unputc(sb, ':');
 310         strbuf_putc(sb, ':');
 311         confline = check_strdup(strbuf_value(sb));
 312         strbuf_close(sb);
 313         trim(confline);
 314         return;
 315 }
 316 /**
 317  * getconfn: get property number
 318  *
 319  *      @param[in]      name    property name
 320  *      @param[out]     num     value (if not @VAR{NULL})
 321  *      @return         1: found, 0: not found
 322  */
 323 int
 324 getconfn(const char *name, int *num)
 325 {
 326         const char *p;
 327         char buf[MAXPROPLEN];
 328 
 329         if (!opened)
 330                 openconf();
 331         snprintf(buf, sizeof(buf), ":%s#", name);
 332         if ((p = locatestring(confline, buf, MATCH_FIRST)) != NULL) {
 333                 p += strlen(buf);
 334                 if (num != NULL)
 335                         *num = atoi(p);
 336                 return 1;
 337         }
 338         return 0;
 339 }
 340 /**
 341  * getconfs: get property string
 342  *
 343  *      @param[in]      name    property name
 344  *      @param[out]     sb      string buffer (if not @VAR{NULL})
 345  *      @return         1: found, 0: not found
 346  */
 347 int
 348 getconfs(const char *name, STRBUF *sb)
 349 {
 350         const char *p;
 351         char buf[MAXPROPLEN];
 352         int all = 0;
 353         int exist = 0;
 354 
 355         if (!opened)
 356                 openconf();
 357         if (!strcmp(name, "skip") || !strcmp(name, "gtags_parser") || !strcmp(name, "langmap"))
 358                 all = 1;
 359         snprintf(buf, sizeof(buf), ":%s=", name);
 360         p = confline;
 361         while ((p = locatestring(p, buf, MATCH_FIRST)) != NULL) {
 362                 if (exist && sb)
 363                         strbuf_putc(sb, ',');           
 364                 exist = 1;
 365                 for (p += strlen(buf); *p && *p != ':'; p++) {
 366                         if (*p == '\\') /* quoted character */
 367                                 p++;
 368                         if (sb)
 369                                 strbuf_putc(sb, *p);
 370                 }
 371                 if (!all)
 372                         break;
 373         }
 374         /*
 375          * If 'bindir' and 'datadir' are not defined then
 376          * return system configuration value.
 377          */
 378         if (!exist) {
 379                 if (!strcmp(name, "bindir")) {
 380                         strbuf_puts(sb, BINDIR);
 381                         exist = 1;
 382                 } else if (!strcmp(name, "datadir")) {
 383 #if defined(_WIN32) && !defined(__CYGWIN__)
 384                         /*
 385                          * Test if this directory exists, and if not, take the
 386                          * directory relative to the binary.
 387                          */
 388                         if (test("d", DATADIR))
 389                                 strbuf_puts(sb, DATADIR);
 390                         else {
 391                                 const char *name = strrchr(_pgmptr, '\\');
 392                                 if (name)
 393                                         strbuf_nputs(sb, _pgmptr, name+1 - _pgmptr);
 394                                 strbuf_puts(sb, "..\\share");
 395                         }
 396 #else
 397                         strbuf_puts(sb, DATADIR);
 398 #endif
 399                         exist = 1;
 400                 } else if (!strcmp(name, "localstatedir")) {
 401                         strbuf_puts(sb, LOCALSTATEDIR);
 402                         exist = 1;
 403                 } else if (!strcmp(name, "sysconfdir")) {
 404                         strbuf_puts(sb, SYSCONFDIR);
 405                         exist = 1;
 406                 }
 407         }
 408         return exist;
 409 }
 410 /**
 411  * getconfb: get property bool value
 412  *
 413  *      @param[in]      name    property name
 414  *      @return         1: @VAR{TRUE}, 0: @VAR{FALSE}
 415  */
 416 int
 417 getconfb(const char *name)
 418 {
 419         char buf[MAXPROPLEN];
 420 
 421         if (!opened)
 422                 openconf();
 423         snprintf(buf, sizeof(buf), ":%s:", name);
 424         if (locatestring(confline, buf, MATCH_FIRST) != NULL)
 425                 return 1;
 426         return 0;
 427 }
 428 /**
 429  * getconfline: print loaded config entry.
 430  */
 431 const char *
 432 getconfline(void)
 433 {
 434         if (!opened)
 435                 openconf();
 436         return confline;
 437 }
 438 void
 439 closeconf(void)
 440 {
 441         if (!opened)
 442                 return;
 443         free(confline);
 444         confline = NULL;
 445         opened = 0;
 446 }

/* [previous][next][first][last][top][bottom][index][help] */