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

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