root/htags/anchor.c

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

DEFINITIONS

This source file includes following definitions.
  1. cmp
  2. anchor_prepare
  3. anchor_load
  4. anchor_unload
  5. anchor_first
  6. anchor_next
  7. anchor_get
  8. define_line
  9. anchor_getlinks
  10. anchor_dump

   1 /*
   2  * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
   3  *      2008    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 #ifdef HAVE_CONFIG_H
  21 #include <config.h>
  22 #endif
  23 #include <stdio.h>
  24 #ifdef STDC_HEADERS
  25 #include <stdlib.h>
  26 #endif
  27 #ifdef HAVE_STRING_H
  28 #include <string.h>
  29 #else
  30 #include <strings.h>
  31 #endif
  32 #ifdef HAVE_CTYPE_H
  33 #include <ctype.h>
  34 #endif
  35 #include "global.h"
  36 #include "anchor.h"
  37 #include "htags.h"
  38 #include "path2url.h"
  39 
  40 static XARGS *anchor_input[GTAGLIM];
  41 static struct anchor *table;
  42 static VARRAY *vb;
  43 
  44 static struct anchor *start;
  45 static struct anchor *curp;
  46 static struct anchor *end;
  47 static struct anchor *CURRENT;
  48 
  49 /** compare routine for @XREF{qsort,3} */
  50 static int
  51 cmp(const void *s1, const void *s2)
  52 {
  53         return ((struct anchor *)s1)->lineno - ((struct anchor *)s2)->lineno;
  54 }
  55 /**
  56  * @name Pointers (as lineno).
  57  */
  58 /** @{ */
  59 static int FIRST;
  60 static int LAST;
  61 static struct anchor *CURRENTDEF;
  62 /** @} */
  63 
  64 /**
  65  * anchor_prepare: setup input stream.
  66  *
  67  *      @param[in]      anchor_stream   file pointer of path list
  68  */
  69 void
  70 anchor_prepare(FILE *anchor_stream)
  71 {
  72         /*
  73          * Option table:
  74          * We use blank string as null option instead of null string("")
  75          * not to change the command length. This length influences
  76          * the number of arguments in the xargs processing.
  77          */
  78         static const char *const options[] = {NULL, " ", "r", "s"};
  79         char comline[MAXFILLEN];
  80         int db;
  81 
  82         for (db = GTAGS; db < GTAGLIM; db++) {
  83                 anchor_input[db] = NULL;
  84                 /*
  85                  * Htags(1) should not use gtags-parser(1) directly;
  86                  * it should use global(1) with the -f option instead.
  87                  * Because gtags-parser is part of the implementation of
  88                  * gtags(1) and global(1), and htags is only an application
  89                  * program which uses global(1). If htags depends on
  90                  * gtags-parser, it will become difficult to change the
  91                  * implementation of gtags and global.
  92                  *
  93                  * Though the output of global -f is not necessarily sorted
  94                  * by the path, it is guaranteed that the records concerning
  95                  * the same file are consecutive.
  96                  */
  97                 if (gtags_exist[db] == 1) {
  98                         snprintf(comline, sizeof(comline), "%s -f%s --encode-path=\" \t\" --result=ctags-xid --nofilter=path", quote_shell(global_path), options[db]);
  99                         anchor_input[db] = xargs_open_with_file(comline, 0, anchor_stream);
 100                 }
 101         }
 102 }
 103 /**
 104  * anchor_load: load anchor table
 105  *
 106  *      @param[in]      path    path name
 107  */
 108 void
 109 anchor_load(const char *path)
 110 {
 111         int db, current_fid;
 112 
 113         /* Get fid of the path */
 114         {
 115                 const char *p = path2fid(path);
 116                 if (p == NULL)
 117                         die("anchor_load: internal error. file '%s' not found in GPATH.", path);
 118                 current_fid = atoi(p);
 119         }
 120         FIRST = LAST = 0;
 121         end = CURRENT = NULL;
 122 
 123         if (vb == NULL)
 124                 vb = varray_open(sizeof(struct anchor), 1000);
 125         else
 126                 varray_reset(vb);
 127 
 128         for (db = GTAGS; db < GTAGLIM; db++) {
 129                 XARGS *xp;
 130                 char *ctags_xid;
 131 
 132                 if ((xp = anchor_input[db]) == NULL)
 133                         continue;
 134                 /*
 135                  * Read from input stream until it reaches end of file
 136                  * or the line of another file appears.
 137                  */
 138                 while ((ctags_xid = xargs_read(xp)) != NULL) {
 139                         SPLIT ptable;
 140                         struct anchor *a;
 141                         int type, fid;
 142                         const char *ctags_x = parse_xid(ctags_xid, NULL, &fid);
 143 
 144                         /*
 145                          * It is the following file.
 146                          */
 147                         if (current_fid != fid) {
 148                                 xargs_unread(xp);
 149                                 break;
 150                         }
 151                         if (split(ctags_x, 4, &ptable) < 4) {
 152                                 recover(&ptable);
 153                                 die("too small number of parts in anchor_load().\n'%s'", ctags_x);
 154                         }
 155                         if (db == GTAGS) {
 156                                 char *p = ptable.part[PART_LINE].start;
 157 
 158                                 for (; *p && isspace((unsigned char)*p); p++)
 159                                         ;
 160                                 if (!*p) {
 161                                         recover(&ptable);
 162                                         die("The output of parser is illegal.\n%s", ctags_x);
 163                                 }
 164                                 /*
 165                                  * Function header is applied only to the anchor whoes type is 'D'.
 166                                  * (D: function, M: macro, T: type)
 167                                  */
 168                                 type = 'T';
 169                                 if (*p == '#')
 170                                         type = 'M';
 171                                 else if (locatestring(p, "typedef", MATCH_AT_FIRST))
 172                                         type = 'T';
 173                                 else if ((p = locatestring(p, ptable.part[PART_TAG].start, MATCH_FIRST)) != NULL) {
 174                                         /* skip a tag and the following blanks */
 175                                         p += strlen(ptable.part[PART_TAG].start);
 176                                         for (; *p && isspace((unsigned char)*p); p++)
 177                                                 ;
 178                                         if (*p == '(')
 179                                                 type = 'D';
 180                                 }
 181                         }  else if (db == GRTAGS)
 182                                 type = 'R';
 183                         else
 184                                 type = 'Y';
 185                         /* allocate an entry */
 186                         a = varray_append(vb);
 187                         a->lineno = atoi(ptable.part[PART_LNO].start);
 188                         a->type = type;
 189                         a->done = 0;
 190                         settag(a, ptable.part[PART_TAG].start);
 191                         recover(&ptable);
 192                 }
 193                 if (ctags_xid == NULL) {
 194                         xargs_close(anchor_input[db]);
 195                         anchor_input[db] = NULL;
 196                 }
 197         }
 198         if (vb->length == 0) {
 199                 table = NULL;
 200         } else {
 201                 int i, used = vb->length;
 202                 /*
 203                  * Sort by lineno.
 204                  */
 205                 table = varray_assign(vb, 0, 0);
 206                 qsort(table, used, sizeof(struct anchor), cmp); 
 207                 /*
 208                  * Setup some lineno.
 209                  */
 210                 for (i = 0; i < used; i++)
 211                         if (table[i].type == 'D')
 212                                 break;
 213                 if (i < used)
 214                         FIRST = table[i].lineno;
 215                 for (i = used - 1; i >= 0; i--)
 216                         if (table[i].type == 'D')
 217                                 break;
 218                 if (i >= 0)
 219                         LAST = table[i].lineno;
 220         }
 221         /*
 222          * Setup loop range.
 223          */
 224         start = table;
 225         curp = NULL;
 226         end = &table[vb->length];
 227         /* anchor_dump(stderr, 0);*/
 228 }
 229 /**
 230  * anchor_unload: unload anchor table
 231  */
 232 void
 233 anchor_unload(void)
 234 {
 235         struct anchor *a;
 236 
 237         for (a = start; a && a < end; a++) {
 238                 if (a->reserve) {
 239                         free(a->reserve);
 240                         a->reserve = NULL;
 241                 }
 242         }
 243         /* We don't free varray */
 244         /* varray_close(vb); */
 245         FIRST = LAST = 0;
 246         start = curp = end = NULL;
 247 }
 248 /**
 249  * anchor_first: return the first anchor
 250  */
 251 struct anchor *
 252 anchor_first(void)
 253 {
 254         if (!start || start == end)
 255                 return NULL;
 256         CURRENT = start;
 257         if (CURRENT->type == 'D')
 258                 CURRENTDEF = CURRENT;
 259         return CURRENT;
 260 }
 261 /**
 262  * anchor_next: return the next anchor
 263  */
 264 struct anchor *
 265 anchor_next(void)
 266 {
 267         if (!start)
 268                 return NULL;
 269         if (++CURRENT >= end)
 270                 return NULL;
 271         if (CURRENT->type == 'D')
 272                 CURRENTDEF = CURRENT;
 273         return CURRENT;
 274 }
 275 /**
 276  * anchor_get: return the specified anchor
 277  *
 278  *      @param[in]      name    name of anchor
 279  *      @param[in]      length  lenght of the name
 280  *      @param[in]      type    ==0: not specified <br>
 281  *                      !=0: D, M, T, R, Y
 282  *      @param[in]      lineno  line number
 283  */
 284 struct anchor *
 285 anchor_get(const char *name, int length, int type, int lineno)
 286 {
 287         struct anchor *p = curp ? curp : start;
 288 
 289         if (table == NULL)
 290                 return NULL;
 291         if (p->lineno > lineno)
 292                 return NULL;
 293         /*
 294          * set pointer to the top of the cluster.
 295          */
 296         for (; p < end && p->lineno < lineno; p++)
 297                 ;
 298         if (p >= end || p->lineno != lineno)
 299                 return NULL;
 300         curp = p;
 301         for (; p < end && p->lineno == lineno; p++)
 302                 if (!p->done && p->length == length && !strcmp(gettag(p), name))
 303                         if (!type || p->type == type)
 304                                 return p;
 305         return NULL;
 306 }
 307 /**
 308  * define_line: check whether or not this is a define line.
 309  *
 310  *      @param[in]      lineno  line number
 311  *      @par Globals used (output):
 312  *              #curp   pointer to the current cluster
 313  *
 314  *      @return         1: definition, 0: not definition
 315  */
 316 int
 317 define_line(int lineno)
 318 {
 319         struct anchor *p = curp ? curp : start;
 320 
 321         if (table == NULL)
 322                 return 0;
 323         if (p->lineno > lineno)
 324                 return 0;
 325         /*
 326          * set pointer to the top of the cluster.
 327          */
 328         for (; p < end && p->lineno < lineno; p++)
 329                 ;
 330         if (p >= end || p->lineno != lineno)
 331                 return 0;
 332         curp = p;
 333         for (; p < end && p->lineno == lineno; p++)
 334                 if (p->type == 'D')
 335                         return 1;
 336         return 0;
 337 }
 338 /**
 339  * anchor_getlinks: return anchor link array
 340  *              (previous, next, first, last, top, bottom)
 341  *
 342  *      @param[in]      lineno  line number
 343  */
 344 int *
 345 anchor_getlinks(int lineno)
 346 {
 347         static int ref[A_SIZE];
 348         int i;
 349 
 350         for (i = 0; i < A_SIZE; i++)
 351                 ref[i] = 0;
 352         if (lineno >= 1 && start) {
 353                 struct anchor *c, *p;
 354 
 355                 if (CURRENTDEF == NULL) {
 356                         for (c = start; c < end; c++)
 357                                 if (c->lineno == lineno && c->type == 'D')
 358                                         break;
 359                         CURRENTDEF = c;
 360                 } else {
 361                         for (c = CURRENTDEF; c >= start; c--)
 362                                 if (c->lineno == lineno && c->type == 'D')
 363                                         break;
 364                 }
 365                 for (p = c - 1; p >= start; p--)
 366                         if (p->type == 'D') {
 367                                 ref[A_PREV] = p->lineno;
 368                                 break;
 369                         }
 370                 for (p = c + 1; p < end; p++)
 371                         if (p->type == 'D') {
 372                                 ref[A_NEXT] = p->lineno;
 373                                 break;
 374                         }
 375         }
 376         if (FIRST > 0 && lineno != FIRST)
 377                 ref[A_FIRST] = FIRST;
 378         if (LAST > 0 && lineno != LAST)
 379                 ref[A_LAST] = LAST;
 380         if (lineno != 0)
 381                 ref[A_TOP] = -1;
 382         if (lineno != -1)
 383                 ref[A_BOTTOM] = -2;
 384         if (FIRST > 0 && FIRST == LAST) {
 385                 if (lineno == 0)
 386                         ref[A_LAST] = 0;
 387                 if (lineno == -1)
 388                         ref[A_FIRST] = 0;
 389         }
 390         return ref;
 391 }
 392 void
 393 anchor_dump(FILE *op, int lineno)
 394 {
 395         struct anchor *a;
 396 
 397         if (op == NULL)
 398                 op = stderr;
 399         for (a = start; a < end ; a++)
 400                 if (lineno == 0 || a->lineno == lineno)
 401                         fprintf(op, "%d %s(%c)\n",
 402                                 a->lineno, gettag(a), a->type);
 403 }

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