home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1990,1991,1992 Chris and John Downey */
- #ifndef lint
- static char *sccsid = "@(#)map.c 2.1 (Chris & John Downey) 7/29/92";
- #endif
-
- /***
-
- * program name:
- xvi
- * function:
- PD version of UNIX "vi" editor, with extensions.
- * module name:
- map.c
- * module function:
- Keyboard input/pushback routines, "map" command.
-
- Note that we provide key mapping through a different interface,
- so that cursor key mappings etc do not show up to the user.
- This works by having a two-stage process; first keymapping is
- done, and then the result is fed through the normal mapping
- process. The intent of the keymapping stage is to convert
- machine-local keys into a standard form.
-
- * bug:
- If a map fails, we just pass all characters which had already
- been accepted, plus the character which caused the mismatch,
- straight through. This is not quite correct because we might
- have got a good match starting at the very next character, i.e.
- if we have mapped
-
- foo to bar
-
- and get input "ffoo", then the seconf 'f' will cause the map to
- fail and both characters will go through, and so the whole thing
- will pass through unmapped.
-
- The only way around this problem is to introduce another flexbuf
- on the input side of the keymap stage, to give us somewhere to
- put all characters after the first, when a map fails. I.e. in the
- case above, we would pass the first 'f' through to the "mp_dest"
- flexbuf, and stuff any characters after that into "mp_src".
-
- * history:
- STEVIE - ST Editor for VI Enthusiasts, Version 3.10
- Originally by Tim Thompson (twitch!tjt)
- Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
- Heavily modified by Chris & John Downey
-
- ***/
-
- #include "xvi.h"
-
- /*
- * This is the fundamental structure type which is used
- * to hold mappings from one string to another.
- */
- typedef struct map {
- struct map *m_next;
- char *m_lhs; /* lhs of map */
- char *m_rhs; /* rhs of map */
- unsigned int m_same; /* no characters same as next map */
- } Map;
-
- /*
- * This structure holds a current position while scanning a map list.
- * It is also effectively used to form a chain of mapping structures,
- * interconnected with flexbufs.
- */
- typedef struct mpos {
- Map *mp_map;
- int mp_index;
- Flexbuf *mp_src;
- Flexbuf *mp_dest;
- } Mpos;
-
- /*
- * Two mapping structures exist; one for "map", and one for "map!".
- */
- static Map *cmd_map = NULL;
- static Map *ins_map = NULL;
- static Map *key_map = NULL;
-
- /*
- * This is the position in cmd_map/ins_map when we are waiting for
- * the next character. When not waiting, mp_map is NULL (as at start).
- * Also stores flexbuf pointers for input and output at each stage.
- */
- static Flexbuf getcbuff;
- static Flexbuf inputbuff;
- static Mpos npos = { NULL, 0, &inputbuff, &getcbuff };
- static Mpos kpos = { NULL, 0, NULL, &inputbuff };
-
- /*
- * This is used for "display" mode; it records the current map which
- * is being displayed. It is used by show_map().
- */
- static Map *curmap;
- static char *show_map P((void));
-
- static void mapthrough P((void));
- static bool_t process_map P((int, Mpos *));
- static void calc_same P((Map *));
- static void map_failed P((Mpos *));
- static void insert_map P((Map **, char *, char *, bool_t));
- static void delete_map P((Map **, char *));
-
- /*VARARGS1*/
- /*PRINTFLIKE*/
- void
- stuff
- #ifdef __STDC__
- (char *format, ...)
- #else /* not __STDC__ */
- (format, va_alist)
- char *format;
- va_dcl
- #endif
- {
- va_list argp;
-
- VA_START(argp, format);
- (void) vformat(npos.mp_dest, format, argp);
- va_end(argp);
- }
-
- int
- map_getc()
- {
- return(flexempty(npos.mp_dest) ? EOF : flexpopch(npos.mp_dest));
- }
-
- void
- map_char(c)
- register int c;
- {
- /*
- * Send the input character through the keymap list.
- */
- if (kpos.mp_map == NULL) {
- kpos.mp_map = key_map;
- kpos.mp_index = 0;
- }
- if (process_map(c, &kpos) == FALSE) {
- /*
- * Send resulting output through the normal map list.
- */
- kpos.mp_map = NULL;
- mapthrough();
- }
- }
-
- /*
- * Process any characters in the input buffer through the
- * cmd_map/ins_map lists into the output buffer, whence
- * characters go into the editor itself.
- */
- static void
- mapthrough()
- {
- while (!flexempty(npos.mp_src)) {
- if (npos.mp_map == NULL) {
- if (State == NORMAL) {
- npos.mp_map = cmd_map;
- } else if (State == INSERT || State == REPLACE) {
- npos.mp_map = ins_map;
- }
- npos.mp_index = 0;
- }
-
- if (process_map(flexpopch(npos.mp_src), &npos) == FALSE) {
- npos.mp_map = NULL;
- }
- }
- }
-
- /*
- * Process the given character through the maplist pointed to
- * by the given position. Returns TRUE if we should continue,
- * or FALSE if this attempt at mapping has terminated (either
- * due to success or definite failure).
- */
- static bool_t
- process_map(c, pos)
- register int c;
- register Mpos *pos;
- {
- register Map *tmp;
- register int ind;
-
- ind = pos->mp_index;
- for (tmp = pos->mp_map; tmp != NULL; tmp = tmp->m_next) {
- if (tmp->m_lhs[ind] == c) {
- if (tmp->m_lhs[ind + 1] == '\0') {
- /*
- * Found complete match. Insert the result into
- * the appropriate output buffer, according to
- * whether "remap" is set or not.
- */
- (void) lformat((Pb(P_remap) && pos->mp_src != NULL) ?
- pos->mp_src : pos->mp_dest, "%s", tmp->m_rhs);
- return(FALSE);
- } else {
- /*
- * Found incomplete match,
- * keep going.
- */
- pos->mp_map = tmp;
- pos->mp_index++;
- }
- return(TRUE);
- }
-
- /*
- * Can't move on to next map entry unless the m_same
- * field is sufficient that the match so far would
- * have worked.
- */
- if (tmp->m_same < ind) {
- break;
- }
- }
-
- map_failed(pos);
-
- /*
- * Don't forget to re-stuff the character we have just received.
- */
- (void) flexaddch(pos->mp_dest, c);
- return(FALSE);
- }
-
- void
- map_timeout()
- {
- if (kpos.mp_map != NULL) {
- map_failed(&kpos);
- mapthrough();
- } else {
- map_failed(&npos);
- }
- }
-
- bool_t
- map_waiting()
- {
- return(kpos.mp_map != NULL || npos.mp_map != NULL);
- }
-
- /*
- * This routine is called when a timeout has occurred.
- */
- static void
- map_failed(pos)
- Mpos *pos;
- {
- register char *cp;
- register Flexbuf *fbp;
- register int i;
-
- if (pos->mp_map != NULL) {
- fbp = pos->mp_dest;
- for (i = 0, cp = pos->mp_map->m_lhs; i < pos->mp_index; i++) {
- (void) flexaddch(fbp, cp[i]);
- }
- pos->mp_map = NULL;
- }
- }
-
- /*
- * Insert the key map lhs as mapping into rhs.
- */
- void
- xvi_keymap(lhs, rhs)
- char *lhs;
- char *rhs;
- {
- insert_map(&key_map, lhs, rhs, FALSE);
- }
-
- /*
- * Insert the entry "lhs" as mapping into "rhs".
- */
- void
- xvi_map(argc, argv, exclam, inter)
- int argc;
- char *argv[];
- bool_t exclam;
- bool_t inter;
- {
- switch (argc) {
- case 2: /* valid input */
- if (argv[0][0] == '\0') {
- if (inter) {
- show_message(curwin, "Usage: map lhs rhs");
- }
- return;
- }
- insert_map(exclam ? &ins_map : &cmd_map, argv[0], argv[1], inter);
- break;
-
- case 0:
- curmap = exclam ? ins_map : cmd_map;
- disp_init(curwin, show_map, (int) curwin->w_ncols, FALSE);
- break;
-
- default:
- if (inter) {
- show_message(curwin, "Wrong number of arguments to map");
- }
- }
- }
-
- static void
- insert_map(maplist, left, right, interactive)
- Map **maplist;
- char *left;
- char *right;
- bool_t interactive;
- {
- char *lhs; /* saved lhs of map */
- char *rhs; /* saved rhs of map */
- Map *mptr; /* new map element */
- Map **p; /* used for loop to find position */
- int rel;
-
- lhs = strsave(left);
- if (lhs == NULL || (rhs = strsave(right)) == NULL) {
- if (interactive) {
- show_message(curwin, "no memory for that map");
- }
- return;
- }
-
- mptr = (Map *) alloc(sizeof(Map));
- if (mptr == NULL) {
- free(lhs);
- free(rhs);
- return;
- }
-
- mptr->m_lhs = lhs;
- mptr->m_rhs = rhs;
-
- p = maplist;
- if ((*p) == NULL || strcmp((*p)->m_lhs, lhs) > 0) {
- /*
- * Either there are no maps yet, or the one
- * we want to enter should go at the start.
- */
- mptr->m_next = *p;
- *p = mptr;
- calc_same(mptr);
- } else if (strcmp((*p)->m_lhs, lhs) == 0) {
- /*
- * We need to replace the rhs of the first map.
- */
- free(lhs);
- free((char *) mptr);
- free((*p)->m_rhs);
- (*p)->m_rhs = rhs;
- calc_same(*p);
- } else {
- for ( ; (*p) != NULL; p = &((*p)->m_next)) {
- /*
- * Set "rel" to +ve if the next element is greater
- * than the current one, -ve if it is less, or 0
- * if they are the same (if the lhs is the same).
- */
- rel = ((*p)->m_next == NULL) ? 1 :
- strcmp((*p)->m_next->m_lhs, lhs);
-
- if (rel >= 0) {
- if (rel > 0) {
- /*
- * The right place to insert
- * the new map.
- */
- mptr->m_next = (*p)->m_next;
- (*p)->m_next = mptr;
- calc_same(*p);
- calc_same(mptr);
- } else /* rel == 0 */ {
- /*
- * The lhs of the new map is identical
- * to that of an existing map.
- * Replace the old rhs with the new.
- */
- free(lhs);
- free((char *) mptr);
- mptr = (*p)->m_next;
- free(mptr->m_rhs);
- mptr->m_rhs = rhs;
- calc_same(mptr);
- }
- return;
- }
- }
- }
- }
-
- void
- xvi_unmap(argc, argv, exclam, inter)
- int argc;
- char *argv[];
- bool_t exclam;
- bool_t inter;
- {
- int count;
-
- if (argc < 1) {
- if (inter) {
- show_message(curwin, "But what do you want me to unmap?");
- }
- return;
- }
-
- for (count = 0; count < argc; count++) {
- delete_map(exclam ? &ins_map : &cmd_map, argv[count]);
- }
- }
-
- static void
- delete_map(maplist, lhs)
- Map **maplist;
- char *lhs;
- {
- Map *p;
-
- p = *maplist;
- if (p != NULL && strcmp(p->m_lhs, lhs) == 0) {
- *maplist = p->m_next;
- } else {
- for (; p != NULL; p = p->m_next) {
- if (p->m_next != NULL && strcmp(lhs, p->m_next->m_lhs) == 0) {
- Map *tmp;
-
- tmp = p->m_next;
- p->m_next = p->m_next->m_next;
- free(tmp->m_lhs);
- free(tmp->m_rhs);
- free((char *) tmp);
- calc_same(p);
- }
- }
- }
- }
-
- static void
- calc_same(mptr)
- Map *mptr;
- {
- register char *a, *b;
-
- mptr->m_same = 0;
- if (mptr->m_next != NULL) {
- for (a = mptr->m_lhs, b = mptr->m_next->m_lhs; *a == *b; a++, b++) {
- mptr->m_same++;
- }
- }
- }
-
- static char *
- show_map()
- {
- static Flexbuf buf;
-
- /*
- * Have we reached the end?
- */
- if (curmap == NULL) {
- return(NULL);
- }
-
- flexclear(&buf);
- (void) lformat(&buf, "%-18.18s %-s", curmap->m_lhs, curmap->m_rhs);
- curmap = curmap->m_next;
- return flexgetstr(&buf);
- }
-