aboutsummaryrefslogtreecommitdiff
path: root/src/if_cscope.c
diff options
context:
space:
mode:
authorEliseo Martínez <eliseomarmol@gmail.com>2014-05-12 02:25:17 +0200
committerEliseo Martínez <eliseomarmol@gmail.com>2014-05-15 20:46:01 +0200
commitda51dc9cf202772f60bd2da975dbef257bd9237c (patch)
tree5c16b93238a153f55634e9323077f30c8133970c /src/if_cscope.c
parentffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff)
downloadrneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz
rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2
rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/. - src/nvim/ becomes the new root dir for nvim executable sources. - src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/if_cscope.c')
-rw-r--r--src/if_cscope.c2167
1 files changed, 0 insertions, 2167 deletions
diff --git a/src/if_cscope.c b/src/if_cscope.c
deleted file mode 100644
index b000b03444..0000000000
--- a/src/if_cscope.c
+++ /dev/null
@@ -1,2167 +0,0 @@
-/*
- * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com>
- * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com>
- *
- * The basic idea/structure of cscope for Vim was borrowed from Nvi. There
- * might be a few lines of code that look similar to what Nvi has.
- *
- * See README.txt for an overview of the Vim source code.
- */
-
-#include "vim.h"
-#include "if_cscope.h"
-#include "charset.h"
-#include "eval.h"
-#include "fileio.h"
-#include "message.h"
-#include "misc1.h"
-#include "misc2.h"
-#include "memory.h"
-#include "os/time.h"
-#include "path.h"
-#include "quickfix.h"
-#include "tag.h"
-#include "ui.h"
-#include "window.h"
-#include "os/os.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#if defined(UNIX)
-# include <sys/wait.h>
-#endif
-#include "if_cscope_defs.h"
-
-static void cs_usage_msg(csid_e x);
-static int cs_add(exarg_T *eap);
-static void cs_stat_emsg(char *fname);
-static int cs_add_common(char *, char *, char *);
-static int cs_check_for_connections(void);
-static int cs_check_for_tags(void);
-static int cs_cnt_connections(void);
-static void cs_reading_emsg(int idx);
-static int cs_cnt_matches(int idx);
-static char * cs_create_cmd(char *csoption, char *pattern);
-static int cs_create_connection(int i);
-static void do_cscope_general(exarg_T *eap, int make_split);
-static void cs_file_results(FILE *, int *);
-static void cs_fill_results(char *, int, int *, char ***,
- char ***, int *);
-static int cs_find(exarg_T *eap);
-static int cs_find_common(char *opt, char *pat, int, int, int,
- char_u *cmdline);
-static int cs_help(exarg_T *eap);
-static void clear_csinfo(int i);
-static int cs_insert_filelist(char *, char *, char *, FileInfo *file_info);
-static int cs_kill(exarg_T *eap);
-static void cs_kill_execute(int, char *);
-static cscmd_T * cs_lookup_cmd(exarg_T *eap);
-static char * cs_make_vim_style_matches(char *, char *,
- char *, char *);
-static char * cs_manage_matches(char **, char **, int, mcmd_e);
-static char * cs_parse_results(int cnumber, char *buf,
- int bufsize, char **context,
- char **linenumber,
- char **search);
-static char * cs_pathcomponents(char *path);
-static void cs_print_tags_priv(char **, char **, int);
-static int cs_read_prompt(int);
-static void cs_release_csp(int, int freefnpp);
-static int cs_reset(exarg_T *eap);
-static char * cs_resolve_file(int, char *);
-static int cs_show(exarg_T *eap);
-
-
-static csinfo_T * csinfo = NULL;
-static int csinfo_size = 0; /* number of items allocated in
- csinfo[] */
-
-static int eap_arg_len; /* length of eap->arg, set in
- cs_lookup_cmd() */
-static cscmd_T cs_cmds[] =
-{
- { "add", cs_add,
- N_("Add a new database"), "add file|dir [pre-path] [flags]", 0 },
- { "find", cs_find,
- N_("Query for a pattern"), "find c|d|e|f|g|i|s|t name", 1 },
- { "help", cs_help,
- N_("Show this message"), "help", 0 },
- { "kill", cs_kill,
- N_("Kill a connection"), "kill #", 0 },
- { "reset", cs_reset,
- N_("Reinit all connections"), "reset", 0 },
- { "show", cs_show,
- N_("Show connections"), "show", 0 },
- { NULL, NULL, NULL, NULL, 0 }
-};
-
-static void cs_usage_msg(csid_e x)
-{
- (void)EMSG2(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
-}
-
-
-static enum {
- EXP_CSCOPE_SUBCMD, /* expand ":cscope" sub-commands */
- EXP_SCSCOPE_SUBCMD, /* expand ":scscope" sub-commands */
- EXP_CSCOPE_FIND, /* expand ":cscope find" arguments */
- EXP_CSCOPE_KILL /* expand ":cscope kill" arguments */
-} expand_what;
-
-/*
- * Function given to ExpandGeneric() to obtain the cscope command
- * expansion.
- */
-char_u *get_cscope_name(expand_T *xp, int idx)
-{
- int current_idx;
- int i;
-
- switch (expand_what) {
- case EXP_CSCOPE_SUBCMD:
- /* Complete with sub-commands of ":cscope":
- * add, find, help, kill, reset, show */
- return (char_u *)cs_cmds[idx].name;
- case EXP_SCSCOPE_SUBCMD:
- /* Complete with sub-commands of ":scscope": same sub-commands as
- * ":cscope" but skip commands which don't support split windows */
- for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++)
- if (cs_cmds[i].cansplit)
- if (current_idx++ == idx)
- break;
- return (char_u *)cs_cmds[i].name;
- case EXP_CSCOPE_FIND:
- {
- const char *query_type[] =
- {
- "c", "d", "e", "f", "g", "i", "s", "t", NULL
- };
-
- /* Complete with query type of ":cscope find {query_type}".
- * {query_type} can be letters (c, d, ... t) or numbers (0, 1,
- * ..., 8) but only complete with letters, since numbers are
- * redundant. */
- return (char_u *)query_type[idx];
- }
- case EXP_CSCOPE_KILL:
- {
- static char connection[5];
-
- /* ":cscope kill" accepts connection numbers or partial names of
- * the pathname of the cscope database as argument. Only complete
- * with connection numbers. -1 can also be used to kill all
- * connections. */
- for (i = 0, current_idx = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname == NULL)
- continue;
- if (current_idx++ == idx) {
- vim_snprintf(connection, sizeof(connection), "%d", i);
- return (char_u *)connection;
- }
- }
- return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL;
- }
- default:
- return NULL;
- }
-}
-
-/*
- * Handle command line completion for :cscope command.
- */
-void set_context_in_cscope_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
-{
- char_u *p;
-
- /* Default: expand subcommands */
- xp->xp_context = EXPAND_CSCOPE;
- xp->xp_pattern = arg;
- expand_what = (cmdidx == CMD_scscope)
- ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD;
-
- /* (part of) subcommand already typed */
- if (*arg != NUL) {
- p = skiptowhite(arg);
- if (*p != NUL) { /* past first word */
- xp->xp_pattern = skipwhite(p);
- if (*skiptowhite(xp->xp_pattern) != NUL)
- xp->xp_context = EXPAND_NOTHING;
- else if (STRNICMP(arg, "add", p - arg) == 0)
- xp->xp_context = EXPAND_FILES;
- else if (STRNICMP(arg, "kill", p - arg) == 0)
- expand_what = EXP_CSCOPE_KILL;
- else if (STRNICMP(arg, "find", p - arg) == 0)
- expand_what = EXP_CSCOPE_FIND;
- else
- xp->xp_context = EXPAND_NOTHING;
- }
- }
-}
-
-
-/*
- * PRIVATE: do_cscope_general
- *
- * Find the command, print help if invalid, and then call the corresponding
- * command function.
- */
-static void
-do_cscope_general (
- exarg_T *eap,
- int make_split /* whether to split window */
-)
-{
- cscmd_T *cmdp;
-
- if ((cmdp = cs_lookup_cmd(eap)) == NULL) {
- cs_help(eap);
- return;
- }
-
- if (make_split) {
- if (!cmdp->cansplit) {
- (void)MSG_PUTS(_(
- "This cscope command does not support splitting the window.\n"));
- return;
- }
- postponed_split = -1;
- postponed_split_flags = cmdmod.split;
- postponed_split_tab = cmdmod.tab;
- }
-
- cmdp->func(eap);
-
- postponed_split_flags = 0;
- postponed_split_tab = 0;
-}
-
-/*
- * PUBLIC: do_cscope
- */
-void do_cscope(exarg_T *eap)
-{
- do_cscope_general(eap, FALSE);
-}
-
-/*
- * PUBLIC: do_scscope
- *
- * same as do_cscope, but splits window, too.
- */
-void do_scscope(exarg_T *eap)
-{
- do_cscope_general(eap, TRUE);
-}
-
-/*
- * PUBLIC: do_cstag
- *
- */
-void do_cstag(exarg_T *eap)
-{
- int ret = FALSE;
-
- if (*eap->arg == NUL) {
- (void)EMSG(_("E562: Usage: cstag <ident>"));
- return;
- }
-
- switch (p_csto) {
- case 0:
- if (cs_check_for_connections()) {
- ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
- FALSE, *eap->cmdlinep);
- if (ret == FALSE) {
- cs_free_tags();
- if (msg_col)
- msg_putchar('\n');
-
- if (cs_check_for_tags())
- ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
- }
- } else if (cs_check_for_tags()) {
- ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
- }
- break;
- case 1:
- if (cs_check_for_tags()) {
- ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
- if (ret == FALSE) {
- if (msg_col)
- msg_putchar('\n');
-
- if (cs_check_for_connections()) {
- ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
- FALSE, FALSE, *eap->cmdlinep);
- if (ret == FALSE)
- cs_free_tags();
- }
- }
- } else if (cs_check_for_connections()) {
- ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
- FALSE, *eap->cmdlinep);
- if (ret == FALSE)
- cs_free_tags();
- }
- break;
- default:
- break;
- }
-
- if (!ret) {
- (void)EMSG(_("E257: cstag: tag not found"));
- g_do_tagpreview = 0;
- }
-
-} /* do_cscope */
-
-
-/*
- * PUBLIC: cs_find
- *
- * this simulates a vim_fgets(), but for cscope, returns the next line
- * from the cscope output. should only be called from find_tags()
- *
- * returns TRUE if eof, FALSE otherwise
- */
-int cs_fgets(char_u *buf, int size)
-{
- char *p;
-
- if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
- return TRUE;
- vim_strncpy(buf, (char_u *)p, size - 1);
-
- return FALSE;
-} /* cs_fgets */
-
-
-/*
- * PUBLIC: cs_free_tags
- *
- * called only from do_tag(), when popping the tag stack
- */
-void cs_free_tags(void)
-{
- cs_manage_matches(NULL, NULL, -1, Free);
-}
-
-/*
- * PUBLIC: cs_print_tags
- *
- * called from do_tag()
- */
-void cs_print_tags(void)
-{
- cs_manage_matches(NULL, NULL, -1, Print);
-}
-
-/*
- * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
- *
- * Checks for the existence of a |cscope| connection. If no
- * parameters are specified, then the function returns:
- *
- * 0, if cscope was not available (not compiled in), or if there
- * are no cscope connections; or
- * 1, if there is at least one cscope connection.
- *
- * If parameters are specified, then the value of {num}
- * determines how existence of a cscope connection is checked:
- *
- * {num} Description of existence check
- * ----- ------------------------------
- * 0 Same as no parameters (e.g., "cscope_connection()").
- * 1 Ignore {prepend}, and use partial string matches for
- * {dbpath}.
- * 2 Ignore {prepend}, and use exact string matches for
- * {dbpath}.
- * 3 Use {prepend}, use partial string matches for both
- * {dbpath} and {prepend}.
- * 4 Use {prepend}, use exact string matches for both
- * {dbpath} and {prepend}.
- *
- * Note: All string comparisons are case sensitive!
- */
-int cs_connection(int num, char_u *dbpath, char_u *ppath)
-{
- int i;
-
- if (num < 0 || num > 4 || (num > 0 && !dbpath))
- return FALSE;
-
- for (i = 0; i < csinfo_size; i++) {
- if (!csinfo[i].fname)
- continue;
-
- if (num == 0)
- return TRUE;
-
- switch (num) {
- case 1:
- if (strstr(csinfo[i].fname, (char *)dbpath))
- return TRUE;
- break;
- case 2:
- if (strcmp(csinfo[i].fname, (char *)dbpath) == 0)
- return TRUE;
- break;
- case 3:
- if (strstr(csinfo[i].fname, (char *)dbpath)
- && ((!ppath && !csinfo[i].ppath)
- || (ppath
- && csinfo[i].ppath
- && strstr(csinfo[i].ppath, (char *)ppath))))
- return TRUE;
- break;
- case 4:
- if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0)
- && ((!ppath && !csinfo[i].ppath)
- || (ppath
- && csinfo[i].ppath
- && (strcmp(csinfo[i].ppath, (char *)ppath) == 0))))
- return TRUE;
- break;
- }
- }
-
- return FALSE;
-} /* cs_connection */
-
-
-/*
- * PRIVATE functions
- ****************************************************************************/
-
-/*
- * PRIVATE: cs_add
- *
- * add cscope database or a directory name (to look for cscope.out)
- * to the cscope connection list
- *
- * MAXPATHL 256
- */
-static int cs_add(exarg_T *eap)
-{
- char *fname, *ppath, *flags = NULL;
-
- if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL) {
- cs_usage_msg(Add);
- return CSCOPE_FAILURE;
- }
- if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
- flags = strtok((char *)NULL, (const char *)" ");
-
- return cs_add_common(fname, ppath, flags);
-}
-
-static void cs_stat_emsg(char *fname)
-{
- char *stat_emsg = _("E563: stat(%s) error: %d");
- char *buf = (char *)alloc((unsigned)strlen(stat_emsg) + MAXPATHL + 10);
-
- (void)sprintf(buf, stat_emsg, fname, errno);
- (void)EMSG(buf);
- free(buf);
-}
-
-
-/*
- * PRIVATE: cs_add_common
- *
- * the common routine to add a new cscope connection. called by
- * cs_add() and cs_reset(). i really don't like to do this, but this
- * routine uses a number of goto statements.
- */
-static int
-cs_add_common (
- char *arg1, /* filename - may contain environment variables */
- char *arg2, /* prepend path - may contain environment variables */
- char *flags
-)
-{
- char *fname = NULL;
- char *fname2 = NULL;
- char *ppath = NULL;
- int i;
- int len;
- int usedlen = 0;
- char_u *fbuf = NULL;
-
- /* get the filename (arg1), expand it, and try to stat it */
- fname = (char *)alloc(MAXPATHL + 1);
-
- expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
- len = (int)STRLEN(fname);
- fbuf = (char_u *)fname;
- (void)modify_fname((char_u *)":p", &usedlen,
- (char_u **)&fname, &fbuf, &len);
- if (fname == NULL)
- goto add_err;
- fname = (char *)vim_strnsave((char_u *)fname, len);
- free(fbuf);
- FileInfo file_info;
- bool file_info_ok = os_get_file_info(fname, &file_info);
- if (!file_info_ok) {
-staterr:
- if (p_csverbose)
- cs_stat_emsg(fname);
- goto add_err;
- }
-
- // get the prepend path (arg2), expand it, and see if it exists
- if (arg2 != NULL) {
- ppath = (char *)alloc(MAXPATHL + 1);
- expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
- if (!os_file_exists((char_u *)ppath))
- goto staterr;
- }
-
- /* if filename is a directory, append the cscope database name to it */
- if ((file_info.stat.st_mode & S_IFMT) == S_IFDIR) {
- fname2 = (char *)alloc((unsigned)(strlen(CSCOPE_DBFILE) + strlen(fname) + 2));
-
- while (fname[strlen(fname)-1] == '/'
- ) {
- fname[strlen(fname)-1] = '\0';
- if (fname[0] == '\0')
- break;
- }
- if (fname[0] == '\0')
- (void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
- else
- (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
-
- file_info_ok = os_get_file_info(fname2, &file_info);
- if (!file_info_ok) {
- if (p_csverbose)
- cs_stat_emsg(fname2);
- goto add_err;
- }
-
- i = cs_insert_filelist(fname2, ppath, flags, &file_info);
- }
- else if (S_ISREG(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode))
- {
- i = cs_insert_filelist(fname, ppath, flags, &file_info);
- } else {
- if (p_csverbose)
- (void)EMSG2(
- _("E564: %s is not a directory or a valid cscope database"),
- fname);
- goto add_err;
- }
-
- if (i != -1) {
- if (cs_create_connection(i) == CSCOPE_FAILURE
- || cs_read_prompt(i) == CSCOPE_FAILURE) {
- cs_release_csp(i, TRUE);
- goto add_err;
- }
-
- if (p_csverbose) {
- msg_clr_eos();
- (void)smsg_attr(hl_attr(HLF_R),
- (char_u *)_("Added cscope database %s"),
- csinfo[i].fname);
- }
- }
-
- free(fname);
- free(fname2);
- free(ppath);
- return CSCOPE_SUCCESS;
-
-add_err:
- free(fname2);
- free(fname);
- free(ppath);
- return CSCOPE_FAILURE;
-} /* cs_add_common */
-
-
-static int cs_check_for_connections(void)
-{
- return cs_cnt_connections() > 0;
-} /* cs_check_for_connections */
-
-static int cs_check_for_tags(void)
-{
- return p_tags[0] != NUL && curbuf->b_p_tags != NULL;
-} /* cs_check_for_tags */
-
-/*
- * PRIVATE: cs_cnt_connections
- *
- * count the number of cscope connections
- */
-static int cs_cnt_connections(void)
-{
- short i;
- short cnt = 0;
-
- for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname != NULL)
- cnt++;
- }
- return cnt;
-} /* cs_cnt_connections */
-
-static void
-cs_reading_emsg (
- int idx /* connection index */
-)
-{
- EMSGN(_("E262: error reading cscope connection %" PRId64), idx);
-}
-
-#define CSREAD_BUFSIZE 2048
-/*
- * PRIVATE: cs_cnt_matches
- *
- * count the number of matches for a given cscope connection.
- */
-static int cs_cnt_matches(int idx)
-{
- char *stok;
- char *buf;
- int nlines;
-
- buf = (char *)alloc(CSREAD_BUFSIZE);
- for (;; ) {
- if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp)) {
- if (feof(csinfo[idx].fr_fp))
- errno = EIO;
-
- cs_reading_emsg(idx);
-
- free(buf);
- return -1;
- }
-
- /*
- * If the database is out of date, or there's some other problem,
- * cscope will output error messages before the number-of-lines output.
- * Display/discard any output that doesn't match what we want.
- * Accept "\S*cscope: X lines", also matches "mlcscope".
- */
- if ((stok = strtok(buf, (const char *)" ")) == NULL)
- continue;
- if (strstr((const char *)stok, "cscope:") == NULL)
- continue;
-
- if ((stok = strtok(NULL, (const char *)" ")) == NULL)
- continue;
- nlines = atoi(stok);
- if (nlines < 0) {
- nlines = 0;
- break;
- }
-
- if ((stok = strtok(NULL, (const char *)" ")) == NULL)
- continue;
- if (strncmp((const char *)stok, "lines", 5))
- continue;
-
- break;
- }
-
- free(buf);
- return nlines;
-} /* cs_cnt_matches */
-
-
-/*
- * PRIVATE: cs_create_cmd
- *
- * Creates the actual cscope command query from what the user entered.
- */
-static char *cs_create_cmd(char *csoption, char *pattern)
-{
- char *cmd;
- short search;
- char *pat;
-
- switch (csoption[0]) {
- case '0': case 's':
- search = 0;
- break;
- case '1': case 'g':
- search = 1;
- break;
- case '2': case 'd':
- search = 2;
- break;
- case '3': case 'c':
- search = 3;
- break;
- case '4': case 't':
- search = 4;
- break;
- case '6': case 'e':
- search = 6;
- break;
- case '7': case 'f':
- search = 7;
- break;
- case '8': case 'i':
- search = 8;
- break;
- default:
- (void)EMSG(_("E561: unknown cscope search type"));
- cs_usage_msg(Find);
- return NULL;
- }
-
- /* Skip white space before the patter, except for text and pattern search,
- * they may want to use the leading white space. */
- pat = pattern;
- if (search != 4 && search != 6)
- while (vim_iswhite(*pat))
- ++pat;
-
- cmd = (char *)alloc((unsigned)(strlen(pat) + 2));
-
- (void)sprintf(cmd, "%d%s", search, pat);
-
- return cmd;
-} /* cs_create_cmd */
-
-
-/*
- * PRIVATE: cs_create_connection
- *
- * This piece of code was taken/adapted from nvi. do we need to add
- * the BSD license notice?
- */
-static int cs_create_connection(int i)
-{
-#ifdef UNIX
- int to_cs[2], from_cs[2];
-#endif
- int len;
- char *prog, *cmd, *ppath = NULL;
-
-#if defined(UNIX)
- /*
- * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
- * from_cs[0] and writes to to_cs[1].
- */
- to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
- if (pipe(to_cs) < 0 || pipe(from_cs) < 0) {
- (void)EMSG(_("E566: Could not create cscope pipes"));
-err_closing:
- if (to_cs[0] != -1)
- (void)close(to_cs[0]);
- if (to_cs[1] != -1)
- (void)close(to_cs[1]);
- if (from_cs[0] != -1)
- (void)close(from_cs[0]);
- if (from_cs[1] != -1)
- (void)close(from_cs[1]);
- return CSCOPE_FAILURE;
- }
-
- switch (csinfo[i].pid = fork()) {
- case -1:
- (void)EMSG(_("E622: Could not fork for cscope"));
- goto err_closing;
- case 0: /* child: run cscope. */
- if (dup2(to_cs[0], STDIN_FILENO) == -1)
- PERROR("cs_create_connection 1");
- if (dup2(from_cs[1], STDOUT_FILENO) == -1)
- PERROR("cs_create_connection 2");
- if (dup2(from_cs[1], STDERR_FILENO) == -1)
- PERROR("cs_create_connection 3");
-
- /* close unused */
- (void)close(to_cs[1]);
- (void)close(from_cs[0]);
-#else
- /* WIN32 */
- /* Create pipes to communicate with cscope */
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0))
- || !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0))) {
- (void)EMSG(_("E566: Could not create cscope pipes"));
-err_closing:
- if (pipe_stdin) {
- CloseHandle(stdin_rd);
- CloseHandle(stdin_wr);
- }
- if (pipe_stdout) {
- CloseHandle(stdout_rd);
- CloseHandle(stdout_wr);
- }
- return CSCOPE_FAILURE;
- }
-#endif
- /* expand the cscope exec for env var's */
- prog = (char *)alloc(MAXPATHL + 1);
- expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL);
-
- /* alloc space to hold the cscope command */
- len = (int)(strlen(prog) + strlen(csinfo[i].fname) + 32);
- if (csinfo[i].ppath) {
- /* expand the prepend path for env var's */
- ppath = (char *)alloc(MAXPATHL + 1);
- expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL);
-
- len += (int)strlen(ppath);
- }
-
- if (csinfo[i].flags)
- len += (int)strlen(csinfo[i].flags);
-
- cmd = (char *)alloc(len);
-
- /* run the cscope command; is there execl for non-unix systems? */
-#if defined(UNIX)
- (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
-#else
- /* WIN32 */
- (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
-#endif
- if (csinfo[i].ppath != NULL) {
- (void)strcat(cmd, " -P");
- (void)strcat(cmd, csinfo[i].ppath);
- }
- if (csinfo[i].flags != NULL) {
- (void)strcat(cmd, " ");
- (void)strcat(cmd, csinfo[i].flags);
- }
-# ifdef UNIX
- /* on Win32 we still need prog */
- free(prog);
-# endif
- free(ppath);
-
-#if defined(UNIX)
-# if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
- /* Change our process group to avoid cscope receiving SIGWINCH. */
-# if defined(HAVE_SETSID)
- (void)setsid();
-# else
- if (setpgid(0, 0) == -1)
- PERROR(_("cs_create_connection setpgid failed"));
-# endif
-# endif
- if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1)
- PERROR(_("cs_create_connection exec failed"));
-
- exit(127);
- /* NOTREACHED */
- default: /* parent. */
- /*
- * Save the file descriptors for later duplication, and
- * reopen as streams.
- */
- if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL)
- PERROR(_("cs_create_connection: fdopen for to_fp failed"));
- if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
- PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
-
- /* close unused */
- (void)close(to_cs[0]);
- (void)close(from_cs[1]);
-
- break;
- }
-
-#else
- /* WIN32 */
- /* Create a new process to run cscope and use pipes to talk with it */
- GetStartupInfo(&si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE; /* Hide child application window */
- si.hStdOutput = stdout_wr;
- si.hStdError = stdout_wr;
- si.hStdInput = stdin_rd;
- created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
- NULL, NULL, &si, &pi);
- free(prog);
- free(cmd);
-
- if (!created) {
- PERROR(_("cs_create_connection exec failed"));
- (void)EMSG(_("E623: Could not spawn cscope process"));
- goto err_closing;
- }
- /* else */
- csinfo[i].pid = pi.dwProcessId;
- csinfo[i].hProc = pi.hProcess;
- CloseHandle(pi.hThread);
-
- /* TODO - tidy up after failure to create files on pipe handles. */
- if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr,
- _O_TEXT|_O_APPEND)) < 0)
- || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL))
- PERROR(_("cs_create_connection: fdopen for to_fp failed"));
- if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd,
- _O_TEXT|_O_RDONLY)) < 0)
- || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL))
- PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
-
- /* Close handles for file descriptors inherited by the cscope process */
- CloseHandle(stdin_rd);
- CloseHandle(stdout_wr);
-
-#endif /* !UNIX */
-
- return CSCOPE_SUCCESS;
-} /* cs_create_connection */
-
-
-/*
- * PRIVATE: cs_find
- *
- * query cscope using command line interface. parse the output and use tselect
- * to allow choices. like Nvi, creates a pipe to send to/from query/cscope.
- *
- * returns TRUE if we jump to a tag or abort, FALSE if not.
- */
-static int cs_find(exarg_T *eap)
-{
- char *opt, *pat;
- int i;
-
- if (cs_check_for_connections() == FALSE) {
- (void)EMSG(_("E567: no cscope connections"));
- return FALSE;
- }
-
- if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL) {
- cs_usage_msg(Find);
- return FALSE;
- }
-
- pat = opt + strlen(opt) + 1;
- if (pat >= (char *)eap->arg + eap_arg_len) {
- cs_usage_msg(Find);
- return FALSE;
- }
-
- /*
- * Let's replace the NULs written by strtok() with spaces - we need the
- * spaces to correctly display the quickfix/location list window's title.
- */
- for (i = 0; i < eap_arg_len; ++i)
- if (NUL == eap->arg[i])
- eap->arg[i] = ' ';
-
- return cs_find_common(opt, pat, eap->forceit, TRUE,
- eap->cmdidx == CMD_lcscope, *eap->cmdlinep);
-} /* cs_find */
-
-
-/*
- * PRIVATE: cs_find_common
- *
- * common code for cscope find, shared by cs_find() and do_cstag()
- */
-static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int use_ll, char_u *cmdline)
-{
- int i;
- char *cmd;
- int *nummatches;
- int totmatches;
- char cmdletter;
- char *qfpos;
-
- /* get cmd letter */
- switch (opt[0]) {
- case '0':
- cmdletter = 's';
- break;
- case '1':
- cmdletter = 'g';
- break;
- case '2':
- cmdletter = 'd';
- break;
- case '3':
- cmdletter = 'c';
- break;
- case '4':
- cmdletter = 't';
- break;
- case '6':
- cmdletter = 'e';
- break;
- case '7':
- cmdletter = 'f';
- break;
- case '8':
- cmdletter = 'i';
- break;
- default:
- cmdletter = opt[0];
- }
-
- qfpos = (char *)vim_strchr(p_csqf, cmdletter);
- if (qfpos != NULL) {
- qfpos++;
- /* next symbol must be + or - */
- if (strchr(CSQF_FLAGS, *qfpos) == NULL) {
- char *nf = _("E469: invalid cscopequickfix flag %c for %c");
- /* strlen will be enough because we use chars */
- char *buf = (char *)alloc((unsigned)strlen(nf));
-
- sprintf(buf, nf, *qfpos, *(qfpos-1));
- (void)EMSG(buf);
- free(buf);
- return FALSE;
- }
-
- if (*qfpos != '0') {
- apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)"cscope",
- curbuf->b_fname, TRUE, curbuf);
- if (did_throw || force_abort)
- return FALSE;
- }
- }
-
- /* create the actual command to send to cscope */
- cmd = cs_create_cmd(opt, pat);
- if (cmd == NULL)
- return FALSE;
-
- nummatches = (int *)alloc(sizeof(int)*csinfo_size);
-
- /* Send query to all open connections, then count the total number
- * of matches so we can alloc all in one swell foop. */
- for (i = 0; i < csinfo_size; i++)
- nummatches[i] = 0;
- totmatches = 0;
- for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL)
- continue;
-
- /* send cmd to cscope */
- (void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
- (void)fflush(csinfo[i].to_fp);
-
- nummatches[i] = cs_cnt_matches(i);
-
- if (nummatches[i] > -1)
- totmatches += nummatches[i];
-
- if (nummatches[i] == 0)
- (void)cs_read_prompt(i);
- }
- free(cmd);
-
- if (totmatches == 0) {
- char *nf = _("E259: no matches found for cscope query %s of %s");
- char *buf;
-
- if (!verbose) {
- free(nummatches);
- return FALSE;
- }
-
- buf = (char *)alloc((unsigned)(strlen(opt) + strlen(pat) + strlen(nf)));
- sprintf(buf, nf, opt, pat);
- (void)EMSG(buf);
- free(buf);
- free(nummatches);
- return FALSE;
- }
-
- if (qfpos != NULL && *qfpos != '0' && totmatches > 0) {
- /* fill error list */
- FILE *f;
- char_u *tmp = vim_tempname('c');
- qf_info_T *qi = NULL;
- win_T *wp = NULL;
-
- f = mch_fopen((char *)tmp, "w");
- if (f == NULL)
- EMSG2(_(e_notopen), tmp);
- else {
- cs_file_results(f, nummatches);
- fclose(f);
- if (use_ll) /* Use location list */
- wp = curwin;
- /* '-' starts a new error list */
- if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
- *qfpos == '-', cmdline) > 0) {
- if (postponed_split != 0) {
- win_split(postponed_split > 0 ? postponed_split : 0,
- postponed_split_flags);
- RESET_BINDING(curwin);
- postponed_split = 0;
- }
-
- apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope",
- curbuf->b_fname, TRUE, curbuf);
- if (use_ll)
- /*
- * In the location list window, use the displayed location
- * list. Otherwise, use the location list for the window.
- */
- qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
- ? wp->w_llist_ref : wp->w_llist;
- qf_jump(qi, 0, 0, forceit);
- }
- }
- os_remove((char *)tmp);
- free(tmp);
- free(nummatches);
- return TRUE;
- } else {
- char **matches = NULL, **contexts = NULL;
- int matched = 0;
-
- /* read output */
- cs_fill_results((char *)pat, totmatches, nummatches, &matches,
- &contexts, &matched);
- free(nummatches);
- if (matches == NULL)
- return FALSE;
-
- (void)cs_manage_matches(matches, contexts, matched, Store);
-
- return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose);
- }
-
-} /* cs_find_common */
-
-/*
- * PRIVATE: cs_help
- *
- * print help
- */
-static int cs_help(exarg_T *eap)
-{
- cscmd_T *cmdp = cs_cmds;
-
- (void)MSG_PUTS(_("cscope commands:\n"));
- while (cmdp->name != NULL) {
- char *help = _(cmdp->help);
- int space_cnt = 30 - vim_strsize((char_u *)help);
-
- /* Use %*s rather than %30s to ensure proper alignment in utf-8 */
- if (space_cnt < 0)
- space_cnt = 0;
- (void)smsg((char_u *)_("%-5s: %s%*s (Usage: %s)"),
- cmdp->name,
- help, space_cnt, " ",
- cmdp->usage);
- if (strcmp(cmdp->name, "find") == 0)
- MSG_PUTS(_("\n"
- " c: Find functions calling this function\n"
- " d: Find functions called by this function\n"
- " e: Find this egrep pattern\n"
- " f: Find this file\n"
- " g: Find this definition\n"
- " i: Find files #including this file\n"
- " s: Find this C symbol\n"
- " t: Find this text string\n"));
-
- cmdp++;
- }
-
- wait_return(TRUE);
- return 0;
-} /* cs_help */
-
-
-static void clear_csinfo(int i)
-{
- csinfo[i].fname = NULL;
- csinfo[i].ppath = NULL;
- csinfo[i].flags = NULL;
-#if defined(UNIX)
- csinfo[i].st_dev = (dev_t)0;
- csinfo[i].st_ino = (ino_t)0;
-#else
- csinfo[i].nVolume = 0;
- csinfo[i].nIndexHigh = 0;
- csinfo[i].nIndexLow = 0;
-#endif
- csinfo[i].pid = 0;
- csinfo[i].fr_fp = NULL;
- csinfo[i].to_fp = NULL;
-}
-
-#ifndef UNIX
-static char *GetWin32Error(void);
-
-static char *GetWin32Error(void)
-{
- char *msg = NULL;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL);
- if (msg != NULL) {
- /* remove trailing \r\n */
- char *pcrlf = strstr(msg, "\r\n");
- if (pcrlf != NULL)
- *pcrlf = '\0';
- }
- return msg;
-}
-
-#endif
-
-/*
- * PRIVATE: cs_insert_filelist
- *
- * insert a new cscope database filename into the filelist
- */
-static int cs_insert_filelist(char *fname, char *ppath, char *flags,
- FileInfo *file_info)
-{
- short i, j;
-
- i = -1; /* can be set to the index of an empty item in csinfo */
- for (j = 0; j < csinfo_size; j++) {
- if (csinfo[j].fname != NULL
- && csinfo[j].st_dev == file_info->stat.st_dev
- && csinfo[j].st_ino == file_info->stat.st_ino) {
- if (p_csverbose)
- (void)EMSG(_("E568: duplicate cscope database not added"));
- return -1;
- }
-
- if (csinfo[j].fname == NULL && i == -1)
- i = j; /* remember first empty entry */
- }
-
- if (i == -1) {
- i = csinfo_size;
- if (csinfo_size == 0) {
- /* First time allocation: allocate only 1 connection. It should
- * be enough for most users. If more is needed, csinfo will be
- * reallocated. */
- csinfo_size = 1;
- csinfo = xcalloc(1, sizeof(csinfo_T));
- } else {
- /* Reallocate space for more connections. */
- csinfo_size *= 2;
- csinfo = xrealloc(csinfo, sizeof(csinfo_T)*csinfo_size);
- }
- for (j = csinfo_size/2; j < csinfo_size; j++)
- clear_csinfo(j);
- }
-
- csinfo[i].fname = (char *)alloc((unsigned)strlen(fname)+1);
-
- (void)strcpy(csinfo[i].fname, (const char *)fname);
-
- if (ppath != NULL) {
- csinfo[i].ppath = (char *)alloc((unsigned)strlen(ppath) + 1);
- (void)strcpy(csinfo[i].ppath, (const char *)ppath);
- } else
- csinfo[i].ppath = NULL;
-
- if (flags != NULL) {
- csinfo[i].flags = (char *)alloc((unsigned)strlen(flags) + 1);
- (void)strcpy(csinfo[i].flags, (const char *)flags);
- } else
- csinfo[i].flags = NULL;
-
- csinfo[i].st_dev = file_info->stat.st_dev;
- csinfo[i].st_ino = file_info->stat.st_ino;
- return i;
-} /* cs_insert_filelist */
-
-
-/*
- * PRIVATE: cs_lookup_cmd
- *
- * find cscope command in command table
- */
-static cscmd_T * cs_lookup_cmd(eap)
-exarg_T *eap;
-{
- cscmd_T *cmdp;
- char *stok;
- size_t len;
-
- if (eap->arg == NULL)
- return NULL;
-
- /* Store length of eap->arg before it gets modified by strtok(). */
- eap_arg_len = (int)STRLEN(eap->arg);
-
- if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
- return NULL;
-
- len = strlen(stok);
- for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp) {
- if (strncmp((const char *)(stok), cmdp->name, len) == 0)
- return cmdp;
- }
- return NULL;
-} /* cs_lookup_cmd */
-
-
-/*
- * PRIVATE: cs_kill
- *
- * nuke em
- */
-static int cs_kill(exarg_T *eap)
-{
- char *stok;
- short i;
-
- if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL) {
- cs_usage_msg(Kill);
- return CSCOPE_FAILURE;
- }
-
- /* only single digit positive and negative integers are allowed */
- if ((strlen(stok) < 2 && VIM_ISDIGIT((int)(stok[0])))
- || (strlen(stok) < 3 && stok[0] == '-'
- && VIM_ISDIGIT((int)(stok[1]))))
- i = atoi(stok);
- else {
- /* It must be part of a name. We will try to find a match
- * within all the names in the csinfo data structure
- */
- for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
- break;
- }
- }
-
- if ((i != -1) && (i >= csinfo_size || i < -1 || csinfo[i].fname == NULL)) {
- if (p_csverbose)
- (void)EMSG2(_("E261: cscope connection %s not found"), stok);
- } else {
- if (i == -1) {
- for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname)
- cs_kill_execute(i, csinfo[i].fname);
- }
- } else
- cs_kill_execute(i, stok);
- }
-
- return 0;
-} /* cs_kill */
-
-
-/*
- * PRIVATE: cs_kill_execute
- *
- * Actually kills a specific cscope connection.
- */
-static void
-cs_kill_execute (
- int i, /* cscope table index */
- char *cname /* cscope database name */
-)
-{
- if (p_csverbose) {
- msg_clr_eos();
- (void)smsg_attr(hl_attr(HLF_R) | MSG_HIST,
- (char_u *)_("cscope connection %s closed"), cname);
- }
- cs_release_csp(i, TRUE);
-}
-
-
-/*
- * PRIVATE: cs_make_vim_style_matches
- *
- * convert the cscope output into a ctags style entry (as might be found
- * in a ctags tags file). there's one catch though: cscope doesn't tell you
- * the type of the tag you are looking for. for example, in Darren Hiebert's
- * ctags (the one that comes with vim), #define's use a line number to find the
- * tag in a file while function definitions use a regexp search pattern.
- *
- * i'm going to always use the line number because cscope does something
- * quirky (and probably other things i don't know about):
- *
- * if you have "# define" in your source file, which is
- * perfectly legal, cscope thinks you have "#define". this
- * will result in a failed regexp search. :(
- *
- * besides, even if this particular case didn't happen, the search pattern
- * would still have to be modified to escape all the special regular expression
- * characters to comply with ctags formatting.
- */
-static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, char *tagstr)
-{
- /* vim style is ctags:
- *
- * <tagstr>\t<filename>\t<linenum_or_search>"\t<extra>
- *
- * but as mentioned above, we'll always use the line number and
- * put the search pattern (if one exists) as "extra"
- *
- * buf is used as part of vim's method of handling tags, and
- * (i think) vim frees it when you pop your tags and get replaced
- * by new ones on the tag stack.
- */
- char *buf;
- size_t amt;
-
- if (search != NULL) {
- amt = strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search) + 6;
- buf = xmalloc(amt);
-
- (void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search);
- } else {
- amt = strlen(fname) + strlen(slno) + strlen(tagstr) + 5;
- buf = xmalloc(amt);
-
- (void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno);
- }
-
- return buf;
-} /* cs_make_vim_style_matches */
-
-
-/*
- * PRIVATE: cs_manage_matches
- *
- * this is kind of hokey, but i don't see an easy way round this..
- *
- * Store: keep a ptr to the (malloc'd) memory of matches originally
- * generated from cs_find(). the matches are originally lines directly
- * from cscope output, but transformed to look like something out of a
- * ctags. see cs_make_vim_style_matches for more details.
- *
- * Get: used only from cs_fgets(), this simulates a vim_fgets() to return
- * the next line from the cscope output. it basically keeps track of which
- * lines have been "used" and returns the next one.
- *
- * Free: frees up everything and resets
- *
- * Print: prints the tags
- */
-static char *cs_manage_matches(char **matches, char **contexts, int totmatches, mcmd_e cmd)
-{
- static char **mp = NULL;
- static char **cp = NULL;
- static int cnt = -1;
- static int next = -1;
- char *p = NULL;
-
- switch (cmd) {
- case Store:
- assert(matches != NULL);
- assert(totmatches > 0);
- if (mp != NULL || cp != NULL)
- (void)cs_manage_matches(NULL, NULL, -1, Free);
- mp = matches;
- cp = contexts;
- cnt = totmatches;
- next = 0;
- break;
- case Get:
- if (next >= cnt)
- return NULL;
-
- p = mp[next];
- next++;
- break;
- case Free:
- if (mp != NULL) {
- if (cnt > 0)
- while (cnt--) {
- free(mp[cnt]);
- if (cp != NULL)
- free(cp[cnt]);
- }
- free(mp);
- free(cp);
- }
- mp = NULL;
- cp = NULL;
- cnt = 0;
- next = 0;
- break;
- case Print:
- cs_print_tags_priv(mp, cp, cnt);
- break;
- default: /* should not reach here */
- (void)EMSG(_("E570: fatal error in cs_manage_matches"));
- return NULL;
- }
-
- return p;
-} /* cs_manage_matches */
-
-
-/*
- * PRIVATE: cs_parse_results
- *
- * parse cscope output
- */
-static char *cs_parse_results(int cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search)
-{
- int ch;
- char *p;
- char *name;
-
- if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL) {
- if (feof(csinfo[cnumber].fr_fp))
- errno = EIO;
-
- cs_reading_emsg(cnumber);
-
- return NULL;
- }
-
- /* If the line's too long for the buffer, discard it. */
- if ((p = strchr(buf, '\n')) == NULL) {
- while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
- ;
- return NULL;
- }
- *p = '\0';
-
- /*
- * cscope output is in the following format:
- *
- * <filename> <context> <line number> <pattern>
- */
- if ((name = strtok((char *)buf, (const char *)" ")) == NULL)
- return NULL;
- if ((*context = strtok(NULL, (const char *)" ")) == NULL)
- return NULL;
- if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
- return NULL;
- *search = *linenumber + strlen(*linenumber) + 1; /* +1 to skip \0 */
-
- /* --- nvi ---
- * If the file is older than the cscope database, that is,
- * the database was built since the file was last modified,
- * or there wasn't a search string, use the line number.
- */
- if (strcmp(*search, "<unknown>") == 0)
- *search = NULL;
-
- name = cs_resolve_file(cnumber, name);
- return name;
-}
-
-/*
- * PRIVATE: cs_file_results
- *
- * write cscope find results to file
- */
-static void cs_file_results(FILE *f, int *nummatches_a)
-{
- int i, j;
- char *buf;
- char *search, *slno;
- char *fullname;
- char *cntx;
- char *context;
-
- buf = (char *)alloc(CSREAD_BUFSIZE);
-
- for (i = 0; i < csinfo_size; i++) {
- if (nummatches_a[i] < 1)
- continue;
-
- for (j = 0; j < nummatches_a[i]; j++) {
- if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
- &slno, &search)) == NULL)
- continue;
-
- context = (char *)alloc((unsigned)strlen(cntx)+5);
-
- if (strcmp(cntx, "<global>")==0)
- strcpy(context, "<<global>>");
- else
- sprintf(context, "<<%s>>", cntx);
-
- if (search == NULL)
- fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
- else
- fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
-
- free(context);
- free(fullname);
- } /* for all matches */
-
- (void)cs_read_prompt(i);
-
- } /* for all cscope connections */
- free(buf);
-}
-
-/*
- * PRIVATE: cs_fill_results
- *
- * get parsed cscope output and calls cs_make_vim_style_matches to convert
- * into ctags format
- * When there are no matches sets "*matches_p" to NULL.
- */
-static void cs_fill_results(char *tagstr, int totmatches, int *nummatches_a, char ***matches_p, char ***cntxts_p, int *matched)
-{
- int i, j;
- char *buf;
- char *search, *slno;
- int totsofar = 0;
- char **matches = NULL;
- char **cntxts = NULL;
- char *fullname;
- char *cntx;
-
- assert(totmatches > 0);
-
- buf = xmalloc(CSREAD_BUFSIZE);
- matches = xmalloc(sizeof(char *) * totmatches);
- cntxts = xmalloc(sizeof(char *) * totmatches);
-
- for (i = 0; i < csinfo_size; i++) {
- if (nummatches_a[i] < 1)
- continue;
-
- for (j = 0; j < nummatches_a[i]; j++) {
- if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
- &slno, &search)) == NULL)
- continue;
-
- matches[totsofar] = cs_make_vim_style_matches(fullname, slno, search,
- tagstr);
-
- free(fullname);
-
- if (strcmp(cntx, "<global>") == 0)
- cntxts[totsofar] = NULL;
- else {
- /* note: if vim_strsave returns NULL, then the context
- * will be "<global>", which is misleading.
- */
- cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx);
- }
-
- totsofar++;
-
- } /* for all matches */
-
- (void)cs_read_prompt(i);
-
- } /* for all cscope connections */
-
- if (totsofar == 0) {
- /* No matches, free the arrays and return NULL in "*matches_p". */
- free(matches);
- matches = NULL;
- free(cntxts);
- cntxts = NULL;
- }
- *matched = totsofar;
- *matches_p = matches;
- *cntxts_p = cntxts;
-
- free(buf);
-} /* cs_fill_results */
-
-
-/* get the requested path components */
-static char *cs_pathcomponents(char *path)
-{
- int i;
- char *s;
-
- if (p_cspc == 0)
- return path;
-
- s = path + strlen(path) - 1;
- for (i = 0; i < p_cspc; ++i)
- while (s > path && *--s != '/'
- )
- ;
- if ((s > path && *s == '/')
- )
- ++s;
- return s;
-}
-
-/*
- * PRIVATE: cs_print_tags_priv
- *
- * called from cs_manage_matches()
- */
-static void cs_print_tags_priv(char **matches, char **cntxts, int num_matches)
-{
- char *buf = NULL;
- int bufsize = 0; /* Track available bufsize */
- int newsize = 0;
- char *ptag;
- char *fname, *lno, *extra, *tbuf;
- int i, idx, num;
- char *globalcntx = "GLOBAL";
- char *cntxformat = " <<%s>>";
- char *context;
- char *cstag_msg = _("Cscope tag: %s");
- char *csfmt_str = "%4d %6s ";
-
- assert (num_matches > 0);
-
- tbuf = (char *)alloc((unsigned)strlen(matches[0]) + 1);
-
- strcpy(tbuf, matches[0]);
- ptag = strtok(tbuf, "\t");
-
- newsize = (int)(strlen(cstag_msg) + strlen(ptag));
- buf = (char *)alloc(newsize);
- bufsize = newsize;
- (void)sprintf(buf, cstag_msg, ptag);
- MSG_PUTS_ATTR(buf, hl_attr(HLF_T));
-
- free(tbuf);
-
- MSG_PUTS_ATTR(_("\n # line"), hl_attr(HLF_T)); /* strlen is 7 */
- msg_advance(msg_col + 2);
- MSG_PUTS_ATTR(_("filename / context / line\n"), hl_attr(HLF_T));
-
- num = 1;
- for (i = 0; i < num_matches; i++) {
- idx = i;
-
- /* if we really wanted to, we could avoid this malloc and strcpy
- * by parsing matches[i] on the fly and placing stuff into buf
- * directly, but that's too much of a hassle
- */
- tbuf = (char *)alloc((unsigned)strlen(matches[idx]) + 1);
- (void)strcpy(tbuf, matches[idx]);
-
- if (strtok(tbuf, (const char *)"\t") == NULL)
- continue;
- if ((fname = strtok(NULL, (const char *)"\t")) == NULL)
- continue;
- if ((lno = strtok(NULL, (const char *)"\t")) == NULL)
- continue;
- extra = strtok(NULL, (const char *)"\t");
-
- lno[strlen(lno)-2] = '\0'; /* ignore ;" at the end */
-
- /* hopefully 'num' (num of matches) will be less than 10^16 */
- newsize = (int)(strlen(csfmt_str) + 16 + strlen(lno));
- if (bufsize < newsize) {
- buf = (char *)xrealloc(buf, newsize);
- bufsize = newsize;
- }
- if (buf != NULL) {
- /* csfmt_str = "%4d %6s "; */
- (void)sprintf(buf, csfmt_str, num, lno);
- MSG_PUTS_ATTR(buf, hl_attr(HLF_CM));
- }
- MSG_PUTS_LONG_ATTR(cs_pathcomponents(fname), hl_attr(HLF_CM));
-
- /* compute the required space for the context */
- if (cntxts[idx] != NULL)
- context = cntxts[idx];
- else
- context = globalcntx;
- newsize = (int)(strlen(context) + strlen(cntxformat));
-
- if (bufsize < newsize) {
- buf = (char *)xrealloc(buf, newsize);
- bufsize = newsize;
- }
- if (buf != NULL) {
- (void)sprintf(buf, cntxformat, context);
-
- /* print the context only if it fits on the same line */
- if (msg_col + (int)strlen(buf) >= (int)Columns)
- msg_putchar('\n');
- msg_advance(12);
- MSG_PUTS_LONG(buf);
- msg_putchar('\n');
- }
- if (extra != NULL) {
- msg_advance(13);
- MSG_PUTS_LONG(extra);
- }
-
- free(tbuf); /* only after printing extra due to strtok use */
-
- if (msg_col)
- msg_putchar('\n');
-
- ui_breakcheck();
- if (got_int) {
- got_int = FALSE; /* don't print any more matches */
- break;
- }
-
- num++;
- } /* for all matches */
-
- free(buf);
-} /* cs_print_tags_priv */
-
-
-/*
- * PRIVATE: cs_read_prompt
- *
- * read a cscope prompt (basically, skip over the ">> ")
- */
-static int cs_read_prompt(int i)
-{
- int ch;
- char *buf = NULL; /* buffer for possible error message from cscope */
- int bufpos = 0;
- char *cs_emsg;
- int maxlen;
- static char *eprompt = "Press the RETURN key to continue:";
- int epromptlen = (int)strlen(eprompt);
- int n;
-
- cs_emsg = _("E609: Cscope error: %s");
- /* compute maximum allowed len for Cscope error message */
- maxlen = (int)(IOSIZE - strlen(cs_emsg));
-
- for (;; ) {
- while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
- /* if there is room and char is printable */
- if (bufpos < maxlen - 1 && vim_isprintc(ch)) {
- if (buf == NULL) /* lazy buffer allocation */
- buf = (char *)alloc(maxlen);
- if (buf != NULL) {
- /* append character to the message */
- buf[bufpos++] = ch;
- buf[bufpos] = NUL;
- if (bufpos >= epromptlen
- && strcmp(&buf[bufpos - epromptlen], eprompt) == 0) {
- /* remove eprompt from buf */
- buf[bufpos - epromptlen] = NUL;
-
- /* print message to user */
- (void)EMSG2(cs_emsg, buf);
-
- /* send RETURN to cscope */
- (void)putc('\n', csinfo[i].to_fp);
- (void)fflush(csinfo[i].to_fp);
-
- /* clear buf */
- bufpos = 0;
- buf[bufpos] = NUL;
- }
- }
- }
-
- for (n = 0; n < (int)strlen(CSCOPE_PROMPT); ++n) {
- if (n > 0)
- ch = getc(csinfo[i].fr_fp);
- if (ch == EOF) {
- PERROR("cs_read_prompt EOF");
- if (buf != NULL && buf[0] != NUL)
- (void)EMSG2(cs_emsg, buf);
- else if (p_csverbose)
- cs_reading_emsg(i); /* don't have additional information */
- cs_release_csp(i, TRUE);
- free(buf);
- return CSCOPE_FAILURE;
- }
-
- if (ch != CSCOPE_PROMPT[n]) {
- ch = EOF;
- break;
- }
- }
-
- if (ch == EOF)
- continue; /* didn't find the prompt */
- break; /* did find the prompt */
- }
-
- free(buf);
- return CSCOPE_SUCCESS;
-}
-
-#if defined(UNIX) && defined(SIGALRM)
-/*
- * Used to catch and ignore SIGALRM below.
- */
-static RETSIGTYPE
-sig_handler SIGDEFARG(sigarg) {
- /* do nothing */
- SIGRETURN;
-}
-
-#endif
-
-/*
- * PRIVATE: cs_release_csp
- *
- * Does the actual free'ing for the cs ptr with an optional flag of whether
- * or not to free the filename. Called by cs_kill and cs_reset.
- */
-static void cs_release_csp(int i, int freefnpp)
-{
- /*
- * Trying to exit normally (not sure whether it is fit to UNIX cscope
- */
- if (csinfo[i].to_fp != NULL) {
- (void)fputs("q\n", csinfo[i].to_fp);
- (void)fflush(csinfo[i].to_fp);
- }
-#if defined(UNIX)
- {
- int waitpid_errno;
- int pstat;
- pid_t pid;
-
-# if defined(HAVE_SIGACTION)
- struct sigaction sa, old;
-
- /* Use sigaction() to limit the waiting time to two seconds. */
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = sig_handler;
-# ifdef SA_NODEFER
- sa.sa_flags = SA_NODEFER;
-# else
- sa.sa_flags = 0;
-# endif
- sigaction(SIGALRM, &sa, &old);
- alarm(2); /* 2 sec timeout */
-
- /* Block until cscope exits or until timer expires */
- pid = waitpid(csinfo[i].pid, &pstat, 0);
- waitpid_errno = errno;
-
- /* cancel pending alarm if still there and restore signal */
- alarm(0);
- sigaction(SIGALRM, &old, NULL);
-# else
- int waited;
-
- /* Can't use sigaction(), loop for two seconds. First yield the CPU
- * to give cscope a chance to exit quickly. */
- sleep(0);
- for (waited = 0; waited < 40; ++waited) {
- pid = waitpid(csinfo[i].pid, &pstat, WNOHANG);
- waitpid_errno = errno;
- if (pid != 0)
- break; /* break unless the process is still running */
- os_delay(50L, FALSE); /* sleep 50 ms */
- }
-# endif
- /*
- * If the cscope process is still running: kill it.
- * Safety check: If the PID would be zero here, the entire X session
- * would be killed. -1 and 1 are dangerous as well.
- */
- if (pid < 0 && csinfo[i].pid > 1) {
-# ifdef ECHILD
- int alive = TRUE;
-
- if (waitpid_errno == ECHILD) {
- /*
- * When using 'vim -g', vim is forked and cscope process is
- * no longer a child process but a sibling. So waitpid()
- * fails with errno being ECHILD (No child processes).
- * Don't send SIGKILL to cscope immediately but wait
- * (polling) for it to exit normally as result of sending
- * the "q" command, hence giving it a chance to clean up
- * its temporary files.
- */
- int waited;
-
- sleep(0);
- for (waited = 0; waited < 40; ++waited) {
- /* Check whether cscope process is still alive */
- if (kill(csinfo[i].pid, 0) != 0) {
- alive = FALSE; /* cscope process no longer exists */
- break;
- }
- os_delay(50L, FALSE); /* sleep 50ms */
- }
- }
- if (alive)
-# endif
- {
- kill(csinfo[i].pid, SIGKILL);
- (void)waitpid(csinfo[i].pid, &pstat, 0);
- }
- }
- }
-#else /* !UNIX */
- if (csinfo[i].hProc != NULL) {
- /* Give cscope a chance to exit normally */
- if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
- TerminateProcess(csinfo[i].hProc, 0);
- CloseHandle(csinfo[i].hProc);
- }
-#endif
-
- if (csinfo[i].fr_fp != NULL)
- (void)fclose(csinfo[i].fr_fp);
- if (csinfo[i].to_fp != NULL)
- (void)fclose(csinfo[i].to_fp);
-
- if (freefnpp) {
- free(csinfo[i].fname);
- free(csinfo[i].ppath);
- free(csinfo[i].flags);
- }
-
- clear_csinfo(i);
-} /* cs_release_csp */
-
-
-/*
- * PRIVATE: cs_reset
- *
- * calls cs_kill on all cscope connections then reinits
- */
-static int cs_reset(exarg_T *eap)
-{
- char **dblist = NULL, **pplist = NULL, **fllist = NULL;
- int i;
- char buf[20]; /* for sprintf " (#%d)" */
-
- if (csinfo_size == 0)
- return CSCOPE_SUCCESS;
-
- /* malloc our db and ppath list */
- dblist = xmalloc(csinfo_size * sizeof(char *));
- pplist = xmalloc(csinfo_size * sizeof(char *));
- fllist = xmalloc(csinfo_size * sizeof(char *));
-
- for (i = 0; i < csinfo_size; i++) {
- dblist[i] = csinfo[i].fname;
- pplist[i] = csinfo[i].ppath;
- fllist[i] = csinfo[i].flags;
- if (csinfo[i].fname != NULL)
- cs_release_csp(i, FALSE);
- }
-
- /* rebuild the cscope connection list */
- for (i = 0; i < csinfo_size; i++) {
- if (dblist[i] != NULL) {
- cs_add_common(dblist[i], pplist[i], fllist[i]);
- if (p_csverbose) {
- /* don't use smsg_attr() because we want to display the
- * connection number in the same line as
- * "Added cscope database..."
- */
- sprintf(buf, " (#%d)", i);
- MSG_PUTS_ATTR(buf, hl_attr(HLF_R));
- }
- }
- free(dblist[i]);
- free(pplist[i]);
- free(fllist[i]);
- }
- free(dblist);
- free(pplist);
- free(fllist);
-
- if (p_csverbose)
- MSG_ATTR(_("All cscope databases reset"), hl_attr(HLF_R) | MSG_HIST);
- return CSCOPE_SUCCESS;
-} /* cs_reset */
-
-
-/*
- * PRIVATE: cs_resolve_file
- *
- * Construct the full pathname to a file found in the cscope database.
- * (Prepends ppath, if there is one and if it's not already prepended,
- * otherwise just uses the name found.)
- *
- * We need to prepend the prefix because on some cscope's (e.g., the one that
- * ships with Solaris 2.6), the output never has the prefix prepended.
- * Contrast this with my development system (Digital Unix), which does.
- */
-static char *cs_resolve_file(int i, char *name)
-{
- char *fullname;
- int len;
- char_u *csdir = NULL;
-
- /*
- * Ppath is freed when we destroy the cscope connection.
- * Fullname is freed after cs_make_vim_style_matches, after it's been
- * copied into the tag buffer used by Vim.
- */
- len = (int)(strlen(name) + 2);
- if (csinfo[i].ppath != NULL)
- len += (int)strlen(csinfo[i].ppath);
- else if (p_csre && csinfo[i].fname != NULL) {
- /* If 'cscoperelative' is set and ppath is not set, use cscope.out
- * path in path resolution. */
- csdir = alloc(MAXPATHL);
- vim_strncpy(csdir, (char_u *)csinfo[i].fname,
- path_tail((char_u *)csinfo[i].fname)
- - (char_u *)csinfo[i].fname);
- len += (int)STRLEN(csdir);
- }
-
- /* Note/example: this won't work if the cscope output already starts
- * "../.." and the prefix path is also "../..". if something like this
- * happens, you are screwed up and need to fix how you're using cscope. */
- if (csinfo[i].ppath != NULL
- && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0)
- && (name[0] != '/')
- ) {
- fullname = xmalloc(len);
- (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
- } else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL) {
- /* Check for csdir to be non empty to avoid empty path concatenated to
- * cscope output. */
- fullname = (char *)concat_fnames(csdir, (char_u *)name, TRUE);
- } else {
- fullname = (char *)vim_strsave((char_u *)name);
- }
-
- free(csdir);
- return fullname;
-}
-
-
-/*
- * PRIVATE: cs_show
- *
- * show all cscope connections
- */
-static int cs_show(exarg_T *eap)
-{
- short i;
- if (cs_cnt_connections() == 0)
- MSG_PUTS(_("no cscope connections\n"));
- else {
- MSG_PUTS_ATTR(
- _(" # pid database name prepend path\n"),
- hl_attr(HLF_T));
- for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname == NULL)
- continue;
-
- if (csinfo[i].ppath != NULL)
- (void)smsg((char_u *)"%2d %-5ld %-34s %-32s",
- i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
- else
- (void)smsg((char_u *)"%2d %-5ld %-34s <none>",
- i, (long)csinfo[i].pid, csinfo[i].fname);
- }
- }
-
- wait_return(TRUE);
- return CSCOPE_SUCCESS;
-} /* cs_show */
-
-
-/*
- * PUBLIC: cs_end
- *
- * Only called when VIM exits to quit any cscope sessions.
- */
-void cs_end(void)
-{
- int i;
-
- for (i = 0; i < csinfo_size; i++)
- cs_release_csp(i, TRUE);
- free(csinfo);
- csinfo_size = 0;
-}
-
-/* the end */