"Fossies" - the Fresh Open Source Software Archive

Member "global-6.6.5/libutil/gpathop.c" (3 Sep 2020, 11401 Bytes) of package /linux/misc/global-6.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gpathop.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.6.4_vs_6.6.5.

    1 /*
    2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2019
    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 "getdbpath.h"
   38 #include "gtagsop.h"
   39 #include "gpathop.h"
   40 #include "makepath.h"
   41 #include "nearsort.h"
   42 #include "strbuf.h"
   43 #include "strlimcpy.h"
   44 
   45 static DBOP *dbop;
   46 static int _startkey;
   47 static int _nextkey;
   48 static int _mode;
   49 static int opened;
   50 static int created;
   51 
   52 static int openflags;
   53 void
   54 set_gpath_flags(int flags) {
   55     openflags = flags;
   56 }
   57 /**
   58  * compare_nearpath: compare function for 'nearness sort'.
   59  */
   60 static const char *nearbase;
   61 static int
   62 compare_nearpath(const void *s1, const void *s2)
   63 {
   64     int ret;
   65 
   66     if ((ret = COMPARE_NEARNESS(*(char **)s1, *(char **)s2, nearbase)) != 0)
   67         return ret;
   68     return strcmp(*(char **)s1, *(char **)s2);
   69 }
   70 /*
   71  * GPATH format version
   72  *
   73  * 1. gtags(1) bury version number in GPATH.
   74  * 2. global(1) pick up the version number from GPATH. If the number
   75  *    is not acceptable version number then global give up work any more
   76  *    and display error message.
   77  * 3. If version number is not found then it assumes version 1.
   78  * 4. GPATH version is independent with the other tag files.
   79  *
   80  * [History of format version]
   81  *
   82  * GLOBAL-4.8.7     no idea about format version.
   83  * GLOBAL-5.0       understand format version.
   84  *          support format version 2.
   85  *
   86  * - Format version 1
   87  *
   88  * GPATH has only source files.
   89  *
   90  *      key             data
   91  *      --------------------
   92  *      ./aaa.c\0       11\0
   93  *
   94  * - Format version 2
   95  *
   96  * GPATH has not only source files but also other files like "README".
   97  * You can distinguish them by the flag following data value.
   98  * At present, the flag value is only 'o' (other files).
   99  *
  100  *      key             data
  101  *      --------------------
  102  *      ./aaa.c\0       11\0
  103  *      ./README\0      12\0o\0         <=== 'o' means other files.
  104  */
  105 static int support_version = 2; /**< acceptable format version   */
  106 static int create_version = 2;  /**< format version of newly created tag file */
  107 /**
  108  * gpath_open: open gpath tag file
  109  *
  110  *  @param[in]  dbpath  GTAGSDBPATH
  111  *  @param[in]  mode    0: read only,
  112  *          1: create,
  113  *          2: modify
  114  *  @return     0: normal,
  115  *          -1: error
  116  */
  117 int
  118 gpath_open(const char *dbpath, int mode)
  119 {
  120     if (opened > 0) {
  121         if (mode != _mode)
  122             die("duplicate open with different mode.");
  123         opened++;
  124         return 0;
  125     }
  126     /*
  127      * We create GPATH just first time.
  128      */
  129     _mode = mode;
  130     if (mode == 1 && created)
  131         mode = 0;
  132     dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), mode, 0644, openflags);
  133     if (dbop == NULL)
  134         return -1;
  135     if (mode == 1) {
  136         dbop_putversion(dbop, create_version);
  137         _startkey = _nextkey = 1;
  138     } else {
  139         int format_version;
  140         const char *path = dbop_get(dbop, NEXTKEY);
  141 
  142         if (path == NULL)
  143             die("nextkey not found in GPATH.");
  144         _startkey = _nextkey = atoi(path);
  145         format_version = dbop_getversion(dbop);
  146         if (format_version > support_version)
  147             die("GPATH seems new format. Please install the latest GLOBAL.");
  148         else if (format_version < support_version)
  149                         die("GPATH seems older format. Please remake tag files."); 
  150     }
  151     opened++;
  152     return 0;
  153 }
  154 /**
  155  * gpath_put: put path name
  156  *
  157  *  @param[in]  path    path name
  158  *  @param[in]  type    path type
  159  *          GPATH_SOURCE: source file,
  160  *          GPATH_OTHER: other file
  161  */
  162 const char *
  163 gpath_put(const char *path, int type)
  164 {
  165     static char sfid[MAXFIDLEN];
  166     STATIC_STRBUF(sb);
  167 
  168     assert(opened > 0);
  169     if (_mode == 1 && created)
  170         return "";
  171     if (dbop_get(dbop, path) != NULL)
  172         return "";
  173     /*
  174      * generate new file id for the path.
  175      */
  176     snprintf(sfid, sizeof(sfid), "%d", _nextkey++);
  177     /*
  178      * path => fid mapping.
  179      */
  180     strbuf_clear(sb);
  181     strbuf_puts(sb, sfid);
  182     dbop_put_path(dbop, path, strbuf_value(sb), type == GPATH_OTHER ? "o" : NULL);
  183     /*
  184      * fid => path mapping.
  185      */
  186     strbuf_clear(sb);
  187     strbuf_puts(sb, path);
  188     dbop_put_path(dbop, sfid, strbuf_value(sb), type == GPATH_OTHER ? "o" : NULL);
  189     return (const char *)sfid;
  190 }
  191 /**
  192  * gpath_path2fid: convert path into id
  193  *
  194  *  @param[in]  path    path name
  195  *  @param[out] type    path type
  196  *          GPATH_SOURCE: source file,
  197  *          GPATH_OTHER: other file
  198  *  @return     file id (string)
  199  */
  200 const char *
  201 gpath_path2fid(const char *path, int *type)
  202 {
  203     const char *fid = dbop_get(dbop, path);
  204     assert(opened > 0);
  205     if (fid && type) {
  206         const char *flag = dbop_getflag(dbop);
  207         *type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
  208             
  209     }
  210     return fid;
  211 }
  212 /**
  213  * gpath_fid2path: convert id into path
  214  *
  215  *  @param[in]  fid file id (string)
  216  *  @param[out] type    path type
  217  *          GPATH_SOURCE: source file,
  218  *          GPATH_OTHER: other file
  219  *  @return     path name
  220  */
  221 const char *
  222 gpath_fid2path(const char *fid, int *type)
  223 {
  224     const char *path = dbop_get(dbop, fid);
  225     assert(opened > 0);
  226     if (path && type) {
  227         const char *flag = dbop_getflag(dbop);
  228         *type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
  229     }
  230     return path;
  231 }
  232 /*
  233  * gpath_path2nfid: convert path into id
  234  *
  235  *  @param[in]  path    path name
  236  *  @param[out] type    path type
  237  *          GPATH_SOURCE: source file
  238  *          GPATH_OTHER: other file
  239  *  @return     file id (integer)
  240  */
  241 int
  242 gpath_path2nfid(const char *path, int *type)
  243 {
  244     const char *sfid = gpath_path2fid(path, type);
  245     return sfid == NULL ? 0 : atoi(sfid);
  246 }
  247 /*
  248  * gpath_nfid2path: convert id into path
  249  *
  250  *  @param[in]  nfid    file id (integer)
  251  *  @param[out] type    path type
  252  *          GPATH_SOURCE: source file
  253  *          GPATH_OTHER: other file
  254  *  @return     path name
  255  */
  256 const char *
  257 gpath_nfid2path(int nfid, int *type)
  258 {
  259     char sfid[MAXFIDLEN];
  260     snprintf(sfid, sizeof(sfid), "%d", nfid);
  261     return gpath_fid2path(sfid, type);
  262 }
  263 /**
  264  * gpath_delete: delete specified path record
  265  *
  266  *  @param[in]  path    path name
  267  */
  268 void
  269 gpath_delete(const char *path)
  270 {
  271     const char *fid;
  272 
  273     assert(opened > 0);
  274     assert(_mode == 2);
  275     assert(path[0] == '.' && path[1] == '/');
  276     fid = dbop_get(dbop, path);
  277     if (fid == NULL)
  278         return;
  279     dbop_delete(dbop, fid);
  280     dbop_delete(dbop, path);
  281 }
  282 /**
  283  * gpath_nextkey: return next key
  284  *
  285  *  @return     next id
  286  */
  287 int
  288 gpath_nextkey(void)
  289 {
  290     assert(_mode != 1);
  291     return _nextkey;
  292 }
  293 /**
  294  * gpath_count: count the number of records
  295  *
  296  *  @param[in]  type    record type
  297  *          GPATH_SOURCE: source file
  298  *          GPATH_OTHER: other file
  299  *          GPATH_BOTH: both above
  300  *  @return     number of records
  301  */
  302 int
  303 gpath_count(int type)
  304 {
  305     const char *path;
  306     int count, source_count, other_count;
  307 
  308     count = source_count = other_count = 0;
  309     for (path = dbop_first(dbop, "./", NULL, DBOP_PREFIX); path != NULL; path = dbop_next(dbop)) {
  310         const char *flag = dbop_getflag(dbop);
  311         if (flag && *flag == 'o')
  312             other_count++;
  313         else
  314             source_count++;
  315     }
  316     switch (type) {
  317     case GPATH_SOURCE:
  318         count = source_count;
  319         break;
  320     case GPATH_OTHER:
  321         count = other_count;
  322         break;
  323     case GPATH_BOTH:
  324         count = source_count + other_count;
  325         break;
  326     default:
  327         break;
  328     }
  329     return count;
  330 }
  331 /**
  332  * gpath_close: close gpath tag file
  333  */
  334 void
  335 gpath_close(void)
  336 {
  337     char fid[MAXFIDLEN];
  338 
  339     assert(opened > 0);
  340     if (--opened > 0)
  341         return;
  342     if (_mode == 1 && created) {
  343         dbop_close(dbop);
  344         return;
  345     }
  346     if (_mode == 1 ||
  347            (_mode == 2 && _startkey < _nextkey))
  348     {
  349         snprintf(fid, sizeof(fid), "%d", _nextkey);
  350         dbop_update(dbop, NEXTKEY, fid);
  351     }
  352     dbop_close(dbop);
  353     if (_mode == 1)
  354         created = 1;
  355 }
  356 
  357 /**
  358  * GFIND *gfind_open(const char *dbpath, const char *local, int target, int flags)
  359  *
  360  * gfind iterator using GPATH.
  361  *
  362  * gfind_xxx() does almost same with find_xxx() but much faster,
  363  * because gfind_xxx() use GPATH (file index).
  364  * If GPATH exist then you should use this.
  365  */
  366 
  367 /**
  368  * gfind_open: start iterator using GPATH.
  369  *
  370  *  @param[in]  dbpath  dbpath
  371  *  @param[in]  local   local prefix,
  372  *          if NULL specified, it assumes "./";
  373  *  @param[in]      target  GPATH_SOURCE: only source file,
  374  *          GPATH_OTHER: only other file,
  375  *          GPATH_BOTH: source file + other file
  376  *  @param[in]  flags   GPATH_NEARSORT
  377  *  @return     GFIND structure
  378  */
  379 GFIND *
  380 gfind_open(const char *dbpath, const char *local, int target, int flags)
  381 {
  382     GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1);
  383 
  384     gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0);
  385     if (gfind->dbop == NULL)
  386         die("GPATH not found.");
  387     gfind->path = NULL;
  388     gfind->prefix = check_strdup(local ? local : "./");
  389     gfind->first = 1;
  390     gfind->eod = 0;
  391     gfind->target = target;
  392     gfind->type = GPATH_SOURCE;
  393     gfind->flags = flags;
  394     gfind->path_array = NULL;
  395     gfind->version = dbop_getversion(gfind->dbop);
  396     if (gfind->version > support_version)
  397         die("GPATH seems new format. Please install the latest GLOBAL.");
  398     else if (gfind->version < support_version)
  399         die("GPATH seems older format. Please remake tag files."); 
  400     /*
  401      * Nearness sort.
  402      * In fact, this timing of sort is not good for performance.
  403      * Reconsideration is needed later.
  404      */
  405     if (gfind->flags & GPATH_NEARSORT) {
  406         const char *path = NULL;
  407         VARRAY *varray = varray_open(sizeof(char *), 100);
  408         POOL *pool = pool_open();
  409         while ((path = gfind_read(gfind)) != NULL) {
  410             char **a = varray_append(varray);
  411             *a = pool_strdup(pool, path, 0);
  412         }
  413         if ((nearbase = get_nearbase_path()) == NULL)
  414             die("cannot get nearbase path.");
  415         qsort(varray_assign(varray, 0, 0), varray->length, sizeof(char *), compare_nearpath);
  416         gfind->path_array = varray;
  417         gfind->pool = pool;
  418         gfind->index = 0;
  419     }
  420     return gfind;
  421 }
  422 /**
  423  * gfind_read: read path using GPATH.
  424  *
  425  *  @param[in]  gfind   GFIND structure
  426  *  @return     path
  427  */
  428 const char *
  429 gfind_read(GFIND *gfind)
  430 {
  431     const char *flag;
  432 
  433     if (gfind->path_array) {
  434         char **a = NULL;
  435         if (gfind->index >= gfind->path_array->length)
  436             return NULL;
  437         a = varray_assign(gfind->path_array, gfind->index++, 0);
  438         return *a;
  439     }
  440     gfind->type = GPATH_SOURCE;
  441     if (gfind->eod)
  442         return NULL;
  443     for (;;) {
  444         if (gfind->first) {
  445             gfind->first = 0;
  446             gfind->path = dbop_first(gfind->dbop, gfind->prefix, NULL, DBOP_KEY | DBOP_PREFIX);
  447         } else {
  448             gfind->path = dbop_next(gfind->dbop);
  449         }
  450         if (gfind->path == NULL) {
  451             gfind->eod = 1;
  452             break;
  453         }
  454         /*
  455          * if gfind->target == 0, return only source files.
  456          * *flag == 'o' means 'other files' like README.
  457          */
  458         flag = dbop_getflag(gfind->dbop);
  459         if (flag == NULL)
  460             flag = "";
  461         gfind->type = (*flag == 'o') ? GPATH_OTHER : GPATH_SOURCE;
  462         if (gfind->type & gfind->target)
  463             break;
  464     }
  465     return gfind->path;
  466 }
  467 /**
  468  * gfind_close: close iterator.
  469  */
  470 void
  471 gfind_close(GFIND *gfind)
  472 {
  473     dbop_close(gfind->dbop);
  474     if (gfind->flags & GPATH_NEARSORT) {
  475         pool_close(gfind->pool);
  476         varray_close(gfind->path_array);
  477     }
  478     free((void *)gfind->prefix);
  479     free(gfind);
  480 }