root/libutil/gpathop.c

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

DEFINITIONS

This source file includes following definitions.
  1. gpath_open
  2. gpath_put
  3. gpath_path2fid
  4. gpath_fid2path
  5. gpath_delete
  6. gpath_nextkey
  7. gpath_close
  8. gfind_open
  9. gfind_read
  10. gfind_close

   1 /*
   2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2006
   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 #ifdef STDC_HEADERS
  26 #include <stdlib.h>
  27 #endif
  28 #ifdef HAVE_STRING_H
  29 #include <string.h>
  30 #else
  31 #include <strings.h>
  32 #endif
  33 
  34 #include "checkalloc.h"
  35 #include "die.h"
  36 #include "dbop.h"
  37 #include "gtagsop.h"
  38 #include "makepath.h"
  39 #include "gpathop.h"
  40 #include "strbuf.h"
  41 #include "strlimcpy.h"
  42 
  43 static DBOP *dbop;
  44 static int _nextkey;
  45 static int _mode;
  46 static int opened;
  47 static int created;
  48 
  49 /**
  50  * @file
  51  * @NAME{GPATH} format version
  52  *
  53  * -# @XREF{gtags,1} bury version number in #GPATH.
  54  * -# @XREF{global,1} pick up the version number from #GPATH. If the number
  55  *    is not acceptable version number then @NAME{global} give up work any more
  56  *    and display error message. <br>
  57  * -# If version number is not found then it assumes version 1.
  58  * -# @NAME{GPATH} version is independent with the other tag files.
  59  *
  60  * @par [History of format version]
  61  *
  62  * @NAME{GLOBAL-4.8.7}          no idea about format version. <br>
  63  * @NAME{GLOBAL-5.0}            understand format version. <br>
  64  *                      support format version 2.
  65  *
  66  * - Format version 1
  67  * @par
  68  *
  69  * #GPATH has only source files.
  70  *
  71  * @par
  72  * @code{.txt}
  73  *      key             data
  74  *      --------------------
  75  *      ./aaa.c\0       11\0
  76  * @endcode
  77  *
  78  * - Format version 2
  79  * @par
  80  *
  81  * #GPATH has not only source files but also other files like @FILE{README}.
  82  * You can distinguish them by the flag following data value.
  83  * At present, the flag value is only @CODE{'o'} (other files).
  84  *
  85  * @par
  86  * @code{.txt}
  87  *      key             data
  88  *      --------------------
  89  *      ./aaa.c\0       11\0
  90  *      ./README\0      12\0o\0         <=== 'o' means other files.
  91  * @endcode
  92  */
  93 static int support_version = 2; /**< acceptable format version   */
  94 static int create_version = 2;  /**< format version of newly created tag file */
  95 /**
  96  * gpath_open: open gpath tag file
  97  *
  98  *      @param[in]      dbpath  @VAR{GTAGSDBPATH}
  99  *      @param[in]      mode    0: read only <br>
 100  *                      1: create <br>
 101  *                      2: modify
 102  *      @return         0: normal <br>
 103  *                      -1: error
 104  */
 105 int
 106 gpath_open(const char *dbpath, int mode)
 107 {
 108         if (opened > 0) {
 109                 if (mode != _mode)
 110                         die("duplicate open with different mode.");
 111                 opened++;
 112                 return 0;
 113         }
 114         /*
 115          * We create GPATH just first time.
 116          */
 117         _mode = mode;
 118         if (mode == 1 && created)
 119                 mode = 0;
 120         dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), mode, 0644, 0);
 121         if (dbop == NULL)
 122                 return -1;
 123         if (mode == 1) {
 124                 dbop_putversion(dbop, create_version);
 125                 _nextkey = 1;
 126                 
 127         } else {
 128                 int format_version;
 129                 const char *path = dbop_get(dbop, NEXTKEY);
 130 
 131                 if (path == NULL)
 132                         die("nextkey not found in GPATH.");
 133                 _nextkey = atoi(path);
 134                 format_version = dbop_getversion(dbop);
 135                 if (format_version > support_version)
 136                         die("GPATH seems new format. Please install the latest GLOBAL.");
 137                 else if (format_version < support_version)
 138                         die("GPATH seems older format. Please remake tag files."); 
 139         }
 140         opened++;
 141         return 0;
 142 }
 143 /**
 144  * gpath_put: put path name
 145  *
 146  *      @param[in]      path    path name
 147  *      @param[in]      type    path type <br>
 148  *                      #GPATH_SOURCE: source file <br>
 149  *                      #GPATH_OTHER: other file
 150  */
 151 void
 152 gpath_put(const char *path, int type)
 153 {
 154         char fid[MAXFIDLEN];
 155         STATIC_STRBUF(sb);
 156 
 157         assert(opened > 0);
 158         if (_mode == 1 && created)
 159                 return;
 160         if (dbop_get(dbop, path) != NULL)
 161                 return;
 162         /*
 163          * generate new file id for the path.
 164          */
 165         snprintf(fid, sizeof(fid), "%d", _nextkey++);
 166         /*
 167          * path => fid mapping.
 168          */
 169         strbuf_clear(sb);
 170         strbuf_puts0(sb, fid);
 171         if (type == GPATH_OTHER)
 172                 strbuf_puts0(sb, "o");
 173         dbop_put_withlen(dbop, path, strbuf_value(sb), strbuf_getlen(sb));
 174         /*
 175          * fid => path mapping.
 176          */
 177         strbuf_clear(sb);
 178         strbuf_puts0(sb, path);
 179         if (type == GPATH_OTHER)
 180                 strbuf_puts0(sb, "o");
 181         dbop_put_withlen(dbop, fid, strbuf_value(sb), strbuf_getlen(sb));
 182 }
 183 /**
 184  * gpath_path2fid: convert path into id
 185  *
 186  *      @param[in]      path    path name
 187  *      @param[out]     type    path type <br>
 188  *                      #GPATH_SOURCE: source file <br>
 189  *                      #GPATH_OTHER: other file
 190  *      @return         file id
 191  */
 192 const char *
 193 gpath_path2fid(const char *path, int *type)
 194 {
 195         const char *fid = dbop_get(dbop, path);
 196         assert(opened > 0);
 197         if (fid && type) {
 198                 const char *flag = dbop_getflag(dbop);
 199                 *type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
 200                         
 201         }
 202         return fid;
 203 }
 204 /**
 205  * gpath_fid2path: convert id into path
 206  *
 207  *      @param[in]      fid     file id
 208  *      @param[out]     type    path type <br>
 209  *                      #GPATH_SOURCE: source file <br>
 210  *                      #GPATH_OTHER: other file
 211  *      @return         path name
 212  */
 213 const char *
 214 gpath_fid2path(const char *fid, int *type)
 215 {
 216         const char *path = dbop_get(dbop, fid);
 217         assert(opened > 0);
 218         if (path && type) {
 219                 const char *flag = dbop_getflag(dbop);
 220                 *type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
 221         }
 222         return path;
 223 }
 224 /**
 225  * gpath_delete: delete specified path record
 226  *
 227  *      @param[in]      path    path name
 228  */
 229 void
 230 gpath_delete(const char *path)
 231 {
 232         const char *fid;
 233 
 234         assert(opened > 0);
 235         assert(_mode == 2);
 236         assert(path[0] == '.' && path[1] == '/');
 237         fid = dbop_get(dbop, path);
 238         if (fid == NULL)
 239                 return;
 240         dbop_delete(dbop, fid);
 241         dbop_delete(dbop, path);
 242 }
 243 /**
 244  * gpath_nextkey: return next key
 245  *
 246  *      @return         next id
 247  */
 248 int
 249 gpath_nextkey(void)
 250 {
 251         assert(_mode != 1);
 252         return _nextkey;
 253 }
 254 /**
 255  * gpath_close: close gpath tag file
 256  */
 257 void
 258 gpath_close(void)
 259 {
 260         char fid[MAXFIDLEN];
 261 
 262         assert(opened > 0);
 263         if (--opened > 0)
 264                 return;
 265         if (_mode == 1 && created) {
 266                 dbop_close(dbop);
 267                 return;
 268         }
 269         if (_mode == 1 || _mode == 2) {
 270                 snprintf(fid, sizeof(fid), "%d", _nextkey);
 271                 dbop_update(dbop, NEXTKEY, fid);
 272         }
 273         dbop_close(dbop);
 274         if (_mode == 1)
 275                 created = 1;
 276 }
 277 
 278 /**
 279  * @fn GFIND *gfind_open(const char *dbpath, const char *local, int target)
 280  *
 281  * @remark gfind iterator using #GPATH.
 282  *
 283  * @par
 284  * @NAME{gfind_xxx()} does almost same with @NAME{find_xxx()} but much faster,
 285  * because @NAME{gfind_xxx()} use #GPATH (file index). <br>
 286  * If #GPATH exist then you should use this.
 287  */
 288 
 289 /**
 290  * gfind_open: start iterator using #GPATH.
 291  *
 292  *      @param[in]      dbpath  dbpath
 293  *      @param[in]      local   local prefix <br>
 294  *                      if @VAR{NULL} specified, it assumes @FILE{./};
 295  *      @param[in]      target  #GPATH_SOURCE: only source file <br>
 296  *                      #GPATH_OTHER: only other file <br>
 297  *                      #GPATH_BOTH: source file + other file
 298  *      @return         #GFIND structure
 299  */
 300 GFIND *
 301 gfind_open(const char *dbpath, const char *local, int target)
 302 {
 303         GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1);
 304 
 305         gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0);
 306         if (gfind->dbop == NULL)
 307                 die("GPATH not found.");
 308         gfind->path = NULL;
 309         gfind->prefix = check_strdup(local ? local : "./");
 310         gfind->first = 1;
 311         gfind->eod = 0;
 312         gfind->target = target;
 313         gfind->type = GPATH_SOURCE;
 314         gfind->version = dbop_getversion(gfind->dbop);
 315         if (gfind->version > support_version)
 316                 die("GPATH seems new format. Please install the latest GLOBAL.");
 317         else if (gfind->version < support_version)
 318                 die("GPATH seems older format. Please remake tag files."); 
 319         return gfind;
 320 }
 321 /**
 322  * gfind_read: read path using #GPATH.
 323  *
 324  *      @param[in]      gfind   #GFIND structure
 325  *      @return         path
 326  */
 327 const char *
 328 gfind_read(GFIND *gfind)
 329 {
 330         const char *flag;
 331 
 332         gfind->type = GPATH_SOURCE;
 333         if (gfind->eod)
 334                 return NULL;
 335         for (;;) {
 336                 if (gfind->first) {
 337                         gfind->first = 0;
 338                         gfind->path = dbop_first(gfind->dbop, gfind->prefix, NULL, DBOP_KEY | DBOP_PREFIX);
 339                 } else {
 340                         gfind->path = dbop_next(gfind->dbop);
 341                 }
 342                 if (gfind->path == NULL) {
 343                         gfind->eod = 1;
 344                         break;
 345                 }
 346                 /*
 347                  * if gfind->target == 0, return only source files.
 348                  * *flag == 'o' means 'other files' like README.
 349                  */
 350                 flag = dbop_getflag(gfind->dbop);
 351                 gfind->type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
 352                 if (gfind->type & gfind->target)
 353                         break;
 354         }
 355         return gfind->path;
 356 }
 357 /**
 358  * gfind_close: close iterator.
 359  */
 360 void
 361 gfind_close(GFIND *gfind)
 362 {
 363         dbop_close(gfind->dbop);
 364         free((void *)gfind->prefix);
 365         free(gfind);
 366 }

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