Hello, This diff generalize the hooks execution and allows to define new hook execution points. For example if your .mg is now...
auto-execute *.c c-mode then with this diff you can change it to... add-hook find-file-hook c-mode add-hook before-save-hook deltrailspace find-file-hook type hooks get executed every time a file is read in and before-save-hook type hooks get executed when a buffer is about to be saved. deltrailspace is a hook that removes trailing whitespace before saving a buffer whose filename matches *.[ch1-9] 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 22 Feb 2012 18:06:59 -0000 @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c tags.c theo.c +SRCS+= cmode.c dired.c hookexec.c hooks.c grep.c tags.c theo.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg 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 22 Feb 2012 18:09:04 -0000 @@ -654,6 +654,19 @@ int next_error(int, int); int globalwdtoggle(int, int); int compile(int, int); +/* hooks.c */ +void cmode_hook(void); +void deltspace_hook(void); + +/* hookexec.c */ +enum hooktype { + HOOKTYPE_UNDEF, + HOOKTYPE_FIND_FILE, + HOOKTYPE_BEFORE_SAVE +}; +int addhook(int, int); +void exechooks(enum hooktype); + /* * Externals. */ Index: file.c =================================================================== RCS file: /home/sunil/cvs/src/usr.bin/mg/file.c,v retrieving revision 1.76 diff -u -p -r1.76 file.c --- file.c 31 Aug 2011 08:58:29 -0000 1.76 +++ file.c 22 Feb 2012 18:11:38 -0000 @@ -238,6 +238,8 @@ readin(char *fname) free(ael); } + exechooks(HOOKTYPE_FIND_FILE); + /* no change */ curbp->b_flag &= ~BFCHG; @@ -572,6 +574,8 @@ buffsave(struct buffer *bp) return (s); } + exechooks(HOOKTYPE_BEFORE_SAVE); + if (makebackup && (bp->b_flag & BFBAK)) { s = fbackupfile(bp->b_fname); /* hard error */ 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 22 Feb 2012 18:13:32 -0000 @@ -21,6 +21,7 @@ static struct funmap *funs; static struct funmap functnames[] = { #ifndef NO_HELP + {addhook, "add-hook",}, {apropos_command, "apropos",}, #endif /* !NO_HELP */ {auto_execute, "auto-execute", }, Index: hookexec.c =================================================================== RCS file: hookexec.c diff -N hookexec.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ hookexec.c 22 Feb 2012 19:00:40 -0000 @@ -0,0 +1,157 @@ +/* + * 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 <sys/tree.h> + +#include "def.h" + +struct hook; +typedef void (*HF)(void); + +static int hcmp(struct hook *, struct hook *); +static enum hooktype hlookup(char *); +static int addhook_helper(enum hooktype, HF); +static HF hfunction(const char *); + +struct hfname +{ + HF fp; + const char *name; +}; + +static struct hfname hfuncnames [] = { + {cmode_hook, "c-mode"}, + {deltspace_hook, "deltrailspace"}, + {NULL, NULL} +}; + +struct hookfunc { + SLIST_ENTRY(hookfunc) entry; + HF fp; +}; + +struct hook { + RB_ENTRY(hook) entry; + SLIST_HEAD(, hookfunc) hfuncs; + enum hooktype t; + +}; + +/* key is enum hooktype and value is a list of HF. */ +static RB_HEAD(hookmap, hook) hmap = RB_INITIALIZER(&hmap); +RB_GENERATE(hookmap, hook, entry, hcmp); + +int +hcmp(struct hook *h1, struct hook *h2) +{ + return (h1->t != h2->t); +} + +/* + * Determine hooktype, hookfunction and add it to the tree. + */ +/* ARGSUSED */ +int +addhook(int f, int n) +{ + char buf[NXNAME], *hfuncname, *htname; + enum hooktype ht; + HF fp; + + htname = eread("hook type: ", buf, NXNAME, EFNEW); + if (htname == NULL) + return (FALSE); + else if ((ht = hlookup(htname)) == HOOKTYPE_UNDEF) + return (FALSE); + + hfuncname = eread("command: ", buf, NXNAME, EFNEW); + if (hfuncname == NULL) + return (FALSE); + else if ((fp = hfunction(hfuncname)) == NULL) + return (FALSE); + + return addhook_helper(ht, fp); +} + +/* + * Helper function to add an entry to tree. If hooktype not present + * in tree initialize list and add fp else just append fp to the list. + */ +int +addhook_helper(enum hooktype t, HF fp) +{ + struct hook h, *hnew, *res; + struct hookfunc *hf; + + if((hf = malloc(sizeof *hf)) == NULL) + return (FALSE); + hf->fp = fp; + h.t = t; + if ((res = RB_FIND(hookmap, &hmap, &h)) == NULL) { + if ((hnew = malloc(sizeof *hnew)) == NULL) + goto cleanup; + hnew->t = t; + SLIST_INIT(&hnew->hfuncs); + SLIST_INSERT_HEAD(&hnew->hfuncs, hf, entry); + RB_INSERT(hookmap, &hmap, hnew); + } else + SLIST_INSERT_HEAD(&res->hfuncs, hf, entry); + return (TRUE); +cleanup: + free(hf); + return (FALSE); +} + +/* + * For a given hooktype find the list of functions in tree and + * execute them sequentially. + */ +void +exechooks(enum hooktype t) +{ + struct hook h, *res; + struct hookfunc *hf; + + h.t = t; + if ((res = RB_FIND(hookmap, &hmap, &h)) == NULL) + return; + SLIST_FOREACH(hf, &res->hfuncs, entry) + (hf->fp)(); +} + +enum hooktype +hlookup(char *s) +{ + if (strcmp(s, "before-save-hook") == 0) + return (HOOKTYPE_BEFORE_SAVE); + else if (strcmp(s, "find-file-hook") == 0) + return (HOOKTYPE_FIND_FILE); + + return (HOOKTYPE_UNDEF); +} + +HF +hfunction(const char *name) +{ + struct hfname *p; + + /* Linear lookup since we have very few hooks for now */ + for (p = hfuncnames; p->name != NULL; p++) + if (strcmp(p->name, name) == 0) + return (p->fp); + return (NULL); +} Index: hooks.c =================================================================== RCS file: hooks.c diff -N hooks.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ hooks.c 22 Feb 2012 18:31:43 -0000 @@ -0,0 +1,61 @@ +/* + * 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 <ctype.h> +#include <fnmatch.h> + +#include "def.h" + +static void ttrim(struct line *); + +/* + * Enable c-mode for C files. + */ +void +cmode_hook(void) +{ + if (fnmatch("*.c", curbp->b_fname, 0) == 0) + cmode(0, 1); +} + +/* + * Delete trailing whitespace for C and manpage sources. + */ +void +deltspace_hook(void) +{ + struct line *lp; + + lp = curbp->b_headp; + if (fnmatch("*.[ch1-9]", curbp->b_fname, 0) != 0) + return; + for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = lforw(lp)) + if (lp->l_text != NULL) + ttrim(lp); +} + +/* + * Lines are not NUL terminated, reduce l_used to actually trim. + */ +void +ttrim(struct line *lp) +{ + char *s; + + s = lp->l_text + lp->l_used - 1; + while (isspace(*s) && s-- > lp->l_text) + lp->l_used--; +}