/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ #include "jove.h" #ifdef ABBREV RCS("$Id: abbrev.c,v 14.31.0.1 1993/07/07 12:12:56 tom Exp tom $") #include "ctype.h" #include "io.h" #include "re.h" #define HASHSIZE 19 typedef struct abbrev Abbr; struct abbrev { unsigned int a_hash; char *a_abbrev, *a_phrase; Abbr *a_next; data_obj *a_cmdhook; }; #define GLOBAL NMAJORS private Abbr *A_tables[NMAJORS + 1][HASHSIZE] ZERO; DEF_INT( "auto-case-abbrev", AutoCaseAbbrev, V_BOOL ) _IF(def ABBREV) = YES; _IF(def PRIVATE) DEF_INT( "save-substituted-abbrevs", SavSAbbrev, V_BOOL ) _IF(def ABBREV) ZERO; _IF(def PRIVATE) private unsigned int hash __(( const char *_(abbrev) )); private Abbr *lookup __(( int _(table), const char *_(abbrev), unsigned _(hashval) )); private char *crlf __(( char *_(str), int _(cr_or_lf) )); private void define __(( int _(table), const char *_(abbrev), const char *_(phrase) )), save_abbrevs __(( const char *_(file) )), rest_abbrevs __(( const char *_(file) )); private unsigned int hash(a) register const char *a; { register unsigned int hashval = *a++; register int c; while (c = *a++) hashval = (hashval << 2) + c; return hashval; } private Abbr * lookup(table, abbrev, hashval) int table; const char *abbrev; unsigned int hashval; { register Abbr *ap; register unsigned int h = hashval; #ifdef MSCBUG /* MSC 4.3 compiler bug!%^#$*# */ register Abbr **tp = A_tables[table]; if (ap = tp[h % HASHSIZE]) #else if (ap = A_tables[table][h % HASHSIZE]) #endif do { if (ap->a_hash == h && strcmp(ap->a_abbrev, abbrev) == 0) break; } while (ap = ap->a_next); return ap; } private void define(table, abbrev, phrase) int table; const char *abbrev, *phrase; { register Abbr *ap; register unsigned int h = hash(abbrev); if ((ap = lookup(table, abbrev, h)) == NULL) { register struct abbrev **tp = &A_tables[table][h % HASHSIZE]; ap = (struct abbrev *) emalloc(sizeof *ap); ap->a_hash = h; ap->a_abbrev = copystr(abbrev); ap->a_next = (*tp); (*tp) = ap; ap->a_cmdhook = NULL; } else free(ap->a_phrase); ap->a_phrase = copystr(phrase); } DEF_CMD( "expand-abbrev", AbbrevExpand, NO ) _IF(def ABBREV) { register char *wp = &genbuf[LBSIZE - 1]; int Cap_count = 0; { /* copy last typed word to buffer */ register int c; register const char *cp = &linebuf[curchar]; *wp = '\0'; while (cp > linebuf && isword(c = *--cp)) { if (isupper(c)) { Cap_count++; } *--wp = c; } if (*wp == '\0') /* not adjacent to word */ return; } { register const Abbr *ap; { register unsigned int h; /* Try to match literal abbrev first; if this fails, then try again as lowercase abbrev if auto-capitalize is on, but only if the literal contained some uppercase characters. */ if ((ap = lookup(curbuf->b_major, wp, h = hash(wp))) || (ap = lookup(GLOBAL, wp, h))) Cap_count = 0; else if (!(Cap_count && True(AutoCaseAbbrev) && ((ap = lookup(curbuf->b_major, wp, h = hash(strlwr(wp)))) || (ap = lookup(GLOBAL, wp, h))))) return; } { register int c; register int o_exp = exp; /* save numeric argument! */ /* * use DelNChar with negative argument since DelPChar behaves funny * in OverWrite mode. It also sets mark so that you can change your * mind about the abbrev expansion. `this_cmd' is cleared to prevent * subsequent kills to be appended to killed abbrev. */ exp = wp - genbuf - (LBSIZE - 1), exp_p = SavSAbbrev, DelNChar(); this_cmd = 0; wp = ap->a_phrase; if (*wp) { set_mark(); if (Cap_count) { c = *wp++; exp = 1, Insert(toupper(c)); if (--Cap_count) { while (*wp) { if (isword(c)) c = *wp++; else c = toupper(*wp++); Insert(c); } } } ins_str(wp, NO); } if (ap->a_cmdhook) DoTimes(ExecCmd(ap->a_cmdhook), 1); exp = o_exp; /* restore numeric argument (oh well...) */ } } } extern const char * const MajorName[]; private const char hdr_pat[] = "^------\\([^ ]* \\)\\{Mode ,\\}abbrevs------$", /* (match optional "Mode" for backward compatibility) */ hdr_fmt[] = "------%sabbrevs------\n"; /* * replace linefeeds to CR or vice versa * this kludge to allow embedded newlines in abbrevs */ private char * crlf(str, from) char *str; register int from; { register char *s = str; while (s = index(s, from)) *s++ = (from == '\n') ? '\r' : '\n'; return str; } private void save_abbrevs(file) const char *file; { register File *fp; register const Abbr *ap; register int mode, i, count = 0; fp = open_file(file, iobuff, F_WRITE|F_TEXT|F_COMPLAIN); { mode = 0; } do { fprintf(fp, hdr_fmt, MajorName[mode]); { i = HASHSIZE - 1; } do { if (ap = A_tables[mode][i]) do { fprintf(fp, "%s:%s\n", ap->a_abbrev, crlf(strcpy(genbuf, ap->a_phrase), '\n')); count++; } while (ap = ap->a_next); } while (--i >= 0); } while (++mode <= GLOBAL); f_close(fp); add_mess(" %d written.", count); } /* * The format of abbrev files recognized has been extended: * everything before the first mode header line is taken as a Global Abbrev, * and abbrevs following an unrecognized mode header line are silently ignored. */ private void rest_abbrevs(file) const char *file; { register int mode = GLOBAL; register char *phrase_p; register char *line = genbuf; register File *fp; REcompile(hdr_pat, YES, compbuf); fp = open_file(file, iobuff, F_READ|F_TEXT|F_COMPLAIN|F_QUIET); while (f_gets(fp, line, LBSIZE) == 0 /*!EOF*/) { if (re_sindex(line, 0, compbuf)) { /* a header line */ putmatch(1, line, LBSIZE); mode = match(MajorName, line); continue; } if (mode < 0) /* ignore unknown abbrev modes */ continue; if (!(phrase_p = index(line, ':')) || phrase_p == line) complain("\"%s\":%d: Abbrev. format error.", file, io_lines); *phrase_p++ = '\0'; /* Null terminate the abbrev. */ define(mode, line, crlf(phrase_p, '\r')); } f_close(fp); message(NullStr); } private const char GlobalPrompt[] = "Global Abbrev: "; #define AbbrPrompt (GlobalPrompt + 7) /* cheat */ private const char AbbrDelim[] = " \r\n"; DEF_CMD( "define-mode-word-abbrev", DefAbbrev, ARG(NO) ); _IF(def ABBREV) DEF_CMD( "define-global-word-abbrev", DefAbbrev, ARG(YES) ) _IF(def ABBREV) { char abbrbuf[LBSIZE]; register char *abbrev = abbrbuf; register const char *prompt = AbbrPrompt; register int mode = curbuf->b_major; register Abbr *ap; if ((LastCmd->Type & ARG(YES)) || exp_p) { /* global-abbrev */ prompt = GlobalPrompt; mode = GLOBAL; } strcpy(abbrev, do_ask(AbbrDelim, (int (*)()) 0, (char *) 0, prompt)); # define phrase ((!InJoverc && \ (ap = lookup(mode, abbrev, hash(abbrev)))) ? \ ap->a_phrase : (char *) 0) define(mode, abbrev, crlf(ask(phrase, "%s%s phrase: ", prompt, abbrev), '\r')); # undef phrase } DEF_CMD( "write-word-abbrev-file", AbbrevIO, ARG(WRITE) ); _IF(def ABBREV) DEF_CMD( "read-word-abbrev-file", AbbrevIO, ARG(READ) ) _IF(def ABBREV) { char filebuf[FILESIZE]; register char *abbr_file = ask_file((char *) 0, (char *) 0, filebuf); register void (*what)__(( const char *_(filename) )) = rest_abbrevs; if (LastCmd->Type & ARG(WRITE)) what = save_abbrevs; (*what)(abbr_file); } #ifndef TINY DEF_CMD( "edit-word-abbrevs", EditAbbrevs, NO ) _IF(def ABBREV)_IF(ndef TINY) { EditParam(save_abbrevs, rest_abbrevs, "Edit Abbreviations"); } #endif DEF_CMD( "bind-macro-to-word-abbrev", BindMtoW, NO ) _IF(def ABBREV) { register Abbr *ap; register const char *abbrev; register unsigned int h; abbrev = do_ask(AbbrDelim, (int (*)()) 0, (char *) 0, AbbrPrompt); if ((ap = lookup(curbuf->b_major, abbrev, h = hash(abbrev))) == NULL && (ap = lookup(GLOBAL, abbrev, h)) == NULL) complain("%s: unknown abbrev.", abbrev); ap->a_cmdhook = findmac("Macro: "); } #endif /* ABBREV */ /*====================================================================== * $Log: abbrev.c,v $ * Revision 14.31.0.1 1993/07/07 12:12:56 tom * (F_TEXT): new option for f_open et al. * * Revision 14.31 1993/02/18 02:56:34 tom * add hash parameter to lookup() to avoid unnecessary computation of hash * value; lookup literal abbrev, and expand it without auto-casing, before * trying lowercased abbrev if "auto-case-abbrev" is in effect; remove * implicit abbrev size limit. * * Revision 14.30 1993/02/06 00:48:32 tom * cleanup whitespace; some random optimizations. * * Revision 14.26 1992/08/26 23:56:49 tom * add "expand-abbrev" command; PRIVATE-ized some Variable defs; * add RCS directives. * */