Annotation of src/usr.bin/vim/getchar.c, Revision 1.2
1.2 ! downsj 1: /* $OpenBSD: getchar.c,v 1.1.1.1 1996/09/07 21:40:26 downsj Exp $ */
1.1 downsj 2: /* vi:set ts=4 sw=4:
3: *
4: * VIM - Vi IMproved by Bram Moolenaar
5: *
6: * Do ":help uganda" in Vim to read copying and usage conditions.
7: * Do ":help credits" in Vim to see a list of people who contributed.
8: */
9:
10: /*
11: * getchar.c
12: *
13: * functions related with getting a character from the user/mapping/redo/...
14: *
15: * manipulations with redo buffer and stuff buffer
16: * mappings and abbreviations
17: */
18:
19: #include "vim.h"
20: #include "globals.h"
21: #include "proto.h"
22: #include "option.h"
23:
24: /*
25: * structure used to store one block of the stuff/redo/macro buffers
26: */
27: struct bufblock
28: {
29: struct bufblock *b_next; /* pointer to next bufblock */
30: char_u b_str[1]; /* contents (actually longer) */
31: };
32:
33: #define MINIMAL_SIZE 20 /* minimal size for b_str */
34:
35: /*
36: * header used for the stuff buffer and the redo buffer
37: */
38: struct buffheader
39: {
40: struct bufblock bh_first; /* first (dummy) block of list */
41: struct bufblock *bh_curr; /* bufblock for appending */
42: int bh_index; /* index for reading */
43: int bh_space; /* space in bh_curr for appending */
44: };
45:
46: static struct buffheader stuffbuff = {{NULL, {NUL}}, NULL, 0, 0};
47: static struct buffheader redobuff = {{NULL, {NUL}}, NULL, 0, 0};
48: static struct buffheader old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};
49: static struct buffheader recordbuff = {{NULL, {NUL}}, NULL, 0, 0};
50:
51: /*
52: * when block_redo is TRUE redo buffer will not be changed
53: * used by edit() to repeat insertions and 'V' command for redoing
54: */
55: static int block_redo = FALSE;
56:
57: /*
58: * structure used for mapping
59: */
60: struct mapblock
61: {
62: struct mapblock *m_next; /* next mapblock */
63: char_u *m_keys; /* mapped from */
64: int m_keylen; /* strlen(m_keys) */
65: char_u *m_str; /* mapped to */
66: int m_mode; /* valid mode */
67: int m_noremap; /* if non-zero no re-mapping for m_str */
68: };
69:
70: static struct mapblock maplist = {NULL, NULL, 0, NULL, 0, 0};
71: /* first dummy entry in maplist */
72:
73: /*
74: * variables used by vgetorpeek() and flush_buffers()
75: *
76: * typebuf[] contains all characters that are not consumed yet.
77: * typebuf[typeoff] is the first valid character in typebuf[].
78: * typebuf[typeoff + typelen - 1] is the last valid char.
79: * typebuf[typeoff + typelen] must be NUL.
80: * The part in front may contain the result of mappings, abbreviations and
81: * @a commands. The length of this part is typemaplen.
82: * After it are characters that come from the terminal.
83: * no_abbr_cnt is the number of characters in typebuf that should not be
84: * considered for abbreviations.
85: * Some parts of typebuf may not be mapped. These parts are remembered in
86: * noremapbuf, which is the same length as typebuf and contains TRUE for the
87: * characters that are not to be remapped. noremapbuf[typeoff] is the first
88: * valid flag.
89: * (typebuf has been put in globals.h, because check_termcode() needs it).
90: */
91: static char_u *noremapbuf = NULL; /* flags for typeahead characters */
92: #define TYPELEN_INIT (3 * (MAXMAPLEN + 3))
93: static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf */
94: static char_u noremapbuf_init[TYPELEN_INIT]; /* initial noremapbuf */
95:
96: static int typemaplen = 0; /* nr of mapped characters in typebuf */
97: static int no_abbr_cnt = 0; /* nr of chars without abbrev. in typebuf */
98: static int last_recorded_len = 0; /* number of last recorded chars */
99:
100: static void free_buff __ARGS((struct buffheader *));
101: static char_u *get_bufcont __ARGS((struct buffheader *, int));
102: static void add_buff __ARGS((struct buffheader *, char_u *));
103: static void add_num_buff __ARGS((struct buffheader *, long));
104: static void add_char_buff __ARGS((struct buffheader *, int));
105: static int read_stuff __ARGS((int));
106: static void start_stuff __ARGS((void));
107: static int read_redo __ARGS((int, int));
108: static void copy_redo __ARGS((int));
109: static void init_typebuf __ARGS((void));
110: static void gotchars __ARGS((char_u *, int));
1.2 ! downsj 111: static void may_sync_undo __ARGS((void));
1.1 downsj 112: static int vgetorpeek __ARGS((int));
113: static int inchar __ARGS((char_u *, int, long));
114: static void map_free __ARGS((struct mapblock *));
115: static void showmap __ARGS((struct mapblock *));
116:
117: /*
118: * free and clear a buffer
119: */
120: static void
121: free_buff(buf)
122: struct buffheader *buf;
123: {
124: register struct bufblock *p, *np;
125:
126: for (p = buf->bh_first.b_next; p != NULL; p = np)
127: {
128: np = p->b_next;
129: vim_free(p);
130: }
131: buf->bh_first.b_next = NULL;
132: }
133:
134: /*
135: * return the contents of a buffer as a single string
136: */
137: static char_u *
138: get_bufcont(buffer, dozero)
139: struct buffheader *buffer;
140: int dozero; /* count == zero is not an error */
141: {
142: long_u count = 0;
143: char_u *p = NULL;
144: char_u *p2;
145: char_u *str;
146: struct bufblock *bp;
147:
148: /* compute the total length of the string */
149: for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
150: count += STRLEN(bp->b_str);
151:
152: if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL)
153: {
154: p2 = p;
155: for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
156: for (str = bp->b_str; *str; )
157: *p2++ = *str++;
158: *p2 = NUL;
159: }
160: return (p);
161: }
162:
163: /*
164: * return the contents of the record buffer as a single string
165: * and clear the record buffer
166: */
167: char_u *
168: get_recorded()
169: {
170: char_u *p;
171: size_t len;
172:
173: p = get_bufcont(&recordbuff, TRUE);
174: free_buff(&recordbuff);
175: /*
176: * Remove the characters that were added the last time, these must be the
177: * (possibly mapped) characters that stopped recording.
178: */
179: len = STRLEN(p);
180: if ((int)len >= last_recorded_len)
181: p[len - last_recorded_len] = NUL;
182: return (p);
183: }
184:
185: /*
186: * return the contents of the redo buffer as a single string
187: */
188: char_u *
189: get_inserted()
190: {
191: return(get_bufcont(&redobuff, FALSE));
192: }
193:
194: /*
195: * add string "s" after the current block of buffer "buf"
196: */
197: static void
198: add_buff(buf, s)
199: register struct buffheader *buf;
200: char_u *s;
201: {
202: struct bufblock *p;
203: long_u n;
204: long_u len;
205:
206: if ((n = STRLEN(s)) == 0) /* don't add empty strings */
207: return;
208:
209: if (buf->bh_first.b_next == NULL) /* first add to list */
210: {
211: buf->bh_space = 0;
212: buf->bh_curr = &(buf->bh_first);
213: }
214: else if (buf->bh_curr == NULL) /* buffer has already been read */
215: {
216: EMSG("Add to read buffer");
217: return;
218: }
219: else if (buf->bh_index != 0)
220: STRCPY(buf->bh_first.b_next->b_str,
221: buf->bh_first.b_next->b_str + buf->bh_index);
222: buf->bh_index = 0;
223:
224: if (buf->bh_space >= (int)n)
225: {
226: strcat((char *)buf->bh_curr->b_str, (char *)s);
227: buf->bh_space -= n;
228: }
229: else
230: {
231: if (n < MINIMAL_SIZE)
232: len = MINIMAL_SIZE;
233: else
234: len = n;
235: p = (struct bufblock *)lalloc((long_u)(sizeof(struct bufblock) + len), TRUE);
236: if (p == NULL)
237: return; /* no space, just forget it */
238: buf->bh_space = len - n;
239: STRCPY(p->b_str, s);
240:
241: p->b_next = buf->bh_curr->b_next;
242: buf->bh_curr->b_next = p;
243: buf->bh_curr = p;
244: }
245: return;
246: }
247:
248: static void
249: add_num_buff(buf, n)
250: struct buffheader *buf;
251: long n;
252: {
253: char_u number[32];
254:
255: sprintf((char *)number, "%ld", n);
256: add_buff(buf, number);
257: }
258:
259: static void
260: add_char_buff(buf, c)
261: struct buffheader *buf;
262: int c;
263: {
264: char_u temp[4];
265:
266: /*
267: * translate special key code into three byte sequence
268: */
269: if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL)
270: {
271: temp[0] = K_SPECIAL;
272: temp[1] = K_SECOND(c);
273: temp[2] = K_THIRD(c);
274: temp[3] = NUL;
275: }
276: else
277: {
278: temp[0] = c;
279: temp[1] = NUL;
280: }
281: add_buff(buf, temp);
282: }
283:
284: /*
285: * get one character from the stuff buffer
286: * If advance == TRUE go to the next char.
287: */
288: static int
289: read_stuff(advance)
290: int advance;
291: {
292: register char_u c;
293: register struct bufblock *curr;
294:
295:
296: if (stuffbuff.bh_first.b_next == NULL) /* buffer is empty */
297: return NUL;
298:
299: curr = stuffbuff.bh_first.b_next;
300: c = curr->b_str[stuffbuff.bh_index];
301:
302: if (advance)
303: {
304: if (curr->b_str[++stuffbuff.bh_index] == NUL)
305: {
306: stuffbuff.bh_first.b_next = curr->b_next;
307: vim_free(curr);
308: stuffbuff.bh_index = 0;
309: }
310: }
311: return c;
312: }
313:
314: /*
315: * prepare stuff buffer for reading (if it contains something)
316: */
317: static void
318: start_stuff()
319: {
320: if (stuffbuff.bh_first.b_next != NULL)
321: {
322: stuffbuff.bh_curr = &(stuffbuff.bh_first);
323: stuffbuff.bh_space = 0;
324: }
325: }
326:
327: /*
328: * check if the stuff buffer is empty
329: */
330: int
331: stuff_empty()
332: {
333: return (stuffbuff.bh_first.b_next == NULL);
334: }
335:
336: /*
337: * Remove the contents of the stuff buffer and the mapped characters in the
338: * typeahead buffer (used in case of an error). If 'typeahead' is true,
339: * flush all typeahead characters (used when interrupted by a CTRL-C).
340: */
341: void
342: flush_buffers(typeahead)
343: int typeahead;
344: {
345: init_typebuf();
346:
347: start_stuff();
348: while (read_stuff(TRUE) != NUL)
349: ;
350:
351: if (typeahead) /* remove all typeahead */
352: {
353: /*
354: * We have to get all characters, because we may delete the first
355: * part of an escape sequence.
356: * In an xterm we get one char at a time and we have to get them
357: * all.
358: */
359: while (inchar(typebuf, MAXMAPLEN, 10L))
360: ;
361: typeoff = MAXMAPLEN;
362: typelen = 0;
363: }
364: else /* remove mapped characters only */
365: {
366: typeoff += typemaplen;
367: typelen -= typemaplen;
368: }
369: typemaplen = 0;
370: no_abbr_cnt = 0;
371: }
372:
373: /*
374: * The previous contents of the redo buffer is kept in old_redobuffer.
375: * This is used for the CTRL-O <.> command in insert mode.
376: */
377: void
378: ResetRedobuff()
379: {
380: if (!block_redo)
381: {
382: free_buff(&old_redobuff);
383: old_redobuff = redobuff;
384: redobuff.bh_first.b_next = NULL;
385: }
386: }
387:
388: void
389: AppendToRedobuff(s)
390: char_u *s;
391: {
392: if (!block_redo)
393: add_buff(&redobuff, s);
394: }
395:
396: void
397: AppendCharToRedobuff(c)
398: int c;
399: {
400: if (!block_redo)
401: add_char_buff(&redobuff, c);
402: }
403:
404: void
405: AppendNumberToRedobuff(n)
406: long n;
407: {
408: if (!block_redo)
409: add_num_buff(&redobuff, n);
410: }
411:
412: void
413: stuffReadbuff(s)
414: char_u *s;
415: {
416: add_buff(&stuffbuff, s);
417: }
418:
419: void
420: stuffcharReadbuff(c)
421: int c;
422: {
423: add_char_buff(&stuffbuff, c);
424: }
425:
426: void
427: stuffnumReadbuff(n)
428: long n;
429: {
430: add_num_buff(&stuffbuff, n);
431: }
432:
433: /*
434: * Read a character from the redo buffer.
435: * The redo buffer is left as it is.
436: * if init is TRUE, prepare for redo, return FAIL if nothing to redo, OK
437: * otherwise
438: * if old is TRUE, use old_redobuff instead of redobuff
439: */
440: static int
441: read_redo(init, old_redo)
442: int init;
443: int old_redo;
444: {
445: static struct bufblock *bp;
446: static char_u *p;
447: int c;
448:
449: if (init)
450: {
451: if (old_redo)
452: bp = old_redobuff.bh_first.b_next;
453: else
454: bp = redobuff.bh_first.b_next;
455: if (bp == NULL)
456: return FAIL;
457: p = bp->b_str;
458: return OK;
459: }
460: if ((c = *p) != NUL)
461: {
462: if (c == K_SPECIAL)
463: {
464: c = TO_SPECIAL(p[1], p[2]);
465: p += 2;
466: }
467: if (*++p == NUL && bp->b_next != NULL)
468: {
469: bp = bp->b_next;
470: p = bp->b_str;
471: }
472: }
473: return c;
474: }
475:
476: /*
477: * copy the rest of the redo buffer into the stuff buffer (could be done faster)
478: * if old_redo is TRUE, use old_redobuff instead of redobuff
479: */
480: static void
481: copy_redo(old_redo)
482: int old_redo;
483: {
484: register int c;
485:
486: while ((c = read_redo(FALSE, old_redo)) != NUL)
487: stuffcharReadbuff(c);
488: }
489:
490: /*
491: * Stuff the redo buffer into the stuffbuff.
492: * Insert the redo count into the command.
493: * If 'old_redo' is TRUE, the last but one command is repeated
494: * instead of the last command (inserting text). This is used for
495: * CTRL-O <.> in insert mode
496: *
497: * return FAIL for failure, OK otherwise
498: */
499: int
500: start_redo(count, old_redo)
501: long count;
502: int old_redo;
503: {
504: register int c;
505:
506: if (read_redo(TRUE, old_redo) == FAIL) /* init the pointers; return if nothing to redo */
507: return FAIL;
508:
509: c = read_redo(FALSE, old_redo);
510:
511: /* copy the buffer name, if present */
512: if (c == '"')
513: {
514: add_buff(&stuffbuff, (char_u *)"\"");
515: c = read_redo(FALSE, old_redo);
516:
517: /* if a numbered buffer is used, increment the number */
518: if (c >= '1' && c < '9')
519: ++c;
520: add_char_buff(&stuffbuff, c);
521: c = read_redo(FALSE, old_redo);
522: }
523:
524: if (c == 'v') /* redo Visual */
525: {
526: VIsual = curwin->w_cursor;
527: VIsual_active = TRUE;
528: redo_VIsual_busy = TRUE;
529: c = read_redo(FALSE, old_redo);
530: }
531:
532: /* try to enter the count (in place of a previous count) */
533: if (count)
534: {
535: while (isdigit(c)) /* skip "old" count */
536: c = read_redo(FALSE, old_redo);
537: add_num_buff(&stuffbuff, count);
538: }
539:
540: /* copy from the redo buffer into the stuff buffer */
541: add_char_buff(&stuffbuff, c);
542: copy_redo(old_redo);
543: return OK;
544: }
545:
546: /*
547: * Repeat the last insert (R, o, O, a, A, i or I command) by stuffing
548: * the redo buffer into the stuffbuff.
549: * return FAIL for failure, OK otherwise
550: */
551: int
552: start_redo_ins()
553: {
554: register int c;
555:
556: if (read_redo(TRUE, FALSE) == FAIL)
557: return FAIL;
558: start_stuff();
559:
560: /* skip the count and the command character */
561: while ((c = read_redo(FALSE, FALSE)) != NUL)
562: {
563: c = TO_UPPER(c);
564: if (vim_strchr((char_u *)"AIRO", c) != NULL)
565: {
566: if (c == 'O')
567: stuffReadbuff(NL_STR);
568: break;
569: }
570: }
571:
572: /* copy the typed text from the redo buffer into the stuff buffer */
573: copy_redo(FALSE);
574: block_redo = TRUE;
575: return OK;
576: }
577:
578: void
579: set_redo_ins()
580: {
581: block_redo = TRUE;
582: }
583:
584: void
585: stop_redo_ins()
586: {
587: block_redo = FALSE;
588: }
589:
590: /*
591: * Initialize typebuf to point to typebuf_init.
592: * Alloc() cannot be used here: In out-of-memory situations it would
593: * be impossible to type anything.
594: */
595: static void
596: init_typebuf()
597: {
598: if (typebuf == NULL)
599: {
600: typebuf = typebuf_init;
601: noremapbuf = noremapbuf_init;
602: typebuflen = TYPELEN_INIT;
603: typelen = 0;
604: typeoff = 0;
605: }
606: }
607:
608: /*
609: * insert a string in position 'offset' in the typeahead buffer (for "@r"
610: * and ":normal" command, vgetorpeek() and check_termcode())
611: *
612: * If noremap is 0, new string can be mapped again.
613: * If noremap is -1, new string cannot be mapped again.
614: * If noremap is >0, that many characters of the new string cannot be mapped.
615: *
616: * If nottyped is TRUE, the string does not return KeyTyped (don't use when
617: * offset is non-zero!).
618: *
619: * return FAIL for failure, OK otherwise
620: */
621: int
622: ins_typebuf(str, noremap, offset, nottyped)
623: char_u *str;
624: int noremap;
625: int offset;
626: int nottyped;
627: {
628: register char_u *s1, *s2;
629: register int newlen;
630: register int addlen;
631: register int i;
632: register int newoff;
633:
634: init_typebuf();
635:
636: addlen = STRLEN(str);
637: /*
638: * Easy case: there is room in front of typebuf[typeoff]
639: */
640: if (offset == 0 && addlen <= typeoff)
641: {
642: typeoff -= addlen;
643: vim_memmove(typebuf + typeoff, str, (size_t)addlen);
644: }
645: /*
646: * Need to allocate new buffer.
647: * In typebuf there must always be room for MAXMAPLEN + 4 characters.
648: * We add some extra room to avoid having to allocate too often.
649: */
650: else
651: {
652: newoff = MAXMAPLEN + 4;
653: newlen = typelen + addlen + newoff + 2 * (MAXMAPLEN + 4);
654: if (newlen < 0) /* string is getting too long */
655: {
656: emsg(e_toocompl); /* also calls flush_buffers */
657: setcursor();
658: return FAIL;
659: }
660: s1 = alloc(newlen);
661: if (s1 == NULL) /* out of memory */
662: return FAIL;
663: s2 = alloc(newlen);
664: if (s2 == NULL) /* out of memory */
665: {
666: vim_free(s1);
667: return FAIL;
668: }
669: typebuflen = newlen;
670:
671: /* copy the old chars, before the insertion point */
672: vim_memmove(s1 + newoff, typebuf + typeoff, (size_t)offset);
673: /* copy the new chars */
674: vim_memmove(s1 + newoff + offset, str, (size_t)addlen);
675: /* copy the old chars, after the insertion point, including
676: * the NUL at the end */
677: vim_memmove(s1 + newoff + offset + addlen, typebuf + typeoff + offset,
678: (size_t)(typelen - offset + 1));
679: if (typebuf != typebuf_init)
680: vim_free(typebuf);
681: typebuf = s1;
682:
683: vim_memmove(s2 + newoff, noremapbuf + typeoff, (size_t)offset);
684: vim_memmove(s2 + newoff + offset + addlen,
685: noremapbuf + typeoff + offset, (size_t)(typelen - offset));
686: if (noremapbuf != noremapbuf_init)
687: vim_free(noremapbuf);
688: noremapbuf = s2;
689:
690: typeoff = newoff;
691: }
692: typelen += addlen;
693:
694: /*
695: * Adjust noremapbuf[] for the new characters:
696: * If noremap < 0: all the new characters are flagged not remappable
697: * If noremap == 0: all the new characters are flagged mappable
698: * If noremap > 0: 'noremap' characters are flagged not remappable, the
699: * rest mappable
700: */
701: if (noremap < 0) /* length not specified */
702: noremap = addlen;
703: for (i = 0; i < addlen; ++i)
704: noremapbuf[typeoff + i + offset] = (noremap-- > 0);
705:
706: /* this is only correct for offset == 0! */
707: if (nottyped) /* the inserted string is not typed */
708: typemaplen += addlen;
709: if (no_abbr_cnt && offset == 0) /* and not used for abbreviations */
710: no_abbr_cnt += addlen;
711:
712: return OK;
713: }
714:
715: /*
716: * Return TRUE if there are no characters in the typeahead buffer that have
717: * not been typed (result from a mapping or come from ":normal").
718: */
719: int
720: typebuf_typed()
721: {
722: return typemaplen == 0;
723: }
724:
725: /*
726: * remove "len" characters from typebuf[typeoff + offset]
727: */
728: void
729: del_typebuf(len, offset)
730: int len;
731: int offset;
732: {
733: int i;
734:
735: typelen -= len;
736: /*
737: * Easy case: Just increase typeoff.
738: */
739: if (offset == 0 && typebuflen - (typeoff + len) >= MAXMAPLEN + 3)
740: typeoff += len;
741: /*
742: * Have to move the characters in typebuf[] and noremapbuf[]
743: */
744: else
745: {
746: i = typeoff + offset;
747: /*
748: * Leave some extra room at the end to avoid reallocation.
749: */
750: if (typeoff > MAXMAPLEN)
751: {
752: vim_memmove(typebuf + MAXMAPLEN, typebuf + typeoff, (size_t)offset);
753: vim_memmove(noremapbuf + MAXMAPLEN, noremapbuf + typeoff,
754: (size_t)offset);
755: typeoff = MAXMAPLEN;
756: }
757: /* adjust typebuf (include the NUL at the end) */
758: vim_memmove(typebuf + typeoff + offset, typebuf + i + len,
759: (size_t)(typelen - offset + 1));
760: /* adjust noremapbuf[] */
761: vim_memmove(noremapbuf + typeoff + offset, noremapbuf + i + len,
762: (size_t)(typelen - offset));
763: }
764:
765: if (typemaplen > offset) /* adjust typemaplen */
766: {
767: if (typemaplen < offset + len)
768: typemaplen = offset;
769: else
770: typemaplen -= len;
771: }
772: if (no_abbr_cnt > offset) /* adjust no_abbr_cnt */
773: {
774: if (no_abbr_cnt < offset + len)
775: no_abbr_cnt = offset;
776: else
777: no_abbr_cnt -= len;
778: }
779: }
780:
781: /*
782: * Write typed characters to script file.
783: * If recording is on put the character in the recordbuffer.
784: */
785: static void
786: gotchars(s, len)
787: char_u *s;
788: int len;
789: {
790: int c;
791: char_u buf[2];
792:
793: /* remember how many chars were last recorded */
794: if (Recording)
795: last_recorded_len += len;
796:
797: buf[1] = NUL;
798: while (len--)
799: {
800: c = *s++;
801: updatescript(c);
802:
803: if (Recording)
804: {
805: buf[0] = c;
806: add_buff(&recordbuff, buf);
807: }
808: }
1.2 ! downsj 809: may_sync_undo();
! 810: }
1.1 downsj 811:
1.2 ! downsj 812: /*
! 813: * Sync undo. Called when typed characters are obtained from the typeahead
! 814: * buffer, or when a menu is used.
! 815: * Do not sync in insert mode, unless cursor key has been used.
! 816: * Also don't sync while reading a script file.
! 817: */
! 818: static void
! 819: may_sync_undo()
! 820: {
1.1 downsj 821: if ((!(State & (INSERT + CMDLINE)) || arrow_used) &&
822: scriptin[curscript] == NULL)
823: u_sync();
824: }
825:
826: /*
827: * open new script file for ":so!" command
828: * return OK on success, FAIL on error
829: */
830: int
831: openscript(name)
832: char_u *name;
833: {
834: int oldcurscript;
835:
836: if (curscript + 1 == NSCRIPT)
837: {
838: emsg(e_nesting);
839: return FAIL;
840: }
841: else
842: {
843: if (scriptin[curscript] != NULL) /* already reading script */
844: ++curscript;
845: /* use NameBuff for expanded name */
846: expand_env(name, NameBuff, MAXPATHL);
847: if ((scriptin[curscript] = fopen((char *)NameBuff, READBIN)) == NULL)
848: {
849: emsg2(e_notopen, name);
850: if (curscript)
851: --curscript;
852: return FAIL;
853: }
854: /*
855: * With command ":g/pat/so! file" we have to execute the
856: * commands from the file now.
857: */
858: if (global_busy)
859: {
860: State = NORMAL;
861: oldcurscript = curscript;
862: do
863: {
864: normal();
865: vpeekc(); /* check for end of file */
866: }
867: while (scriptin[oldcurscript]);
868: State = CMDLINE;
869: }
870: }
871: return OK;
872: }
873:
874: /*
875: * updatescipt() is called when a character can be written into the script file
876: * or when we have waited some time for a character (c == 0)
877: *
878: * All the changed memfiles are synced if c == 0 or when the number of typed
879: * characters reaches 'updatecount' and 'updatecount' is non-zero.
880: */
881: void
882: updatescript(c)
883: int c;
884: {
885: static int count = 0;
886:
887: if (c && scriptout)
888: putc(c, scriptout);
889: if (c == 0 || (p_uc > 0 && ++count >= p_uc))
890: {
891: ml_sync_all(c == 0, TRUE);
892: count = 0;
893: }
894: }
895:
896: #define K_NEEDMORET -1 /* keylen value for incomplete key-code */
897: #define M_NEEDMORET -2 /* keylen value for incomplete mapping */
898:
899: static int old_char = -1; /* ungotten character */
900:
901: int
902: vgetc()
903: {
904: int c, c2;
905:
906: mod_mask = 0x0;
907: last_recorded_len = 0;
908: for (;;) /* this is done twice if there are modifiers */
909: {
910: if (mod_mask) /* no mapping after modifier has been read */
911: {
912: ++no_mapping;
913: ++allow_keys;
914: }
915: c = vgetorpeek(TRUE);
916: if (mod_mask)
917: {
918: --no_mapping;
919: --allow_keys;
920: }
921:
922: /* Get two extra bytes for special keys */
923: if (c == K_SPECIAL)
924: {
925: ++no_mapping;
926: c2 = vgetorpeek(TRUE); /* no mapping for these chars */
927: c = vgetorpeek(TRUE);
928: --no_mapping;
929: if (c2 == KS_MODIFIER)
930: {
931: mod_mask = c;
932: continue;
933: }
934: c = TO_SPECIAL(c2, c);
935: }
936: #ifdef MSDOS
937: /*
938: * If K_NUL was typed, it is replaced by K_NUL, 3 in mch_inchar().
939: * Delete the 3 here.
940: */
941: else if (c == K_NUL && vpeekc() == 3)
942: (void)vgetorpeek(TRUE);
943: #endif
944:
945: return check_shifted_spec_key(c);
946: }
947: }
948:
949: int
950: vpeekc()
951: {
952: return (vgetorpeek(FALSE));
953: }
954:
955: /*
956: * Call vpeekc() without causing anything to be mapped.
957: * Return TRUE if a character is available, FALSE otherwise.
958: */
959: int
960: char_avail()
961: {
962: int retval;
963:
964: ++no_mapping;
965: retval = vgetorpeek(FALSE);
966: --no_mapping;
967: return (retval != NUL);
968: }
969:
970: void
971: vungetc(c) /* unget one character (can only be done once!) */
972: int c;
973: {
974: old_char = c;
975: }
976:
977: /*
978: * get a character: 1. from a previously ungotten character
979: * 2. from the stuffbuffer
980: * 3. from the typeahead buffer
981: * 4. from the user
982: *
983: * if "advance" is TRUE (vgetc()):
984: * really get the character.
985: * KeyTyped is set to TRUE in the case the user typed the key.
986: * KeyStuffed is TRUE if the character comes from the stuff buffer.
987: * if "advance" is FALSE (vpeekc()):
988: * just look whether there is a character available.
989: */
990:
991: static int
992: vgetorpeek(advance)
993: int advance;
994: {
995: register int c, c1;
996: int keylen = 0; /* init for gcc */
997: #ifdef AMIGA
998: char_u *s;
999: #endif
1000: register struct mapblock *mp;
1001: int timedout = FALSE; /* waited for more than 1 second
1002: for mapping to complete */
1003: int mapdepth = 0; /* check for recursive mapping */
1004: int mode_deleted = FALSE; /* set when mode has been deleted */
1005: int local_State;
1006: register int mlen;
1007: int max_mlen;
1008: int i;
1009: #ifdef USE_GUI
1010: int idx;
1011: #endif
1012:
1013: /*
1014: * VISUAL state is never set, it is used only here, therefore a check is
1015: * made if NORMAL state is actually VISUAL state.
1016: */
1017: local_State = State;
1018: if ((State & NORMAL) && VIsual_active)
1019: local_State = VISUAL;
1020:
1021: /*
1022: * get a character: 1. from a previously ungotten character
1023: */
1024: if (old_char >= 0)
1025: {
1026: c = old_char;
1027: if (advance)
1028: old_char = -1;
1029: return c;
1030: }
1031:
1032: if (advance)
1033: KeyStuffed = FALSE;
1034:
1035: init_typebuf();
1036: start_stuff();
1037: if (advance && typemaplen == 0)
1038: Exec_reg = FALSE;
1039: do
1040: {
1041: /*
1042: * get a character: 2. from the stuffbuffer
1043: */
1044: c = read_stuff(advance);
1045: if (c != NUL && !got_int)
1046: {
1047: if (advance)
1048: {
1049: KeyTyped = FALSE;
1050: KeyStuffed = TRUE;
1051: }
1052: if (no_abbr_cnt == 0)
1053: no_abbr_cnt = 1; /* no abbreviations now */
1054: }
1055: else
1056: {
1057: /*
1058: * Loop until we either find a matching mapped key, or we
1059: * are sure that it is not a mapped key.
1060: * If a mapped key sequence is found we go back to the start to
1061: * try re-mapping.
1062: */
1063:
1064: for (;;)
1065: {
1066: mch_breakcheck(); /* check for CTRL-C */
1067: if (got_int)
1068: {
1069: c = inchar(typebuf, MAXMAPLEN, 0L); /* flush all input */
1070: /*
1071: * If inchar returns TRUE (script file was active) or we are
1072: * inside a mapping, get out of insert mode.
1073: * Otherwise we behave like having gotten a CTRL-C.
1074: * As a result typing CTRL-C in insert mode will
1075: * really insert a CTRL-C.
1076: */
1077: if ((c || typemaplen) && (State & (INSERT + CMDLINE)))
1078: c = ESC;
1079: else
1080: c = Ctrl('C');
1081: flush_buffers(TRUE); /* flush all typeahead */
1082: break;
1083: }
1084: else if (typelen > 0) /* check for a mappable key sequence */
1085: {
1086: /*
1087: * walk through the maplist until we find an
1088: * entry that matches.
1089: *
1090: * Don't look for mappings if:
1091: * - timed out
1092: * - no_mapping set: mapping disabled (e.g. for CTRL-V)
1093: * - typebuf[typeoff] should not be remapped
1094: * - in insert or cmdline mode and 'paste' option set
1095: * - waiting for "hit return to continue" and CR or SPACE
1096: * typed
1097: * - waiting for a char with --more--
1098: * - in Ctrl-X mode, and we get a valid char for that mode
1099: */
1100: mp = NULL;
1101: max_mlen = 0;
1102: if (!timedout && no_mapping == 0 && (typemaplen == 0 ||
1103: (p_remap && noremapbuf[typeoff] == FALSE))
1104: && !(p_paste && (State & (INSERT + CMDLINE)))
1105: && !(State == HITRETURN && (typebuf[typeoff] == CR
1106: || typebuf[typeoff] == ' '))
1107: && State != ASKMORE
1108: #ifdef INSERT_EXPAND
1109: && !(ctrl_x_mode && is_ctrl_x_key(typebuf[typeoff]))
1110: #endif
1111: )
1112: {
1113: c1 = typebuf[typeoff];
1114: #ifdef HAVE_LANGMAP
1115: LANGMAP_ADJUST(c1, TRUE);
1116: #endif
1117: for (mp = maplist.m_next; mp; mp = mp->m_next)
1118: {
1119: /*
1120: * Only consider an entry if
1121: * - the first character matches and
1122: * - it is not an abbreviation and
1123: * - it is for the current state
1124: */
1125: if ( mp->m_keys[0] == c1 &&
1126: !(mp->m_mode & ABBREV) &&
1127: (mp->m_mode & local_State))
1128: {
1129: int n;
1130: #ifdef HAVE_LANGMAP
1131: int c2;
1132: #endif
1133:
1134: /* find the match length of this mapping */
1135: for (mlen = 1; mlen < typelen; ++mlen)
1136: {
1137: #ifdef HAVE_LANGMAP
1138: c2 = typebuf[typeoff + mlen];
1139: LANGMAP_ADJUST(c2, TRUE);
1140: if (mp->m_keys[mlen] != c2)
1141: #else
1142: if (mp->m_keys[mlen] !=
1143: typebuf[typeoff + mlen])
1144: #endif
1145: break;
1146: }
1147:
1148: /* if one of the typed keys cannot be
1149: * remapped, skip the entry */
1150: for (n = 0; n < mlen; ++n)
1151: if (noremapbuf[typeoff + n] == TRUE)
1152: break;
1153: if (n != mlen)
1154: continue;
1155:
1156: /* (partly) match found */
1157: keylen = mp->m_keylen;
1158: if (mlen == (keylen > typelen ?
1159: typelen : keylen))
1160: {
1161: /* partial match, need more chars */
1162: if (keylen > typelen)
1163: keylen = M_NEEDMORET;
1164: break;
1165: }
1166: /* no match, may have to check for
1167: * termcode at next character */
1168: if (max_mlen < mlen)
1169: max_mlen = mlen;
1170: }
1171: }
1172: }
1173: if (mp == NULL) /* no match found */
1174: {
1175: /*
1176: * check if we have a terminal code, when
1177: * mapping is allowed,
1178: * keys have not been mapped,
1179: * and not an ESC sequence, not in insert mode or
1180: * p_ek is on,
1181: * and when not timed out,
1182: */
1183: if ((no_mapping == 0 || allow_keys != 0) &&
1184: (typemaplen == 0 ||
1185: (p_remap && noremapbuf[typeoff] == FALSE)) &&
1186: !timedout)
1187: keylen = check_termcode(max_mlen + 1);
1188: else
1189: keylen = 0;
1190: if (keylen == 0) /* no matching terminal code */
1191: {
1192: #ifdef AMIGA /* check for window bounds report */
1193: if (typemaplen == 0 &&
1194: (typebuf[typeoff] & 0xff) == CSI)
1195: {
1196: for (s = typebuf + typeoff + 1;
1197: s < typebuf + typeoff + typelen &&
1198: (isdigit(*s) || *s == ';' || *s == ' ');
1199: ++s)
1200: ;
1201: if (*s == 'r' || *s == '|') /* found one */
1202: {
1203: del_typebuf((int)(s + 1 -
1204: (typebuf + typeoff)), 0);
1205: /* get size and redraw screen */
1206: set_winsize(0, 0, FALSE);
1207: continue;
1208: }
1209: if (*s == NUL) /* need more characters */
1210: keylen = K_NEEDMORET;
1211: }
1212: if (keylen >= 0)
1213: #endif
1214: {
1215: /*
1216: * get a character: 3. from the typeahead buffer
1217: */
1218: c = typebuf[typeoff] & 255;
1219: if (advance) /* remove chars from typebuf */
1220: {
1221: if (typemaplen)
1222: KeyTyped = FALSE;
1223: else
1224: {
1225: KeyTyped = TRUE;
1226: /* write char to script file(s) */
1227: gotchars(typebuf + typeoff, 1);
1228: }
1229: del_typebuf(1, 0);
1230: }
1231: break; /* got character, break for loop */
1232: }
1233: }
1234: if (keylen > 0) /* full matching terminal code */
1235: {
1236: #ifdef USE_GUI
1237: if (typebuf[typeoff] == K_SPECIAL &&
1238: typebuf[typeoff + 1] == KS_MENU)
1239: {
1240: /*
1.2 ! downsj 1241: * Using a menu may cause a break in undo!
! 1242: * It's like using gotchars(), but without
! 1243: * recording or writing to a script file.
1.1 downsj 1244: */
1.2 ! downsj 1245: may_sync_undo();
1.1 downsj 1246: del_typebuf(3, 0);
1247: idx = gui_get_menu_index(current_menu,
1248: local_State);
1249: if (idx != MENU_INDEX_INVALID)
1250: {
1251: ins_typebuf(current_menu->strings[idx],
1252: current_menu->noremap[idx] ? -1 : 0,
1253: 0, TRUE);
1254: }
1255: }
1256: #endif /* USE_GUI */
1257: continue; /* try mapping again */
1258: }
1259:
1260: /* partial match: get some more characters */
1261: keylen = K_NEEDMORET;
1262: }
1263: /* complete match */
1264: if (keylen >= 0 && keylen <= typelen)
1265: {
1266: /* write chars to script file(s) */
1267: if (keylen > typemaplen)
1268: gotchars(typebuf + typeoff + typemaplen,
1269: keylen - typemaplen);
1270:
1271: del_typebuf(keylen, 0); /* remove the mapped keys */
1272:
1273: /*
1274: * Put the replacement string in front of mapstr.
1275: * The depth check catches ":map x y" and ":map y x".
1276: */
1277: if (++mapdepth >= p_mmd)
1278: {
1279: EMSG("recursive mapping");
1280: if (State == CMDLINE)
1281: redrawcmdline();
1282: else
1283: setcursor();
1284: flush_buffers(FALSE);
1285: mapdepth = 0; /* for next one */
1286: c = -1;
1287: break;
1288: }
1289: /*
1290: * Insert the 'to' part in the typebuf.
1291: * If 'from' field is the same as the start of the
1.2 ! downsj 1292: * 'to' field, don't remap the first character.
1.1 downsj 1293: * If m_noremap is set, don't remap the whole 'to'
1294: * part.
1295: */
1296: if (ins_typebuf(mp->m_str, mp->m_noremap ? -1 :
1297: STRNCMP(mp->m_str, mp->m_keys,
1.2 ! downsj 1298: (size_t)keylen) ? 0 : 1,
1.1 downsj 1299: 0, TRUE) == FAIL)
1300: {
1301: c = -1;
1302: break;
1303: }
1304: continue;
1305: }
1306: }
1307: /*
1308: * special case: if we get an <ESC> in insert mode and there
1309: * are no more characters at once, we pretend to go out of
1310: * insert mode. This prevents the one second delay after
1311: * typing an <ESC>. If we get something after all, we may
1312: * have to redisplay the mode. That the cursor is in the wrong
1313: * place does not matter.
1314: */
1315: c = 0;
1316: if (advance && typelen == 1 && typebuf[typeoff] == ESC &&
1317: !no_mapping && typemaplen == 0 && (State & INSERT) &&
1318: (p_timeout || (keylen == K_NEEDMORET && p_ttimeout)) &&
1319: (c = inchar(typebuf + typeoff + typelen, 3, 0L)) == 0)
1320: {
1321: if (p_smd)
1322: {
1323: delmode();
1324: mode_deleted = TRUE;
1325: }
1326: if (curwin->w_cursor.col != 0) /* move cursor one left if
1327: possible */
1328: {
1329: if (curwin->w_col)
1330: {
1331: if (did_ai)
1332: {
1333: /*
1334: * We are expecting to truncate the trailing
1335: * white-space, so find the last non-white
1336: * character -- webb
1337: */
1338: colnr_t col, vcol;
1339: char_u *ptr;
1340:
1341: col = vcol = curwin->w_col = 0;
1342: ptr = ml_get_curline();
1343: while (col < curwin->w_cursor.col)
1344: {
1345: if (!vim_iswhite(ptr[col]))
1346: curwin->w_col = vcol;
1347: vcol += lbr_chartabsize(ptr + col,
1348: (colnr_t)vcol);
1349: ++col;
1350: }
1351: if (curwin->w_p_nu)
1352: curwin->w_col += 8;
1353: }
1354: else
1355: --curwin->w_col;
1356: }
1357: else if (curwin->w_p_wrap && curwin->w_row)
1358: {
1359: --curwin->w_row;
1360: curwin->w_col = Columns - 1;
1361: }
1362: }
1363: setcursor();
1364: flushbuf();
1365: }
1366: typelen += c;
1367: /* buffer full, don't map */
1368: if (typelen >= typemaplen + MAXMAPLEN)
1369: {
1370: timedout = TRUE;
1371: continue;
1372: }
1373: /*
1374: * get a character: 4. from the user
1375: */
1376: /*
1377: * If we have a partial match (and are going to wait for more
1378: * input from the user), show the partially matched characters
1379: * to the user with showcmd -- webb.
1380: */
1381: i = 0;
1382: if (typelen > 0 && (State & (NORMAL | INSERT)) && advance)
1383: {
1384: push_showcmd();
1385: while (i < typelen)
1386: (void)add_to_showcmd(typebuf[typeoff + i++], TRUE);
1387: }
1388:
1389: c = inchar(typebuf + typeoff + typelen,
1390: typemaplen + MAXMAPLEN - typelen,
1391: !advance
1392: ? 0
1393: : ((typelen == 0 || !(p_timeout || (p_ttimeout &&
1394: keylen == K_NEEDMORET)))
1395: ? -1L
1396: : ((keylen == K_NEEDMORET && p_ttm >= 0)
1397: ? p_ttm
1398: : p_tm)));
1399:
1400: if (i)
1401: pop_showcmd();
1402:
1403: if (c <= NUL) /* no character available */
1404: {
1405: if (!advance)
1406: break;
1407: if (typelen) /* timed out */
1408: {
1409: timedout = TRUE;
1410: continue;
1411: }
1412: }
1413: else
1414: { /* allow mapping for just typed characters */
1415: while (typebuf[typeoff + typelen] != NUL)
1416: noremapbuf[typeoff + typelen++] = FALSE;
1417: }
1418: } /* for (;;) */
1419: } /* if (!character from stuffbuf) */
1420:
1421: /* if advance is FALSE don't loop on NULs */
1422: } while (c < 0 || (advance && c == NUL));
1423:
1424: /*
1425: * The "INSERT" message is taken care of here:
1426: * if we return an ESC to exit insert mode, the message is deleted
1427: * if we don't return an ESC but deleted the message before, redisplay it
1428: */
1429: if (p_smd && (State & INSERT))
1430: {
1431: if (c == ESC && !mode_deleted && !no_mapping)
1432: delmode();
1433: else if (c != ESC && mode_deleted)
1434: showmode();
1435: }
1436:
1437: return c;
1438: }
1439:
1440: /*
1441: * inchar() - get one character from
1442: * 1. a scriptfile
1443: * 2. the keyboard
1444: *
1445: * As much characters as we can get (upto 'maxlen') are put in buf and
1446: * NUL terminated (buffer length must be 'maxlen' + 1).
1447: * Minimum for 'maxlen' is 3!!!!
1448: *
1449: * If we got an interrupt all input is read until none is available.
1450: *
1451: * If wait_time == 0 there is no waiting for the char.
1452: * If wait_time == n we wait for n msec for a character to arrive.
1453: * If wait_time == -1 we wait forever for a character to arrive.
1454: *
1455: * Return the number of obtained characters.
1456: */
1457:
1458: static int
1459: inchar(buf, maxlen, wait_time)
1460: char_u *buf;
1461: int maxlen;
1462: long wait_time; /* milli seconds */
1463: {
1464: int len = 0; /* init for GCC */
1465: int retesc = FALSE; /* return ESC with gotint */
1466: register int c;
1467: register int i;
1468:
1469: if (wait_time == -1L || wait_time > 100L) /* flush output before waiting */
1470: {
1471: cursor_on();
1472: flushbuf();
1473: }
1474: /*
1475: * Don't reset these when at the hit-return prompt, otherwise a endless
1476: * recursive loop may result (write error in swapfile, hit-return, timeout
1477: * on char wait, flush swapfile, write error....).
1478: */
1479: if (State != HITRETURN)
1480: {
1481: did_outofmem_msg = FALSE; /* display out of memory message (again) */
1482: did_swapwrite_msg = FALSE; /* display swap file write error again */
1483: }
1484: undo_off = FALSE; /* restart undo now */
1485:
1486: /*
1487: * first try script file
1488: * If interrupted: Stop reading script files.
1489: */
1490: c = -1;
1491: while (scriptin[curscript] != NULL && c < 0)
1492: {
1493: if (got_int || (c = getc(scriptin[curscript])) < 0) /* reached EOF */
1494: {
1495: /* when reading script file is interrupted, return an ESC to
1496: get back to normal mode */
1497: if (got_int)
1498: retesc = TRUE;
1499: fclose(scriptin[curscript]);
1500: scriptin[curscript] = NULL;
1501: if (curscript > 0)
1502: --curscript;
1503: }
1504: else
1505: {
1506: buf[0] = c;
1507: len = 1;
1508: }
1509: }
1510:
1511: if (c < 0) /* did not get a character from script */
1512: {
1513: /*
1514: * If we got an interrupt, skip all previously typed characters and
1515: * return TRUE if quit reading script file.
1516: */
1517: if (got_int) /* skip typed characters */
1518: {
1519: while (mch_inchar(buf, maxlen, 0L))
1520: ;
1521: return retesc;
1522: }
1523: /* fill up to a third of the buffer, because each character may be
1524: * tripled below */
1525: len = mch_inchar(buf, maxlen / 3, wait_time);
1526: }
1527:
1528: /*
1529: * Two characters are special: NUL and K_SPECIAL.
1530: * Replace NUL by K_SPECIAL KS_ZERO K_FILLER
1531: * Replace K_SPECIAL by K_SPECIAL KS_SPECIAL K_FILLER
1532: * Don't replace K_SPECIAL when reading a script file.
1533: */
1534: for (i = len; --i >= 0; ++buf)
1535: {
1536: if (buf[0] == NUL || (buf[0] == K_SPECIAL && c < 0))
1537: {
1538: vim_memmove(buf + 3, buf + 1, (size_t)i);
1539: buf[2] = K_THIRD(buf[0]);
1540: buf[1] = K_SECOND(buf[0]);
1541: buf[0] = K_SPECIAL;
1542: buf += 2;
1543: len += 2;
1544: }
1545: }
1546: *buf = NUL; /* add trailing NUL */
1547: return len;
1548: }
1549:
1550: /*
1551: * map[!] : show all key mappings
1552: * map[!] {lhs} : show key mapping for {lhs}
1553: * map[!] {lhs} {rhs} : set key mapping for {lhs} to {rhs}
1554: * noremap[!] {lhs} {rhs} : same, but no remapping for {rhs}
1555: * unmap[!] {lhs} : remove key mapping for {lhs}
1556: * abbr : show all abbreviations
1557: * abbr {lhs} : show abbreviations for {lhs}
1558: * abbr {lhs} {rhs} : set abbreviation for {lhs} to {rhs}
1559: * noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
1560: * unabbr {lhs} : remove abbreviation for {lhs}
1561: *
1562: * maptype == 1 for unmap command, 2 for noremap command.
1563: *
1564: * keys is pointer to any arguments. Note: keys cannot be a read-only string,
1565: * it will be modified.
1566: *
1567: * for :map mode is NORMAL + VISUAL
1568: * for :map! mode is INSERT + CMDLINE
1569: * for :cmap mode is CMDLINE
1570: * for :imap mode is INSERT
1571: * for :nmap mode is NORMAL
1572: * for :vmap mode is VISUAL
1573: * for :abbr mode is INSERT + CMDLINE + ABBREV
1574: * for :iabbr mode is INSERT + ABBREV
1575: * for :cabbr mode is CMDLINE + ABBREV
1576: *
1577: * Return 0 for success
1578: * 1 for invalid arguments
1579: * 2 for no match
1580: * 3 for ambiguety
1581: * 4 for out of mem
1582: */
1583: int
1584: do_map(maptype, keys, mode)
1585: int maptype;
1586: char_u *keys;
1587: int mode;
1588: {
1589: struct mapblock *mp, *mprev;
1590: char_u *arg;
1591: char_u *p;
1592: int n;
1593: int len = 0; /* init for GCC */
1594: char_u *newstr;
1595: int hasarg;
1596: int haskey;
1597: int did_it = FALSE;
1598: int abbrev = 0;
1599: int round;
1600: char_u *keys_buf = NULL;
1601: char_u *arg_buf = NULL;
1602: int retval = 0;
1603: int do_backslash;
1604:
1605: if (mode & ABBREV) /* not a mapping but an abbreviation */
1606: {
1607: abbrev = ABBREV;
1608: mode &= ~ABBREV;
1609: }
1610: /*
1611: * find end of keys and skip CTRL-Vs (and backslashes) in it
1612: * Accept backslash like CTRL-V when 'cpoptions' does not contain 'B'.
1613: * with :unmap white space is included in the keys, no argument possible
1614: */
1615: p = keys;
1616: do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
1617: while (*p && (maptype == 1 || !vim_iswhite(*p)))
1618: {
1619: if ((p[0] == Ctrl('V') || (do_backslash && p[0] == '\\')) &&
1620: p[1] != NUL)
1621: ++p; /* skip CTRL-V or backslash */
1622: ++p;
1623: }
1624: if (*p != NUL)
1625: *p++ = NUL;
1626: p = skipwhite(p);
1627: arg = p;
1628: hasarg = (*arg != NUL);
1629: haskey = (*keys != NUL);
1630:
1631: /* check for :unmap without argument */
1632: if (maptype == 1 && !haskey)
1633: {
1634: retval = 1;
1635: goto theend;
1636: }
1637:
1638: /*
1639: * If mapping has been given as ^V<C_UP> say, then replace the term codes
1640: * with the appropriate two bytes. If it is a shifted special key, unshift
1641: * it too, giving another two bytes.
1642: * replace_termcodes() may move the result to allocated memory, which
1643: * needs to be freed later (*keys_buf and *arg_buf).
1644: * replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
1645: */
1646: if (haskey)
1647: keys = replace_termcodes(keys, &keys_buf, TRUE);
1648: if (hasarg)
1649: arg = replace_termcodes(arg, &arg_buf, FALSE);
1650:
1651: /*
1652: * check arguments and translate function keys
1653: */
1654: if (haskey)
1655: {
1656: len = STRLEN(keys);
1657: if (len > MAXMAPLEN) /* maximum length of MAXMAPLEN chars */
1658: {
1659: retval = 1;
1660: goto theend;
1661: }
1662:
1663: if (abbrev)
1664: {
1665: /*
1666: * If an abbreviation ends in a keyword character, the
1667: * rest must be all keyword-char or all non-keyword-char.
1668: * Otherwise we won't be able to find the start of it in a
1669: * vi-compatible way.
1670: * An abbrevation cannot contain white space.
1671: */
1672: if (iswordchar(keys[len - 1])) /* ends in keyword char */
1673: for (n = 0; n < len - 2; ++n)
1674: if (iswordchar(keys[n]) != iswordchar(keys[len - 2]))
1675: {
1676: retval = 1;
1677: goto theend;
1678: }
1679: for (n = 0; n < len; ++n)
1680: if (vim_iswhite(keys[n]))
1681: {
1682: retval = 1;
1683: goto theend;
1684: }
1685: }
1686: }
1687:
1688: if (haskey && hasarg && abbrev) /* if we will add an abbreviation */
1689: no_abbr = FALSE; /* reset flag that indicates there are
1690: no abbreviations */
1691:
1692: if (!haskey || (maptype != 1 && !hasarg))
1693: msg_start();
1694: /*
1695: * Find an entry in the maplist that matches.
1696: * For :unmap we may loop two times: once to try to unmap an entry with a
1697: * matching 'from' part, a second time, if the first fails, to unmap an
1698: * entry with a matching 'to' part. This was done to allow ":ab foo bar" to be
1699: * unmapped by typing ":unab foo", where "foo" will be replaced by "bar" because
1700: * of the abbreviation.
1701: */
1702: for (round = 0; (round == 0 || maptype == 1) && round <= 1 &&
1703: !did_it && !got_int; ++round)
1704: {
1705: for (mp = maplist.m_next, mprev = &maplist; mp && !got_int;
1706: mprev = mp, mp = mp->m_next)
1707: {
1708: /* skip entries with wrong mode */
1709: if (!(mp->m_mode & mode) || (mp->m_mode & ABBREV) != abbrev)
1710: continue;
1711: if (!haskey) /* show all entries */
1712: {
1713: showmap(mp);
1714: did_it = TRUE;
1715: }
1716: else /* do we have a match? */
1717: {
1718: if (round) /* second round: try 'to' string for unmap */
1719: {
1720: n = STRLEN(mp->m_str);
1721: p = mp->m_str;
1722: }
1723: else
1724: {
1725: n = mp->m_keylen;
1726: p = mp->m_keys;
1727: }
1728: if (!STRNCMP(p, keys, (size_t)(n < len ? n : len)))
1729: {
1730: if (maptype == 1) /* delete entry */
1731: {
1732: if (n != len) /* not a full match */
1733: continue;
1734: /*
1735: * We reset the indicated mode bits. If nothing is
1736: * left the entry is deleted below.
1737: */
1738: mp->m_mode &= (~mode | ABBREV);
1739: did_it = TRUE; /* remember that we did something */
1740: }
1741: else if (!hasarg) /* show matching entry */
1742: {
1743: showmap(mp);
1744: did_it = TRUE;
1745: }
1746: else if (n != len) /* new entry is ambigious */
1747: {
1748: if (abbrev) /* for abbreviations that's ok */
1749: continue;
1750: retval = 3;
1751: goto theend;
1752: }
1753: else
1754: {
1755: mp->m_mode &= (~mode | ABBREV); /* remove mode bits */
1756: if (!(mp->m_mode & ~ABBREV) && !did_it) /* reuse existing entry */
1757: {
1758: newstr = strsave(arg);
1759: if (newstr == NULL)
1760: {
1761: retval = 4; /* no mem */
1762: goto theend;
1763: }
1764: vim_free(mp->m_str);
1765: mp->m_str = newstr;
1766: mp->m_noremap = maptype;
1767: mp->m_mode = mode + abbrev;
1768: did_it = TRUE;
1769: }
1770: }
1771: if (!(mp->m_mode & ~ABBREV)) /* entry can be deleted */
1772: {
1773: map_free(mprev);
1774: mp = mprev; /* continue with next entry */
1775: }
1776: }
1777: }
1778: }
1779: }
1780:
1781: if (maptype == 1) /* delete entry */
1782: {
1783: if (!did_it)
1784: retval = 2; /* no match */
1785: goto theend;
1786: }
1787:
1788: if (!haskey || !hasarg) /* print entries */
1789: {
1790: if (!did_it)
1791: {
1792: if (abbrev)
1793: MSG("No abbreviation found");
1794: else
1795: MSG("No mapping found");
1796: }
1797: goto theend; /* listing finished */
1798: }
1799:
1800: if (did_it) /* have added the new entry already */
1801: goto theend;
1802: /*
1803: * get here when we have to add a new entry
1804: */
1805: /* allocate a new entry for the maplist */
1806: mp = (struct mapblock *)alloc((unsigned)sizeof(struct mapblock));
1807: if (mp == NULL)
1808: {
1809: retval = 4; /* no mem */
1810: goto theend;
1811: }
1812: mp->m_keys = strsave(keys);
1813: mp->m_str = strsave(arg);
1814: if (mp->m_keys == NULL || mp->m_str == NULL)
1815: {
1816: vim_free(mp->m_keys);
1817: vim_free(mp->m_str);
1818: vim_free(mp);
1819: retval = 4; /* no mem */
1820: goto theend;
1821: }
1822: mp->m_keylen = STRLEN(mp->m_keys);
1823: mp->m_noremap = maptype;
1824: mp->m_mode = mode + abbrev;
1825:
1826: /* add the new entry in front of the maplist */
1827: mp->m_next = maplist.m_next;
1828: maplist.m_next = mp;
1829:
1830: theend:
1831: vim_free(keys_buf);
1832: vim_free(arg_buf);
1833: return retval;
1834: }
1835:
1836: /*
1837: * Delete one entry from the maplist.
1838: * The argument is a pointer to the PREVIOUS entry!
1839: */
1840: static void
1841: map_free(mprev)
1842: struct mapblock *mprev;
1843: {
1844: struct mapblock *mp;
1845:
1846: mp = mprev->m_next;
1847: vim_free(mp->m_keys);
1848: vim_free(mp->m_str);
1849: mprev->m_next = mp->m_next;
1850: vim_free(mp);
1851: }
1852:
1853: /*
1854: * Clear all mappings or abbreviations.
1855: * 'abbr' should be FALSE for mappings, TRUE for abbreviations.
1856: */
1857: void
1.2 ! downsj 1858: map_clear(modec, forceit, abbr)
1.1 downsj 1859: int modec;
1.2 ! downsj 1860: int forceit;
1.1 downsj 1861: int abbr;
1862: {
1863: struct mapblock *mp;
1864: int mode;
1865:
1.2 ! downsj 1866: if (forceit) /* :mapclear! */
1.1 downsj 1867: mode = INSERT + CMDLINE;
1868: else if (modec == 'i')
1869: mode = INSERT;
1870: else if (modec == 'n')
1871: mode = NORMAL;
1872: else if (modec == 'c')
1873: mode = CMDLINE;
1874: else if (modec == 'v')
1875: mode = VISUAL;
1876: else
1877: mode = VISUAL + NORMAL;
1878:
1879: for (mp = &maplist; mp->m_next != NULL; )
1880: {
1881: if (abbr != !(mp->m_next->m_mode & ABBREV) && mp->m_next->m_mode & mode)
1882: {
1883: mp->m_next->m_mode &= ~mode;
1884: if ((mp->m_next->m_mode & ~ABBREV) == 0) /* entry can be deleted */
1885: {
1886: map_free(mp);
1887: continue;
1888: }
1889: }
1890: mp = mp->m_next;
1891: }
1892: }
1893:
1894: static void
1895: showmap(mp)
1896: struct mapblock *mp;
1897: {
1898: int len;
1899:
1900: if (msg_didout)
1901: msg_outchar('\n');
1902: if ((mp->m_mode & (INSERT + CMDLINE)) == INSERT + CMDLINE)
1903: MSG_OUTSTR("! ");
1904: else if (mp->m_mode & INSERT)
1905: MSG_OUTSTR("i ");
1906: else if (mp->m_mode & CMDLINE)
1907: MSG_OUTSTR("c ");
1908: else if (!(mp->m_mode & VISUAL))
1909: MSG_OUTSTR("n ");
1910: else if (!(mp->m_mode & NORMAL))
1911: MSG_OUTSTR("v ");
1912: else
1913: MSG_OUTSTR(" ");
1914: /* Get length of what we write */
1915: len = msg_outtrans_special(mp->m_keys, TRUE);
1916: do
1917: {
1918: msg_outchar(' '); /* padd with blanks */
1919: ++len;
1920: } while (len < 12);
1921: if (mp->m_noremap)
1922: msg_outchar('*');
1923: else
1924: msg_outchar(' ');
1925: /* Use FALSE below if we only want things like <Up> to show up as such on
1926: * the rhs, and not M-x etc, TRUE gets both -- webb
1927: */
1928: msg_outtrans_special(mp->m_str, TRUE);
1929: flushbuf(); /* show one line at a time */
1930: }
1931:
1932: /*
1933: * Check for an abbreviation.
1934: * Cursor is at ptr[col]. When inserting, mincol is where insert started.
1935: * "c" is the character typed before check_abbr was called.
1936: *
1937: * Historic vi practice: The last character of an abbreviation must be an id
1938: * character ([a-zA-Z0-9_]). The characters in front of it must be all id
1939: * characters or all non-id characters. This allows for abbr. "#i" to
1940: * "#include".
1941: *
1942: * Vim addition: Allow for abbreviations that end in a non-keyword character.
1943: * Then there must be white space before the abbr.
1944: *
1945: * return TRUE if there is an abbreviation, FALSE if not
1946: */
1947: int
1948: check_abbr(c, ptr, col, mincol)
1949: int c;
1950: char_u *ptr;
1951: int col;
1952: int mincol;
1953: {
1954: int len;
1955: int j;
1956: char_u tb[4];
1957: struct mapblock *mp;
1958: int is_id = TRUE;
1959: int vim_abbr;
1960:
1961: if (no_abbr_cnt) /* abbrev. are not recursive */
1962: return FALSE;
1963:
1964: /*
1965: * Check for word before the cursor: If it ends in a keyword char all
1966: * chars before it must be al keyword chars or non-keyword chars, but not
1967: * white space. If it ends in a non-keyword char we accept any characters
1968: * before it except white space.
1969: */
1970: if (col == 0) /* cannot be an abbr. */
1971: return FALSE;
1972:
1973: if (!iswordchar(ptr[col - 1]))
1974: vim_abbr = TRUE; /* Vim added abbr. */
1975: else
1976: {
1977: vim_abbr = FALSE; /* vi compatible abbr. */
1978: if (col > 1)
1979: is_id = iswordchar(ptr[col - 2]);
1980: }
1981: for (len = col - 1; len > 0 && !vim_isspace(ptr[len - 1]) &&
1982: (vim_abbr || is_id == iswordchar(ptr[len - 1])); --len)
1983: ;
1984:
1985: if (len < mincol)
1986: len = mincol;
1987: if (len < col) /* there is a word in front of the cursor */
1988: {
1989: ptr += len;
1990: len = col - len;
1991: for (mp = maplist.m_next; mp; mp = mp->m_next)
1992: {
1993: /* find entries with right mode and keys */
1994: if ((mp->m_mode & ABBREV) == ABBREV &&
1995: (mp->m_mode & State) &&
1996: mp->m_keylen == len &&
1997: !STRNCMP(mp->m_keys, ptr, (size_t)len))
1998: break;
1999: }
2000: if (mp)
2001: {
2002: /*
2003: * Found a match:
2004: * Insert the rest of the abbreviation in typebuf[].
2005: * This goes from end to start.
2006: *
2007: * Characters 0x000 - 0x100: normal chars, may need CTRL-V,
2008: * except K_SPECIAL: Becomes K_SPECIAL KS_SPECIAL K_FILLER
2009: * Characters where IS_SPECIAL() == TRUE: key codes, need
2010: * K_SPECIAL. Other characters (with ABBR_OFF): don't use CTRL-V.
2011: */
2012: j = 0;
2013: /* special key code, split up */
2014: if (IS_SPECIAL(c) || c == K_SPECIAL)
2015: {
2016: tb[j++] = K_SPECIAL;
2017: tb[j++] = K_SECOND(c);
2018: c = K_THIRD(c);
2019: }
2020: else if (c < 0x100 && (c < ' ' || c > '~'))
2021: tb[j++] = Ctrl('V'); /* special char needs CTRL-V */
2022: tb[j++] = c;
2023: tb[j] = NUL;
2024: /* insert the last typed char */
2025: (void)ins_typebuf(tb, TRUE, 0, TRUE);
2026: /* insert the to string */
1.2 ! downsj 2027: (void)ins_typebuf(mp->m_str, mp->m_noremap ? -1 : 0, 0, TRUE);
1.1 downsj 2028: /* no abbrev. for these chars */
2029: no_abbr_cnt += STRLEN(mp->m_str) + j + 1;
2030:
2031: tb[0] = Ctrl('H');
2032: tb[1] = NUL;
2033: while (len--) /* delete the from string */
2034: (void)ins_typebuf(tb, TRUE, 0, TRUE);
2035: return TRUE;
2036: }
2037: }
2038: return FALSE;
2039: }
2040:
2041: /*
2042: * Write map commands for the current mappings to an .exrc file.
2043: * Return FAIL on error, OK otherwise.
2044: */
2045: int
2046: makemap(fd)
2047: FILE *fd;
2048: {
2049: struct mapblock *mp;
2050: char_u c1;
2051: char_u *p;
2052:
2053: for (mp = maplist.m_next; mp; mp = mp->m_next)
2054: {
2055: c1 = NUL;
2056: p = (char_u *)"map";
2057: switch (mp->m_mode)
2058: {
2059: case NORMAL + VISUAL:
2060: break;
2061: case NORMAL:
2062: c1 = 'n';
2063: break;
2064: case VISUAL:
2065: c1 = 'v';
2066: break;
2067: case CMDLINE + INSERT:
2068: p = (char_u *)"map!";
2069: break;
2070: case CMDLINE:
2071: c1 = 'c';
2072: break;
2073: case INSERT:
2074: c1 = 'i';
2075: break;
2076: case INSERT + CMDLINE + ABBREV:
2077: p = (char_u *)"abbr";
2078: break;
2079: case CMDLINE + ABBREV:
2080: c1 = 'c';
2081: p = (char_u *)"abbr";
2082: break;
2083: case INSERT + ABBREV:
2084: c1 = 'i';
2085: p = (char_u *)"abbr";
2086: break;
2087: default:
2088: EMSG("makemap: Illegal mode");
2089: return FAIL;
2090: }
2091: if (c1 && putc(c1, fd) < 0)
2092: return FAIL;
2093: if (mp->m_noremap && fprintf(fd, "nore") < 0)
2094: return FAIL;
2095: if (fprintf(fd, (char *)p) < 0)
2096: return FAIL;
2097:
2098: if ( putc(' ', fd) < 0 || putescstr(fd, mp->m_keys, FALSE) == FAIL ||
2099: putc(' ', fd) < 0 || putescstr(fd, mp->m_str, FALSE) == FAIL ||
2100: #ifdef USE_CRNL
2101: putc('\r', fd) < 0 ||
2102: #endif
2103: putc('\n', fd) < 0)
2104: return FAIL;
2105: }
2106: return OK;
2107: }
2108:
2109: /*
2110: * write escape string to file
2111: *
2112: * return FAIL for failure, OK otherwise
2113: */
2114: int
2115: putescstr(fd, str, set)
2116: FILE *fd;
2117: char_u *str;
2118: int set; /* TRUE for makeset, FALSE for makemap */
2119: {
2120: int c;
2121: int modifiers;
2122:
2123: for ( ; *str; ++str)
2124: {
2125: c = *str;
2126: /*
2127: * Special key codes have to be translated to be able to make sense
2128: * when they are read back.
2129: */
2130: if (c == K_SPECIAL && !set)
2131: {
2132: modifiers = 0x0;
2133: if (str[1] == KS_MODIFIER)
2134: {
2135: modifiers = str[2];
2136: str += 3;
2137: c = *str;
2138: }
2139: if (c == K_SPECIAL)
2140: {
2141: c = TO_SPECIAL(str[1], str[2]);
2142: str += 2;
2143: }
2144: if (IS_SPECIAL(c) || modifiers) /* special key */
2145: {
2146: fprintf(fd, (char *)get_special_key_name(c, modifiers));
2147: continue;
2148: }
2149: }
2150: /*
2151: * A '\n' in a map command should be written as <NL>.
2152: * A '\n' in a set command should be written as \^V^J.
2153: */
2154: if (c == NL)
2155: {
2156: if (set)
2157: fprintf(fd, "\\\026\n");
2158: else
2159: fprintf(fd, "<NL>");
2160: continue;
2161: }
2162: /*
2163: * some characters have to be escaped with CTRL-V to
2164: * prevent them from misinterpreted in DoOneCmd().
2165: * A space, Tab and '"' has to be escaped with a backslash to
2166: * prevent it to be misinterpreted in do_set().
2167: */
2168: if (set && (vim_iswhite(c) || c == '"' || c == '\\'))
2169: {
2170: if (putc('\\', fd) < 0)
2171: return FAIL;
2172: }
2173: else if (c < ' ' || c > '~' || c == '|')
2174: {
2175: if (putc(Ctrl('V'), fd) < 0)
2176: return FAIL;
2177: }
2178: if (putc(c, fd) < 0)
2179: return FAIL;
2180: }
2181: return OK;
2182: }
2183:
2184: /*
2185: * Check all mappings for the presence of special key codes.
2186: * Used after ":set term=xxx".
2187: */
2188: void
2189: check_map_keycodes()
2190: {
2191: struct mapblock *mp;
2192: char_u *p;
2193: int i;
2194: char_u buf[3];
2195: char_u *save_name;
2196:
2197: save_name = sourcing_name;
2198: sourcing_name = (char_u *)"mappings";/* don't give error messages */
2199: for (mp = maplist.m_next; mp != NULL; mp = mp->m_next)
2200: {
2201: for (i = 0; i <= 1; ++i) /* do this twice */
2202: {
2203: if (i == 0)
2204: p = mp->m_keys; /* once for the "from" part */
2205: else
2206: p = mp->m_str; /* and once for the "to" part */
2207: while (*p)
2208: {
2209: if (*p == K_SPECIAL)
2210: {
2211: ++p;
2212: if (*p < 128) /* only for "normal" termcap entries */
2213: {
2214: buf[0] = p[0];
2215: buf[1] = p[1];
2216: buf[2] = NUL;
2217: (void)add_termcap_entry(buf, FALSE);
2218: }
2219: ++p;
2220: }
2221: ++p;
2222: }
2223: }
2224: }
2225: sourcing_name = save_name;
2226: }