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

Annotation of src/usr.bin/mg/cscope.c, Revision 1.9

1.9     ! bcallah     1: /*     $OpenBSD: cscope.c,v 1.8 2014/11/16 04:16:41 guenther Exp $     */
1.2       jasper      2:
1.1       lum         3: /*
1.3       lum         4:  * This file is in the public domain.
1.1       lum         5:  *
1.3       lum         6:  * Author: Sunil Nimmagadda <sunil@sunilnimmagadda.com>
1.1       lum         7:  */
                      8:
1.9     ! bcallah     9: #include <sys/queue.h>
        !            10: #include <sys/stat.h>
1.1       lum        11: #include <sys/types.h>
                     12: #include <ctype.h>
1.9     ! bcallah    13: #include <errno.h>
1.1       lum        14: #include <fcntl.h>
                     15: #include <fnmatch.h>
1.8       guenther   16: #include <limits.h>
1.9     ! bcallah    17: #include <signal.h>
1.1       lum        18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <string.h>
1.9     ! bcallah    21: #include <unistd.h>
1.1       lum        22:
                     23: #include "def.h"
                     24:
                     25: #define CSSYMBOL      0
                     26: #define CSDEFINITION  1
                     27: #define CSCALLEDFUNCS 2
                     28: #define CSCALLERFUNCS 3
                     29: #define CSTEXT        4
                     30: #define CSEGREP       6
                     31: #define CSFINDFILE    7
                     32: #define CSINCLUDES    8
                     33:
                     34: struct cstokens {
                     35:        const char *fname;
                     36:        const char *function;
                     37:        const char *lineno;
                     38:        const char *pattern;
                     39: };
                     40:
                     41: struct csmatch {
                     42:        TAILQ_ENTRY(csmatch) entry;
                     43:        int lineno;
                     44: };
                     45:
                     46: struct csrecord {
                     47:        TAILQ_ENTRY(csrecord) entry;
                     48:        char *filename;
                     49:        TAILQ_HEAD(matches, csmatch) matches;
                     50: };
                     51:
                     52: static TAILQ_HEAD(csrecords, csrecord) csrecords = TAILQ_HEAD_INITIALIZER(csrecords);
                     53: static struct csrecord *addentryr;
                     54: static struct csrecord *currecord;
                     55: static struct csmatch  *curmatch;
                     56: static const char      *addentryfn;
                     57: static const char      *csprompt[] = {
                     58:        "Find this symbol: ",
                     59:        "Find this global definition: ",
                     60:        "Find functions called by this function: ",
                     61:        "Find functions calling this function: ",
                     62:        "Find this text string: ",
                     63:        "Change this text string: ",
                     64:        "Find this egrep pattern: ",
                     65:        "Find this file: ",
                     66:        "Find files #including this file: "
                     67: };
                     68:
                     69: static int  addentry(struct buffer *, char *);
                     70: static void csflush(void);
                     71: static int  do_cscope(int);
                     72: static int  csexists(const char *);
                     73: static int  getattr(char *, struct cstokens *);
                     74: static int  jumptomatch(void);
                     75: static void prettyprint(struct buffer *, struct cstokens *);
                     76: static const char *ltrim(const char *);
                     77:
                     78: /*
                     79:  * Find this symbol. Bound to C-c s s
                     80:  */
                     81: /* ARGSUSED */
                     82: int
                     83: cssymbol(int f, int n)
                     84: {
                     85:        return (do_cscope(CSSYMBOL));
                     86: }
                     87:
                     88: /*
                     89:  * Find this global definition. Bound to C-c s d
                     90:  */
                     91: /* ARGSUSED */int
                     92: csdefinition(int f, int n)
                     93: {
                     94:        return (do_cscope(CSDEFINITION));
                     95: }
                     96:
                     97: /*
                     98:  * Find functions called by this function. Bound to C-c s l
                     99:  */
                    100: /* ARGSUSED */
                    101: int
                    102: csfuncalled(int f, int n)
                    103: {
                    104:        return (do_cscope(CSCALLEDFUNCS));
                    105: }
                    106:
                    107: /*
                    108:  * Find functions calling this function. Bound to C-c s c
                    109:  */
                    110: /* ARGSUSED */
                    111: int
                    112: cscallerfuncs(int f, int n)
                    113: {
                    114:        return (do_cscope(CSCALLERFUNCS));
                    115: }
                    116:
                    117: /*
                    118:  * Find this text. Bound to C-c s t
                    119:  */
                    120: /* ARGSUSED */
                    121: int
                    122: csfindtext(int f, int n)
                    123: {
                    124:        return (do_cscope(CSTEXT));
                    125: }
                    126:
                    127: /*
                    128:  * Find this egrep pattern. Bound to C-c s e
                    129:  */
                    130: /* ARGSUSED */
                    131: int
                    132: csegrep(int f, int n)
                    133: {
                    134:        return (do_cscope(CSEGREP));
                    135: }
                    136:
                    137: /*
                    138:  * Find this file. Bound to C-c s f
                    139:  */
                    140: /* ARGSUSED */
                    141: int
                    142: csfindfile(int f, int n)
                    143: {
                    144:        return (do_cscope(CSFINDFILE));
                    145: }
                    146:
                    147: /*
                    148:  * Find files #including this file. Bound to C-c s i
                    149:  */
                    150: /* ARGSUSED */
                    151: int
                    152: csfindinc(int f, int n)
                    153: {
                    154:        return (do_cscope(CSINCLUDES));
                    155: }
                    156:
                    157: /*
                    158:  * Create list of files to index in the given directory
                    159:  * using cscope-indexer.
                    160:  */
                    161: /* ARGSUSED */
                    162: int
                    163: cscreatelist(int f, int n)
                    164: {
                    165:        struct buffer *bp;
                    166:        struct stat sb;
                    167:        FILE *fpipe;
                    168:        char dir[NFILEN], cmd[BUFSIZ], title[BUFSIZ], *line, *bufp;
                    169:        size_t len;
                    170:        int clen;
                    171:
                    172:        if (getbufcwd(dir, sizeof(dir)) == FALSE)
                    173:                dir[0] = '\0';
                    174:
                    175:        bufp = eread("Index files in directory: ", dir,
                    176:            sizeof(dir), EFCR | EFDEF | EFNEW | EFNUL);
                    177:
                    178:        if (bufp == NULL)
                    179:                return (ABORT);
                    180:        else if (bufp[0] == '\0')
                    181:                return (FALSE);
                    182:
                    183:        if (stat(dir, &sb) == -1) {
1.5       lum       184:                dobeep();
1.1       lum       185:                ewprintf("stat: %s", strerror(errno));
                    186:                return (FALSE);
                    187:        } else if (S_ISDIR(sb.st_mode) == 0) {
1.5       lum       188:                dobeep();
1.1       lum       189:                ewprintf("%s: Not a directory", dir);
                    190:                return (FALSE);
                    191:        }
                    192:
                    193:        if (csexists("cscope-indexer") == FALSE) {
1.5       lum       194:                dobeep();
1.1       lum       195:                ewprintf("no such file or directory, cscope-indexer");
                    196:                return (FALSE);
                    197:        }
                    198:
                    199:        clen = snprintf(cmd, sizeof(cmd), "cscope-indexer -v %s", dir);
                    200:        if (clen < 0 || clen >= sizeof(cmd))
                    201:                return (FALSE);
                    202:
                    203:        if ((fpipe = popen(cmd, "r")) == NULL) {
1.5       lum       204:                dobeep();
1.1       lum       205:                ewprintf("problem opening pipe");
                    206:                return (FALSE);
                    207:        }
                    208:
                    209:        bp = bfind("*cscope*", TRUE);
1.4       jsg       210:        if (bclear(bp) != TRUE) {
                    211:                pclose(fpipe);
1.1       lum       212:                return (FALSE);
1.4       jsg       213:        }
1.1       lum       214:        bp->b_flag |= BFREADONLY;
                    215:
                    216:        clen = snprintf(title, sizeof(title), "%s%s",
                    217:            "Creating cscope file list 'cscope.files' in: ", dir);
1.6       jsg       218:        if (clen < 0 || clen >= sizeof(title)) {
                    219:                pclose(fpipe);
1.1       lum       220:                return (FALSE);
1.6       jsg       221:        }
1.1       lum       222:        addline(bp, title);
                    223:        addline(bp, "");
                    224:        /* All lines are NUL terminated */
                    225:        while ((line = fgetln(fpipe, &len)) != NULL) {
                    226:                line[len - 1] = '\0';
                    227:                addline(bp, line);
                    228:        }
                    229:        pclose(fpipe);
                    230:        return (popbuftop(bp, WNONE));
                    231: }
                    232:
                    233: /*
                    234:  * Next Symbol. Bound to C-c s n
                    235:  */
                    236: /* ARGSUSED */
                    237: int
                    238: csnextmatch(int f, int n)
                    239: {
                    240:        struct csrecord *r;
                    241:        struct csmatch *m;
                    242:
                    243:        if (curmatch == NULL) {
                    244:                if ((r = TAILQ_FIRST(&csrecords)) == NULL) {
1.5       lum       245:                        dobeep();
1.1       lum       246:                        ewprintf("The *cscope* buffer does not exist yet");
                    247:                        return (FALSE);
                    248:                }
                    249:                currecord = r;
                    250:                curmatch = TAILQ_FIRST(&r->matches);
                    251:        } else {
                    252:                m = TAILQ_NEXT(curmatch, entry);
                    253:                if (m == NULL) {
                    254:                        r = TAILQ_NEXT(currecord, entry);
                    255:                        if (r == NULL) {
1.5       lum       256:                                dobeep();
1.1       lum       257:                                ewprintf("The end of *cscope* buffer has been"
                    258:                                    " reached");
                    259:                                return (FALSE);
                    260:                        } else {
                    261:                                currecord = r;
                    262:                                curmatch = TAILQ_FIRST(&currecord->matches);
                    263:                        }
                    264:                } else
                    265:                        curmatch = m;
                    266:        }
                    267:        return (jumptomatch());
                    268: }
                    269:
                    270: /*
                    271:  * Previous Symbol. Bound to C-c s p
                    272:  */
                    273: /* ARGSUSED */
                    274: int
                    275: csprevmatch(int f, int n)
                    276: {
                    277:        struct csmatch *m;
                    278:        struct csrecord *r;
                    279:
                    280:        if (curmatch == NULL)
                    281:                return (FALSE);
                    282:        else {
                    283:                m  = TAILQ_PREV(curmatch, matches, entry);
                    284:                if (m)
                    285:                        curmatch = m;
                    286:                else {
                    287:                        r = TAILQ_PREV(currecord, csrecords, entry);
                    288:                        if (r == NULL) {
1.5       lum       289:                                dobeep();
1.1       lum       290:                                ewprintf("The beginning of *cscope* buffer has"
                    291:                                    " been reached");
                    292:                                return (FALSE);
                    293:                        } else {
                    294:                                currecord = r;
                    295:                                curmatch = TAILQ_LAST(&currecord->matches,
                    296:                                    matches);
                    297:                        }
                    298:                }
                    299:        }
                    300:        return (jumptomatch());
                    301: }
                    302:
                    303: /*
                    304:  * Next file.
                    305:  */
                    306: int
                    307: csnextfile(int f, int n)
                    308: {
                    309:        struct csrecord *r;
                    310:
                    311:        if (curmatch == NULL) {
                    312:                if ((r = TAILQ_FIRST(&csrecords)) == NULL) {
1.5       lum       313:                        dobeep();
1.1       lum       314:                        ewprintf("The *cscope* buffer does not exist yet");
                    315:                        return (FALSE);
                    316:                }
                    317:
                    318:        } else {
                    319:                if ((r = TAILQ_NEXT(currecord, entry)) == NULL) {
1.5       lum       320:                        dobeep();
1.1       lum       321:                        ewprintf("The end of *cscope* buffer has been reached");
                    322:                        return (FALSE);
                    323:                }
                    324:        }
                    325:        currecord = r;
                    326:        curmatch = TAILQ_FIRST(&currecord->matches);
                    327:        return (jumptomatch());
                    328: }
                    329:
                    330: /*
                    331:  * Previous file.
                    332:  */
                    333: int
                    334: csprevfile(int f, int n)
                    335: {
                    336:        struct csrecord *r;
                    337:
                    338:        if (curmatch == NULL) {
                    339:                if ((r = TAILQ_FIRST(&csrecords)) == NULL) {
1.5       lum       340:                        dobeep();
1.1       lum       341:                        ewprintf("The *cscope* buffer does not exist yet");
                    342:                        return (FALSE);
                    343:                }
                    344:
                    345:        } else {
                    346:                if ((r = TAILQ_PREV(currecord, csrecords, entry)) == NULL) {
1.5       lum       347:                        dobeep();
1.1       lum       348:                        ewprintf("The beginning of *cscope* buffer has been"
                    349:                            " reached");
                    350:                        return (FALSE);
                    351:                }
                    352:        }
                    353:        currecord = r;
                    354:        curmatch = TAILQ_FIRST(&currecord->matches);
                    355:        return (jumptomatch());
                    356: }
                    357:
                    358: /*
                    359:  * The current symbol location is extracted from currecord->filename and
                    360:  * curmatch->lineno. Load the file similar to filevisit and goto the
                    361:  * lineno recorded.
                    362:  */
                    363: int
                    364: jumptomatch(void)
                    365: {
                    366:        struct buffer *bp;
                    367:        char *adjf;
                    368:
                    369:        if (curmatch == NULL || currecord == NULL)
                    370:                return (FALSE);
                    371:        adjf = adjustname(currecord->filename, TRUE);
                    372:        if (adjf == NULL)
                    373:                return (FALSE);
                    374:        if ((bp = findbuffer(adjf)) == NULL)
                    375:                return (FALSE);
                    376:        curbp = bp;
                    377:        if (showbuffer(bp, curwp, WFFULL) != TRUE)
                    378:                return (FALSE);
                    379:        if (bp->b_fname[0] == '\0') {
                    380:                if (readin(adjf) != TRUE)
                    381:                        killbuffer(bp);
                    382:        }
                    383:        gotoline(FFARG, curmatch->lineno);
                    384:        return (TRUE);
                    385:
                    386: }
                    387:
                    388: /*
                    389:  * Ask for the symbol, construct cscope commandline with the symbol
                    390:  * and passed in index. Popen cscope, read the output into *cscope*
                    391:  * buffer and pop it.
                    392:  */
                    393: int
                    394: do_cscope(int i)
                    395: {
                    396:        struct buffer *bp;
                    397:        FILE *fpipe;
                    398:        char pattern[MAX_TOKEN], cmd[BUFSIZ], title[BUFSIZ];
                    399:        char *p, *buf;
                    400:        int clen, nores = 0;
                    401:        size_t len;
                    402:
                    403:        /* If current buffer isn't a source file just return */
                    404:        if (fnmatch("*.[chy]", curbp->b_fname, 0) != 0) {
1.5       lum       405:                dobeep();
1.1       lum       406:                ewprintf("C-c s not defined");
                    407:                return (FALSE);
                    408:        }
                    409:
                    410:        if (curtoken(0, 1, pattern) == FALSE)
                    411:                return (FALSE);
                    412:        p = eread(csprompt[i], pattern, MAX_TOKEN, EFNEW | EFCR | EFDEF);
                    413:        if (p == NULL)
                    414:                return (ABORT);
                    415:        else if (p[0] == '\0')
                    416:                return (FALSE);
                    417:
                    418:        if (csexists("cscope") == FALSE) {
1.5       lum       419:                dobeep();
1.1       lum       420:                ewprintf("no such file or directory, cscope");
                    421:                return (FALSE);
                    422:        }
                    423:
                    424:        csflush();
                    425:        clen = snprintf(cmd, sizeof(cmd), "cscope -L -%d %s 2>/dev/null",
                    426:            i, pattern);
                    427:        if (clen < 0 || clen >= sizeof(cmd))
                    428:                return (FALSE);
                    429:
                    430:        if ((fpipe = popen(cmd, "r")) == NULL) {
1.5       lum       431:                dobeep();
1.1       lum       432:                ewprintf("problem opening pipe");
                    433:                return (FALSE);
                    434:        }
                    435:
                    436:        bp = bfind("*cscope*", TRUE);
1.4       jsg       437:        if (bclear(bp) != TRUE) {
                    438:                pclose(fpipe);
1.1       lum       439:                return (FALSE);
1.4       jsg       440:        }
1.1       lum       441:        bp->b_flag |= BFREADONLY;
                    442:
                    443:        clen = snprintf(title, sizeof(title), "%s%s", csprompt[i], pattern);
1.6       jsg       444:        if (clen < 0 || clen >= sizeof(title)) {
                    445:                pclose(fpipe);
1.1       lum       446:                return (FALSE);
1.6       jsg       447:        }
1.1       lum       448:        addline(bp, title);
                    449:        addline(bp, "");
                    450:        addline(bp, "-------------------------------------------------------------------------------");
                    451:        /* All lines are NUL terminated */
                    452:        while ((buf = fgetln(fpipe, &len)) != NULL) {
                    453:                buf[len - 1] = '\0';
                    454:                if (addentry(bp, buf) != TRUE)
                    455:                        return (FALSE);
                    456:                nores = 1;
                    457:        };
                    458:        pclose(fpipe);
                    459:        addline(bp, "-------------------------------------------------------------------------------");
                    460:        if (nores == 0)
                    461:                ewprintf("No matches were found.");
                    462:        return (popbuftop(bp, WNONE));
                    463: }
                    464:
                    465: /*
                    466:  * For each line read from cscope output, extract the tokens,
                    467:  * add them to list and pretty print a line in *cscope* buffer.
                    468:  */
                    469: int
                    470: addentry(struct buffer *bp, char *csline)
                    471: {
                    472:        struct csrecord *r;
                    473:        struct csmatch *m;
                    474:        struct cstokens t;
                    475:        int lineno;
                    476:        char buf[BUFSIZ];
                    477:        const char *errstr;
                    478:
                    479:        r = NULL;
                    480:        if (getattr(csline, &t) == FALSE)
                    481:                return (FALSE);
                    482:
                    483:        lineno = strtonum(t.lineno, INT_MIN, INT_MAX, &errstr);
                    484:        if (errstr)
                    485:                return (FALSE);
                    486:
                    487:        if (addentryfn == NULL || strcmp(addentryfn, t.fname) != 0) {
                    488:                if ((r = malloc(sizeof(struct csrecord))) == NULL)
                    489:                        return (FALSE);
                    490:                addentryr = r;
                    491:                if ((r->filename = strndup(t.fname, NFILEN)) == NULL)
                    492:                        goto cleanup;
                    493:                addentryfn = r->filename;
                    494:                TAILQ_INIT(&r->matches);
                    495:                if ((m = malloc(sizeof(struct csmatch))) == NULL)
                    496:                        goto cleanup;
                    497:                m->lineno = lineno;
                    498:                TAILQ_INSERT_TAIL(&r->matches, m, entry);
                    499:                TAILQ_INSERT_TAIL(&csrecords, r, entry);
                    500:                addline(bp, "");
                    501:                if (snprintf(buf, sizeof(buf), "*** %s", t.fname) < 0)
                    502:                        goto cleanup;
                    503:                addline(bp, buf);
                    504:        } else {
                    505:                if ((m = malloc(sizeof(struct csmatch))) == NULL)
                    506:                        goto cleanup;
                    507:                m->lineno = lineno;
                    508:                TAILQ_INSERT_TAIL(&addentryr->matches, m, entry);
                    509:        }
                    510:        prettyprint(bp, &t);
                    511:        return (TRUE);
                    512: cleanup:
                    513:        free(r);
                    514:        return (FALSE);
                    515: }
                    516:
                    517: /*
                    518:  * Cscope line: <filename> <function> <lineno> <pattern>
                    519:  */
                    520: int
                    521: getattr(char *line, struct cstokens *t)
                    522: {
                    523:        char *p;
                    524:
                    525:        if ((p = strchr(line, ' ')) == NULL)
                    526:                return (FALSE);
                    527:        *p++ = '\0';
                    528:        t->fname = line;
                    529:        line = p;
                    530:
                    531:        if ((p = strchr(line, ' ')) == NULL)
                    532:                return (FALSE);
                    533:        *p++ = '\0';
                    534:        t->function = line;
                    535:        line = p;
                    536:
                    537:        if ((p = strchr(line, ' ')) == NULL)
                    538:                return (FALSE);
                    539:        *p++ = '\0';
                    540:        t->lineno = line;
                    541:
                    542:        if (*p == '\0')
                    543:                return (FALSE);
                    544:        t->pattern = p;
                    545:
                    546:        return (TRUE);
                    547: }
                    548:
                    549: void
                    550: prettyprint(struct buffer *bp, struct cstokens *t)
                    551: {
                    552:        char buf[BUFSIZ];
                    553:
                    554:        if (snprintf(buf, sizeof(buf), "%s[%s]\t\t%s",
                    555:            t->function, t->lineno, ltrim(t->pattern)) < 0)
                    556:                return;
                    557:        addline(bp, buf);
                    558: }
                    559:
                    560: const char *
                    561: ltrim(const char *s)
                    562: {
1.7       guenther  563:        while (isblank((unsigned char)*s))
1.1       lum       564:                s++;
                    565:        return s;
                    566: }
                    567:
                    568: void
                    569: csflush(void)
                    570: {
                    571:        struct csrecord *r;
                    572:        struct csmatch *m;
                    573:
                    574:        while ((r = TAILQ_FIRST(&csrecords)) != NULL) {
                    575:                free(r->filename);
                    576:                while ((m = TAILQ_FIRST(&r->matches)) != NULL) {
                    577:                        TAILQ_REMOVE(&r->matches, m, entry);
                    578:                        free(m);
                    579:                }
                    580:                TAILQ_REMOVE(&csrecords, r, entry);
                    581:                free(r);
                    582:        }
                    583:        addentryr = NULL;
                    584:        addentryfn = NULL;
                    585:        currecord = NULL;
                    586:        curmatch = NULL;
                    587: }
                    588:
                    589: /*
                    590:  * Check if the cmd exists in $PATH. Split on ":" and iterate through
                    591:  * all paths in $PATH.
                    592:  */
                    593: int
                    594: csexists(const char *cmd)
                    595: {
                    596:        char fname[NFILEN], *dir, *path, *pathc, *tmp;
                    597:        int  cmdlen, dlen;
                    598:
                    599:        /* Special case if prog contains '/' */
                    600:        if (strchr(cmd, '/')) {
                    601:                if (access(cmd, F_OK) == -1)
                    602:                        return (FALSE);
                    603:                else
                    604:                        return (TRUE);
                    605:        }
                    606:        if ((tmp = getenv("PATH")) == NULL)
                    607:                return (FALSE);
                    608:        if ((pathc = path = strndup(tmp, NFILEN)) == NULL) {
1.5       lum       609:                dobeep();
1.1       lum       610:                ewprintf("out of memory");
                    611:                return (FALSE);
                    612:        }
                    613:        cmdlen = strlen(cmd);
                    614:        while ((dir = strsep(&path, ":")) != NULL) {
                    615:                if (*dir == '\0')
                    616:                        *dir = '.';
                    617:
                    618:                dlen = strlen(dir);
                    619:                while (dir[dlen-1] == '/')
                    620:                        dir[--dlen] = '\0';     /* strip trailing '/' */
                    621:
                    622:                if (dlen + 1 + cmdlen >= sizeof(fname))  {
1.5       lum       623:                        dobeep();
1.1       lum       624:                        ewprintf("path too long");
                    625:                        goto cleanup;
                    626:                }
                    627:                snprintf(fname, sizeof(fname), "%s/%s", dir, cmd);
                    628:                if(access(fname, F_OK) == 0) {
                    629:                       free(pathc);
                    630:                       return (TRUE);
                    631:               }
                    632:        }
                    633: cleanup:
                    634:        free(pathc);
                    635:        return (FALSE);
                    636: }