home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / if_cscope.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-30  |  49.8 KB  |  2,250 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com>
  4.  * Ported to Win32 by Sergey Khorev <khorev@softlab.ru>
  5.  *
  6.  * The basic idea/structure of cscope for Vim was borrowed from Nvi.  There
  7.  * might be a few lines of code that look similar to what Nvi has.
  8.  *
  9.  * See README.txt for an overview of the Vim source code.
  10.  */
  11.  
  12. #include "vim.h"
  13.  
  14. #if defined(FEAT_CSCOPE) || defined(PROTO)
  15.  
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <assert.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #if defined(UNIX)
  22. # include <sys/wait.h>
  23. #else
  24.     /* not UNIX, must be WIN32 */
  25. # include <io.h>
  26. # include <fcntl.h>
  27. # include <process.h>
  28. # define STDIN_FILENO    0
  29. # define STDOUT_FILENO   1
  30. # define STDERR_FILENO   2
  31. # define pipe(fds) _pipe(fds, 256, O_TEXT|O_NOINHERIT)
  32. #endif
  33. #include "if_cscope.h"
  34.  
  35. static void        cs_usage_msg __ARGS((csid_e x));
  36. static int        cs_add __ARGS((exarg_T *eap));
  37. static void        cs_stat_emsg __ARGS((char *fname));
  38. static int        cs_add_common __ARGS((char *, char *, char *));
  39. static int        cs_check_for_connections __ARGS((void));
  40. static int        cs_check_for_tags __ARGS((void));
  41. static int        cs_cnt_connections __ARGS((void));
  42. static void        cs_reading_emsg __ARGS((int idx));
  43. static int        cs_cnt_matches __ARGS((int idx));
  44. static char *        cs_create_cmd __ARGS((char *csoption, char *pattern));
  45. static int        cs_create_connection __ARGS((int i));
  46. static void        do_cscope_general __ARGS((exarg_T *eap, int make_split));
  47. static void        cs_file_results __ARGS((FILE *, int *));
  48. static void        cs_fill_results __ARGS((char *, int , int *, char ***,
  49.             char ***, int *));
  50. static int        cs_find __ARGS((exarg_T *eap));
  51. static int        cs_find_common __ARGS((char *opt, char *pat, int, int ));
  52. static int        cs_help __ARGS((exarg_T *eap));
  53. static void        cs_init __ARGS((void));
  54. static void        clear_csinfo __ARGS((int i));
  55. static int        cs_insert_filelist __ARGS((char *, char *, char *,
  56.             struct stat *));
  57. static int        cs_kill __ARGS((exarg_T *eap));
  58. static void        cs_kill_execute __ARGS((int, char *));
  59. static cscmd_T *    cs_lookup_cmd __ARGS((exarg_T *eap));
  60. static char *        cs_make_vim_style_matches __ARGS((char *, char *,
  61.             char *, char *));
  62. static char *        cs_manage_matches __ARGS((char **, char **, int, mcmd_e));
  63. static char *        cs_parse_results __ARGS((int cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search));
  64. static char *        cs_pathcomponents __ARGS((char *path));
  65. static void        cs_print_tags_priv __ARGS((char **, char **, int));
  66. static int        cs_read_prompt __ARGS((int ));
  67. static void        cs_release_csp __ARGS((int, int freefnpp));
  68. static int        cs_reset __ARGS((exarg_T *eap));
  69. static char *        cs_resolve_file __ARGS((int, char *));
  70. static int        cs_show __ARGS((exarg_T *eap));
  71.  
  72.  
  73. static csinfo_T        csinfo[CSCOPE_MAX_CONNECTIONS];
  74. static cscmd_T        cs_cmds[] =
  75. {
  76.     { "add",    cs_add,
  77.         N_("Add a new database"),     "add file|dir [pre-path] [flags]", 0 },
  78.     { "find",    cs_find,
  79.         N_("Query for a pattern"),    FIND_USAGE, 1 },
  80.     { "help",    cs_help,
  81.         N_("Show this message"),      "help", 0 },
  82.     { "kill",    cs_kill,
  83.         N_("Kill a connection"),      "kill #", 0 },
  84.     { "reset",    cs_reset,
  85.         N_("Reinit all connections"), "reset", 0 },
  86.     { "show",    cs_show,
  87.         N_("Show connections"),       "show", 0 },
  88.     { NULL }
  89. };
  90.  
  91.     static void
  92. cs_usage_msg(x)
  93.     csid_e x;
  94. {
  95.     (void)EMSG2(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
  96. }
  97.  
  98. /*
  99.  * PRIVATE: do_cscope_general
  100.  *
  101.  * find the command, print help if invalid, and the then call the
  102.  * corresponding command function,
  103.  * called from do_cscope and do_scscope
  104.  */
  105.     static void
  106. do_cscope_general(eap, make_split)
  107.     exarg_T    *eap;
  108.     int        make_split; /* whether to split window */
  109. {
  110.     cscmd_T *cmdp;
  111.  
  112.     cs_init();
  113.     if ((cmdp = cs_lookup_cmd(eap)) == NULL)
  114.     {
  115.     cs_help(eap);
  116.     return;
  117.     }
  118.  
  119. #ifdef FEAT_WINDOWS
  120.     if (make_split)
  121.     {
  122.     if (!cmdp->cansplit)
  123.     {
  124.         (void)MSG_PUTS(_("This cscope command does not support splitting the window.\n"));
  125.         return;
  126.     }
  127.     postponed_split = -1;
  128.     }
  129. #endif
  130.  
  131.     cmdp->func(eap);
  132. }
  133.  
  134. /*
  135.  * PUBLIC: do_cscope
  136.  */
  137.     void
  138. do_cscope(eap)
  139.     exarg_T *eap;
  140. {
  141.     do_cscope_general(eap, FALSE);
  142. }
  143.  
  144. /*
  145.  * PUBLIC: do_scscope
  146.  *
  147.  * same as do_cscope, but splits window, too.
  148.  */
  149.     void
  150. do_scscope(eap)
  151.     exarg_T *eap;
  152. {
  153.     do_cscope_general(eap, TRUE);
  154. }
  155.  
  156. /*
  157.  * PUBLIC: do_cstag
  158.  *
  159.  */
  160.     void
  161. do_cstag(eap)
  162.     exarg_T *eap;
  163. {
  164.     int ret = FALSE;
  165.  
  166.     cs_init();
  167.  
  168.     if (eap->arg == NULL || strlen((const char *)(eap->arg)) == 0)
  169.     {
  170.     (void)EMSG(_("E562: Usage: cstag <ident>"));
  171.     return;
  172.     }
  173.  
  174.     switch (p_csto)
  175.     {
  176.     case 0 :
  177.     if (cs_check_for_connections())
  178.     {
  179.         ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE);
  180.         if (ret == FALSE)
  181.         {
  182.         cs_free_tags();
  183.         if (msg_col)
  184.             msg_putchar('\n');
  185.  
  186.         if (cs_check_for_tags())
  187.             ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
  188.         }
  189.     }
  190.     else if (cs_check_for_tags())
  191.     {
  192.         ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
  193.     }
  194.     break;
  195.     case 1 :
  196.     if (cs_check_for_tags())
  197.     {
  198.         ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
  199.         if (ret == FALSE)
  200.         {
  201.         if (msg_col)
  202.             msg_putchar('\n');
  203.  
  204.         if (cs_check_for_connections())
  205.         {
  206.             ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
  207.                      FALSE);
  208.             if (ret == FALSE)
  209.             cs_free_tags();
  210.         }
  211.         }
  212.     }
  213.     else if (cs_check_for_connections())
  214.     {
  215.         ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE);
  216.         if (ret == FALSE)
  217.         cs_free_tags();
  218.     }
  219.     break;
  220.     default :
  221.     break;
  222.     }
  223.  
  224.     if (!ret)
  225.     {
  226.     (void)EMSG(_("E257: cstag: tag not found"));
  227. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  228.     g_do_tagpreview = 0;
  229. #endif
  230.     }
  231.  
  232. } /* do_cscope */
  233.  
  234.  
  235. /*
  236.  * PUBLIC: cs_find
  237.  *
  238.  * this simulates a vim_fgets(), but for cscope, returns the next line
  239.  * from the cscope output.  should only be called from find_tags()
  240.  *
  241.  * returns TRUE if eof, FALSE otherwise
  242.  */
  243.     int
  244. cs_fgets(buf, size)
  245.     char_u    *buf;
  246.     int        size;
  247. {
  248.     char *p;
  249.  
  250.     if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
  251.     return TRUE;
  252.  
  253.     if ((int)strlen(p) > size)
  254.     {
  255.     strncpy((char *)buf, p, size - 1);
  256.     buf[size] = '\0';
  257.     }
  258.     else
  259.     (void)strcpy((char *)buf, p);
  260.  
  261.     return FALSE;
  262. } /* cs_fgets */
  263.  
  264.  
  265. /*
  266.  * PUBLIC: cs_free_tags
  267.  *
  268.  * called only from do_tag(), when popping the tag stack
  269.  */
  270.     void
  271. cs_free_tags()
  272. {
  273.     cs_manage_matches(NULL, NULL, -1, Free);
  274. }
  275.  
  276.  
  277. /*
  278.  * PUBLIC: cs_print_tags
  279.  *
  280.  * called from do_tag()
  281.  */
  282.     void
  283. cs_print_tags()
  284. {
  285.     cs_manage_matches(NULL, NULL, -1, Print);
  286. }
  287.  
  288.  
  289. /*
  290.  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
  291.  *
  292.  *        Checks for the existence of a |cscope| connection.  If no
  293.  *        parameters are specified, then the function returns:
  294.  *
  295.  *        0, if cscope was not available (not compiled in), or if there
  296.  *        are no cscope connections; or
  297.  *        1, if there is at least one cscope connection.
  298.  *
  299.  *        If parameters are specified, then the value of {num}
  300.  *        determines how existence of a cscope connection is checked:
  301.  *
  302.  *        {num}    Description of existence check
  303.  *        -----    ------------------------------
  304.  *        0    Same as no parameters (e.g., "cscope_connection()").
  305.  *        1    Ignore {prepend}, and use partial string matches for
  306.  *            {dbpath}.
  307.  *        2    Ignore {prepend}, and use exact string matches for
  308.  *            {dbpath}.
  309.  *        3    Use {prepend}, use partial string matches for both
  310.  *            {dbpath} and {prepend}.
  311.  *        4    Use {prepend}, use exact string matches for both
  312.  *            {dbpath} and {prepend}.
  313.  *
  314.  *        Note: All string comparisons are case sensitive!
  315.  */
  316. #if defined(FEAT_EVAL) || defined(PROTO)
  317.     int
  318. cs_connection(num, dbpath, ppath)
  319.     int num;
  320.     char_u *dbpath;
  321.     char_u *ppath;
  322. {
  323.     int i;
  324.  
  325.     if (num < 0 || num > 4 || (num > 0 && !dbpath))
  326.     return FALSE;
  327.  
  328.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  329.     {
  330.     if (!csinfo[i].fname)
  331.         continue;
  332.  
  333.     if (num == 0)
  334.         return TRUE;
  335.  
  336.     switch (num)
  337.     {
  338.     case 1:
  339.         if (strstr(csinfo[i].fname, (char *)dbpath))
  340.         return TRUE;
  341.         break;
  342.     case 2:
  343.         if (strcmp(csinfo[i].fname, (char *)dbpath) == 0)
  344.         return TRUE;
  345.         break;
  346.     case 3:
  347.         if (strstr(csinfo[i].fname, (char *)dbpath)
  348.             && ((!ppath && !csinfo[i].ppath)
  349.             || (ppath
  350.                 && csinfo[i].ppath
  351.                 && strstr(csinfo[i].ppath, (char *)ppath))))
  352.         return TRUE;
  353.         break;
  354.     case 4:
  355.         if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0)
  356.             && ((!ppath && !csinfo[i].ppath)
  357.             || (ppath
  358.                 && csinfo[i].ppath
  359.                 && (strcmp(csinfo[i].ppath, (char *)ppath) == 0))))
  360.         return TRUE;
  361.         break;
  362.     }
  363.     }
  364.  
  365.     return FALSE;
  366. } /* cs_connection */
  367. #endif
  368.  
  369.  
  370. /*
  371.  * PRIVATE functions
  372.  ****************************************************************************/
  373.  
  374. /*
  375.  * PRIVATE: cs_add
  376.  *
  377.  * add cscope database or a directory name (to look for cscope.out)
  378.  * the the cscope connection list
  379.  *
  380.  * MAXPATHL 256
  381.  */
  382. /* ARGSUSED */
  383.     static int
  384. cs_add(eap)
  385.     exarg_T *eap;
  386. {
  387.     char *fname, *ppath, *flags = NULL;
  388.  
  389.     if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL)
  390.     {
  391.     cs_usage_msg(Add);
  392.     return CSCOPE_FAILURE;
  393.     }
  394.     if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
  395.     flags = strtok((char *)NULL, (const char *)" ");
  396.  
  397.     return cs_add_common(fname, ppath, flags);
  398. }
  399.  
  400.     static void
  401. cs_stat_emsg(fname)
  402.     char *fname;
  403. {
  404.     char *stat_emsg = _("E563: stat(%s) error: %d");
  405.     char *buf = (char *)alloc((unsigned)strlen(stat_emsg) + MAXPATHL + 10);
  406.  
  407.     if (buf != NULL)
  408.     {
  409.     (void)sprintf(buf, stat_emsg, fname, errno);
  410.     (void)EMSG(buf);
  411.     vim_free(buf);
  412.     }
  413.     else
  414.     (void)EMSG(_("E563: stat error"));
  415. }
  416.  
  417.  
  418. /*
  419.  * PRIVATE: cs_add_common
  420.  *
  421.  * the common routine to add a new cscope connection.  called by
  422.  * cs_add() and cs_reset().  i really don't like to do this, but this
  423.  * routine uses a number of goto statements.
  424.  */
  425.     static int
  426. cs_add_common(arg1, arg2, flags)
  427.     char *arg1;        /* filename - may contain environment variables */
  428.     char *arg2;        /* prepend path - may contain environment variables */
  429.     char *flags;
  430. {
  431.     struct stat statbuf;
  432.     int ret;
  433.     char *fname = NULL;
  434.     char *fname2 = NULL;
  435.     char *ppath = NULL;
  436.     int i;
  437.  
  438.     /* get the filename (arg1), expand it, and try to stat it */
  439.     if ((fname = (char *)alloc(MAXPATHL+1)) == NULL)
  440.     goto add_err;
  441.  
  442.     expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
  443.     ret = stat(fname, &statbuf);
  444.     if (ret < 0)
  445.     {
  446. staterr:
  447.     if (p_csverbose)
  448.         cs_stat_emsg(fname);
  449.     goto add_err;
  450.     }
  451.  
  452.     /* get the prepend path (arg2), expand it, and try to stat it */
  453.     if (arg2 != NULL)
  454.     {
  455.     struct stat statbuf2;
  456.  
  457.     if ((ppath = (char *)alloc(MAXPATHL+1)) == NULL)
  458.         goto add_err;
  459.  
  460.     expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
  461.     ret = stat(ppath, &statbuf2);
  462.     if (ret < 0)
  463.         goto staterr;
  464.     }
  465.  
  466.     /* if filename is a directory, append the cscope database name to it */
  467.     if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  468.     {
  469.     fname2 = (char *)alloc(strlen(CSCOPE_DBFILE) + strlen(fname) + 2);
  470.     if (fname2 == NULL)
  471.         goto add_err;
  472.  
  473.     while (fname[strlen(fname)-1] == '/'
  474. #ifdef WIN32
  475.         || fname[strlen(fname)-1] == '\\'
  476. #endif
  477.         )
  478.     {
  479.         fname[strlen(fname)-1] = '\0';
  480.         if (strlen(fname) == 0)
  481.         break;
  482.     }
  483.     if (fname[0] == '\0')
  484.         (void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
  485.     else
  486.         (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
  487.  
  488.     ret = stat(fname2, &statbuf);
  489.     if (ret < 0)
  490.     {
  491.         if (p_csverbose)
  492.         cs_stat_emsg(fname2);
  493.         goto add_err;
  494.     }
  495.  
  496.     i = cs_insert_filelist(fname2, ppath, flags, &statbuf);
  497.     }
  498. #if defined(UNIX)
  499.     else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
  500. #else
  501.     /* substitute define S_ISREG from os_unix.h */
  502.     else if (((statbuf.st_mode) & S_IFMT) == S_IFREG)
  503. #endif
  504.     {
  505.     i = cs_insert_filelist(fname, ppath, flags, &statbuf);
  506.     }
  507.     else
  508.     {
  509.     if (p_csverbose)
  510.         (void)EMSG2(
  511.         _("E564: %s is not a directory or a valid cscope database"),
  512.         fname);
  513.     goto add_err;
  514.     }
  515.  
  516.     if (i != -1)
  517.     {
  518.     if (cs_create_connection(i) == CSCOPE_FAILURE
  519.         || cs_read_prompt(i) == CSCOPE_FAILURE)
  520.         goto add_err;
  521.  
  522.     if (p_csverbose)
  523.     {
  524.         msg_clr_eos();
  525.         (void)smsg_attr(hl_attr(HLF_R),
  526.                 (char_u *)_("Added cscope database %s"),
  527.                 csinfo[i].fname);
  528.     }
  529.     }
  530.  
  531.     vim_free(fname);
  532.     vim_free(fname2);
  533.     vim_free(ppath);
  534.     return CSCOPE_SUCCESS;
  535.  
  536. add_err:
  537.     vim_free(fname2);
  538.     vim_free(fname);
  539.     vim_free(ppath);
  540.     return CSCOPE_FAILURE;
  541. } /* cs_add_common */
  542.  
  543.  
  544.     static int
  545. cs_check_for_connections()
  546. {
  547.     return (cs_cnt_connections() > 0);
  548. } /* cs_check_for_connections */
  549.  
  550.  
  551.     static int
  552. cs_check_for_tags()
  553. {
  554.     return (p_tags[0] != NUL && curbuf->b_p_tags != NUL);
  555. } /* cs_check_for_tags */
  556.  
  557.  
  558. /*
  559.  * PRIVATE: cs_cnt_connections
  560.  *
  561.  * count the number of cscope connections
  562.  */
  563.     static int
  564. cs_cnt_connections()
  565. {
  566.     short i;
  567.     short cnt = 0;
  568.  
  569.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  570.     {
  571.     if (csinfo[i].fname != NULL)
  572.         cnt++;
  573.     }
  574.     return cnt;
  575. } /* cs_cnt_connections */
  576.  
  577.     static void
  578. cs_reading_emsg(idx)
  579.     int idx;    /* connection index */
  580. {
  581.     EMSGN(_("E262: error reading cscope connection %ld"), idx);
  582. }
  583.  
  584. #define    CSREAD_BUFSIZE    2048
  585. /*
  586.  * PRIVATE: cs_cnt_matches
  587.  *
  588.  * count the number of matches for a given cscope connection.
  589.  */
  590.     static int
  591. cs_cnt_matches(idx)
  592.     int idx;
  593. {
  594.     char *stok;
  595.     char *buf;
  596.     int nlines;
  597.  
  598.     buf = (char *)alloc(CSREAD_BUFSIZE);
  599.     if (buf == NULL)
  600.     return 0;
  601.     for (;;)
  602.     {
  603.     if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp))
  604.     {
  605.         if (feof(csinfo[idx].fr_fp))
  606.         errno = EIO;
  607.  
  608.         cs_reading_emsg(idx);
  609.  
  610.         vim_free(buf);
  611.         return -1;
  612.     }
  613.  
  614.     /*
  615.      * If the database is out of date, or there's some other problem,
  616.      * cscope will output error messages before the number-of-lines output.
  617.      * Display/discard any output that doesn't match what we want.
  618.      */
  619.     if ((stok = strtok(buf, (const char *)" ")) == NULL)
  620.         continue;
  621.     if (strcmp((const char *)stok, "cscope:"))
  622.         continue;
  623.  
  624.     if ((stok = strtok(NULL, (const char *)" ")) == NULL)
  625.         continue;
  626.     nlines = atoi(stok);
  627.     if (nlines < 0)
  628.     {
  629.         nlines = 0;
  630.         break;
  631.     }
  632.  
  633.     if ((stok = strtok(NULL, (const char *)" ")) == NULL)
  634.         continue;
  635.     if (strncmp((const char *)stok, "lines", 5))
  636.         continue;
  637.  
  638.     break;
  639.     }
  640.  
  641.     vim_free(buf);
  642.     return nlines;
  643. } /* cs_cnt_matches */
  644.  
  645.  
  646. /*
  647.  * PRIVATE: cs_create_cmd
  648.  *
  649.  * Creates the actual cscope command query from what the user entered.
  650.  */
  651.     static char *
  652. cs_create_cmd(csoption, pattern)
  653.     char *csoption;
  654.     char *pattern;
  655. {
  656.     char *cmd;
  657.     short search;
  658.  
  659.     switch (csoption[0])
  660.     {
  661.     case '0' : case 's' :
  662.     search = 0;
  663.     break;
  664.     case '1' : case 'g' :
  665.     search = 1;
  666.     break;
  667.     case '2' : case 'd' :
  668.     search = 2;
  669.     break;
  670.     case '3' : case 'c' :
  671.     search = 3;
  672.     break;
  673.     case '4' : case 't' :
  674.     search = 4;
  675.     break;
  676.     case '6' : case 'e' :
  677.     search = 6;
  678.     break;
  679.     case '7' : case 'f' :
  680.     search = 7;
  681.     break;
  682.     case '8' : case 'i' :
  683.     search = 8;
  684.     break;
  685.     default :
  686.     (void)EMSG(_("E561: unknown cscope search type"));
  687.     cs_usage_msg(Find);
  688.     return NULL;
  689.     }
  690.  
  691.     if ((cmd = (char *)alloc(strlen(pattern) + 2)) == NULL)
  692.     return NULL;
  693.  
  694.     (void)sprintf(cmd, "%d%s", search, pattern);
  695.  
  696.     return cmd;
  697. } /* cs_create_cmd */
  698.  
  699.  
  700. /*
  701.  * PRIVATE: cs_create_connection
  702.  *
  703.  * This piece of code was taken/adapted from nvi.  do we need to add
  704.  * the BSD license notice?
  705.  */
  706.     static int
  707. cs_create_connection(i)
  708.     int i;
  709. {
  710.     int to_cs[2], from_cs[2], len;
  711.     char *prog, *cmd, *ppath = NULL;
  712. #ifndef UNIX
  713.     int in_save, out_save, err_save;
  714.     int ph;
  715. # ifdef FEAT_GUI
  716.     HWND activewnd = NULL;
  717.     HWND consolewnd = NULL;
  718. # endif
  719. #endif
  720.  
  721.     /*
  722.      * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
  723.      * from_cs[0] and writes to to_cs[1].
  724.      */
  725.     to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
  726.     if (pipe(to_cs) < 0 || pipe(from_cs) < 0)
  727.     {
  728.     (void)EMSG(_("E566: Could not create cscope pipes"));
  729. err_closing:
  730.     if (to_cs[0] != -1)
  731.         (void)close(to_cs[0]);
  732.     if (to_cs[1] != -1)
  733.         (void)close(to_cs[1]);
  734.     if (from_cs[0] != -1)
  735.         (void)close(from_cs[0]);
  736.     if (from_cs[1] != -1)
  737.         (void)close(from_cs[1]);
  738.     return CSCOPE_FAILURE;
  739.     }
  740.  
  741. #if defined(UNIX)
  742.     switch (csinfo[i].pid = fork())
  743.     {
  744.     case -1:
  745.     (void)EMSG(_("E622: Could not fork for cscope"));
  746.     goto err_closing;
  747.     case 0:                /* child: run cscope. */
  748. #else
  749.     in_save = dup(STDIN_FILENO);
  750.     out_save = dup(STDOUT_FILENO);
  751.     err_save = dup(STDERR_FILENO);
  752. #endif
  753.     if (dup2(to_cs[0], STDIN_FILENO) == -1)
  754.         perror("cs_create_connection 1");
  755.     if (dup2(from_cs[1], STDOUT_FILENO) == -1)
  756.         perror("cs_create_connection 2");
  757.     if (dup2(from_cs[1], STDERR_FILENO) == -1)
  758.         perror("cs_create_connection 3");
  759.  
  760.     /* close unused */
  761. #if defined(UNIX)
  762.     (void)close(to_cs[1]);
  763.     (void)close(from_cs[0]);
  764. #else
  765.     /* On win32 we must close opposite ends because we are the parent */
  766.     (void)close(to_cs[0]);
  767.     to_cs[0] = -1;
  768.     (void)close(from_cs[1]);
  769.     from_cs[1] = -1;
  770. #endif
  771.     /* expand the cscope exec for env var's */
  772.     if ((prog = (char *)alloc(MAXPATHL + 1)) == NULL)
  773.     {
  774. #ifdef UNIX
  775.         return CSCOPE_FAILURE;
  776. #else
  777.         goto err_closing;
  778. #endif
  779.     }
  780.     expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL);
  781.  
  782.     /* alloc space to hold the cscope command */
  783.     len = strlen(prog) + strlen(csinfo[i].fname) + 32;
  784.     if (csinfo[i].ppath)
  785.     {
  786.         /* expand the prepend path for env var's */
  787.         if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
  788.         {
  789.         vim_free(prog);
  790. #ifdef UNIX
  791.         return CSCOPE_FAILURE;
  792. #else
  793.         goto err_closing;
  794. #endif
  795.         }
  796.         expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL);
  797.  
  798.         len += strlen(ppath);
  799.     }
  800.  
  801.     if (csinfo[i].flags)
  802.         len += strlen(csinfo[i].flags);
  803.  
  804.     if ((cmd = (char *)alloc(len)) == NULL)
  805.     {
  806.         vim_free(prog);
  807.         vim_free(ppath);
  808. #ifdef UNIX
  809.         return CSCOPE_FAILURE;
  810. #else
  811.         goto err_closing;
  812. #endif
  813.     }
  814.  
  815.     /* run the cscope command; is there execl for non-unix systems? */
  816. #if defined(UNIX)
  817.     (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
  818. #else
  819.     (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
  820. #endif
  821.     if (csinfo[i].ppath != NULL)
  822.     {
  823.         (void)strcat(cmd, " -P");
  824.         (void)strcat(cmd, csinfo[i].ppath);
  825.     }
  826.     if (csinfo[i].flags != NULL)
  827.     {
  828.         (void)strcat(cmd, " ");
  829.         (void)strcat(cmd, csinfo[i].flags);
  830.     }
  831. # ifdef UNIX
  832.       /* on Win32 we still need prog */
  833.     vim_free(prog);
  834. # endif
  835.     vim_free(ppath);
  836.  
  837. #if defined(UNIX)
  838.     if (execl("/bin/sh", "sh", "-c", cmd, NULL) == -1)
  839.         perror(_("cs_create_connection exec failed"));
  840.  
  841.     exit(127);
  842.     /* NOTREACHED */
  843.     default:    /* parent. */
  844. #else
  845. # ifdef FEAT_GUI
  846.     activewnd = GetForegroundWindow(); /* on win9x cscope steals focus */
  847.     /* Dirty hack to hide annoying console window */
  848.     if (AllocConsole())
  849.     {
  850.         char *title;
  851.         title = (char *)alloc(1024);
  852.         if (title == NULL)
  853.         FreeConsole();
  854.         else
  855.         {
  856.         GetConsoleTitle(title, 1024); /* save for future restore */
  857.         SetConsoleTitle(
  858.             "GVIMCS{5499421B-CBEF-45b0-85EF-38167FDEA5C5}GVIMCS");
  859.         Sleep(40); /* as stated in MS KB we must wait 40 ms */
  860.         consolewnd = FindWindow(NULL,
  861.             "GVIMCS{5499421B-CBEF-45b0-85EF-38167FDEA5C5}GVIMCS");
  862.         if (consolewnd != NULL)
  863.             ShowWindow(consolewnd, SW_HIDE);
  864.         SetConsoleTitle(title);
  865.         vim_free(title);
  866.         }
  867.     }
  868. # endif
  869.     /* May be use &shell, &shellquote etc */
  870. # ifdef __BORLANDC__
  871.     /* BCC 5.5 uses a different function name for spawnlp */
  872.     ph = spawnlp(P_NOWAIT, prog, cmd, NULL);
  873. # else
  874.     ph = _spawnlp(_P_NOWAIT, prog, cmd, NULL);
  875. # endif
  876.     vim_free(prog);
  877.     vim_free(cmd);
  878. # ifdef FEAT_GUI
  879.     /* Dirty hack part two */
  880.     if (activewnd != NULL)
  881.         /* restoring focus */
  882.         SetForegroundWindow(activewnd);
  883.     if (consolewnd != NULL)
  884.         FreeConsole();
  885.  
  886. # endif
  887.     if (ph == -1)
  888.     {
  889.         perror(_("cs_create_connection exec failed"));
  890.         (void)EMSG(_("E623: Could not spawn cscope process"));
  891.         goto err_closing;
  892.     }
  893.     /* else */
  894.     csinfo[i].pid = 0;
  895.     csinfo[i].hProc = (HANDLE)ph;
  896.  
  897. #endif /* !UNIX */
  898.     /*
  899.      * Save the file descriptors for later duplication, and
  900.      * reopen as streams.
  901.      */
  902.     if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL)
  903.         perror(_("cs_create_connection: fdopen for to_fp failed"));
  904.     if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
  905.         perror(_("cs_create_connection: fdopen for fr_fp failed"));
  906.  
  907. #if defined(UNIX)
  908.     /* close unused */
  909.     (void)close(to_cs[0]);
  910.     (void)close(from_cs[1]);
  911.  
  912.     break;
  913.     }
  914. #else
  915.     /* restore stdhandles */
  916.     dup2(in_save, STDIN_FILENO);
  917.     dup2(out_save, STDOUT_FILENO);
  918.     dup2(err_save, STDERR_FILENO);
  919.     close(in_save);
  920.     close(out_save);
  921.     close(err_save);
  922. #endif
  923.     return CSCOPE_SUCCESS;
  924. } /* cs_create_connection */
  925.  
  926.  
  927. /*
  928.  * PRIVATE: cs_find
  929.  *
  930.  * query cscope using command line interface.  parse the output and use tselect
  931.  * to allow choices.  like Nvi, creates a pipe to send to/from query/cscope.
  932.  *
  933.  * returns TRUE if we jump to a tag or abort, FALSE if not.
  934.  */
  935.     static int
  936. cs_find(eap)
  937.     exarg_T *eap;
  938. {
  939.     char *opt, *pat;
  940.  
  941.     if (cs_check_for_connections() == FALSE)
  942.     {
  943.     (void)EMSG(_("E567: no cscope connections"));
  944.     return FALSE;
  945.     }
  946.  
  947.     if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL)
  948.     {
  949.     cs_usage_msg(Find);
  950.     return FALSE;
  951.     }
  952.  
  953.     pat = opt + strlen(opt) + 1;
  954.     if (pat == NULL || (pat != NULL && pat[0] == '\0'))
  955.     {
  956.     cs_usage_msg(Find);
  957.     return FALSE;
  958.     }
  959.  
  960.     return cs_find_common(opt, pat, eap->forceit, TRUE);
  961. } /* cs_find */
  962.  
  963.  
  964. /*
  965.  * PRIVATE: cs_find_common
  966.  *
  967.  * common code for cscope find, shared by cs_find() and do_cstag()
  968.  */
  969.     static int
  970. cs_find_common(opt, pat, forceit, verbose)
  971.     char *opt;
  972.     char *pat;
  973.     int forceit;
  974.     int verbose;
  975. {
  976.     int i;
  977.     char *cmd;
  978.     char **matches, **contexts;
  979.     int nummatches[CSCOPE_MAX_CONNECTIONS], totmatches, matched;
  980. #ifdef FEAT_QUICKFIX
  981.     char cmdletter;
  982.     char *qfpos;
  983. #endif
  984.  
  985.     /* create the actual command to send to cscope */
  986.     cmd = cs_create_cmd(opt, pat);
  987.     if (cmd == NULL)
  988.     return FALSE;
  989.  
  990.     /* send query to all open connections, then count the total number
  991.      * of matches so we can alloc matchesp all in one swell foop
  992.      */
  993.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  994.     nummatches[i] = 0;
  995.     totmatches = 0;
  996.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  997.     {
  998.     if (csinfo[i].fname == NULL)
  999.         continue;
  1000.  
  1001.     /* send cmd to cscope */
  1002.     (void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
  1003.     (void)fflush(csinfo[i].to_fp);
  1004.  
  1005.     nummatches[i] = cs_cnt_matches(i);
  1006.  
  1007.     if (nummatches[i] > -1)
  1008.         totmatches += nummatches[i];
  1009.  
  1010.     if (nummatches[i] == 0)
  1011.         (void)cs_read_prompt(i);
  1012.     }
  1013.     vim_free(cmd);
  1014.  
  1015.     if (totmatches == 0)
  1016.     {
  1017.     char *nf = _("E259: no matches found for cscope query %s of %s");
  1018.     char *buf;
  1019.  
  1020.     if (!verbose)
  1021.         return FALSE;
  1022.  
  1023.     buf = (char *)alloc(strlen(opt) + strlen(pat) + strlen(nf));
  1024.     if (buf == NULL)
  1025.         (void)EMSG(nf);
  1026.     else
  1027.     {
  1028.         sprintf(buf, nf, opt, pat);
  1029.         (void)EMSG(buf);
  1030.         vim_free(buf);
  1031.     }
  1032.     return FALSE;
  1033.     }
  1034.  
  1035. #ifdef FEAT_QUICKFIX
  1036.     /* get cmd letter */
  1037.     switch (opt[0])
  1038.     {
  1039.     case '0' :
  1040.     cmdletter = 's';
  1041.     break;
  1042.     case '1' :
  1043.     cmdletter = 'g';
  1044.     break;
  1045.     case '2' :
  1046.     cmdletter = 'd';
  1047.     break;
  1048.     case '3' :
  1049.     cmdletter = 'c';
  1050.     break;
  1051.     case '4' :
  1052.     cmdletter = 't';
  1053.     break;
  1054.     case '6' :
  1055.     cmdletter = 'e';
  1056.     break;
  1057.     case '7' :
  1058.     cmdletter = 'f';
  1059.     break;
  1060.     case '8' :
  1061.     cmdletter = 'i';
  1062.     break;
  1063.     default :
  1064.     cmdletter = opt[0];
  1065.     }
  1066.  
  1067.     qfpos = (char *)vim_strchr(p_csqf, cmdletter);
  1068.     if (qfpos != NULL)
  1069.     {
  1070.     qfpos++;
  1071.     /* next symbol must be + or - */
  1072.     if (strchr(CSQF_FLAGS, *qfpos) == NULL)
  1073.     {
  1074.         char *nf = _("E469: invalid cscopequickfix flag %c for %c");
  1075.         char *buf = (char *)alloc(strlen(nf));
  1076.  
  1077.         /* strlen will be enough because we use chars */
  1078.         if (buf != NULL)
  1079.         {
  1080.         sprintf(buf, nf, *qfpos, *(qfpos-1));
  1081.         (void)EMSG(buf);
  1082.         vim_free(buf);
  1083.         }
  1084.         return FALSE;
  1085.     }
  1086.     }
  1087.     if (qfpos != NULL && *qfpos != '0' && totmatches > 1)
  1088.     {
  1089.     /* fill error list */
  1090.     FILE *f;
  1091.     char_u *tmp = vim_tempname('c');
  1092.  
  1093.     f = fopen((char *)tmp, "w");
  1094.     cs_file_results(f, nummatches);
  1095.     fclose(f);
  1096.     /* '-' starts a new error list */
  1097.     if (qf_init(tmp, (char_u *)"%f%*\\t%l%*\\t%m", *qfpos == '-') > 0)
  1098.         qf_jump(0, 0, forceit);
  1099.     mch_remove(tmp);
  1100.     vim_free(tmp);
  1101.     return TRUE;
  1102.     }
  1103.     else
  1104. #endif /* FEAT_QUICKFIX */
  1105.     {
  1106.     /* read output */
  1107.     cs_fill_results((char *)pat, totmatches, nummatches, &matches,
  1108.                              &contexts, &matched);
  1109.     if (matches == NULL)
  1110.         return FALSE;
  1111.  
  1112.     (void)cs_manage_matches(matches, contexts, totmatches, Store);
  1113.  
  1114.     return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose);
  1115.     }
  1116.  
  1117. } /* cs_find_common */
  1118.  
  1119. /*
  1120.  * PRIVATE: cs_help
  1121.  *
  1122.  * print help
  1123.  */
  1124. /* ARGSUSED */
  1125.     static int
  1126. cs_help(eap)
  1127.     exarg_T *eap;
  1128. {
  1129.     cscmd_T *cmdp = cs_cmds;
  1130.  
  1131.     (void)MSG_PUTS(_("cscope commands:\n"));
  1132.     while (cmdp->name != NULL)
  1133.     {
  1134.     (void)smsg((char_u *)_("%-5s: %-30s (Usage: %s)"),
  1135.                       cmdp->name, _(cmdp->help), cmdp->usage);
  1136.     if (strcmp(cmdp->name, "find") == 0)
  1137.         MSG_PUTS(FIND_HELP);
  1138.     cmdp++;
  1139.     }
  1140.  
  1141.     wait_return(TRUE);
  1142.     return 0;
  1143. } /* cs_help */
  1144.  
  1145.  
  1146. /*
  1147.  * PRIVATE: cs_init
  1148.  *
  1149.  * initialize cscope structure if not already
  1150.  */
  1151.     static void
  1152. cs_init()
  1153. {
  1154.     short i;
  1155.     static int init_already = FALSE;
  1156.  
  1157.     if (init_already)
  1158.     return;
  1159.  
  1160.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  1161.     clear_csinfo(i);
  1162.  
  1163.     init_already = TRUE;
  1164. } /* cs_init */
  1165.  
  1166.     static void
  1167. clear_csinfo(i)
  1168.     int        i;
  1169. {
  1170.     csinfo[i].fname  = NULL;
  1171.     csinfo[i].ppath  = NULL;
  1172.     csinfo[i].flags  = NULL;
  1173. #if defined(UNIX)
  1174.     csinfo[i].st_dev = (dev_t)0;
  1175.     csinfo[i].st_ino = (ino_t)0;
  1176. #else
  1177.     csinfo[i].nVolume = 0;
  1178.     csinfo[i].nIndexHigh = 0;
  1179.     csinfo[i].nIndexLow = 0;
  1180. #endif
  1181.     csinfo[i].pid    = -1;
  1182.     csinfo[i].fr_fp  = NULL;
  1183.     csinfo[i].to_fp  = NULL;
  1184. }
  1185.  
  1186. #ifndef UNIX
  1187. static char *GetWin32Error __ARGS((void));
  1188.  
  1189.     static char *
  1190. GetWin32Error()
  1191. {
  1192.     char *msg = NULL;
  1193.     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
  1194.         NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL);
  1195.     if (msg != NULL)
  1196.     {
  1197.     /* remove trailing \r\n */
  1198.     char *pcrlf = strstr(msg, "\r\n");
  1199.     if (pcrlf != NULL)
  1200.         *pcrlf = '\0';
  1201.     }
  1202.     return msg;
  1203. }
  1204. #endif
  1205. /*
  1206.  * PRIVATE: cs_insert_filelist
  1207.  *
  1208.  * insert a new cscope database filename into the filelist
  1209.  */
  1210.     static int
  1211. cs_insert_filelist(fname, ppath, flags, sb)
  1212.     char *fname;
  1213.     char *ppath;
  1214.     char *flags;
  1215.     struct stat *sb;
  1216. {
  1217.     short    i, j;
  1218. #ifndef UNIX
  1219.     HANDLE    hFile;
  1220.     BY_HANDLE_FILE_INFORMATION bhfi;
  1221.  
  1222.     vim_memset(&bhfi, 0, sizeof(bhfi));
  1223.     /* On windows 9x GetFileInformationByHandle doesn't work, so skip it */
  1224.     if (!mch_windows95())
  1225.     {
  1226.     hFile = CreateFile(fname, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
  1227.                          FILE_ATTRIBUTE_NORMAL, NULL);
  1228.     if (hFile == INVALID_HANDLE_VALUE)
  1229.     {
  1230.         if (p_csverbose)
  1231.         {
  1232.         char *cant_msg = _("E625: cannot open cscope database: %s");
  1233.         char *winmsg = GetWin32Error();
  1234.  
  1235.         if (winmsg != NULL)
  1236.         {
  1237.             (void)EMSG2(cant_msg, winmsg);
  1238.             LocalFree(winmsg);
  1239.         }
  1240.         else
  1241.             /* subst filename if can't get error text */
  1242.             (void)EMSG2(cant_msg, fname);
  1243.         }
  1244.         return -1;
  1245.     }
  1246.     if (!GetFileInformationByHandle(hFile, &bhfi))
  1247.     {
  1248.         CloseHandle(hFile);
  1249.         if (p_csverbose)
  1250.         (void)EMSG(_("E626: cannot get cscope database information"));
  1251.         return -1;
  1252.     }
  1253.     CloseHandle(hFile);
  1254.     }
  1255. #endif
  1256.  
  1257.     i = -1; /* can be set to the index of an empty item in csinfo */
  1258.     for (j = 0; j < CSCOPE_MAX_CONNECTIONS; j++)
  1259.     {
  1260.     if (csinfo[j].fname != NULL
  1261. #if defined(UNIX)
  1262.         && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
  1263. #else
  1264.         /* compare pathnames first */
  1265.         && ((fullpathcmp(csinfo[j].fname, fname, FALSE) & FPC_SAME)
  1266.         /* if not Windows 9x, test index file atributes too */
  1267.         || (!mch_windows95()
  1268.             && csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
  1269.             && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
  1270.             && csinfo[j].nIndexLow == bhfi.nFileIndexLow))
  1271. #endif
  1272.         )
  1273.     {
  1274.         if (p_csverbose)
  1275.         (void)EMSG(_("E568: duplicate cscope database not added"));
  1276.         return -1;
  1277.     }
  1278.  
  1279.     if (csinfo[j].fname == NULL && i == -1)
  1280.         i = j; /* remember first empty entry */
  1281.     }
  1282.  
  1283.     if (i == -1)
  1284.     {
  1285.     if (p_csverbose)
  1286.         (void)EMSG(_("E569: maximum number of cscope connections reached"));
  1287.     return -1;
  1288.     }
  1289.  
  1290.     if ((csinfo[i].fname = (char *)alloc(strlen(fname)+1)) == NULL)
  1291.     return -1;
  1292.  
  1293.     (void)strcpy(csinfo[i].fname, (const char *)fname);
  1294.  
  1295.     if (ppath != NULL)
  1296.     {
  1297.     if ((csinfo[i].ppath = (char *)alloc(strlen(ppath) + 1)) == NULL)
  1298.     {
  1299.         vim_free(csinfo[i].fname);
  1300.         csinfo[i].fname = NULL;
  1301.         return -1;
  1302.     }
  1303.     (void)strcpy(csinfo[i].ppath, (const char *)ppath);
  1304.     } else
  1305.     csinfo[i].ppath = NULL;
  1306.  
  1307.     if (flags != NULL)
  1308.     {
  1309.     if ((csinfo[i].flags = (char *)alloc(strlen(flags) + 1)) == NULL)
  1310.     {
  1311.         vim_free(csinfo[i].fname);
  1312.         vim_free(csinfo[i].ppath);
  1313.         csinfo[i].fname = NULL;
  1314.         csinfo[i].ppath = NULL;
  1315.         return -1;
  1316.     }
  1317.     (void)strcpy(csinfo[i].flags, (const char *)flags);
  1318.     } else
  1319.     csinfo[i].flags = NULL;
  1320.  
  1321. #if defined(UNIX)
  1322.     csinfo[i].st_dev = sb->st_dev;
  1323.     csinfo[i].st_ino = sb->st_ino;
  1324.  
  1325. #else
  1326.     csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
  1327.     csinfo[i].nIndexLow = bhfi.nFileIndexLow;
  1328.     csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
  1329. #endif
  1330.     return i;
  1331. } /* cs_insert_filelist */
  1332.  
  1333.  
  1334. /*
  1335.  * PRIVATE: cs_lookup_cmd
  1336.  *
  1337.  * find cscope command in command table
  1338.  */
  1339.     static cscmd_T *
  1340. cs_lookup_cmd(exp)
  1341.     exarg_T *exp;
  1342. {
  1343.     cscmd_T *cmdp;
  1344.     char *stok;
  1345.     size_t len;
  1346.  
  1347.     if (exp->arg == NULL)
  1348.     return NULL;
  1349.  
  1350.     if ((stok = strtok((char *)(exp->arg), (const char *)" ")) == NULL)
  1351.     return NULL;
  1352.  
  1353.     len = strlen(stok);
  1354.     for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp)
  1355.     {
  1356.     if (strncmp((const char *)(stok), cmdp->name, len) == 0)
  1357.         return (cmdp);
  1358.     }
  1359.     return NULL;
  1360. } /* cs_lookup_cmd */
  1361.  
  1362.  
  1363. /*
  1364.  * PRIVATE: cs_kill
  1365.  *
  1366.  * nuke em
  1367.  */
  1368. /* ARGSUSED */
  1369.     static int
  1370. cs_kill(eap)
  1371.     exarg_T *eap;
  1372. {
  1373.     char *stok;
  1374.     short i;
  1375.  
  1376.     if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL)
  1377.     {
  1378.     cs_usage_msg(Kill);
  1379.     return CSCOPE_FAILURE;
  1380.     }
  1381.  
  1382.     /* only single digit positive and negative integers are allowed */
  1383.     if ((strlen(stok) < 2 && isdigit((int)(stok[0])))
  1384.         || (strlen(stok) < 3 && stok[0] == '-' && isdigit((int)(stok[1]))))
  1385.     i = atoi(stok);
  1386.     else
  1387.     {
  1388.     /* It must be part of a name.  We will try to find a match
  1389.      * within all the names in the csinfo data structure
  1390.      */
  1391.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  1392.     {
  1393.         if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
  1394.         break;
  1395.     }
  1396.     }
  1397.  
  1398.     if ((i >= CSCOPE_MAX_CONNECTIONS || i < -1 || csinfo[i].fname == NULL)
  1399.         && i != -1)
  1400.     {
  1401.     if (p_csverbose)
  1402.         (void)EMSG2(_("E261: cscope connection %s not found"), stok);
  1403.     }
  1404.     else
  1405.     {
  1406.     if (i == -1)
  1407.     {
  1408.         for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  1409.         {
  1410.         if (csinfo[i].fname)
  1411.             cs_kill_execute(i, csinfo[i].fname);
  1412.         }
  1413.     }
  1414.     else
  1415.         cs_kill_execute(i, stok);
  1416.     }
  1417.  
  1418.     return 0;
  1419. } /* cs_kill */
  1420.  
  1421.  
  1422. /*
  1423.  * PRIVATE: cs_kill_execute
  1424.  *
  1425.  * Actually kills a specific cscope connection.
  1426.  */
  1427.     static void
  1428. cs_kill_execute(i, cname)
  1429.     int i;        /* cscope table index */
  1430.     char *cname;    /* cscope database name */
  1431. {
  1432.     if (p_csverbose)
  1433.     {
  1434.     msg_clr_eos();
  1435.     (void)smsg_attr(hl_attr(HLF_R) | MSG_HIST,
  1436.         (char_u *)_("cscope connection %s closed"), cname);
  1437.     }
  1438.     cs_release_csp(i, TRUE);
  1439. }
  1440.  
  1441.  
  1442. /*
  1443.  * PRIVATE: cs_make_vim_style_matches
  1444.  *
  1445.  * convert the cscope output into into a ctags style entry (as might be found
  1446.  * in a ctags tags file).  there's one catch though: cscope doesn't tell you
  1447.  * the type of the tag you are looking for.  for example, in Darren Hiebert's
  1448.  * ctags (the one that comes with vim), #define's use a line number to find the
  1449.  * tag in a file while function definitions use a regexp search pattern.
  1450.  *
  1451.  * i'm going to always use the line number because cscope does something
  1452.  * quirky (and probably other things i don't know about):
  1453.  *
  1454.  *     if you have "#  define" in your source file, which is
  1455.  *     perfectly legal, cscope thinks you have "#define".  this
  1456.  *     will result in a failed regexp search. :(
  1457.  *
  1458.  * besides, even if this particular case didn't happen, the search pattern
  1459.  * would still have to be modified to escape all the special regular expression
  1460.  * characters to comply with ctags formatting.
  1461.  */
  1462.     static char *
  1463. cs_make_vim_style_matches(fname, slno, search, tagstr)
  1464.     char *fname;
  1465.     char *slno;
  1466.     char *search;
  1467.     char *tagstr;
  1468. {
  1469.     /* vim style is ctags:
  1470.      *
  1471.      *        <tagstr>\t<filename>\t<linenum_or_search>"\t<extra>
  1472.      *
  1473.      * but as mentioned above, we'll always use the line number and
  1474.      * put the search pattern (if one exists) as "extra"
  1475.      *
  1476.      * buf is used as part of vim's method of handling tags, and
  1477.      * (i think) vim frees it when you pop your tags and get replaced
  1478.      * by new ones on the tag stack.
  1479.      */
  1480.     char *buf;
  1481.     int amt;
  1482.  
  1483.     if (search != NULL)
  1484.     {
  1485.     amt = strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search)+6;
  1486.     if ((buf = (char *)alloc(amt)) == NULL)
  1487.         return NULL;
  1488.  
  1489.     (void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search);
  1490.     }
  1491.     else
  1492.     {
  1493.     amt = strlen(fname) + strlen(slno) + strlen(tagstr) + 5;
  1494.     if ((buf = (char *)alloc(amt)) == NULL)
  1495.         return NULL;
  1496.  
  1497.     (void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno);
  1498.     }
  1499.  
  1500.     return buf;
  1501. } /* cs_make_vim_style_matches */
  1502.  
  1503.  
  1504. /*
  1505.  * PRIVATE: cs_manage_matches
  1506.  *
  1507.  * this is kind of hokey, but i don't see an easy way round this..
  1508.  *
  1509.  * Store: keep a ptr to the (malloc'd) memory of matches originally
  1510.  * generated from cs_find().  the matches are originally lines directly
  1511.  * from cscope output, but transformed to look like something out of a
  1512.  * ctags.  see cs_make_vim_style_matches for more details.
  1513.  *
  1514.  * Get: used only from cs_fgets(), this simulates a vim_fgets() to return
  1515.  * the next line from the cscope output.  it basically keeps track of which
  1516.  * lines have been "used" and returns the next one.
  1517.  *
  1518.  * Free: frees up everything and resets
  1519.  *
  1520.  * Print: prints the tags
  1521.  */
  1522.     static char *
  1523. cs_manage_matches(matches, contexts, totmatches, cmd)
  1524.     char **matches;
  1525.     char **contexts;
  1526.     int totmatches;
  1527.     mcmd_e cmd;
  1528. {
  1529.     static char **mp = NULL;
  1530.     static char **cp = NULL;
  1531.     static int cnt = -1;
  1532.     static int next = -1;
  1533.     char *p = NULL;
  1534.  
  1535.     switch (cmd)
  1536.     {
  1537.     case Store:
  1538.     assert(matches != NULL);
  1539.     assert(totmatches > 0);
  1540.     if (mp != NULL || cp != NULL)
  1541.         (void)cs_manage_matches(NULL, NULL, -1, Free);
  1542.     mp = matches;
  1543.     cp = contexts;
  1544.     cnt = totmatches;
  1545.     next = 0;
  1546.     break;
  1547.     case Get:
  1548.     if (next >= cnt)
  1549.         return NULL;
  1550.  
  1551.     p = mp[next];
  1552.     next++;
  1553.     break;
  1554.     case Free:
  1555.     if (mp != NULL)
  1556.     {
  1557.         if (cnt > 0)
  1558.         while (cnt--)
  1559.         {
  1560.             vim_free(mp[cnt]);
  1561.             if (cp != NULL)
  1562.             vim_free(cp[cnt]);
  1563.         }
  1564.         vim_free(mp);
  1565.         vim_free(cp);
  1566.     }
  1567.     mp = NULL;
  1568.     cp = NULL;
  1569.     cnt = 0;
  1570.     next = 0;
  1571.     break;
  1572.     case Print:
  1573.     cs_print_tags_priv(mp, cp, cnt);
  1574.     break;
  1575.     default:    /* should not reach here */
  1576.     (void)EMSG(_("E570: fatal error in cs_manage_matches"));
  1577.     return NULL;
  1578.     }
  1579.  
  1580.     return p;
  1581. } /* cs_manage_matches */
  1582.  
  1583.  
  1584. /*
  1585.  * PRIVATE: cs_parse_results
  1586.  *
  1587.  * parse cscope output
  1588.  */
  1589.     static char *
  1590. cs_parse_results(cnumber, buf, bufsize, context, linenumber, search)
  1591.     int cnumber;
  1592.     char *buf;
  1593.     int bufsize;
  1594.     char **context;
  1595.     char **linenumber;
  1596.     char **search;
  1597. {
  1598.     int ch;
  1599.     char *p;
  1600.     char *name;
  1601.  
  1602.     if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL)
  1603.     {
  1604.     if (feof(csinfo[cnumber].fr_fp))
  1605.         errno = EIO;
  1606.  
  1607.     cs_reading_emsg(cnumber);
  1608.  
  1609.     return NULL;
  1610.     }
  1611.  
  1612.     /* If the line's too long for the buffer, discard it. */
  1613.     if ((p = strchr(buf, '\n')) == NULL)
  1614.     {
  1615.     while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
  1616.         ;
  1617.     return NULL;
  1618.     }
  1619.     *p = '\0';
  1620.  
  1621.     /*
  1622.      * cscope output is in the following format:
  1623.      *
  1624.      *    <filename> <context> <line number> <pattern>
  1625.      */
  1626.     if ((name = strtok((char *)buf, (const char *)" ")) == NULL)
  1627.     return NULL;
  1628.     if ((*context = strtok(NULL, (const char *)" ")) == NULL)
  1629.     return NULL;
  1630.     if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
  1631.     return NULL;
  1632.     *search = *linenumber + strlen(*linenumber) + 1;    /* +1 to skip \0 */
  1633.  
  1634.     /* --- nvi ---
  1635.      * If the file is older than the cscope database, that is,
  1636.      * the database was built since the file was last modified,
  1637.      * or there wasn't a search string, use the line number.
  1638.      */
  1639.     if (strcmp(*search, "<unknown>") == 0)
  1640.     *search = NULL;
  1641.  
  1642.     name = cs_resolve_file(cnumber, name);
  1643.     return name;
  1644. }
  1645.  
  1646. /*
  1647.  * PRIVATE: cs_file_results
  1648.  *
  1649.  * write cscope find results to file
  1650.  */
  1651.     static void
  1652. cs_file_results(f, nummatches_a)
  1653.     FILE *f;
  1654.     int *nummatches_a;
  1655. {
  1656.     int i, j;
  1657.     char *buf;
  1658.     char *search, *slno;
  1659.     char *fullname;
  1660.     char *cntx;
  1661.     char *context;
  1662.  
  1663.     buf = (char *)alloc(CSREAD_BUFSIZE);
  1664.     if (buf == NULL)
  1665.     return;
  1666.  
  1667.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  1668.     {
  1669.     if (nummatches_a[i] < 1)
  1670.         continue;
  1671.  
  1672.     for (j = 0; j < nummatches_a[i]; j++)
  1673.     {
  1674.        if ((fullname=cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
  1675.                &slno, &search))==NULL)
  1676.            continue;
  1677.  
  1678.        context = (char *)alloc(strlen(cntx)+5);
  1679.        if (context==NULL)
  1680.            continue;
  1681.  
  1682.        if (strcmp(cntx, "<global>")==0)
  1683.            strcpy(context, "<<global>>");
  1684.        else
  1685.            sprintf(context, "<<%s>>", cntx);
  1686.  
  1687.        if (search==NULL)
  1688.            fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
  1689.        else
  1690.            fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
  1691.  
  1692.        vim_free(context);
  1693.        vim_free(fullname);
  1694.     } /* for all matches */
  1695.  
  1696.     (void)cs_read_prompt(i);
  1697.  
  1698.     } /* for all cscope connections */
  1699.     vim_free(buf);
  1700. }
  1701.  
  1702. /*
  1703.  * PRIVATE: cs_fill_results
  1704.  *
  1705.  * get parsed cscope output and calls cs_make_vim_style_matches to convert
  1706.  * into ctags format
  1707.  */
  1708.     static void
  1709. cs_fill_results(tagstr, totmatches, nummatches_a, matches_p, cntxts_p, matched)
  1710.     char *tagstr;
  1711.     int totmatches;
  1712.     int *nummatches_a;
  1713.     char ***matches_p;
  1714.     char ***cntxts_p;
  1715.     int *matched;
  1716. {
  1717.     int i, j;
  1718.     char *buf;
  1719.     char *search, *slno;
  1720.     int totsofar = 0;
  1721.     char **matches = NULL;
  1722.     char **cntxts = NULL;
  1723.     char *fullname;
  1724.     char *cntx;
  1725.  
  1726.     assert(totmatches > 0);
  1727.  
  1728.     buf = (char *)alloc(CSREAD_BUFSIZE);
  1729.     if (buf == NULL)
  1730.     return;
  1731.  
  1732.     if ((matches = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
  1733.     goto parse_out;
  1734.     if ((cntxts = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
  1735.     goto parse_out;
  1736.  
  1737.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  1738.     {
  1739.     if (nummatches_a[i] < 1)
  1740.         continue;
  1741.  
  1742.     for (j = 0; j < nummatches_a[i]; j++)
  1743.     {
  1744.        if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
  1745.                &slno, &search)) == NULL)
  1746.         continue;
  1747.  
  1748.         matches[totsofar] = cs_make_vim_style_matches(fullname, slno,
  1749.                               search, tagstr);
  1750.  
  1751.         vim_free(fullname);
  1752.  
  1753.         if (strcmp(cntx, "<global>") == 0)
  1754.         cntxts[totsofar] = NULL;
  1755.         else
  1756.         /* note: if vim_strsave returns NULL, then the context
  1757.          * will be "<global>", which is misleading.
  1758.          */
  1759.         cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx);
  1760.  
  1761.         if (matches[totsofar] != NULL)
  1762.         totsofar++;
  1763.  
  1764.     } /* for all matches */
  1765.  
  1766.     (void)cs_read_prompt(i);
  1767.  
  1768.     } /* for all cscope connections */
  1769.  
  1770. parse_out:
  1771.     *matched = totsofar;
  1772.     *matches_p = matches;
  1773.     *cntxts_p = cntxts;
  1774.     vim_free(buf);
  1775. } /* cs_fill_results */
  1776.  
  1777.  
  1778. /* get the requested path components */
  1779.     static char *
  1780. cs_pathcomponents(path)
  1781.     char    *path;
  1782. {
  1783.     int        i;
  1784.     char    *s;
  1785.  
  1786.     if (p_cspc == 0)
  1787.     return path;
  1788.  
  1789.     s = path + strlen(path) - 1;
  1790.     for (i = 0; i < p_cspc; ++i)
  1791.     while (s > path && *--s != '/'
  1792. #ifdef WIN32
  1793.         && *--s != '\\'
  1794. #endif
  1795.         )
  1796.         ;
  1797.     if (s > path && *s == '/'
  1798. #ifdef WIN32
  1799.     || s > path && *s == '\\'
  1800. #endif
  1801.         )
  1802.     ++s;
  1803.     return s;
  1804. }
  1805.  
  1806. /*
  1807.  * PRIVATE: cs_print_tags_priv
  1808.  *
  1809.  * called from cs_manage_matches()
  1810.  */
  1811.     static void
  1812. cs_print_tags_priv(matches, cntxts, num_matches)
  1813.     char **matches;
  1814.     char **cntxts;
  1815.     int num_matches;
  1816. {
  1817.     char    *buf = NULL;
  1818.     int        bufsize = 0; /* Track available bufsize */
  1819.     int        newsize = 0;
  1820.     char    *ptag;
  1821.     char    *fname, *lno, *extra, *tbuf;
  1822.     int        i, j, idx, num;
  1823.     char_u    *in_cur_file;
  1824.     char    *globalcntx = "GLOBAL";
  1825.     char    *cntxformat = " <<%s>>";
  1826.     char    *context;
  1827.  
  1828.     assert (num_matches > 0);
  1829.  
  1830.     if ((tbuf = (char *)alloc(strlen(matches[0]) + 1)) == NULL)
  1831.     return;
  1832.  
  1833.     strcpy(tbuf, matches[0]);
  1834.     ptag = strtok(tbuf, "\t");
  1835.  
  1836.     (void)smsg_attr(hl_attr(HLF_T), (char_u *)_("Cscope tag: %s"), ptag);
  1837.  
  1838.     vim_free(tbuf);
  1839.  
  1840.     MSG_PUTS_ATTR(_("\n   #   line"), hl_attr(HLF_T));    /* strlen is 7 */
  1841.     msg_advance(msg_col + 2);
  1842.     MSG_PUTS_ATTR(_("filename / context / line\n"), hl_attr(HLF_T));
  1843.  
  1844.     /*
  1845.      * for normal tags (non-cscope tags), vim sorts the tags before printing.
  1846.      * hence, the output from 'matches' needs to be sorted as well (but we're
  1847.      * not actually sorting the contents of 'matches').  for sorting, we simply
  1848.      * print all tags in the current file before any other tags.  this idea
  1849.      * was suggested by Jeffrey George <jgeorge@texas.net>
  1850.      */
  1851.     in_cur_file = alloc_clear(num_matches);
  1852.     if (in_cur_file != NULL)
  1853.     {
  1854.     if (curbuf->b_fname != NULL)
  1855.     {
  1856.         char *f;
  1857.         int fname_len, ffname_len;
  1858.  
  1859.         fname_len = strlen((const char *)(curbuf->b_fname));
  1860.         ffname_len = strlen((const char *)(curbuf->b_ffname));
  1861.  
  1862.         for (i = 0; i < num_matches; i++)
  1863.         {
  1864.         if ((f = strchr(matches[i], '\t')) != NULL)
  1865.         {
  1866.             f++;
  1867.             if (strncmp((const char *)(curbuf->b_fname), f, fname_len)
  1868.                                       == 0
  1869.                 || strncmp((const char *)(curbuf->b_ffname), f,
  1870.                                  ffname_len) == 0)
  1871.             in_cur_file[i] = TRUE;
  1872.         }
  1873.         }
  1874.     }
  1875.     }
  1876.  
  1877.     /*
  1878.      * if we were able to allocate 'in_cur_file', then we make two passes
  1879.      * through 'matches'.  the first pass prints the tags in the current file,
  1880.      * while the second prints all remaining tags.  if we were unable to
  1881.      * allocate 'in_cur_file', we'll just make one pass through 'matches' and
  1882.      * print them unsorted.
  1883.      */
  1884.     num = 1;
  1885.     for (j = (in_cur_file) ? 2 : 1; j > 0; j--)
  1886.     {
  1887.     for (i = 0; i < num_matches; i++)
  1888.     {
  1889.         if (in_cur_file)
  1890.         {
  1891.         if (((j == 2) && (in_cur_file[i] == TRUE))
  1892.             || ((j == 1) && (in_cur_file[i] == FALSE)))
  1893.             idx = i;
  1894.         else
  1895.             continue;
  1896.         }
  1897.         else
  1898.         idx = i;
  1899.  
  1900.         /* if we really wanted to, we could avoid this malloc and strcpy
  1901.          * by parsing matches[i] on the fly and placing stuff into buf
  1902.          * directly, but that's too much of a hassle
  1903.          */
  1904.         if ((tbuf = (char *)alloc(strlen(matches[idx]) + 1)) == NULL)
  1905.         continue;
  1906.         (void)strcpy(tbuf, matches[idx]);
  1907.  
  1908.         if ((fname = strtok(tbuf, (const char *)"\t")) == NULL)
  1909.         continue;
  1910.         if ((fname = strtok(NULL, (const char *)"\t")) == NULL)
  1911.         continue;
  1912.         if ((lno = strtok(NULL, (const char *)"\t")) == NULL)
  1913.         {
  1914.         /* if NULL, then no "extra", although in cscope's case, there
  1915.          * should always be "extra".
  1916.          */
  1917.         extra = NULL;
  1918.         }
  1919.  
  1920.         extra = lno + strlen(lno) + 1;
  1921.  
  1922.         lno[strlen(lno)-2] = '\0';  /* ignore ;" at the end */
  1923.  
  1924.         (void)smsg_attr(hl_attr(HLF_CM), (char_u *)"%4d %6s  ", num, lno);
  1925.         MSG_PUTS_LONG_ATTR(cs_pathcomponents(fname), hl_attr(HLF_CM));
  1926.  
  1927.         /* compute the required space for the context */
  1928.         if (cntxts[idx] != NULL)
  1929.         context = cntxts[idx];
  1930.         else
  1931.         context = globalcntx;
  1932.         newsize = strlen(context) + strlen(cntxformat);
  1933.  
  1934.         if (bufsize < newsize)
  1935.         {
  1936.         buf = (char *)vim_realloc(buf, newsize);
  1937.         if (buf == NULL)
  1938.             bufsize = 0;
  1939.         else
  1940.             bufsize = newsize;
  1941.         }
  1942.         if (buf != NULL )
  1943.         {
  1944.         (void)sprintf(buf, cntxformat, context);
  1945.  
  1946.         /* print the context only if it fits on the same line */
  1947.         if (msg_col + (int)strlen(buf) >= (int)Columns)
  1948.             msg_putchar('\n');
  1949.         msg_advance(12);
  1950.         MSG_PUTS_LONG(buf);
  1951.         msg_putchar('\n');
  1952.         }
  1953.         if (extra != NULL)
  1954.         {
  1955.         msg_advance(13);
  1956.         MSG_PUTS_LONG(extra);
  1957.         }
  1958.  
  1959.         vim_free(tbuf); /* only after printing extra due to strtok use */
  1960.  
  1961.         if (msg_col)
  1962.         msg_putchar('\n');
  1963.  
  1964.         ui_breakcheck();
  1965.         if (got_int)
  1966.         {
  1967.         got_int = FALSE;    /* don't print any more matches */
  1968.         j = 1;
  1969.         break;
  1970.         }
  1971.  
  1972.         num++;
  1973.     } /* for all matches */
  1974.     } /* 1 or 2 passes through 'matches' */
  1975.  
  1976.     vim_free(in_cur_file);
  1977.     vim_free(buf);
  1978. } /* cs_print_tags_priv */
  1979.  
  1980.  
  1981. /*
  1982.  * PRIVATE: cs_read_prompt
  1983.  *
  1984.  * read a cscope prompt (basically, skip over the ">> ")
  1985.  */
  1986.     static int
  1987. cs_read_prompt(i)
  1988.     int i;
  1989. {
  1990.     int        ch;
  1991.     char    *buf = NULL; /* buffer for possible error message from cscope */
  1992.     int        bufpos = 0;
  1993.     static char    *cs_emsg = N_("E609: Cscope error: %s");
  1994.         /* maximum allowed len for Cscope error message */
  1995.     int        maxlen = IOSIZE - strlen(_(cs_emsg));
  1996.  
  1997.     for (;;)
  1998.     {
  1999.     while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
  2000.         /* if verbose, have space and char is printable */
  2001.         if (p_csverbose && bufpos < maxlen - 1 && vim_isprintc(ch))
  2002.         {
  2003.         if (buf == NULL) /* lazy buffer allocation */
  2004.             buf = (char *)alloc(maxlen);
  2005.  
  2006.         if (buf != NULL) /* append character to a string */
  2007.         {
  2008.             buf[bufpos++] = ch;
  2009.             buf[bufpos] = NUL;
  2010.         }
  2011.         }
  2012.  
  2013.     if (ch == EOF)
  2014.     {
  2015.         perror("cs_read_prompt EOF(1)");
  2016.         if (buf != NULL && buf[0] != NUL)
  2017.         (void)EMSG2(_(cs_emsg), buf);
  2018.         else if (p_csverbose)
  2019.         cs_reading_emsg(i); /* don't have additional information */
  2020.         cs_release_csp(i, TRUE);
  2021.         vim_free(buf);
  2022.         return CSCOPE_FAILURE;
  2023.     }
  2024.  
  2025.     ch = getc(csinfo[i].fr_fp);
  2026.     if (ch == EOF)
  2027.         perror("cs_read_prompt EOF(2)");
  2028.     if (ch != CSCOPE_PROMPT[1])
  2029.         continue;
  2030.  
  2031.     ch = getc(csinfo[i].fr_fp);
  2032.     if (ch == EOF)
  2033.         perror("cs_read_prompt EOF(3)");
  2034.     if (ch != CSCOPE_PROMPT[2])
  2035.         continue;
  2036.     break;
  2037.     }
  2038.     vim_free(buf);
  2039.     return CSCOPE_SUCCESS;
  2040. } /* cs_read_prompt */
  2041.  
  2042.  
  2043. /*
  2044.  * PRIVATE: cs_release_csp
  2045.  *
  2046.  * does the actual free'ing for the cs ptr with an optional flag of whether
  2047.  * or not to free the filename.  called by cs_kill and cs_reset.
  2048.  */
  2049.     static void
  2050. cs_release_csp(i, freefnpp)
  2051.     int i;
  2052.     int freefnpp;
  2053. {
  2054. #if defined(UNIX)
  2055.     int pstat;
  2056. #else
  2057.     /*
  2058.      * Trying to exit normally (not sure whether it is fit to UNIX cscope
  2059.      */
  2060.     (void)fputs("q\n", csinfo[i].to_fp);
  2061.     (void)fflush(csinfo[i].to_fp);
  2062.     /* give cscope chance to exit normally */
  2063.     if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
  2064.     TerminateProcess(csinfo[i].hProc, 0);
  2065. #endif
  2066.  
  2067.     if (csinfo[i].fr_fp != NULL)
  2068.     (void)fclose(csinfo[i].fr_fp);
  2069.     if (csinfo[i].to_fp != NULL)
  2070.     (void)fclose(csinfo[i].to_fp);
  2071.  
  2072.     /*
  2073.      * Safety check: If the PID would be zero here, the entire X session would
  2074.      * be killed...
  2075.      */
  2076. #if defined(UNIX)
  2077.     if (csinfo[i].pid != 0)
  2078.     {
  2079.     kill(csinfo[i].pid, SIGTERM);
  2080.     (void)waitpid(csinfo[i].pid, &pstat, 0);
  2081.     }
  2082. #endif
  2083.  
  2084.     if (freefnpp)
  2085.     {
  2086.     vim_free(csinfo[i].fname);
  2087.     vim_free(csinfo[i].ppath);
  2088.     vim_free(csinfo[i].flags);
  2089.     }
  2090.  
  2091.     clear_csinfo(i);
  2092. } /* cs_release_csp */
  2093.  
  2094.  
  2095. /*
  2096.  * PRIVATE: cs_reset
  2097.  *
  2098.  * calls cs_kill on all cscope connections then reinits
  2099.  */
  2100. /* ARGSUSED */
  2101.     static int
  2102. cs_reset(eap)
  2103.     exarg_T *eap;
  2104. {
  2105.     char    **dblist = NULL, **pplist = NULL, **fllist = NULL;
  2106.     int    i;
  2107.     char buf[8]; /* for sprintf " (#%d)" */
  2108.  
  2109.     /* malloc our db and ppath list */
  2110.     dblist = (char **)alloc(CSCOPE_MAX_CONNECTIONS * sizeof(char *));
  2111.     pplist = (char **)alloc(CSCOPE_MAX_CONNECTIONS * sizeof(char *));
  2112.     fllist = (char **)alloc(CSCOPE_MAX_CONNECTIONS * sizeof(char *));
  2113.     if (dblist == NULL || pplist == NULL || fllist == NULL)
  2114.     {
  2115.     vim_free(dblist);
  2116.     vim_free(pplist);
  2117.     vim_free(fllist);
  2118.     return CSCOPE_FAILURE;
  2119.     }
  2120.  
  2121.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  2122.     {
  2123.     dblist[i] = csinfo[i].fname;
  2124.     pplist[i] = csinfo[i].ppath;
  2125.     fllist[i] = csinfo[i].flags;
  2126.     if (csinfo[i].fname != NULL)
  2127.         cs_release_csp(i, FALSE);
  2128.     }
  2129.  
  2130.     /* rebuild the cscope connection list */
  2131.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  2132.     {
  2133.     if (dblist[i] != NULL)
  2134.     {
  2135.         cs_add_common(dblist[i], pplist[i], fllist[i]);
  2136.         if (p_csverbose)
  2137.         {
  2138.         /* dont' use smsg_attr because want to display
  2139.          * connection number in the same line as
  2140.          * "Added cscope database..."
  2141.          */
  2142.         sprintf(buf, " (#%d)", i);
  2143.         MSG_PUTS_ATTR(buf, hl_attr(HLF_R));
  2144.         }
  2145.     }
  2146.     vim_free(dblist[i]);
  2147.     vim_free(pplist[i]);
  2148.     vim_free(fllist[i]);
  2149.     }
  2150.     vim_free(dblist);
  2151.     vim_free(pplist);
  2152.     vim_free(fllist);
  2153.  
  2154.     if (p_csverbose)
  2155.     MSG_ATTR(_("All cscope databases reset"), hl_attr(HLF_R) | MSG_HIST);
  2156.     return CSCOPE_SUCCESS;
  2157. } /* cs_reset */
  2158.  
  2159.  
  2160. /*
  2161.  * PRIVATE: cs_resolve_file
  2162.  *
  2163.  * construct the full pathname to a file found in the cscope database.
  2164.  * (Prepends ppath, if there is one and if it's not already prepended,
  2165.  * otherwise just uses the name found.)
  2166.  *
  2167.  * we need to prepend the prefix because on some cscope's (e.g., the one that
  2168.  * ships with Solaris 2.6), the output never has the prefix prepended.
  2169.  * contrast this with my development system (Digital Unix), which does.
  2170.  */
  2171.     static char *
  2172. cs_resolve_file(i, name)
  2173.     int i;
  2174.     char *name;
  2175. {
  2176.     char *fullname;
  2177.     int len;
  2178.  
  2179.     /*
  2180.      * ppath is freed when we destroy the cscope connection.
  2181.      * fullname is freed after cs_make_vim_style_matches, after it's been
  2182.      * copied into the tag buffer used by vim
  2183.      */
  2184.     len = strlen(name) + 2;
  2185.     if (csinfo[i].ppath != NULL)
  2186.     len += strlen(csinfo[i].ppath);
  2187.  
  2188.     if ((fullname = (char *)alloc(len)) == NULL)
  2189.     return NULL;
  2190.  
  2191.     /*
  2192.      * note/example: this won't work if the cscope output already starts
  2193.      * "../.." and the prefix path is also "../..".  if something like this
  2194.      * happens, you are screwed up and need to fix how you're using cscope.
  2195.      */
  2196.     if (csinfo[i].ppath != NULL &&
  2197.     (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) &&
  2198.     (name[0] != '/')
  2199. #ifdef WIN32
  2200.     && name[0] != '\\' && name[1] != ':'
  2201. #endif
  2202.     )
  2203.     (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
  2204.     else
  2205.     (void)sprintf(fullname, "%s", name);
  2206.  
  2207.     return fullname;
  2208. } /* cs_resolve_file */
  2209.  
  2210.  
  2211. /*
  2212.  * PRIVATE: cs_show
  2213.  *
  2214.  * show all cscope connections
  2215.  */
  2216. /* ARGSUSED */
  2217.     static int
  2218. cs_show(eap)
  2219.     exarg_T *eap;
  2220. {
  2221.     short i;
  2222.     if (cs_cnt_connections() == 0)
  2223.     MSG_PUTS(_("no cscope connections\n"));
  2224.     else
  2225.     {
  2226.     MSG_PUTS_ATTR(
  2227.         _(" # pid    database name                       prepend path\n"),
  2228.         hl_attr(HLF_T));
  2229.     for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
  2230.     {
  2231.         if (csinfo[i].fname == NULL)
  2232.         continue;
  2233.  
  2234.         if (csinfo[i].ppath != NULL)
  2235.         (void)smsg((char_u *)"%2d %-5ld  %-34s  %-32s",
  2236.             i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
  2237.         else
  2238.         (void)smsg((char_u *)"%2d %-5ld  %-34s  <none>",
  2239.                i, (long)csinfo[i].pid, csinfo[i].fname);
  2240.     }
  2241.     }
  2242.  
  2243.     wait_return(TRUE);
  2244.     return CSCOPE_SUCCESS;
  2245. } /* cs_show */
  2246.  
  2247. #endif    /* FEAT_CSCOPE */
  2248.  
  2249. /* the end */
  2250.