summaryrefslogtreecommitdiff
path: root/usr.bin/mg
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/mg')
-rw-r--r--usr.bin/mg/Makefile4
-rw-r--r--usr.bin/mg/README6
-rw-r--r--usr.bin/mg/cscope.c617
-rw-r--r--usr.bin/mg/def.h20
-rw-r--r--usr.bin/mg/funmap.c15
-rw-r--r--usr.bin/mg/keymap.c44
-rw-r--r--usr.bin/mg/mg.156
-rw-r--r--usr.bin/mg/tags.c2
8 files changed, 753 insertions, 11 deletions
diff --git a/usr.bin/mg/Makefile b/usr.bin/mg/Makefile
index 4f65776b5eb..7ef7a7c5864 100644
--- a/usr.bin/mg/Makefile
+++ b/usr.bin/mg/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.25 2011/11/28 04:41:39 lum Exp $
+# $OpenBSD: Makefile,v 1.26 2012/06/07 15:15:04 lum Exp $
PROG= mg
@@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo.c dir.c display.c \
#
# More or less standalone extensions.
#
-SRCS+= cmode.c dired.c grep.c tags.c theo.c
+SRCS+= cmode.c cscope.c dired.c grep.c tags.c theo.c
afterinstall:
${INSTALL} -d ${DESTDIR}${DOCDIR}/mg
diff --git a/usr.bin/mg/README b/usr.bin/mg/README
index c1c6a7a846a..ce73b220843 100644
--- a/usr.bin/mg/README
+++ b/usr.bin/mg/README
@@ -73,6 +73,12 @@ Unlike GNU Emacs, Mg's minibuffer isn't multi-line aware and hence
some commands like "shell-command-on-region" always pop up a buffer to
display output irrespective of output's size.
+While navigating source code using Mg's cscope commands, the cursor
+is always at the match location rather than in *cscope* buffer. Mg uses
+the same keybindings of GNU Emacs's xcscope package for it's cscope commands.
+As Mg's keybindings are case-insensitive some of the commands don't have a
+default keybinding.
+
New implementation oddities:
insert and define-key are new commands corresponding to the mocklisp
diff --git a/usr.bin/mg/cscope.c b/usr.bin/mg/cscope.c
new file mode 100644
index 00000000000..d741637c2ce
--- /dev/null
+++ b/usr.bin/mg/cscope.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2012 Sunil Nimmagadda <sunil@sunilnimmagadda.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "def.h"
+
+#define CSSYMBOL 0
+#define CSDEFINITION 1
+#define CSCALLEDFUNCS 2
+#define CSCALLERFUNCS 3
+#define CSTEXT 4
+#define CSEGREP 6
+#define CSFINDFILE 7
+#define CSINCLUDES 8
+
+struct cstokens {
+ const char *fname;
+ const char *function;
+ const char *lineno;
+ const char *pattern;
+};
+
+struct csmatch {
+ TAILQ_ENTRY(csmatch) entry;
+ int lineno;
+};
+
+struct csrecord {
+ TAILQ_ENTRY(csrecord) entry;
+ char *filename;
+ TAILQ_HEAD(matches, csmatch) matches;
+};
+
+static TAILQ_HEAD(csrecords, csrecord) csrecords = TAILQ_HEAD_INITIALIZER(csrecords);
+static struct csrecord *addentryr;
+static struct csrecord *currecord;
+static struct csmatch *curmatch;
+static const char *addentryfn;
+static const char *csprompt[] = {
+ "Find this symbol: ",
+ "Find this global definition: ",
+ "Find functions called by this function: ",
+ "Find functions calling this function: ",
+ "Find this text string: ",
+ "Change this text string: ",
+ "Find this egrep pattern: ",
+ "Find this file: ",
+ "Find files #including this file: "
+};
+
+static int addentry(struct buffer *, char *);
+static void csflush(void);
+static int do_cscope(int);
+static int csexists(const char *);
+static int getattr(char *, struct cstokens *);
+static int jumptomatch(void);
+static void prettyprint(struct buffer *, struct cstokens *);
+static const char *ltrim(const char *);
+
+/*
+ * Find this symbol. Bound to C-c s s
+ */
+/* ARGSUSED */
+int
+cssymbol(int f, int n)
+{
+ return (do_cscope(CSSYMBOL));
+}
+
+/*
+ * Find this global definition. Bound to C-c s d
+ */
+/* ARGSUSED */int
+csdefinition(int f, int n)
+{
+ return (do_cscope(CSDEFINITION));
+}
+
+/*
+ * Find functions called by this function. Bound to C-c s l
+ */
+/* ARGSUSED */
+int
+csfuncalled(int f, int n)
+{
+ return (do_cscope(CSCALLEDFUNCS));
+}
+
+/*
+ * Find functions calling this function. Bound to C-c s c
+ */
+/* ARGSUSED */
+int
+cscallerfuncs(int f, int n)
+{
+ return (do_cscope(CSCALLERFUNCS));
+}
+
+/*
+ * Find this text. Bound to C-c s t
+ */
+/* ARGSUSED */
+int
+csfindtext(int f, int n)
+{
+ return (do_cscope(CSTEXT));
+}
+
+/*
+ * Find this egrep pattern. Bound to C-c s e
+ */
+/* ARGSUSED */
+int
+csegrep(int f, int n)
+{
+ return (do_cscope(CSEGREP));
+}
+
+/*
+ * Find this file. Bound to C-c s f
+ */
+/* ARGSUSED */
+int
+csfindfile(int f, int n)
+{
+ return (do_cscope(CSFINDFILE));
+}
+
+/*
+ * Find files #including this file. Bound to C-c s i
+ */
+/* ARGSUSED */
+int
+csfindinc(int f, int n)
+{
+ return (do_cscope(CSINCLUDES));
+}
+
+/*
+ * Create list of files to index in the given directory
+ * using cscope-indexer.
+ */
+/* ARGSUSED */
+int
+cscreatelist(int f, int n)
+{
+ struct buffer *bp;
+ struct stat sb;
+ FILE *fpipe;
+ char dir[NFILEN], cmd[BUFSIZ], title[BUFSIZ], *line, *bufp;
+ size_t len;
+ int clen;
+
+ if (getbufcwd(dir, sizeof(dir)) == FALSE)
+ dir[0] = '\0';
+
+ bufp = eread("Index files in directory: ", dir,
+ sizeof(dir), EFCR | EFDEF | EFNEW | EFNUL);
+
+ if (bufp == NULL)
+ return (ABORT);
+ else if (bufp[0] == '\0')
+ return (FALSE);
+
+ if (stat(dir, &sb) == -1) {
+ ewprintf("stat: %s", strerror(errno));
+ return (FALSE);
+ } else if (S_ISDIR(sb.st_mode) == 0) {
+ ewprintf("%s: Not a directory", dir);
+ return (FALSE);
+ }
+
+ if (csexists("cscope-indexer") == FALSE) {
+ ewprintf("no such file or directory, cscope-indexer");
+ return (FALSE);
+ }
+
+ clen = snprintf(cmd, sizeof(cmd), "cscope-indexer -v %s", dir);
+ if (clen < 0 || clen >= sizeof(cmd))
+ return (FALSE);
+
+ if ((fpipe = popen(cmd, "r")) == NULL) {
+ ewprintf("problem opening pipe");
+ return (FALSE);
+ }
+
+ bp = bfind("*cscope*", TRUE);
+ if (bclear(bp) != TRUE)
+ return (FALSE);
+ bp->b_flag |= BFREADONLY;
+
+ clen = snprintf(title, sizeof(title), "%s%s",
+ "Creating cscope file list 'cscope.files' in: ", dir);
+ if (clen < 0 || clen >= sizeof(title))
+ return (FALSE);
+ addline(bp, title);
+ addline(bp, "");
+ /* All lines are NUL terminated */
+ while ((line = fgetln(fpipe, &len)) != NULL) {
+ line[len - 1] = '\0';
+ addline(bp, line);
+ }
+ pclose(fpipe);
+ return (popbuftop(bp, WNONE));
+}
+
+/*
+ * Next Symbol. Bound to C-c s n
+ */
+/* ARGSUSED */
+int
+csnextmatch(int f, int n)
+{
+ struct csrecord *r;
+ struct csmatch *m;
+
+ if (curmatch == NULL) {
+ if ((r = TAILQ_FIRST(&csrecords)) == NULL) {
+ ewprintf("The *cscope* buffer does not exist yet");
+ return (FALSE);
+ }
+ currecord = r;
+ curmatch = TAILQ_FIRST(&r->matches);
+ } else {
+ m = TAILQ_NEXT(curmatch, entry);
+ if (m == NULL) {
+ r = TAILQ_NEXT(currecord, entry);
+ if (r == NULL) {
+ ewprintf("The end of *cscope* buffer has been"
+ " reached");
+ return (FALSE);
+ } else {
+ currecord = r;
+ curmatch = TAILQ_FIRST(&currecord->matches);
+ }
+ } else
+ curmatch = m;
+ }
+ return (jumptomatch());
+}
+
+/*
+ * Previous Symbol. Bound to C-c s p
+ */
+/* ARGSUSED */
+int
+csprevmatch(int f, int n)
+{
+ struct csmatch *m;
+ struct csrecord *r;
+
+ if (curmatch == NULL)
+ return (FALSE);
+ else {
+ m = TAILQ_PREV(curmatch, matches, entry);
+ if (m)
+ curmatch = m;
+ else {
+ r = TAILQ_PREV(currecord, csrecords, entry);
+ if (r == NULL) {
+ ewprintf("The beginning of *cscope* buffer has"
+ " been reached");
+ return (FALSE);
+ } else {
+ currecord = r;
+ curmatch = TAILQ_LAST(&currecord->matches,
+ matches);
+ }
+ }
+ }
+ return (jumptomatch());
+}
+
+/*
+ * Next file.
+ */
+int
+csnextfile(int f, int n)
+{
+ struct csrecord *r;
+
+ if (curmatch == NULL) {
+ if ((r = TAILQ_FIRST(&csrecords)) == NULL) {
+ ewprintf("The *cscope* buffer does not exist yet");
+ return (FALSE);
+ }
+
+ } else {
+ if ((r = TAILQ_NEXT(currecord, entry)) == NULL) {
+ ewprintf("The end of *cscope* buffer has been reached");
+ return (FALSE);
+ }
+ }
+ currecord = r;
+ curmatch = TAILQ_FIRST(&currecord->matches);
+ return (jumptomatch());
+}
+
+/*
+ * Previous file.
+ */
+int
+csprevfile(int f, int n)
+{
+ struct csrecord *r;
+
+ if (curmatch == NULL) {
+ if ((r = TAILQ_FIRST(&csrecords)) == NULL) {
+ ewprintf("The *cscope* buffer does not exist yet");
+ return (FALSE);
+ }
+
+ } else {
+ if ((r = TAILQ_PREV(currecord, csrecords, entry)) == NULL) {
+ ewprintf("The beginning of *cscope* buffer has been"
+ " reached");
+ return (FALSE);
+ }
+ }
+ currecord = r;
+ curmatch = TAILQ_FIRST(&currecord->matches);
+ return (jumptomatch());
+}
+
+/*
+ * The current symbol location is extracted from currecord->filename and
+ * curmatch->lineno. Load the file similar to filevisit and goto the
+ * lineno recorded.
+ */
+int
+jumptomatch(void)
+{
+ struct buffer *bp;
+ char *adjf;
+
+ if (curmatch == NULL || currecord == NULL)
+ return (FALSE);
+ adjf = adjustname(currecord->filename, TRUE);
+ if (adjf == NULL)
+ return (FALSE);
+ if ((bp = findbuffer(adjf)) == NULL)
+ return (FALSE);
+ curbp = bp;
+ if (showbuffer(bp, curwp, WFFULL) != TRUE)
+ return (FALSE);
+ if (bp->b_fname[0] == '\0') {
+ if (readin(adjf) != TRUE)
+ killbuffer(bp);
+ }
+ gotoline(FFARG, curmatch->lineno);
+ return (TRUE);
+
+}
+
+/*
+ * Ask for the symbol, construct cscope commandline with the symbol
+ * and passed in index. Popen cscope, read the output into *cscope*
+ * buffer and pop it.
+ */
+int
+do_cscope(int i)
+{
+ struct buffer *bp;
+ FILE *fpipe;
+ char pattern[MAX_TOKEN], cmd[BUFSIZ], title[BUFSIZ];
+ char *p, *buf;
+ int clen, nores = 0;
+ size_t len;
+
+ /* If current buffer isn't a source file just return */
+ if (fnmatch("*.[chy]", curbp->b_fname, 0) != 0) {
+ ewprintf("C-c s not defined");
+ return (FALSE);
+ }
+
+ if (curtoken(0, 1, pattern) == FALSE)
+ return (FALSE);
+ p = eread(csprompt[i], pattern, MAX_TOKEN, EFNEW | EFCR | EFDEF);
+ if (p == NULL)
+ return (ABORT);
+ else if (p[0] == '\0')
+ return (FALSE);
+
+ if (csexists("cscope") == FALSE) {
+ ewprintf("no such file or directory, cscope");
+ return (FALSE);
+ }
+
+ csflush();
+ clen = snprintf(cmd, sizeof(cmd), "cscope -L -%d %s 2>/dev/null",
+ i, pattern);
+ if (clen < 0 || clen >= sizeof(cmd))
+ return (FALSE);
+
+ if ((fpipe = popen(cmd, "r")) == NULL) {
+ ewprintf("problem opening pipe");
+ return (FALSE);
+ }
+
+ bp = bfind("*cscope*", TRUE);
+ if (bclear(bp) != TRUE)
+ return (FALSE);
+ bp->b_flag |= BFREADONLY;
+
+ clen = snprintf(title, sizeof(title), "%s%s", csprompt[i], pattern);
+ if (clen < 0 || clen >= sizeof(title))
+ return (FALSE);
+ addline(bp, title);
+ addline(bp, "");
+ addline(bp, "-------------------------------------------------------------------------------");
+ /* All lines are NUL terminated */
+ while ((buf = fgetln(fpipe, &len)) != NULL) {
+ buf[len - 1] = '\0';
+ if (addentry(bp, buf) != TRUE)
+ return (FALSE);
+ nores = 1;
+ };
+ pclose(fpipe);
+ addline(bp, "-------------------------------------------------------------------------------");
+ if (nores == 0)
+ ewprintf("No matches were found.");
+ return (popbuftop(bp, WNONE));
+}
+
+/*
+ * For each line read from cscope output, extract the tokens,
+ * add them to list and pretty print a line in *cscope* buffer.
+ */
+int
+addentry(struct buffer *bp, char *csline)
+{
+ struct csrecord *r;
+ struct csmatch *m;
+ struct cstokens t;
+ int lineno;
+ char buf[BUFSIZ];
+ const char *errstr;
+
+ r = NULL;
+ if (getattr(csline, &t) == FALSE)
+ return (FALSE);
+
+ lineno = strtonum(t.lineno, INT_MIN, INT_MAX, &errstr);
+ if (errstr)
+ return (FALSE);
+
+ if (addentryfn == NULL || strcmp(addentryfn, t.fname) != 0) {
+ if ((r = malloc(sizeof(struct csrecord))) == NULL)
+ return (FALSE);
+ addentryr = r;
+ if ((r->filename = strndup(t.fname, NFILEN)) == NULL)
+ goto cleanup;
+ addentryfn = r->filename;
+ TAILQ_INIT(&r->matches);
+ if ((m = malloc(sizeof(struct csmatch))) == NULL)
+ goto cleanup;
+ m->lineno = lineno;
+ TAILQ_INSERT_TAIL(&r->matches, m, entry);
+ TAILQ_INSERT_TAIL(&csrecords, r, entry);
+ addline(bp, "");
+ if (snprintf(buf, sizeof(buf), "*** %s", t.fname) < 0)
+ goto cleanup;
+ addline(bp, buf);
+ } else {
+ if ((m = malloc(sizeof(struct csmatch))) == NULL)
+ goto cleanup;
+ m->lineno = lineno;
+ TAILQ_INSERT_TAIL(&addentryr->matches, m, entry);
+ }
+ prettyprint(bp, &t);
+ return (TRUE);
+cleanup:
+ free(r);
+ return (FALSE);
+}
+
+/*
+ * Cscope line: <filename> <function> <lineno> <pattern>
+ */
+int
+getattr(char *line, struct cstokens *t)
+{
+ char *p;
+
+ if ((p = strchr(line, ' ')) == NULL)
+ return (FALSE);
+ *p++ = '\0';
+ t->fname = line;
+ line = p;
+
+ if ((p = strchr(line, ' ')) == NULL)
+ return (FALSE);
+ *p++ = '\0';
+ t->function = line;
+ line = p;
+
+ if ((p = strchr(line, ' ')) == NULL)
+ return (FALSE);
+ *p++ = '\0';
+ t->lineno = line;
+
+ if (*p == '\0')
+ return (FALSE);
+ t->pattern = p;
+
+ return (TRUE);
+}
+
+void
+prettyprint(struct buffer *bp, struct cstokens *t)
+{
+ char buf[BUFSIZ];
+
+ if (snprintf(buf, sizeof(buf), "%s[%s]\t\t%s",
+ t->function, t->lineno, ltrim(t->pattern)) < 0)
+ return;
+ addline(bp, buf);
+}
+
+const char *
+ltrim(const char *s)
+{
+ while (isblank(*s))
+ s++;
+ return s;
+}
+
+void
+csflush(void)
+{
+ struct csrecord *r;
+ struct csmatch *m;
+
+ while ((r = TAILQ_FIRST(&csrecords)) != NULL) {
+ free(r->filename);
+ while ((m = TAILQ_FIRST(&r->matches)) != NULL) {
+ TAILQ_REMOVE(&r->matches, m, entry);
+ free(m);
+ }
+ TAILQ_REMOVE(&csrecords, r, entry);
+ free(r);
+ }
+ addentryr = NULL;
+ addentryfn = NULL;
+ currecord = NULL;
+ curmatch = NULL;
+}
+
+/*
+ * Check if the cmd exists in $PATH. Split on ":" and iterate through
+ * all paths in $PATH.
+ */
+int
+csexists(const char *cmd)
+{
+ char fname[NFILEN], *dir, *path, *pathc, *tmp;
+ int cmdlen, dlen;
+
+ /* Special case if prog contains '/' */
+ if (strchr(cmd, '/')) {
+ if (access(cmd, F_OK) == -1)
+ return (FALSE);
+ else
+ return (TRUE);
+ }
+ if ((tmp = getenv("PATH")) == NULL)
+ return (FALSE);
+ if ((pathc = path = strndup(tmp, NFILEN)) == NULL) {
+ ewprintf("out of memory");
+ return (FALSE);
+ }
+ cmdlen = strlen(cmd);
+ while ((dir = strsep(&path, ":")) != NULL) {
+ if (*dir == '\0')
+ *dir = '.';
+
+ dlen = strlen(dir);
+ while (dir[dlen-1] == '/')
+ dir[--dlen] = '\0'; /* strip trailing '/' */
+
+ if (dlen + 1 + cmdlen >= sizeof(fname)) {
+ ewprintf("path too long");
+ goto cleanup;
+ }
+ snprintf(fname, sizeof(fname), "%s/%s", dir, cmd);
+ if(access(fname, F_OK) == 0) {
+ free(pathc);
+ return (TRUE);
+ }
+ }
+cleanup:
+ free(pathc);
+ return (FALSE);
+}
diff --git a/usr.bin/mg/def.h b/usr.bin/mg/def.h
index e7b59c525a5..d334caa75c1 100644
--- a/usr.bin/mg/def.h
+++ b/usr.bin/mg/def.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: def.h,v 1.122 2012/05/29 05:40:36 lum Exp $ */
+/* $OpenBSD: def.h,v 1.123 2012/06/07 15:15:04 lum Exp $ */
/* This file is in the public domain. */
@@ -103,6 +103,8 @@ typedef int (*PF)(int, int); /* generally useful type */
#define KBACK 0x02 /* Backwards insert into kill ring */
#define KREG 0x04 /* This is a region-based kill */
+#define MAX_TOKEN 64
+
/*
* This structure holds the starting position
* (as a line/offset pair) and the number of characters in a
@@ -513,6 +515,22 @@ int joinline(int, int);
int findtag(int, int);
int poptag(int, int);
int tagsvisit(int, int);
+int curtoken(int, int, char *);
+
+/* cscope.c */
+int cssymbol(int, int);
+int csdefinition(int, int);
+int csfuncalled(int, int);
+int cscallerfuncs(int, int);
+int csfindtext(int, int);
+int csegrep(int, int);
+int csfindfile(int, int);
+int csfindinc(int, int);
+int csnextfile(int, int);
+int csnextmatch(int, int);
+int csprevfile(int, int);
+int csprevmatch(int, int);
+int cscreatelist(int, int);
/* extend.c X */
int insert(int, int);
diff --git a/usr.bin/mg/funmap.c b/usr.bin/mg/funmap.c
index 696be91130b..01275541f22 100644
--- a/usr.bin/mg/funmap.c
+++ b/usr.bin/mg/funmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: funmap.c,v 1.38 2012/04/12 04:47:59 lum Exp $ */
+/* $OpenBSD: funmap.c,v 1.39 2012/06/07 15:15:04 lum Exp $ */
/* This file is in the public domain */
@@ -182,6 +182,19 @@ static struct funmap functnames[] = {
{showcpos, "what-cursor-position",},
{filewrite, "write-file",},
{yank, "yank",},
+ {cssymbol, "cscope-find-this-symbol",},
+ {csdefinition, "cscope-find-global-definition",},
+ {csfuncalled, "cscope-find-called-functions",},
+ {cscallerfuncs, "cscope-find-functions-calling-this-function",},
+ {csfindtext, "cscope-find-this-text-string",},
+ {csegrep, "cscope-find-egrep-pattern",},
+ {csfindfile, "cscope-find-this-file",},
+ {csfindinc, "cscope-find-files-including-file",},
+ {csnextmatch, "cscope-next-symbol",},
+ {csprevmatch, "cscope-prev-symbol",},
+ {csnextfile, "cscope-next-file",},
+ {csprevfile, "cscope-prev-file",},
+ {cscreatelist, "cscope-create-list-of-files-to-index"},
{NULL, NULL,}
};
diff --git a/usr.bin/mg/keymap.c b/usr.bin/mg/keymap.c
index 54134242a23..94aead6560e 100644
--- a/usr.bin/mg/keymap.c
+++ b/usr.bin/mg/keymap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: keymap.c,v 1.49 2012/04/12 04:47:59 lum Exp $ */
+/* $OpenBSD: keymap.c,v 1.50 2012/06/07 15:15:04 lum Exp $ */
/* This file is in the public domain. */
@@ -39,17 +39,55 @@ struct KEYMAPE (2 + IMAPEXT) helpmap = {
}
};
-struct KEYMAPE (1 + IMAPEXT) ccmap = {
+static PF cCsc[] = {
+ cscallerfuncs, /* c */
+ csdefinition, /* d */
+ csegrep, /* e */
+ csfindfile, /* f */
+ rescan, /* g */
+ rescan, /* h */
+ csfindinc, /* i */
+ rescan, /* j */
+ rescan, /* k */
+ rescan, /* l */
+ rescan, /* m */
+ csnextmatch, /* n */
+ rescan, /* o */
+ csprevmatch, /* p */
+ rescan, /* q */
+ rescan, /* r */
+ cssymbol, /* s */
+ csfindtext /* t */
+};
+
+static struct KEYMAPE (1 + IMAPEXT) cCsmap = {
1,
1 + IMAPEXT,
rescan,
{
{
- CCHR('@'), CCHR('@'), (PF[]){ rescan }, NULL
+ 'c', 't', cCsc, NULL
}
}
};
+static PF cCs[] = {
+ NULL /* s */
+};
+
+struct KEYMAPE (2 + IMAPEXT) ccmap = {
+ 2,
+ 2 + IMAPEXT,
+ rescan,
+ {
+ {
+ CCHR('@'), CCHR('@'), (PF[]){ rescan }, NULL
+ },
+ {
+ 's', 's', cCs, (KEYMAP *) & cCsmap
+ }
+ }
+};
static PF cX4cF[] = {
poptofile, /* ^f */
diff --git a/usr.bin/mg/mg.1 b/usr.bin/mg/mg.1
index 3de7feeee71..83e7c9131ae 100644
--- a/usr.bin/mg/mg.1
+++ b/usr.bin/mg/mg.1
@@ -1,7 +1,7 @@
-.\" $OpenBSD: mg.1,v 1.60 2012/05/25 15:41:09 lum Exp $
+.\" $OpenBSD: mg.1,v 1.61 2012/06/07 15:15:04 lum Exp $
.\" This file is in the public domain.
.\"
-.Dd $Mdocdate: May 25 2012 $
+.Dd $Mdocdate: June 7 2012 $
.Dt MG 1
.Os
.Sh NAME
@@ -79,6 +79,14 @@ supports tag files created by
.Xr ctags 1 ,
allowing the user to quickly locate various object definitions.
Note though that emacs uses etags, not ctags.
+.Sh CSCOPE
+.Nm
+supports navigating source code using cscope.
+However,
+.Nm
+requires cscope and cscope-indexer executables to be present in
+.Ev PATH
+for it to work.
.Sh DEFAULT KEY BINDINGS
Normal editing commands are very similar to GNU Emacs.
In the following examples, C-x means Control-x, and M-x means Meta-x,
@@ -92,6 +100,24 @@ set-mark-command
beginning-of-line
.It C-b
backward-char
+.It C-c s c
+cscope-find-functions-calling-this-function
+.It C-c s d
+cscope-find-global-definition
+.It C-c s e
+cscope-find-egrep-pattern
+.It C-c s f
+cscope-find-this-file
+.It C-c s i
+cscope-find-files-including-file
+.It C-c s n
+cscope-next-symbol
+.It C-c s p
+cscope-prev-symbol
+.It C-c s s
+cscope-find-this-symbol
+.It C-c s t
+cscope-find-this-text-string
.It C-d
delete-char
.It C-e
@@ -369,6 +395,32 @@ This is a bit like a kill-region followed by a yank.
Count the number of lines matching the supplied regular expression.
.It count-non-matches
Count the number of lines not matching the supplied regular expression.
+.It cscope-find-this-symbol
+List the matches for the given symbol.
+.It cscope-find-global-definition
+List global definitions for the given literal.
+.It cscope-find-called-functions
+List functions called from the given function.
+.It cscope-find-functions-calling-this-function
+List functions calling the given function.
+.It cscope-find-this-text-string
+List locations matching the given text string.
+.It cscope-find-egrep-pattern
+List locations matching the given extended regular expression pattern.
+.It cscope-find-this-file
+List filenames matching the given filename.
+.It cscope-find-files-including-file
+List files that #include the given filename.
+.It cscope-next-symbol
+Navigate to the next match.
+.It cscope-prev-symbol
+Navigate to the previous match.
+.It cscope-next-file
+Nagivate to the next file.
+.It cscope-prev-file
+Navigate to the previous file.
+.It cscope-create-list-of-files-to-index
+Create cscope's List and Index in the given directory.
.It define-key
Prompts the user for a named keymap (mode),
a key, and an
diff --git a/usr.bin/mg/tags.c b/usr.bin/mg/tags.c
index 5ee9a9965bf..55574dd3779 100644
--- a/usr.bin/mg/tags.c
+++ b/usr.bin/mg/tags.c
@@ -33,7 +33,6 @@ static int addctag(char *);
static int atbow(void);
void closetags(void);
static int ctagcmp(struct ctag *, struct ctag *);
-static int curtoken(int, int, char *);
static int loadbuffer(char *);
static int loadtags(const char *);
static int pushtag(char *);
@@ -42,7 +41,6 @@ static struct ctag *searchtag(char *);
static char *strip(char *, size_t);
static void unloadtags(void);
-#define MAX_TOKEN 64
#define DEFAULTFN "tags"
char *tagsfn = NULL;