home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_cscope.c < prev    next >
C/C++ Source or Header  |  1996-09-15  |  24KB  |  1,058 lines

  1. /*-
  2.  * Copyright (c) 1994, 1996
  3.  *    Rob Mayoff.  All rights reserved.
  4.  * Copyright (c) 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)ex_cscope.c    10.13 (Berkeley) 9/15/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/param.h>
  17. #include <sys/types.h>        /* XXX: param.h may not have included types.h */
  18. #include <sys/queue.h>
  19. #include <sys/stat.h>
  20. #include <sys/time.h>
  21. #include <sys/wait.h>
  22.  
  23. #include <bitstring.h>
  24. #include <ctype.h>
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #include <limits.h>
  28. #include <stddef.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <termios.h>
  33. #include <unistd.h>
  34.  
  35. #include "../common/common.h"
  36. #include "pathnames.h"
  37. #include "tag.h"
  38.  
  39. #define    CSCOPE_DBFILE        "cscope.out"
  40. #define    CSCOPE_PATHS        "cscope.tpath"
  41.  
  42. /*
  43.  * 0name    find all uses of name
  44.  * 1name    find definition of name
  45.  * 2name    find all function calls made from name
  46.  * 3name    find callers of name
  47.  * 4string    find text string (cscope 12.9)
  48.  * 4name    find assignments to name (cscope 13.3)
  49.  * 5pattern    change pattern -- NOT USED
  50.  * 6pattern    find pattern
  51.  * 7name    find files with name as substring
  52.  * 8name    find files #including name
  53.  */
  54. #define    FINDHELP "\
  55. find c|d|e|f|g|i|s|t buffer|pattern\n\
  56.       c: find callers of name\n\
  57.       d: find all function calls made from name\n\
  58.       e: find pattern\n\
  59.       f: find files with name as substring\n\
  60.       g: find definition of name\n\
  61.       i: find files #including name\n\
  62.       s: find all uses of name\n\
  63.       t: find assignments to name"
  64.  
  65. static int cscope_add __P((SCR *, EXCMD *, char *));
  66. static int cscope_find __P((SCR *, EXCMD*, char *));
  67. static int cscope_help __P((SCR *, EXCMD *, char *));
  68. static int cscope_kill __P((SCR *, EXCMD *, char *));
  69. static int cscope_reset __P((SCR *, EXCMD *, char *));
  70.  
  71. typedef struct _cc {
  72.     char     *name;
  73.     int    (*function) __P((SCR *, EXCMD *, char *));
  74.     char     *help_msg;
  75.     char     *usage_msg;
  76. } CC;
  77.  
  78. static CC const cscope_cmds[] = {
  79.     { "add",   cscope_add,
  80.       "Add a new cscope database", "add file | directory" },
  81.     { "find",  cscope_find,
  82.       "Query the databases for a pattern", FINDHELP },
  83.     { "help",  cscope_help,
  84.       "Show help for cscope commands", "help [command]" },
  85.     { "kill",  cscope_kill,
  86.       "Kill a cscope connection", "kill number" },
  87.     { "reset", cscope_reset,
  88.       "Discard all current cscope connections", "reset" },
  89.     { NULL }
  90. };
  91.  
  92. static TAGQ    *create_cs_cmd __P((SCR *, char *, size_t *));
  93. static int     csc_help __P((SCR *, char *));
  94. static void     csc_file __P((SCR *,
  95.             CSC *, char *, char **, size_t *, int *));
  96. static int     get_paths __P((SCR *, CSC *));
  97. static CC const    *lookup_ccmd __P((char *));
  98. static int     parse __P((SCR *, CSC *, TAGQ *, int *));
  99. static int     read_prompt __P((SCR *, CSC *));
  100. static int     run_cscope __P((SCR *, CSC *, char *));
  101. static int     start_cscopes __P((SCR *, EXCMD *));
  102. static int     terminate __P((SCR *, CSC *, int));
  103.  
  104. /*
  105.  * ex_cscope --
  106.  *    Perform an ex cscope.
  107.  *
  108.  * PUBLIC: int ex_cscope __P((SCR *, EXCMD *));
  109.  */
  110. int
  111. ex_cscope(sp, cmdp)
  112.     SCR *sp;
  113.     EXCMD *cmdp;
  114. {
  115.     CC const *ccp;
  116.     EX_PRIVATE *exp;
  117.     int i;
  118.     char *cmd, *p;
  119.  
  120.     /* Initialize the default cscope directories. */
  121.     exp = EXP(sp);
  122.     if (!F_ISSET(exp, EXP_CSCINIT) && start_cscopes(sp, cmdp))
  123.         return (1);
  124.     F_SET(exp, EXP_CSCINIT);
  125.  
  126.     /* Skip leading whitespace. */
  127.     for (p = cmdp->argv[0]->bp, i = cmdp->argv[0]->len; i > 0; --i, ++p)
  128.         if (!isspace(*p))
  129.             break;
  130.     if (i == 0)
  131.         goto usage;
  132.  
  133.     /* Skip the command to any arguments. */
  134.     for (cmd = p; i > 0; --i, ++p)
  135.         if (isspace(*p))
  136.             break;
  137.     if (*p != '\0') {
  138.         *p++ = '\0';
  139.         for (; *p && isspace(*p); ++p);
  140.     }
  141.  
  142.     if ((ccp = lookup_ccmd(cmd)) == NULL) {
  143. usage:        msgq(sp, M_ERR, "309|Use \"cscope help\" for help");
  144.         return (1);
  145.     }
  146.  
  147.     /* Call the underlying function. */
  148.     return (ccp->function(sp, cmdp, p));
  149. }
  150.  
  151. /*
  152.  * start_cscopes --
  153.  *    Initialize the cscope package.
  154.  */
  155. static int
  156. start_cscopes(sp, cmdp)
  157.     SCR *sp;
  158.     EXCMD *cmdp;
  159. {
  160.     size_t blen, len;
  161.     char *bp, *cscopes, *p, *t;
  162.  
  163.     /*
  164.      * EXTENSION #1:
  165.      *
  166.      * If the CSCOPE_DIRS environment variable is set, we treat it as a
  167.      * list of cscope directories that we're using, similar to the tags
  168.      * edit option.
  169.      *
  170.      * XXX
  171.      * This should probably be an edit option, although that implies that
  172.      * we start/stop cscope processes periodically, instead of once when
  173.      * the editor starts.
  174.      */
  175.     if ((cscopes = getenv("CSCOPE_DIRS")) == NULL)
  176.         return (0);
  177.     len = strlen(cscopes);
  178.     GET_SPACE_RET(sp, bp, blen, len);
  179.     memcpy(bp, cscopes, len + 1);
  180.  
  181.     for (cscopes = t = bp; (p = strsep(&t, "\t :")) != NULL;)
  182.         if (*p != '\0')
  183.             (void)cscope_add(sp, cmdp, p);
  184.  
  185.     FREE_SPACE(sp, bp, blen);
  186.     return (0);
  187. }
  188.  
  189. /*
  190.  * cscope_add --
  191.  *    The cscope add command.
  192.  */
  193. static int
  194. cscope_add(sp, cmdp, dname)
  195.     SCR *sp;
  196.     EXCMD *cmdp;
  197.     char *dname;
  198. {
  199.     struct stat sb;
  200.     EX_PRIVATE *exp;
  201.     CSC *csc;
  202.     size_t len;
  203.     int cur_argc;
  204.     char *dbname, path[MAXPATHLEN];
  205.  
  206.     exp = EXP(sp);
  207.  
  208.     /*
  209.      *  0 additional args: usage.
  210.      *  1 additional args: matched a file.
  211.      * >1 additional args: object, too many args.
  212.      */
  213.     cur_argc = cmdp->argc;
  214.     if (argv_exp2(sp, cmdp, dname, strlen(dname)))
  215.         return (1);
  216.     if (cmdp->argc == cur_argc) {
  217.         (void)csc_help(sp, "add");
  218.         return (1);
  219.     }
  220.     if (cmdp->argc == cur_argc + 1)
  221.         dname = cmdp->argv[cur_argc]->bp;
  222.     else {
  223.         ex_emsg(sp, dname, EXM_FILECOUNT);
  224.         return (1);
  225.     }
  226.  
  227.     /*
  228.      * The user can specify a specific file (so they can have multiple
  229.      * Cscope databases in a single directory) or a directory.  If the
  230.      * file doesn't exist, we're done.  If it's a directory, append the
  231.      * standard database file name and try again.  Store the directory
  232.      * name regardless so that we can use it as a base for searches.
  233.      */
  234.     if (stat(dname, &sb)) {
  235.         msgq(sp, M_SYSERR, dname);
  236.         return (1);
  237.     }
  238.     if (S_ISDIR(sb.st_mode)) {
  239.         (void)snprintf(path, sizeof(path),
  240.             "%s/%s", dname, CSCOPE_DBFILE);
  241.         if (stat(path, &sb)) {
  242.             msgq(sp, M_SYSERR, path);
  243.             return (1);
  244.         }
  245.         dbname = CSCOPE_DBFILE;
  246.     } else if ((dbname = strrchr(dname, '/')) != NULL)
  247.         *dbname++ = '\0';
  248.  
  249.     /* Allocate a cscope connection structure and initialize its fields. */
  250.     len = strlen(dname);
  251.     CALLOC_RET(sp, csc, CSC *, 1, sizeof(CSC) + len);
  252.     csc->dname = csc->buf;
  253.     csc->dlen = len;
  254.     memcpy(csc->dname, dname, len);
  255.     csc->mtime = sb.st_mtime;
  256.  
  257.     /* Get the search paths for the cscope. */
  258.     if (get_paths(sp, csc))
  259.         goto err;
  260.  
  261.     /* Start the cscope process. */
  262.     if (run_cscope(sp, csc, dbname))
  263.         goto err;
  264.  
  265.     /*
  266.      * Add the cscope connection to the screen's list.  From now on, 
  267.      * on error, we have to call terminate, which expects the csc to
  268.      * be on the chain.
  269.      */
  270.     LIST_INSERT_HEAD(&exp->cscq, csc, q);
  271.  
  272.     /* Read the initial prompt from the cscope to make sure it's okay. */
  273.     if (read_prompt(sp, csc)) {
  274.         terminate(sp, csc, 0);
  275.         return (1);
  276.     }
  277.  
  278.     return (0);
  279.  
  280. err:    free(csc);
  281.     return (1);
  282. }
  283.  
  284. /*
  285.  * get_paths --
  286.  *    Get the directories to search for the files associated with this
  287.  *    cscope database.
  288.  */
  289. static int
  290. get_paths(sp, csc)
  291.     SCR *sp;
  292.     CSC *csc;
  293. {
  294.     struct stat sb;
  295.     int fd, nentries;
  296.     size_t len;
  297.     char *p, **pathp, buf[MAXPATHLEN * 2];
  298.  
  299.     /*
  300.      * EXTENSION #2:
  301.      *
  302.      * If there's a cscope directory with a file named CSCOPE_PATHS, it
  303.      * contains a colon-separated list of paths in which to search for
  304.      * files returned by cscope.
  305.      *
  306.      * XXX
  307.      * These paths are absolute paths, and not relative to the cscope
  308.      * directory.  To fix this, rewrite the each path using the cscope
  309.      * directory as a prefix.
  310.      */
  311.     (void)snprintf(buf, sizeof(buf), "%s/%s", csc->dname, CSCOPE_PATHS);
  312.     if (stat(buf, &sb) == 0) {
  313.         /* Read in the CSCOPE_PATHS file. */
  314.         len = sb.st_size;
  315.         MALLOC_RET(sp, csc->pbuf, char *, len + 1);
  316.         if ((fd = open(buf, O_RDONLY, 0)) < 0 ||
  317.             read(fd, csc->pbuf, len) != len) {
  318.              msgq_str(sp, M_SYSERR, buf, "%s");
  319.              if (fd >= 0)
  320.                 (void)close(fd);
  321.              return (1);
  322.         }
  323.         (void)close(fd);
  324.         csc->pbuf[len] = '\0';
  325.  
  326.         /* Count up the entries. */
  327.         for (nentries = 0, p = csc->pbuf; *p != '\0'; ++p)
  328.             if (p[0] == ':' && p[1] != '\0')
  329.                 ++nentries;
  330.  
  331.         /* Build an array of pointers to the paths. */
  332.         CALLOC_GOTO(sp,
  333.             csc->paths, char **, nentries + 1, sizeof(char **));
  334.         for (pathp = csc->paths, p = strtok(csc->pbuf, ":");
  335.             p != NULL; p = strtok(NULL, ":"))
  336.             *pathp++ = p;
  337.         return (0);
  338.     }
  339.  
  340.     /*
  341.      * If the CSCOPE_PATHS file doesn't exist, we look for files
  342.      * relative to the cscope directory.
  343.      */
  344.     if ((csc->pbuf = strdup(csc->dname)) == NULL) {
  345.         msgq(sp, M_SYSERR, NULL);
  346.         return (1);
  347.     }
  348.     CALLOC_GOTO(sp, csc->paths, char **, 2, sizeof(char *));
  349.     csc->paths[0] = csc->pbuf;
  350.     return (0);
  351.  
  352. alloc_err:
  353.     if (csc->pbuf != NULL) {
  354.         free(csc->pbuf);
  355.         csc->pbuf = NULL;
  356.     }
  357.     return (1);
  358. }
  359.  
  360. /*
  361.  * run_cscope --
  362.  *    Fork off the cscope process.
  363.  */
  364. static int
  365. run_cscope(sp, csc, dbname)
  366.     SCR *sp;
  367.     CSC *csc;
  368.     char *dbname;
  369. {
  370.     int to_cs[2], from_cs[2];
  371.     char cmd[MAXPATHLEN * 2];
  372.  
  373.     /*
  374.      * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
  375.      * from_cs[0] and writes to to_cs[1].
  376.      */
  377.     to_cs[0] = to_cs[1] = from_cs[0] = from_cs[0] = -1;
  378.     if (pipe(to_cs) < 0 || pipe(from_cs) < 0) {
  379.         msgq(sp, M_SYSERR, "pipe");
  380.         goto err;
  381.     }
  382.     switch (csc->pid = vfork()) {
  383.     case -1:
  384.         msgq(sp, M_SYSERR, "vfork");
  385. err:        if (to_cs[0] != -1)
  386.             (void)close(to_cs[0]);
  387.         if (to_cs[1] != -1)
  388.             (void)close(to_cs[1]);
  389.         if (from_cs[0] != -1)
  390.             (void)close(from_cs[0]);
  391.         if (from_cs[1] != -1)
  392.             (void)close(from_cs[1]);
  393.         return (1);
  394.     case 0:                /* child: run cscope. */
  395.         (void)dup2(to_cs[0], STDIN_FILENO);
  396.         (void)dup2(from_cs[1], STDOUT_FILENO);
  397.         (void)dup2(from_cs[1], STDERR_FILENO);
  398.  
  399.         /* Close unused file descriptors. */
  400.         (void)close(to_cs[1]);
  401.         (void)close(from_cs[0]);
  402.  
  403.         /* Run the cscope command. */
  404. #define    CSCOPE_CMD_FMT        "cd '%s' && exec cscope -dl -f %s"
  405.         (void)snprintf(cmd, sizeof(cmd),
  406.             CSCOPE_CMD_FMT, csc->dname, dbname);
  407.         (void)execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
  408.         msgq_str(sp, M_SYSERR, cmd, "execl: %s");
  409.         _exit (127);
  410.         /* NOTREACHED */
  411.     default:            /* parent. */
  412.         /* Close unused file descriptors. */
  413.         (void)close(to_cs[0]);
  414.         (void)close(from_cs[1]);
  415.  
  416.         /*
  417.          * Save the file descriptors for later duplication, and
  418.          * reopen as streams.
  419.          */
  420.         csc->to_fd = to_cs[1];
  421.         csc->to_fp = fdopen(to_cs[1], "w");
  422.         csc->from_fd = from_cs[0];
  423.         csc->from_fp = fdopen(from_cs[0], "r");
  424.         break;
  425.     }
  426.     return (0);
  427. }
  428.  
  429. /*
  430.  * cscope_find --
  431.  *    The cscope find command.
  432.  */
  433. static int
  434. cscope_find(sp, cmdp, pattern)
  435.     SCR *sp;
  436.     EXCMD *cmdp;
  437.     char *pattern;
  438. {
  439.     CSC *csc, *csc_next;
  440.     EX_PRIVATE *exp;
  441.     FREF *frp;
  442.     TAGQ *rtqp, *tqp;
  443.     TAG *rtp;
  444.     recno_t lno;
  445.     size_t cno, search;
  446.     int force, istmp, matches;
  447.  
  448.     exp = EXP(sp);
  449.  
  450.     /* Check for connections. */
  451.     if (exp->cscq.lh_first == NULL) {
  452.         msgq(sp, M_ERR, "310|No cscope connections running");
  453.         return (1);
  454.     }
  455.  
  456.     /*
  457.      * Allocate all necessary memory before doing anything hard.  If the
  458.      * tags stack is empty, we'll need the `local context' TAGQ structure
  459.      * later.
  460.      */
  461.     rtp = NULL;
  462.     rtqp = NULL;
  463.     if (exp->tq.cqh_first == (void *)&exp->tq) {
  464.         /* Initialize the `local context' tag queue structure. */
  465.         CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ));
  466.         CIRCLEQ_INIT(&rtqp->tagq);
  467.  
  468.         /* Initialize and link in its tag structure. */
  469.         CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG));
  470.         CIRCLEQ_INSERT_HEAD(&rtqp->tagq, rtp, q);
  471.         rtqp->current = rtp; 
  472.     }
  473.  
  474.     /* Create the cscope command. */
  475.     if ((tqp = create_cs_cmd(sp, pattern, &search)) == NULL)
  476.         goto err;
  477.  
  478.     /*
  479.      * Stick the current context in a convenient place, we'll lose it
  480.      * when we switch files.
  481.      */
  482.     frp = sp->frp;
  483.     lno = sp->lno;
  484.     cno = sp->cno;
  485.     istmp = F_ISSET(sp->frp, FR_TMPFILE) && !F_ISSET(cmdp, E_NEWSCREEN);
  486.  
  487.     /* Search all open connections for a match. */
  488.     matches = 0;
  489.     for (csc = exp->cscq.lh_first; csc != NULL; csc = csc_next) {
  490.         /* Copy csc->q.lh_next here in case csc is killed. */
  491.         csc_next = csc->q.le_next;
  492.  
  493.         /*
  494.          * Send the command to the cscope program.  (We skip the
  495.          * first two bytes of the command, because we stored the
  496.          * search cscope command character and a leading space
  497.          * there.)
  498.          */
  499.         (void)fprintf(csc->to_fp, "%d%s\n", search, tqp->tag + 2);
  500.         (void)fflush(csc->to_fp);
  501.  
  502.         /* Read the output. */
  503.         if (parse(sp, csc, tqp, &matches)) {
  504.             if (rtqp != NULL)
  505.                 free(rtqp);
  506.             tagq_free(sp, tqp);
  507.             return (1);
  508.         }
  509.     }
  510.  
  511.     if (matches == 0) {
  512.         msgq(sp, M_INFO, "278|No matches for query");
  513.         return (0);
  514.     }
  515.  
  516.     tqp->current = tqp->tagq.cqh_first;
  517.  
  518.     /* Try to switch to the first tag. */
  519.     force = FL_ISSET(cmdp->iflags, E_C_FORCE);
  520.     if (F_ISSET(cmdp, E_NEWSCREEN)) {
  521.         if (ex_tag_Nswitch(sp, tqp->current, force))
  522.             goto err;
  523.  
  524.         /* Everything else gets done in the new screen. */
  525.         sp = sp->nextdisp;
  526.         exp = EXP(sp);
  527.     } else
  528.         if (ex_tag_nswitch(sp, tqp->current, force))
  529.             goto err;
  530.  
  531.     /*
  532.      * If this is the first tag, put a `current location' queue entry
  533.      * in place, so we can pop all the way back to the current mark.
  534.      * Note, it doesn't point to much of anything, it's a placeholder.
  535.      */
  536.     if (exp->tq.cqh_first == (void *)&exp->tq) {
  537.         CIRCLEQ_INSERT_HEAD(&exp->tq, rtqp, q);
  538.     } else
  539.         rtqp = exp->tq.cqh_first;
  540.  
  541.     /* Link the current TAGQ structure into place. */
  542.     CIRCLEQ_INSERT_HEAD(&exp->tq, tqp, q);
  543.  
  544.     (void)cscope_search(sp, tqp, tqp->current);
  545.  
  546.     /*
  547.      * Move the current context from the temporary save area into the
  548.      * right structure.
  549.      *
  550.      * If we were in a temporary file, we don't have a context to which
  551.      * we can return, so just make it be the same as what we're moving
  552.      * to.  It will be a little odd that ^T doesn't change anything, but
  553.      * I don't think it's a big deal.
  554.      */
  555.     if (istmp) {
  556.         rtqp->current->frp = sp->frp;
  557.         rtqp->current->lno = sp->lno;
  558.         rtqp->current->cno = sp->cno;
  559.     } else {
  560.         rtqp->current->frp = frp;
  561.         rtqp->current->lno = lno;
  562.         rtqp->current->cno = cno;
  563.     }
  564.  
  565.     return (0);
  566.  
  567. err:
  568. alloc_err:
  569.     if (rtqp != NULL)
  570.         free(rtqp);
  571.     if (rtp != NULL)
  572.         free(rtp);
  573.     return (1);
  574. }
  575.  
  576. /*
  577.  * create_cs_cmd --
  578.  *    Build a cscope command, creating and initializing the base TAGQ.
  579.  */
  580. static TAGQ *
  581. create_cs_cmd(sp, pattern, searchp)
  582.     SCR *sp;
  583.     char *pattern;
  584.     size_t *searchp;
  585. {
  586.     CB *cbp;
  587.     TAGQ *tqp;
  588.     size_t tlen;
  589.     char *p;
  590.  
  591.     /*
  592.      * Cscope supports a "change pattern" command which we never use,
  593.      * cscope command 5.  Set CSCOPE_QUERIES[5] to " " since the user
  594.      * can't pass " " as the first character of pattern.  That way the
  595.      * user can't ask for pattern 5 so we don't need any special-case
  596.      * code.
  597.      */
  598. #define    CSCOPE_QUERIES        "sgdct efi"
  599.  
  600.     if (pattern == NULL)
  601.         goto usage;
  602.  
  603.     /* Skip leading blanks, check for command character. */
  604.     for (; isblank(pattern[0]); ++pattern);
  605.     if (pattern[0] == '\0' || !isblank(pattern[1]))
  606.         goto usage;
  607.     for (*searchp = 0, p = CSCOPE_QUERIES;
  608.         *p != '\0' && *p != pattern[0]; ++*searchp, ++p);
  609.     if (*p == '\0') {
  610.         msgq(sp, M_ERR,
  611.             "311|%s: unknown search type: use one of %s",
  612.             KEY_NAME(sp, pattern[0]), CSCOPE_QUERIES);
  613.         return (NULL);
  614.     }
  615.  
  616.     /* Skip <blank> characters to the pattern. */
  617.     for (p = pattern + 1; *p != '\0' && isblank(*p); ++p);
  618.     if (*p == '\0') {
  619. usage:        (void)csc_help(sp, "find");
  620.         return (NULL);
  621.     }
  622.  
  623.     /* The user can specify the contents of a buffer as the pattern. */
  624.     cbp = NULL;
  625.     if (p[0] == '"' && p[1] != '\0' && p[2] == '\0')
  626.         CBNAME(sp, cbp, p[1]);
  627.     if (cbp != NULL) {
  628.         p = cbp->textq.cqh_first->lb;
  629.         tlen = cbp->textq.cqh_first->len;
  630.     } else
  631.         tlen = strlen(p);
  632.  
  633.     /* Allocate and initialize the TAGQ structure. */
  634.     CALLOC(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + tlen + 3);
  635.     if (tqp == NULL)
  636.         return (NULL);
  637.     CIRCLEQ_INIT(&tqp->tagq);
  638.     tqp->tag = tqp->buf;
  639.     tqp->tag[0] = pattern[0];
  640.     tqp->tag[1] = ' ';
  641.     tqp->tlen = tlen + 2;
  642.     memcpy(tqp->tag + 2, p, tlen);
  643.     tqp->tag[tlen + 2] = '\0';
  644.     F_SET(tqp, TAG_CSCOPE);
  645.  
  646.     return (tqp);
  647. }
  648.  
  649. /*
  650.  * parse --
  651.  *    Parse the cscope output.
  652.  */
  653. static int
  654. parse(sp, csc, tqp, matchesp)
  655.     SCR *sp;
  656.     CSC *csc;
  657.     TAGQ *tqp;
  658.     int *matchesp;
  659. {
  660.     TAG *tp;
  661.     recno_t slno;
  662.     size_t dlen, nlen, slen;
  663.     int ch, i, isolder, nlines;
  664.     char *dname, *name, *search, *p, *t, dummy[2], buf[2048];
  665.  
  666.     for (;;) {
  667.         if (!fgets(buf, sizeof(buf), csc->from_fp))
  668.             goto io_err;
  669.  
  670.         /*
  671.          * If the database is out of date, or there's some other
  672.          * problem, cscope will output error messages before the
  673.          * number-of-lines output.  Display/discard any output
  674.          * that doesn't match what we want.
  675.          */
  676. #define    CSCOPE_NLINES_FMT    "cscope: %d lines%1[\n]"
  677.         if (sscanf(buf, CSCOPE_NLINES_FMT, &nlines, dummy) == 2)
  678.             break;
  679.         if ((p = strchr(buf, '\n')) != NULL)
  680.             *p = '\0';
  681.         msgq(sp, M_ERR, "%s: \"%s\"", csc->dname, buf);
  682.     }
  683.  
  684.     while (nlines--) {
  685.         if (fgets(buf, sizeof(buf), csc->from_fp) == NULL)
  686.             goto io_err;
  687.  
  688.         /* If the line's too long for the buffer, discard it. */
  689.         if ((p = strchr(buf, '\n')) == NULL) {
  690.             while ((ch = getc(csc->from_fp)) != EOF && ch != '\n');
  691.             continue;
  692.         }
  693.         *p = '\0';
  694.  
  695.         /*
  696.          * The cscope output is in the following format:
  697.          *
  698.          *    <filename> <context> <line number> <pattern>
  699.          *
  700.          * Figure out how long everything is so we can allocate in one
  701.          * swell foop, but discard anything that looks wrong.
  702.          */
  703.         for (p = buf, i = 0;
  704.             i < 3 && (t = strsep(&p, "\t ")) != NULL; ++i)
  705.             switch (i) {
  706.             case 0:            /* Filename. */
  707.                 name = t;
  708.                 nlen = strlen(name);
  709.                 break;
  710.             case 1:            /* Context. */
  711.                 break;
  712.             case 2:            /* Line number. */
  713.                 slno = (recno_t)atol(t);
  714.                 break;
  715.             }
  716.         if (i != 3 || p == NULL || t == NULL)
  717.             continue;
  718.  
  719.         /* The rest of the string is the search pattern. */
  720.         search = p;
  721.         slen = strlen(p);
  722.  
  723.         /* Resolve the file name. */
  724.         csc_file(sp, csc, name, &dname, &dlen, &isolder);
  725.  
  726.         /*
  727.          * If the file is older than the cscope database, that is,
  728.          * the database was built since the file was last modified,
  729.          * or there wasn't a search string, use the line number.
  730.          */
  731.         if (isolder || strcmp(search, "<unknown>") == 0) {
  732.             search = NULL;
  733.             slen = 0;
  734.         }
  735.  
  736.         /*
  737.          * Allocate and initialize a tag structure plus the variable
  738.          * length cscope information that follows it.
  739.          */
  740.         CALLOC_RET(sp, tp,
  741.             TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + slen + 1);
  742.         tp->fname = tp->buf;
  743.         if (dlen != 0) {
  744.             memcpy(tp->fname, dname, dlen);
  745.             tp->fname[dlen] = '/';
  746.             ++dlen;
  747.         }
  748.         memcpy(tp->fname + dlen, name, nlen + 1);
  749.         tp->fnlen = dlen + nlen;
  750.         tp->slno = slno;
  751.         if (slen != 0) {
  752.             tp->search = tp->fname + tp->fnlen + 1;
  753.             memcpy(tp->search, search, (tp->slen = slen) + 1);
  754.         }
  755.         CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
  756.  
  757.         ++*matchesp;
  758.     }
  759.  
  760.     (void)read_prompt(sp, csc);
  761.     return (0);
  762.  
  763. io_err:    if (feof(csc->from_fp))
  764.         errno = EIO;
  765.     msgq_str(sp, M_SYSERR, "%s", csc->dname);
  766.     terminate(sp, csc, 0);
  767.     return (1);
  768. }
  769.  
  770. /*
  771.  * csc_file --
  772.  *    Search for the right path to this file.
  773.  */
  774. static void
  775. csc_file(sp, csc, name, dirp, dlenp, isolderp)
  776.     SCR *sp;
  777.     CSC *csc;
  778.     char *name, **dirp;
  779.     size_t *dlenp;
  780.     int *isolderp;
  781. {
  782.     struct stat sb;
  783.     char **pp, buf[MAXPATHLEN];
  784.  
  785.     /*
  786.      * Check for the file in all of the listed paths.  If we don't
  787.      * find it, we simply return it unchanged.  We have to do this
  788.      * now, even though it's expensive, because if the user changes
  789.      * directories, we can't change our minds as to where the file
  790.      * lives.
  791.      */
  792.     for (pp = csc->paths; *pp != NULL; ++pp) {
  793.         (void)snprintf(buf, sizeof(buf), "%s/%s", *pp, name);
  794.         if (stat(buf, &sb) == 0) {
  795.             *dirp = *pp;
  796.             *dlenp = strlen(*pp);
  797.             *isolderp = sb.st_mtime < csc->mtime;
  798.             return;
  799.         }
  800.     }
  801.     *dlenp = 0;
  802. }
  803.  
  804. /*
  805.  * cscope_help --
  806.  *    The cscope help command.
  807.  */
  808. static int
  809. cscope_help(sp, cmdp, subcmd)
  810.     SCR *sp;
  811.     EXCMD *cmdp;
  812.     char *subcmd;
  813. {
  814.     return (csc_help(sp, subcmd));
  815. }
  816.  
  817. /*
  818.  * csc_help --
  819.  *    Display help/usage messages.
  820.  */
  821. static int
  822. csc_help(sp, cmd)
  823.     SCR *sp;
  824.     char *cmd;
  825. {
  826.     CC const *ccp;
  827.  
  828.     if (cmd != NULL && *cmd != '\0')
  829.         if ((ccp = lookup_ccmd(cmd)) == NULL) {
  830.             ex_printf(sp,
  831.                 "%s doesn't match any cscope command\n", cmd);
  832.             return (1);
  833.         } else {
  834.             ex_printf(sp,
  835.                   "Command: %s (%s)\n", ccp->name, ccp->help_msg);
  836.             ex_printf(sp, "  Usage: %s\n", ccp->usage_msg);
  837.             return (0);
  838.         }
  839.  
  840.     ex_printf(sp, "cscope commands:\n");
  841.     for (ccp = cscope_cmds; ccp->name != NULL; ++ccp)
  842.         ex_printf(sp, "  %*s: %s\n", 5, ccp->name, ccp->help_msg);
  843.     return (0);
  844. }
  845.  
  846. /*
  847.  * cscope_kill --
  848.  *    The cscope kill command.
  849.  */
  850. static int
  851. cscope_kill(sp, cmdp, cn)
  852.     SCR *sp;
  853.     EXCMD *cmdp;
  854.     char *cn;
  855. {
  856.     return (terminate(sp, NULL, atoi(cn)));
  857. }
  858.  
  859. /*
  860.  * terminate --
  861.  *    Detach from a cscope process.
  862.  */
  863. static int
  864. terminate(sp, csc, n)
  865.     SCR *sp;
  866.     CSC *csc;
  867.     int n;
  868. {
  869.     EX_PRIVATE *exp;
  870.     int i, pstat;
  871.  
  872.     exp = EXP(sp);
  873.  
  874.     /*
  875.      * We either get a csc structure or a number.  If not provided a
  876.      * csc structure, find the right one.
  877.      */
  878.     if (csc == NULL) {
  879.         if (n < 1)
  880.             goto badno;
  881.         for (i = 1, csc = exp->cscq.lh_first;
  882.             csc != NULL; csc = csc->q.le_next, i++)
  883.             if (i == n)
  884.                 break;
  885.         if (csc == NULL) {
  886. badno:            msgq(sp, M_ERR, "312|%d: no such cscope session", n);
  887.             return (1);
  888.         }
  889.     }
  890.  
  891.     /*
  892.      * XXX
  893.      * Theoretically, we have the only file descriptors to the process,
  894.      * so closing them should let it exit gracefully, deleting temporary
  895.      * files, etc.  The original vi cscope integration sent the cscope
  896.      * connection a SIGTERM signal, so I'm not sure if closing the file
  897.      * descriptors is sufficient.
  898.      */
  899.     if (csc->from_fp != NULL)
  900.         (void)fclose(csc->from_fp);
  901.     if (csc->to_fp != NULL)
  902.         (void)fclose(csc->to_fp);
  903.     (void)waitpid(csc->pid, &pstat, 0);
  904.  
  905.     /* Discard cscope connection information. */
  906.     LIST_REMOVE(csc, q);
  907.     if (csc->pbuf != NULL)
  908.         free(csc->pbuf);
  909.     if (csc->paths != NULL)
  910.         free(csc->paths);
  911.     free(csc);
  912.     return (0);
  913. }
  914.  
  915. /*
  916.  * cscope_reset --
  917.  *    The cscope reset command.
  918.  */
  919. static int
  920. cscope_reset(sp, cmdp, notusedp)
  921.     SCR *sp;
  922.     EXCMD *cmdp;
  923.     char *notusedp;
  924. {
  925.     EX_PRIVATE *exp;
  926.  
  927.     for (exp = EXP(sp); exp->cscq.lh_first != NULL;)
  928.         if (cscope_kill(sp, cmdp, "1"))
  929.             return (1);
  930.     return (0);
  931. }
  932.  
  933. /*
  934.  * cscope_display --
  935.  *    Display current connections.
  936.  *
  937.  * PUBLIC: int cscope_display __P((SCR *));
  938.  */
  939. int
  940. cscope_display(sp)
  941.     SCR *sp;
  942. {
  943.     EX_PRIVATE *exp;
  944.     CSC *csc;
  945.     int i;
  946.  
  947.     exp = EXP(sp);
  948.     if (exp->cscq.lh_first == NULL) {
  949.         ex_printf(sp, "No cscope connections.\n");
  950.         return (0);
  951.     }
  952.     for (i = 1,
  953.         csc = exp->cscq.lh_first; csc != NULL; ++i, csc = csc->q.le_next)
  954.         ex_printf(sp,
  955.             "%2d %s (process %lu)\n", i, csc->dname, (u_long)csc->pid);
  956.     return (0);
  957. }
  958.  
  959. /*
  960.  * cscope_search --
  961.  *    Search a file for a cscope entry.
  962.  *
  963.  * PUBLIC: int cscope_search __P((SCR *, TAGQ *, TAG *));
  964.  */
  965. int
  966. cscope_search(sp, tqp, tp)
  967.     SCR *sp;
  968.     TAGQ *tqp;
  969.     TAG *tp;
  970. {
  971.     MARK m;
  972.  
  973.     /* If we don't have a search pattern, use the line number. */
  974.     if (tp->search == NULL) {
  975.         if (!db_exist(sp, tp->slno)) {
  976.             tag_msg(sp, TAG_BADLNO, tqp->tag);
  977.             return (1);
  978.         }
  979.         m.lno = tp->slno;
  980.     } else {
  981.         /*
  982.          * Search for the tag; cheap fallback for C functions
  983.          * if the name is the same but the arguments have changed.
  984.          */
  985.         m.lno = 1;
  986.         m.cno = 0;
  987.         if (f_search(sp, &m, &m,
  988.             tp->search, tp->slen, NULL, SEARCH_CSCOPE | SEARCH_FILE)) {
  989.             tag_msg(sp, TAG_SEARCH, tqp->tag);
  990.             return (1);
  991.         }
  992.  
  993.         /*
  994.          * !!!
  995.          * Historically, tags set the search direction if it wasn't
  996.          * already set.
  997.          */
  998.         if (sp->searchdir == NOTSET)
  999.             sp->searchdir = FORWARD;
  1000.     }
  1001.  
  1002.     /*
  1003.      * !!!
  1004.      * Tags move to the first non-blank, NOT the search pattern start.
  1005.      */
  1006.     sp->lno = m.lno;
  1007.     sp->cno = 0;
  1008.     (void)nonblank(sp, sp->lno, &sp->cno);
  1009.     return (0);
  1010. }
  1011.  
  1012.  
  1013. /*
  1014.  * lookup_ccmd --
  1015.  *    Return a pointer to the command structure.
  1016.  */
  1017. static CC const *
  1018. lookup_ccmd(name)
  1019.     char *name;
  1020. {
  1021.     CC const *ccp;
  1022.     size_t len;
  1023.  
  1024.     len = strlen(name);
  1025.     for (ccp = cscope_cmds; ccp->name != NULL; ++ccp)
  1026.         if (strncmp(name, ccp->name, len) == 0)
  1027.             return (ccp);
  1028.     return (NULL);
  1029. }
  1030.  
  1031. /*
  1032.  * read_prompt --
  1033.  *    Read a prompt from cscope.
  1034.  */
  1035. static int
  1036. read_prompt(sp, csc)
  1037.     SCR *sp;
  1038.     CSC *csc;
  1039. {
  1040.     int ch;
  1041.  
  1042. #define    CSCOPE_PROMPT        ">> "
  1043.     for (;;) {
  1044.         while ((ch =
  1045.             getc(csc->from_fp)) != EOF && ch != CSCOPE_PROMPT[0]);
  1046.         if (ch == EOF) {
  1047.             terminate(sp, csc, 0);
  1048.             return (1);
  1049.         }
  1050.         if (getc(csc->from_fp) != CSCOPE_PROMPT[1])
  1051.             continue;
  1052.         if (getc(csc->from_fp) != CSCOPE_PROMPT[2])
  1053.             continue;
  1054.         break;
  1055.     }
  1056.     return (0);
  1057. }
  1058.