[BACK]Return to tags.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/tags.c, Revision 1.12

1.1       etheisen    1: /*
1.11      shadchin    2:  * Copyright (C) 1984-2012  Mark Nudelman
1.4       millert     3:  *
                      4:  * You may distribute under the terms of either the GNU General Public
                      5:  * License or the Less License, as specified in the README file.
1.1       etheisen    6:  *
1.11      shadchin    7:  * For more information, see the README file.
1.1       etheisen    8:  */
1.12    ! nicm        9: /*
        !            10:  * Modified for use with illumos.
        !            11:  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
        !            12:  */
1.1       etheisen   13:
                     14: #include "less.h"
                     15:
1.12    ! nicm       16: #define        WHITESP(c)      ((c) == ' ' || (c) == '\t')
1.1       etheisen   17:
1.12    ! nicm       18: char *tags = "tags";
1.1       etheisen   19:
1.4       millert    20: static int total;
                     21: static int curseq;
1.1       etheisen   22:
                     23: extern int linenums;
1.10      millert    24: extern volatile sig_atomic_t sigs;
1.4       millert    25:
                     26: enum tag_result {
                     27:        TAG_FOUND,
                     28:        TAG_NOFILE,
                     29:        TAG_NOTAG,
                     30:        TAG_NOTYPE,
                     31:        TAG_INTR
                     32: };
                     33:
                     34: /*
                     35:  * Tag type
                     36:  */
                     37: enum {
                     38:        T_CTAGS,        /* 'tags': standard and extended format (ctags) */
                     39:        T_CTAGS_X,      /* stdin: cross reference format (ctags) */
                     40:        T_GTAGS,        /* 'GTAGS': function defenition (global) */
                     41:        T_GRTAGS,       /* 'GRTAGS': function reference (global) */
                     42:        T_GSYMS,        /* 'GSYMS': other symbols (global) */
                     43:        T_GPATH         /* 'GPATH': path name (global) */
                     44: };
                     45:
                     46: static enum tag_result findctag();
                     47: static enum tag_result findgtag();
                     48: static char *nextgtag();
                     49: static char *prevgtag();
1.12    ! nicm       50: static off_t ctagsearch();
        !            51: static off_t gtagsearch();
1.4       millert    52: static int getentry();
                     53:
                     54: /*
                     55:  * The list of tags generated by the last findgtag() call.
                     56:  *
                     57:  * Use either pattern or line number.
                     58:  * findgtag() always uses line number, so pattern is always NULL.
1.9       shadchin   59:  * findctag() uses either pattern (in which case line number is 0),
1.4       millert    60:  * or line number (in which case pattern is NULL).
                     61:  */
                     62: struct taglist {
                     63:        struct tag *tl_first;
                     64:        struct tag *tl_last;
                     65: };
1.12    ! nicm       66: #define        TAG_END  ((struct tag *)&taglist)
1.4       millert    67: static struct taglist taglist = { TAG_END, TAG_END };
                     68: struct tag {
                     69:        struct tag *next, *prev; /* List links */
                     70:        char *tag_file;         /* Source file containing the tag */
                     71:        LINENUM tag_linenum;    /* Appropriate line number in source file */
                     72:        char *tag_pattern;      /* Pattern used to find the tag */
1.12    ! nicm       73:        int tag_endline;        /* True if the pattern includes '$' */
1.4       millert    74: };
                     75: static struct tag *curtag;
                     76:
1.12    ! nicm       77: #define        TAG_INS(tp) \
1.9       shadchin   78:        (tp)->next = TAG_END; \
                     79:        (tp)->prev = taglist.tl_last; \
                     80:        taglist.tl_last->next = (tp); \
                     81:        taglist.tl_last = (tp);
1.4       millert    82:
1.12    ! nicm       83: #define        TAG_RM(tp) \
1.4       millert    84:        (tp)->next->prev = (tp)->prev; \
                     85:        (tp)->prev->next = (tp)->next;
                     86:
                     87: /*
                     88:  * Delete tag structures.
                     89:  */
1.12    ! nicm       90: void
        !            91: cleantags(void)
1.4       millert    92: {
1.12    ! nicm       93:        struct tag *tp;
1.4       millert    94:
                     95:        /*
                     96:         * Delete any existing tag list.
                     97:         * {{ Ideally, we wouldn't do this until after we know that we
                     98:         *    can load some other tag information. }}
                     99:         */
1.12    ! nicm      100:        while ((tp = taglist.tl_first) != TAG_END) {
1.4       millert   101:                TAG_RM(tp);
                    102:                free(tp);
                    103:        }
                    104:        curtag = NULL;
                    105:        total = curseq = 0;
                    106: }
                    107:
                    108: /*
                    109:  * Create a new tag entry.
                    110:  */
1.12    ! nicm      111: static struct tag *
        !           112: maketagent(char *file, LINENUM linenum, char *pattern, int endline)
1.4       millert   113: {
1.12    ! nicm      114:        struct tag *tp;
1.4       millert   115:
1.12    ! nicm      116:        tp = ecalloc(sizeof (struct tag), 1);
1.4       millert   117:        tp->tag_file = save(file);
                    118:        tp->tag_linenum = linenum;
                    119:        tp->tag_endline = endline;
                    120:        if (pattern == NULL)
                    121:                tp->tag_pattern = NULL;
                    122:        else
                    123:                tp->tag_pattern = save(pattern);
                    124:        return (tp);
                    125: }
                    126:
                    127: /*
                    128:  * Get tag mode.
                    129:  */
1.12    ! nicm      130: static int
        !           131: gettagtype(void)
1.4       millert   132: {
                    133:        int f;
                    134:
                    135:        if (strcmp(tags, "GTAGS") == 0)
1.12    ! nicm      136:                return (T_GTAGS);
1.4       millert   137:        if (strcmp(tags, "GRTAGS") == 0)
1.12    ! nicm      138:                return (T_GRTAGS);
1.4       millert   139:        if (strcmp(tags, "GSYMS") == 0)
1.12    ! nicm      140:                return (T_GSYMS);
1.4       millert   141:        if (strcmp(tags, "GPATH") == 0)
1.12    ! nicm      142:                return (T_GPATH);
1.4       millert   143:        if (strcmp(tags, "-") == 0)
1.12    ! nicm      144:                return (T_CTAGS_X);
1.4       millert   145:        f = open(tags, OPEN_READ);
1.12    ! nicm      146:        if (f >= 0) {
        !           147:                (void) close(f);
        !           148:                return (T_CTAGS);
1.4       millert   149:        }
1.12    ! nicm      150:        return (T_GTAGS);
1.4       millert   151: }
1.1       etheisen  152:
                    153: /*
1.4       millert   154:  * Find tags in tag file.
1.1       etheisen  155:  * Find a tag in the "tags" file.
1.4       millert   156:  * Sets "tag_file" to the name of the file containing the tag,
1.1       etheisen  157:  * and "tagpattern" to the search pattern which should be used
                    158:  * to find the tag.
                    159:  */
1.12    ! nicm      160: void
        !           161: findtag(char *tag)
1.4       millert   162: {
                    163:        int type = gettagtype();
                    164:        enum tag_result result;
                    165:
                    166:        if (type == T_CTAGS)
                    167:                result = findctag(tag);
                    168:        else
                    169:                result = findgtag(tag, type);
1.12    ! nicm      170:        switch (result) {
1.4       millert   171:        case TAG_FOUND:
                    172:        case TAG_INTR:
                    173:                break;
                    174:        case TAG_NOFILE:
                    175:                error("No tags file", NULL_PARG);
                    176:                break;
                    177:        case TAG_NOTAG:
                    178:                error("No such tag in tags file", NULL_PARG);
                    179:                break;
                    180:        case TAG_NOTYPE:
                    181:                error("unknown tag type", NULL_PARG);
                    182:                break;
                    183:        }
                    184: }
                    185:
                    186: /*
                    187:  * Search for a tag.
                    188:  */
1.12    ! nicm      189: off_t
        !           190: tagsearch(void)
1.4       millert   191: {
                    192:        if (curtag == NULL)
1.12    ! nicm      193:                return (-1);  /* No gtags loaded! */
1.4       millert   194:        if (curtag->tag_linenum != 0)
1.12    ! nicm      195:                return (gtagsearch());
1.4       millert   196:        else
1.12    ! nicm      197:                return (ctagsearch());
1.4       millert   198: }
                    199:
                    200: /*
                    201:  * Go to the next tag.
                    202:  */
1.12    ! nicm      203: char *
        !           204: nexttag(int n)
1.4       millert   205: {
1.12    ! nicm      206:        char *tagfile = NULL;
1.4       millert   207:
                    208:        while (n-- > 0)
                    209:                tagfile = nextgtag();
1.12    ! nicm      210:        return (tagfile);
1.4       millert   211: }
                    212:
                    213: /*
                    214:  * Go to the previous tag.
                    215:  */
1.12    ! nicm      216: char *
        !           217: prevtag(int n)
1.4       millert   218: {
1.12    ! nicm      219:        char *tagfile = NULL;
1.4       millert   220:
                    221:        while (n-- > 0)
                    222:                tagfile = prevgtag();
1.12    ! nicm      223:        return (tagfile);
1.4       millert   224: }
                    225:
                    226: /*
                    227:  * Return the total number of tags.
                    228:  */
1.12    ! nicm      229: int
        !           230: ntags(void)
1.4       millert   231: {
1.12    ! nicm      232:        return (total);
1.4       millert   233: }
                    234:
                    235: /*
                    236:  * Return the sequence number of current tag.
                    237:  */
1.12    ! nicm      238: int
        !           239: curr_tag(void)
1.4       millert   240: {
1.12    ! nicm      241:        return (curseq);
1.4       millert   242: }
                    243:
1.12    ! nicm      244: /*
1.4       millert   245:  * ctags
                    246:  */
                    247:
                    248: /*
                    249:  * Find tags in the "tags" file.
                    250:  * Sets curtag to the first tag entry.
                    251:  */
1.12    ! nicm      252: static enum tag_result
        !           253: findctag(char *tag)
1.1       etheisen  254: {
                    255:        char *p;
1.12    ! nicm      256:        FILE *f;
        !           257:        int taglen;
1.4       millert   258:        LINENUM taglinenum;
                    259:        char *tagfile;
                    260:        char *tagpattern;
                    261:        int tagendline;
1.1       etheisen  262:        int search_char;
                    263:        int err;
1.4       millert   264:        char tline[TAGLINE_SIZE];
                    265:        struct tag *tp;
1.1       etheisen  266:
1.4       millert   267:        p = shell_unquote(tags);
                    268:        f = fopen(p, "r");
                    269:        free(p);
                    270:        if (f == NULL)
1.12    ! nicm      271:                return (TAG_NOFILE);
1.1       etheisen  272:
1.4       millert   273:        cleantags();
                    274:        total = 0;
1.1       etheisen  275:        taglen = strlen(tag);
                    276:
                    277:        /*
                    278:         * Search the tags file for the desired tag.
                    279:         */
1.12    ! nicm      280:        while (fgets(tline, sizeof (tline), f) != NULL) {
1.4       millert   281:                if (tline[0] == '!')
                    282:                        /* Skip header of extended format. */
                    283:                        continue;
1.1       etheisen  284:                if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen]))
                    285:                        continue;
                    286:
                    287:                /*
                    288:                 * Found it.
                    289:                 * The line contains the tag, the filename and the
                    290:                 * location in the file, separated by white space.
1.12    ! nicm      291:                 * The location is either a decimal line number,
1.1       etheisen  292:                 * or a search pattern surrounded by a pair of delimiters.
                    293:                 * Parse the line and extract these parts.
                    294:                 */
1.4       millert   295:                tagpattern = NULL;
1.1       etheisen  296:
                    297:                /*
                    298:                 * Skip over the whitespace after the tag name.
                    299:                 */
                    300:                p = skipsp(tline+taglen);
                    301:                if (*p == '\0')
                    302:                        /* File name is missing! */
                    303:                        continue;
                    304:
                    305:                /*
                    306:                 * Save the file name.
                    307:                 * Skip over the whitespace after the file name.
                    308:                 */
                    309:                tagfile = p;
                    310:                while (!WHITESP(*p) && *p != '\0')
                    311:                        p++;
                    312:                *p++ = '\0';
                    313:                p = skipsp(p);
                    314:                if (*p == '\0')
                    315:                        /* Pattern is missing! */
                    316:                        continue;
                    317:
                    318:                /*
1.12    ! nicm      319:                 * First see if it is a line number.
1.1       etheisen  320:                 */
1.4       millert   321:                tagendline = 0;
1.1       etheisen  322:                taglinenum = getnum(&p, 0, &err);
1.12    ! nicm      323:                if (err) {
1.1       etheisen  324:                        /*
                    325:                         * No, it must be a pattern.
1.12    ! nicm      326:                         * Delete the initial "^" (if present) and
1.1       etheisen  327:                         * the final "$" from the pattern.
                    328:                         * Delete any backslash in the pattern.
                    329:                         */
                    330:                        taglinenum = 0;
                    331:                        search_char = *p++;
                    332:                        if (*p == '^')
                    333:                                p++;
1.4       millert   334:                        tagpattern = p;
1.12    ! nicm      335:                        while (*p != search_char && *p != '\0') {
1.1       etheisen  336:                                if (*p == '\\')
                    337:                                        p++;
1.4       millert   338:                                p++;
1.1       etheisen  339:                        }
1.4       millert   340:                        tagendline = (p[-1] == '$');
                    341:                        if (tagendline)
                    342:                                p--;
                    343:                        *p = '\0';
1.1       etheisen  344:                }
1.12    ! nicm      345:                tp = maketagent(tagfile, taglinenum, tagpattern, tagendline);
1.4       millert   346:                TAG_INS(tp);
                    347:                total++;
1.1       etheisen  348:        }
                    349:        fclose(f);
1.4       millert   350:        if (total == 0)
1.12    ! nicm      351:                return (TAG_NOTAG);
1.4       millert   352:        curtag = taglist.tl_first;
                    353:        curseq = 1;
1.12    ! nicm      354:        return (TAG_FOUND);
1.4       millert   355: }
                    356:
                    357: /*
                    358:  * Edit current tagged file.
                    359:  */
1.12    ! nicm      360: int
        !           361: edit_tagfile(void)
1.4       millert   362: {
                    363:        if (curtag == NULL)
                    364:                return (1);
                    365:        return (edit(curtag->tag_file));
1.1       etheisen  366: }
                    367:
                    368: /*
                    369:  * Search for a tag.
                    370:  * This is a stripped-down version of search().
                    371:  * We don't use search() for several reasons:
                    372:  *   - We don't want to blow away any search string we may have saved.
                    373:  *   - The various regular-expression functions (from different systems:
1.12    ! nicm      374:  *     regcmp vs. re_comp) behave differently in the presence of
1.1       etheisen  375:  *     parentheses (which are almost always found in a tag).
                    376:  */
1.12    ! nicm      377: static off_t
        !           378: ctagsearch(void)
1.1       etheisen  379: {
1.12    ! nicm      380:        off_t pos, linepos;
1.4       millert   381:        LINENUM linenum;
                    382:        int len;
1.1       etheisen  383:        char *line;
                    384:
                    385:        pos = ch_zero();
                    386:        linenum = find_linenum(pos);
                    387:
1.12    ! nicm      388:        for (;;) {
1.1       etheisen  389:                /*
1.12    ! nicm      390:                 * Get lines until we find a matching one or
1.1       etheisen  391:                 * until we hit end-of-file.
                    392:                 */
                    393:                if (ABORT_SIGS())
1.12    ! nicm      394:                        return (-1);
1.1       etheisen  395:
                    396:                /*
1.12    ! nicm      397:                 * Read the next line, and save the
1.1       etheisen  398:                 * starting position of that line in linepos.
                    399:                 */
                    400:                linepos = pos;
1.9       shadchin  401:                pos = forw_raw_line(pos, &line, (int *)NULL);
1.1       etheisen  402:                if (linenum != 0)
                    403:                        linenum++;
                    404:
1.12    ! nicm      405:                if (pos == -1) {
1.1       etheisen  406:                        /*
                    407:                         * We hit EOF without a match.
                    408:                         */
                    409:                        error("Tag not found", NULL_PARG);
1.12    ! nicm      410:                        return (-1);
1.1       etheisen  411:                }
                    412:
                    413:                /*
                    414:                 * If we're using line numbers, we might as well
                    415:                 * remember the information we have now (the position
                    416:                 * and line number of the current line).
                    417:                 */
                    418:                if (linenums)
                    419:                        add_lnum(linenum, pos);
                    420:
                    421:                /*
                    422:                 * Test the line to see if we have a match.
                    423:                 * Use strncmp because the pattern may be
                    424:                 * truncated (in the tags file) if it is too long.
1.4       millert   425:                 * If tagendline is set, make sure we match all
                    426:                 * the way to end of line (no extra chars after the match).
1.1       etheisen  427:                 */
1.4       millert   428:                len = strlen(curtag->tag_pattern);
                    429:                if (strncmp(curtag->tag_pattern, line, len) == 0 &&
1.12    ! nicm      430:                    (!curtag->tag_endline || line[len] == '\0' ||
        !           431:                    line[len] == '\r')) {
1.4       millert   432:                        curtag->tag_linenum = find_linenum(linepos);
1.1       etheisen  433:                        break;
1.4       millert   434:                }
1.1       etheisen  435:        }
                    436:
                    437:        return (linepos);
                    438: }
                    439:
1.12    ! nicm      440: /*
1.4       millert   441:  * gtags
                    442:  */
                    443:
                    444: /*
                    445:  * Find tags in the GLOBAL's tag file.
                    446:  * The findgtag() will try and load information about the requested tag.
                    447:  * It does this by calling "global -x tag" and storing the parsed output
                    448:  * for future use by gtagsearch().
                    449:  * Sets curtag to the first tag entry.
                    450:  */
1.12    ! nicm      451: static enum tag_result
        !           452: findgtag(char *tag, int type)
1.4       millert   453: {
                    454:        char buf[256];
                    455:        FILE *fp;
                    456:        struct tag *tp;
                    457:
                    458:        if (type != T_CTAGS_X && tag == NULL)
1.12    ! nicm      459:                return (TAG_NOFILE);
1.4       millert   460:
                    461:        cleantags();
                    462:        total = 0;
                    463:
                    464:        /*
                    465:         * If type == T_CTAGS_X then read ctags's -x format from stdin
                    466:         * else execute global(1) and read from it.
                    467:         */
1.12    ! nicm      468:        if (type == T_CTAGS_X) {
1.4       millert   469:                fp = stdin;
                    470:                /* Set tag default because we cannot read stdin again. */
                    471:                tags = "tags";
1.12    ! nicm      472:        } else {
1.9       shadchin  473:                char *command;
1.4       millert   474:                char *flag;
                    475:                char *qtag;
                    476:                char *cmd = lgetenv("LESSGLOBALTAGS");
                    477:
                    478:                if (cmd == NULL || *cmd == '\0')
1.12    ! nicm      479:                        return (TAG_NOFILE);
1.4       millert   480:                /* Get suitable flag value for global(1). */
1.12    ! nicm      481:                switch (type) {
1.4       millert   482:                case T_GTAGS:
1.12    ! nicm      483:                        flag = "";
1.4       millert   484:                        break;
                    485:                case T_GRTAGS:
                    486:                        flag = "r";
                    487:                        break;
                    488:                case T_GSYMS:
                    489:                        flag = "s";
                    490:                        break;
                    491:                case T_GPATH:
                    492:                        flag = "P";
                    493:                        break;
                    494:                default:
1.12    ! nicm      495:                        return (TAG_NOTYPE);
1.4       millert   496:                }
                    497:
                    498:                /* Get our data from global(1). */
                    499:                qtag = shell_quote(tag);
                    500:                if (qtag == NULL)
                    501:                        qtag = tag;
1.12    ! nicm      502:                command = easprintf("%s -x%s %s", cmd, flag, qtag);
1.4       millert   503:                if (qtag != tag)
                    504:                        free(qtag);
                    505:                fp = popen(command, "r");
1.9       shadchin  506:                free(command);
1.4       millert   507:        }
1.12    ! nicm      508:        if (fp != NULL) {
        !           509:                while (fgets(buf, sizeof (buf), fp)) {
1.4       millert   510:                        char *name, *file, *line;
1.12    ! nicm      511:                        int len;
1.4       millert   512:
1.12    ! nicm      513:                        if (sigs) {
1.4       millert   514:                                if (fp != stdin)
                    515:                                        pclose(fp);
1.12    ! nicm      516:                                return (TAG_INTR);
1.4       millert   517:                        }
1.9       shadchin  518:                        len = strlen(buf);
1.12    ! nicm      519:                        if (len > 0 && buf[len-1] == '\n') {
1.9       shadchin  520:                                buf[len-1] = '\0';
1.12    ! nicm      521:                        } else {
1.4       millert   522:                                int c;
                    523:                                do {
                    524:                                        c = fgetc(fp);
                    525:                                } while (c != '\n' && c != EOF);
                    526:                        }
                    527:
1.12    ! nicm      528:                        if (getentry(buf, &name, &file, &line)) {
1.4       millert   529:                                /*
                    530:                                 * Couldn't parse this line for some reason.
                    531:                                 * We'll just pretend it never happened.
                    532:                                 */
                    533:                                break;
                    534:                        }
                    535:
                    536:                        /* Make new entry and add to list. */
1.12    ! nicm      537:                        tp = maketagent(file, (LINENUM) atoi(line), NULL, 0);
1.4       millert   538:                        TAG_INS(tp);
                    539:                        total++;
                    540:                }
1.12    ! nicm      541:                if (fp != stdin) {
        !           542:                        if (pclose(fp)) {
1.4       millert   543:                                curtag = NULL;
                    544:                                total = curseq = 0;
1.12    ! nicm      545:                                return (TAG_NOFILE);
1.4       millert   546:                        }
                    547:                }
                    548:        }
                    549:
                    550:        /* Check to see if we found anything. */
                    551:        tp = taglist.tl_first;
                    552:        if (tp == TAG_END)
1.12    ! nicm      553:                return (TAG_NOTAG);
1.4       millert   554:        curtag = tp;
                    555:        curseq = 1;
1.12    ! nicm      556:        return (TAG_FOUND);
1.4       millert   557: }
                    558:
                    559: static int circular = 0;       /* 1: circular tag structure */
                    560:
                    561: /*
                    562:  * Return the filename required for the next gtag in the queue that was setup
                    563:  * by findgtag().  The next call to gtagsearch() will try to position at the
                    564:  * appropriate tag.
                    565:  */
1.12    ! nicm      566: static char *
        !           567: nextgtag(void)
1.4       millert   568: {
                    569:        struct tag *tp;
                    570:
                    571:        if (curtag == NULL)
                    572:                /* No tag loaded */
1.12    ! nicm      573:                return (NULL);
1.4       millert   574:
                    575:        tp = curtag->next;
1.12    ! nicm      576:        if (tp == TAG_END) {
1.4       millert   577:                if (!circular)
1.12    ! nicm      578:                        return (NULL);
1.4       millert   579:                /* Wrapped around to the head of the queue */
                    580:                curtag = taglist.tl_first;
                    581:                curseq = 1;
1.12    ! nicm      582:        } else {
1.4       millert   583:                curtag = tp;
                    584:                curseq++;
                    585:        }
                    586:        return (curtag->tag_file);
                    587: }
                    588:
                    589: /*
                    590:  * Return the filename required for the previous gtag in the queue that was
                    591:  * setup by findgtat().  The next call to gtagsearch() will try to position
                    592:  * at the appropriate tag.
                    593:  */
1.12    ! nicm      594: static char *
        !           595: prevgtag(void)
1.4       millert   596: {
                    597:        struct tag *tp;
                    598:
                    599:        if (curtag == NULL)
                    600:                /* No tag loaded */
1.12    ! nicm      601:                return (NULL);
1.4       millert   602:
                    603:        tp = curtag->prev;
1.12    ! nicm      604:        if (tp == TAG_END) {
1.4       millert   605:                if (!circular)
1.12    ! nicm      606:                        return (NULL);
1.4       millert   607:                /* Wrapped around to the tail of the queue */
                    608:                curtag = taglist.tl_last;
                    609:                curseq = total;
1.12    ! nicm      610:        } else {
1.4       millert   611:                curtag = tp;
                    612:                curseq--;
                    613:        }
                    614:        return (curtag->tag_file);
                    615: }
                    616:
                    617: /*
                    618:  * Position the current file at at what is hopefully the tag that was chosen
                    619:  * using either findtag() or one of nextgtag() and prevgtag().  Returns -1
1.5       jmc       620:  * if it was unable to position at the tag, 0 if successful.
1.4       millert   621:  */
1.12    ! nicm      622: static off_t
        !           623: gtagsearch(void)
1.4       millert   624: {
                    625:        if (curtag == NULL)
1.12    ! nicm      626:                return (-1);  /* No gtags loaded! */
1.4       millert   627:        return (find_pos(curtag->tag_linenum));
                    628: }
                    629:
                    630: /*
                    631:  * The getentry() parses both standard and extended ctags -x format.
                    632:  *
                    633:  * [standard format]
                    634:  * <tag>   <lineno>  <file>         <image>
                    635:  * +------------------------------------------------
                    636:  * |main     30      main.c         main(argc, argv)
                    637:  * |func     21      subr.c         func(arg)
                    638:  *
                    639:  * The following commands write this format.
                    640:  *     o Traditinal Ctags with -x option
                    641:  *     o Global with -x option
                    642:  *             See <http://www.gnu.org/software/global/global.html>
                    643:  *
                    644:  * [extended format]
                    645:  * <tag>   <type>  <lineno>   <file>        <image>
                    646:  * +----------------------------------------------------------
                    647:  * |main     function 30      main.c         main(argc, argv)
                    648:  * |func     function 21      subr.c         func(arg)
                    649:  *
                    650:  * The following commands write this format.
                    651:  *     o Exuberant Ctags with -x option
                    652:  *             See <http://ctags.sourceforge.net>
                    653:  *
                    654:  * Returns 0 on success, -1 on error.
                    655:  * The tag, file, and line will each be NUL-terminated pointers
                    656:  * into buf.
                    657:  */
1.12    ! nicm      658: static int
        !           659: getentry(char *buf, char **tag, char **file, char **line)
1.4       millert   660: {
                    661:        char *p = buf;
                    662:
1.12    ! nicm      663:        for (*tag = p; *p && !isspace(*p); p++)         /* tag name */
1.4       millert   664:                ;
                    665:        if (*p == 0)
                    666:                return (-1);
                    667:        *p++ = 0;
1.12    ! nicm      668:        for (; *p && isspace(*p); p++)                  /* (skip blanks) */
1.4       millert   669:                ;
                    670:        if (*p == 0)
                    671:                return (-1);
                    672:        /*
                    673:         * If the second part begin with other than digit,
                    674:         * it is assumed tag type. Skip it.
                    675:         */
1.12    ! nicm      676:        if (!isdigit(*p)) {
        !           677:                for (; *p && !isspace(*p); p++)         /* (skip tag type) */
1.4       millert   678:                        ;
1.12    ! nicm      679:                for (; *p && isspace(*p); p++)          /* (skip blanks) */
1.4       millert   680:                        ;
                    681:        }
1.12    ! nicm      682:        if (!isdigit(*p))
1.4       millert   683:                return (-1);
                    684:        *line = p;                                      /* line number */
1.12    ! nicm      685:        for (*line = p;  *p && !isspace(*p);  p++)
1.4       millert   686:                ;
                    687:        if (*p == 0)
                    688:                return (-1);
                    689:        *p++ = 0;
1.12    ! nicm      690:        for (; *p && isspace(*p); p++)          /* (skip blanks) */
1.4       millert   691:                ;
                    692:        if (*p == 0)
                    693:                return (-1);
                    694:        *file = p;                                      /* file name */
1.12    ! nicm      695:        for (*file = p;  *p && !isspace(*p);  p++)
1.4       millert   696:                ;
                    697:        if (*p == 0)
                    698:                return (-1);
                    699:        *p = 0;
                    700:
                    701:        /* value check */
                    702:        if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0)
                    703:                return (0);
                    704:        return (-1);
                    705: }