[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.1.1.3

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