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

1.10    ! jasper      1: /*     $OpenBSD: cscope.c,v 1.9 2015/03/19 21:22:15 bcallah 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;
1.10    ! jasper    171:
1.1       lum       172:        if (getbufcwd(dir, sizeof(dir)) == FALSE)
                    173:                dir[0] = '\0';
1.10    ! jasper    174:
        !           175:        bufp = eread("Index files in directory: ", dir,
1.1       lum       176:            sizeof(dir), EFCR | EFDEF | EFNEW | EFNUL);
1.10    ! jasper    177:
1.1       lum       178:        if (bufp == NULL)
                    179:                return (ABORT);
                    180:        else if (bufp[0] == '\0')
                    181:                return (FALSE);
1.10    ! jasper    182:
1.1       lum       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:        }
1.10    ! jasper    192:
1.1       lum       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:        }
1.10    ! jasper    198:
1.1       lum       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:        }
1.10    ! jasper    208:
1.1       lum       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);
1.10    ! jasper    230:        return (popbuftop(bp, WNONE));
1.1       lum       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;
1.10    ! jasper    242:
1.1       lum       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;
1.10    ! jasper    310:
1.1       lum       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);
1.10    ! jasper    327:        return (jumptomatch());
1.1       lum       328: }
                    329:
                    330: /*
                    331:  * Previous file.
                    332:  */
                    333: int
                    334: csprevfile(int f, int n)
                    335: {
                    336:        struct csrecord *r;
1.10    ! jasper    337:
1.1       lum       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);
1.10    ! jasper    355:        return (jumptomatch());
1.1       lum       356: }
                    357:
                    358: /*
1.10    ! jasper    359:  * The current symbol location is extracted from currecord->filename and
        !           360:  * curmatch->lineno. Load the file similar to filevisit and goto the
1.1       lum       361:  * lineno recorded.
                    362:  */
                    363: int
                    364: jumptomatch(void)
                    365: {
                    366:        struct buffer *bp;
                    367:        char *adjf;
1.10    ! jasper    368:
1.1       lum       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:  * Ask for the symbol, construct cscope commandline with the symbol
1.10    ! jasper    389:  * and passed in index. Popen cscope, read the output into *cscope*
1.1       lum       390:  * buffer and pop it.
                    391:  */
                    392: int
                    393: do_cscope(int i)
                    394: {
                    395:        struct buffer *bp;
                    396:        FILE *fpipe;
                    397:        char pattern[MAX_TOKEN], cmd[BUFSIZ], title[BUFSIZ];
                    398:        char *p, *buf;
                    399:        int clen, nores = 0;
                    400:        size_t len;
                    401:
                    402:        /* If current buffer isn't a source file just return */
                    403:        if (fnmatch("*.[chy]", curbp->b_fname, 0) != 0) {
1.5       lum       404:                dobeep();
1.1       lum       405:                ewprintf("C-c s not defined");
                    406:                return (FALSE);
                    407:        }
1.10    ! jasper    408:
1.1       lum       409:        if (curtoken(0, 1, pattern) == FALSE)
1.10    ! jasper    410:                return (FALSE);
1.1       lum       411:        p = eread(csprompt[i], pattern, MAX_TOKEN, EFNEW | EFCR | EFDEF);
                    412:        if (p == NULL)
                    413:                return (ABORT);
                    414:        else if (p[0] == '\0')
                    415:                return (FALSE);
                    416:
                    417:        if (csexists("cscope") == FALSE) {
1.5       lum       418:                dobeep();
1.1       lum       419:                ewprintf("no such file or directory, cscope");
                    420:                return (FALSE);
                    421:        }
1.10    ! jasper    422:
1.1       lum       423:        csflush();
                    424:        clen = snprintf(cmd, sizeof(cmd), "cscope -L -%d %s 2>/dev/null",
                    425:            i, pattern);
                    426:        if (clen < 0 || clen >= sizeof(cmd))
                    427:                return (FALSE);
                    428:
                    429:        if ((fpipe = popen(cmd, "r")) == NULL) {
1.5       lum       430:                dobeep();
1.1       lum       431:                ewprintf("problem opening pipe");
                    432:                return (FALSE);
                    433:        }
1.10    ! jasper    434:
1.1       lum       435:        bp = bfind("*cscope*", TRUE);
1.4       jsg       436:        if (bclear(bp) != TRUE) {
                    437:                pclose(fpipe);
1.1       lum       438:                return (FALSE);
1.4       jsg       439:        }
1.1       lum       440:        bp->b_flag |= BFREADONLY;
                    441:
                    442:        clen = snprintf(title, sizeof(title), "%s%s", csprompt[i], pattern);
1.6       jsg       443:        if (clen < 0 || clen >= sizeof(title)) {
                    444:                pclose(fpipe);
1.1       lum       445:                return (FALSE);
1.6       jsg       446:        }
1.1       lum       447:        addline(bp, title);
                    448:        addline(bp, "");
                    449:        addline(bp, "-------------------------------------------------------------------------------");
                    450:        /* All lines are NUL terminated */
                    451:        while ((buf = fgetln(fpipe, &len)) != NULL) {
                    452:                buf[len - 1] = '\0';
                    453:                if (addentry(bp, buf) != TRUE)
                    454:                        return (FALSE);
                    455:                nores = 1;
1.10    ! jasper    456:        };
1.1       lum       457:        pclose(fpipe);
                    458:        addline(bp, "-------------------------------------------------------------------------------");
                    459:        if (nores == 0)
                    460:                ewprintf("No matches were found.");
                    461:        return (popbuftop(bp, WNONE));
                    462: }
                    463:
                    464: /*
                    465:  * For each line read from cscope output, extract the tokens,
                    466:  * add them to list and pretty print a line in *cscope* buffer.
                    467:  */
                    468: int
                    469: addentry(struct buffer *bp, char *csline)
                    470: {
                    471:        struct csrecord *r;
                    472:        struct csmatch *m;
                    473:        struct cstokens t;
                    474:        int lineno;
                    475:        char buf[BUFSIZ];
                    476:        const char *errstr;
                    477:
                    478:        r = NULL;
                    479:        if (getattr(csline, &t) == FALSE)
                    480:                return (FALSE);
                    481:
                    482:        lineno = strtonum(t.lineno, INT_MIN, INT_MAX, &errstr);
                    483:        if (errstr)
                    484:                return (FALSE);
1.10    ! jasper    485:
1.1       lum       486:        if (addentryfn == NULL || strcmp(addentryfn, t.fname) != 0) {
                    487:                if ((r = malloc(sizeof(struct csrecord))) == NULL)
                    488:                        return (FALSE);
                    489:                addentryr = r;
                    490:                if ((r->filename = strndup(t.fname, NFILEN)) == NULL)
                    491:                        goto cleanup;
                    492:                addentryfn = r->filename;
                    493:                TAILQ_INIT(&r->matches);
                    494:                if ((m = malloc(sizeof(struct csmatch))) == NULL)
                    495:                        goto cleanup;
                    496:                m->lineno = lineno;
                    497:                TAILQ_INSERT_TAIL(&r->matches, m, entry);
                    498:                TAILQ_INSERT_TAIL(&csrecords, r, entry);
                    499:                addline(bp, "");
                    500:                if (snprintf(buf, sizeof(buf), "*** %s", t.fname) < 0)
                    501:                        goto cleanup;
                    502:                addline(bp, buf);
                    503:        } else {
                    504:                if ((m = malloc(sizeof(struct csmatch))) == NULL)
                    505:                        goto cleanup;
                    506:                m->lineno = lineno;
                    507:                TAILQ_INSERT_TAIL(&addentryr->matches, m, entry);
                    508:        }
                    509:        prettyprint(bp, &t);
                    510:        return (TRUE);
                    511: cleanup:
                    512:        free(r);
                    513:        return (FALSE);
                    514: }
                    515:
                    516: /*
                    517:  * Cscope line: <filename> <function> <lineno> <pattern>
                    518:  */
                    519: int
                    520: getattr(char *line, struct cstokens *t)
                    521: {
                    522:        char *p;
                    523:
                    524:        if ((p = strchr(line, ' ')) == NULL)
                    525:                return (FALSE);
                    526:        *p++ = '\0';
                    527:        t->fname = line;
                    528:        line = p;
                    529:
                    530:        if ((p = strchr(line, ' ')) == NULL)
                    531:                return (FALSE);
                    532:        *p++ = '\0';
                    533:        t->function = line;
                    534:        line = p;
                    535:
                    536:        if ((p = strchr(line, ' ')) == NULL)
                    537:                return (FALSE);
                    538:        *p++ = '\0';
                    539:        t->lineno = line;
                    540:
                    541:        if (*p == '\0')
                    542:                return (FALSE);
                    543:        t->pattern = p;
                    544:
                    545:        return (TRUE);
                    546: }
                    547:
                    548: void
                    549: prettyprint(struct buffer *bp, struct cstokens *t)
                    550: {
                    551:        char buf[BUFSIZ];
                    552:
                    553:        if (snprintf(buf, sizeof(buf), "%s[%s]\t\t%s",
                    554:            t->function, t->lineno, ltrim(t->pattern)) < 0)
                    555:                return;
                    556:        addline(bp, buf);
                    557: }
                    558:
                    559: const char *
                    560: ltrim(const char *s)
                    561: {
1.7       guenther  562:        while (isblank((unsigned char)*s))
1.1       lum       563:                s++;
                    564:        return s;
                    565: }
                    566:
                    567: void
                    568: csflush(void)
                    569: {
                    570:        struct csrecord *r;
                    571:        struct csmatch *m;
1.10    ! jasper    572:
1.1       lum       573:        while ((r = TAILQ_FIRST(&csrecords)) != NULL) {
                    574:                free(r->filename);
                    575:                while ((m = TAILQ_FIRST(&r->matches)) != NULL) {
                    576:                        TAILQ_REMOVE(&r->matches, m, entry);
                    577:                        free(m);
                    578:                }
                    579:                TAILQ_REMOVE(&csrecords, r, entry);
                    580:                free(r);
                    581:        }
                    582:        addentryr = NULL;
                    583:        addentryfn = NULL;
                    584:        currecord = NULL;
                    585:        curmatch = NULL;
                    586: }
                    587:
                    588: /*
                    589:  * Check if the cmd exists in $PATH. Split on ":" and iterate through
                    590:  * all paths in $PATH.
                    591:  */
                    592: int
                    593: csexists(const char *cmd)
                    594: {
                    595:        char fname[NFILEN], *dir, *path, *pathc, *tmp;
                    596:        int  cmdlen, dlen;
                    597:
                    598:        /* Special case if prog contains '/' */
                    599:        if (strchr(cmd, '/')) {
                    600:                if (access(cmd, F_OK) == -1)
                    601:                        return (FALSE);
                    602:                else
                    603:                        return (TRUE);
                    604:        }
                    605:        if ((tmp = getenv("PATH")) == NULL)
                    606:                return (FALSE);
                    607:        if ((pathc = path = strndup(tmp, NFILEN)) == NULL) {
1.5       lum       608:                dobeep();
1.1       lum       609:                ewprintf("out of memory");
                    610:                return (FALSE);
                    611:        }
                    612:        cmdlen = strlen(cmd);
                    613:        while ((dir = strsep(&path, ":")) != NULL) {
                    614:                if (*dir == '\0')
                    615:                        *dir = '.';
                    616:
                    617:                dlen = strlen(dir);
                    618:                while (dir[dlen-1] == '/')
                    619:                        dir[--dlen] = '\0';     /* strip trailing '/' */
                    620:
                    621:                if (dlen + 1 + cmdlen >= sizeof(fname))  {
1.5       lum       622:                        dobeep();
1.1       lum       623:                        ewprintf("path too long");
                    624:                        goto cleanup;
                    625:                }
                    626:                snprintf(fname, sizeof(fname), "%s/%s", dir, cmd);
                    627:                if(access(fname, F_OK) == 0) {
                    628:                       free(pathc);
                    629:                       return (TRUE);
                    630:               }
                    631:        }
                    632: cleanup:
                    633:        free(pathc);
                    634:        return (FALSE);
                    635: }