On Fri, Sep 02, 2011 at 02:23:28PM -0300, Christiano F. Haesbaert wrote: > On 2 September 2011 14:17, Matthew Dempsky <matt...@dempsky.org> wrote: > > On Fri, Sep 2, 2011 at 8:55 AM, Sunil Nimmagadda > > <su...@sunilnimmagadda.com> 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 <su...@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/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 */