On Fri, Sep 02, 2011 at 02:23:28PM -0300, Christiano F. Haesbaert wrote:
> On 2 September 2011 14:17, Matthew Dempsky <[email protected]> wrote:
> > On Fri, Sep 2, 2011 at 8:55 AM, Sunil Nimmagadda
> > <[email protected]> wrote:
> >> This diff adds tags support to Mg. I am NOT an emacs user so if this
> >> combination is a bit odd then please excuse. It parses the tags file
> >> generated by ctags(1) and maintains a tree. M-. on first character of
> >> a word jumps to it's definition and M-* jumps back to previous location.
> >
> > I'd love to have ctags support in mg.
> >
>
> cscope would be cool too, if not too much bloat.
This diff adds some cscope support in mg. Keybindings are same as
xcscope that comes with emacs.
Find this symbol C-c s s
Find this global definition C-c s d
Find functions called by this function C-c s l
Find functions calling this function C-c s c
Find this text C-c s t
Find this egrep pattern C-c s e
Find this file C-c s f
Find files #including this file C-c s i
Find next symbol C-c s n
Find prev symbol C-c s p
Comments?
Index: Makefile
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/Makefile,v
retrieving revision 1.25
diff -u -p -r1.25 Makefile
--- Makefile 28 Nov 2011 04:41:39 -0000 1.25
+++ Makefile 29 Feb 2012 18:06:23 -0000
@@ -2,6 +2,9 @@
PROG= mg
+#Uncomment to build cscope support. Cscope package is required.
+CSCOPE= yes
+
LDADD+= -lcurses -lutil
DPADD+= ${LIBCURSES} ${LIBUTIL}
@@ -25,6 +28,11 @@ SRCS= autoexec.c basic.c buffer.c cinfo.
# More or less standalone extensions.
#
SRCS+= cmode.c dired.c grep.c tags.c theo.c
+
+.ifdef CSCOPE
+CFLAGS+= -DCSCOPE
+SRCS+= cscope.c
+.endif
afterinstall:
${INSTALL} -d ${DESTDIR}${DOCDIR}/mg
Index: buffer.c
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/buffer.c,v
retrieving revision 1.77
diff -u -p -r1.77 buffer.c
--- buffer.c 23 Jan 2011 00:45:03 -0000 1.77
+++ buffer.c 29 Feb 2012 16:51:02 -0000
@@ -792,10 +792,8 @@ notmodified(int f, int n)
return (TRUE);
}
-#ifndef NO_HELP
/*
- * Popbuf and set all windows to top of buffer. Currently only used by
- * help functions.
+ * Popbuf and set all windows to top of buffer.
*/
int
popbuftop(struct buffer *bp, int flags)
@@ -814,7 +812,6 @@ popbuftop(struct buffer *bp, int flags)
}
return (popbuf(bp, flags) != NULL);
}
-#endif
/*
* Return the working directory for the current buffer, terminated
Index: cscope.c
===================================================================
RCS file: cscope.c
diff -N cscope.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ cscope.c 29 Feb 2012 17:49:50 -0000
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012 Sunil Nimmagadda <[email protected]>
+ *
+ * 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/queue.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "def.h"
+
+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(const char *);
+static void csflush();
+static int do_cscope(int);
+static int getattr(const char *, char **, int *);
+static int jumptomatch();
+
+/*
+ * Find this symbol. Bound to C-c s s
+ */
+/* ARGSUSED */
+int
+cssymbol(int f, int n)
+{
+ return (do_cscope(0));
+}
+
+/*
+ * Find this global definition. Bound to C-c s d
+ */
+/* ARGSUSED */int
+csdefinition(int f, int n)
+{
+ return (do_cscope(1));
+}
+
+/*
+ * Find functions called by this function. Bound to C-c s l
+ */
+/* ARGSUSED */
+int
+csfuncalled(int f, int n)
+{
+ return (do_cscope(2));
+}
+
+/*
+ * Find functions calling this function. Bound to C-c s c
+ */
+/* ARGSUSED */
+int
+cscallerfuncs(int f, int n)
+{
+ return (do_cscope(3));
+}
+
+/*
+ * Find this text. Bound to C-c s t
+ */
+/* ARGSUSED */
+int
+csfindtext(int f, int n)
+{
+ return (do_cscope(4));
+}
+
+/*
+ * Find this egrep pattern. Bound to C-c s e
+ */
+/* ARGSUSED */
+int
+csegrep(int f, int n)
+{
+ return (do_cscope(6));
+}
+
+/*
+ * Find this file. Bound to C-c s f
+ */
+/* ARGSUSED */
+int
+csfindfile(int f, int n)
+{
+ return (do_cscope(7));
+}
+
+/*
+ * Find files #including this file. Bound to C-c s i
+ */
+/* ARGSUSED */
+int
+csfindinc(int f, int n)
+{
+ return (do_cscope(8));
+}
+
+/*
+ * 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());
+}
+
+/*
+ * 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()
+{
+ 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[BUFSIZ], cmd[BUFSIZ], title[BUFSIZ], *p, *buf;
+ int clen;
+ size_t len;
+
+ p = eread(csprompt[i], pattern, BUFSIZ, EFNEW | EFNUL);
+ if (p == NULL)
+ return (FALSE);
+ else if (p[0] == '\0')
+ 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, ""); /* blank line */
+
+ /* All lines are '\n' terminated */
+ while ((buf = fgetln(fpipe, &len)) != NULL) {
+ if (addentry(buf) != TRUE)
+ return (FALSE);
+ buf[len - 1] = '\0';
+ addline(bp, buf);
+ }
+ pclose(fpipe);
+ return (popbuftop(bp, WNONE));
+}
+
+/*
+ * For each line read from cscope output, extract the filename and lineno
+ * attributes and add them to the list.
+ */
+int
+addentry(const char *csline)
+{
+ struct csrecord *r;
+ struct csmatch *m;
+ int lineno;
+ char *fname;
+
+ r = NULL;
+ if (getattr(csline, &fname, &lineno) == FALSE)
+ return (FALSE);
+ if (addentryfn == NULL || strcmp(addentryfn, fname) != 0) {
+ if ((r = malloc(sizeof(struct csrecord))) == NULL)
+ goto cleanup;
+ addentryr = r;
+ r->filename = fname;
+ addentryfn = fname;
+ 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);
+ } else {
+ if ((m = malloc(sizeof(struct csmatch))) == NULL)
+ goto cleanup;
+ m->lineno = lineno;
+ TAILQ_INSERT_TAIL(&addentryr->matches, m, entry);
+ }
+ return (TRUE);
+cleanup:
+ free(r);
+ free(fname);
+ return (FALSE);
+}
+
+/*
+ * A cscope line is of the form <filename> <function> <lineno> <text pattern>
+ * Extract the filename and lineno parts and return them.
+ */
+int
+getattr(const char *csline, char **fname, int *lineno)
+{
+ char *p, *line, *strlineno;
+ const char *errstr;
+
+ /* get the filename column */
+ if ((p = strchr(csline, ' ')) == NULL)
+ return (FALSE);
+ line = p + 1;
+ if ((*fname = strndup(csline, p - csline)) == NULL)
+ return (FALSE);
+ /* ignore function column */
+ if ((p = strchr(line, ' ')) == NULL)
+ return (FALSE);
+ line = p + 1;
+ /* extract lineno */
+ if ((p = strchr(line, ' ')) == NULL)
+ return (FALSE);
+ if ((strlineno = strndup(line, p - line)) == NULL)
+ return (FALSE);
+ *lineno = strtonum(strlineno, INT_MIN, INT_MAX, &errstr);
+ if (errstr)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * Delete entries and free memory.
+ */
+void
+csflush()
+{
+ 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;
+}
Index: def.h
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/def.h,v
retrieving revision 1.118
diff -u -p -r1.118 def.h
--- def.h 10 Dec 2011 14:09:48 -0000 1.118
+++ def.h 29 Feb 2012 16:51:02 -0000
@@ -520,6 +520,20 @@ int findtag(int, int);
int poptag(int, int);
int tagsvisit(int, int);
+#ifdef CSCOPE
+/* 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 csnextmatch(int, int);
+int csprevmatch(int, int);
+#endif /* CSCOPE */
+
/* extend.c X */
int insert(int, int);
int bindtokey(int, int);
Index: funmap.c
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/funmap.c,v
retrieving revision 1.35
diff -u -p -r1.35 funmap.c
--- funmap.c 28 Nov 2011 04:41:39 -0000 1.35
+++ funmap.c 29 Feb 2012 18:00:14 -0000
@@ -196,6 +196,18 @@ static struct funmap functnames[] = {
{showcpos, "what-cursor-position",},
{filewrite, "write-file",},
{yank, "yank",},
+#ifdef CSCOPE
+ {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",},
+#endif /* CSCOPE */
{NULL, NULL,}
};
Index: keymap.c
===================================================================
RCS file: /home/sunil/cvs/src/usr.bin/mg/keymap.c,v
retrieving revision 1.46
diff -u -p -r1.46 keymap.c
--- keymap.c 28 Nov 2011 04:41:39 -0000 1.46
+++ keymap.c 29 Feb 2012 16:51:02 -0000
@@ -41,6 +41,57 @@ struct KEYMAPE (2 + IMAPEXT) helpmap = {
};
#endif /* !NO_HELP */
+#ifdef CSCOPE
+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,
+ {
+ {
+ '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
+ }
+ }
+};
+#else
struct KEYMAPE (1 + IMAPEXT) ccmap = {
1,
1 + IMAPEXT,
@@ -51,7 +102,7 @@ struct KEYMAPE (1 + IMAPEXT) ccmap = {
}
}
};
-
+#endif /* CSCOPE */
static PF cX4cF[] = {
poptofile, /* ^f */