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

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