|
|
1.1 root 1: /* tio.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 14407 SW Teal Blvd. #C
6: * Beaverton, OR 97005
7: * [email protected]
8: */
9:
10:
11: /* This file contains terminal I/O functions */
12:
13: #include "config.h"
14: #include "vi.h"
15: #include "ctype.h"
16:
17: static int showmsg P_((void));
18:
19: /* This function reads in a line from the terminal. */
20: int vgets(prompt, buf, bsize)
21: int prompt; /* the prompt character, or '\0' for none */
22: char *buf; /* buffer into which the string is read */
23: int bsize; /* size of the buffer */
24: {
25: int len; /* how much we've read so far */
26: int ch; /* a character from the user */
27: int quoted; /* is the next char quoted? */
28: int tab; /* column position of cursor */
29: char widths[132]; /* widths of characters */
30: int word; /* index of first letter of word */
31: #ifndef NO_DIGRAPH
32: int erased; /* 0, or first char of a digraph */
33: #endif
34:
35: /* show the prompt */
36: move(LINES - 1, 0);
37: tab = 0;
38: if (prompt)
39: {
40: addch(prompt);
41: tab = 1;
42: }
43: clrtoeol();
44: refresh();
45:
46: /* read in the line */
47: #ifndef NO_DIGRAPH
48: erased =
49: #endif
50: quoted = len = 0;
51: for (;;)
52: {
53: #ifndef NO_ABBR
54: if (quoted || mode == MODE_EX)
55: {
56: ch = getkey(0);
57: }
58: else
59: {
60: /* maybe expand an abbreviation while getting key */
61: for (word = len; --word >= 0 && isalnum(buf[word]); )
62: {
63: }
64: word++;
65: ch = getabkey(WHEN_EX, &buf[word], len - word);
66: }
67: #else
68: ch = getkey(0);
69: #endif
70: #ifndef NO_EXTENSIONS
71: if (ch == ctrl('O'))
72: {
73: ch = getkey(quoted ? 0 : WHEN_EX);
74: }
75: #endif
76:
77: /* some special conversions */
78: if (ch == ctrl('D') && len == 0)
79: ch = ctrl('[');
80: #ifndef NO_DIGRAPH
81: if (*o_digraph && erased != 0 && ch != '\b')
82: {
83: ch = digraph(erased, ch);
84: erased = 0;
85: }
86: #endif
87:
88: /* inhibit detection of special chars (except ^J) after a ^V */
89: if (quoted && ch != '\n')
90: {
91: ch |= 256;
92: }
93:
94: /* process the character */
95: switch(ch)
96: {
97: case ctrl('V'):
98: qaddch('^');
99: qaddch('\b');
100: quoted = TRUE;
101: break;
102:
103: case ctrl('['):
104: return -1;
105:
106: case '\n':
107: #if OSK
108: case '\l':
109: #else
110: case '\r':
111: #endif
112: clrtoeol();
113: goto BreakBreak;
114:
115: case '\b':
116: if (len > 0)
117: {
118: len--;
119: #ifndef NO_DIGRAPH
120: erased = buf[len];
121: #endif
122: for (ch = widths[len]; ch > 0; ch--)
123: addch('\b');
124: if (mode == MODE_EX)
125: {
126: clrtoeol();
127: }
128: tab -= widths[len];
129: }
130: else
131: {
132: return -1;
133: }
134: break;
135:
136: default:
137: /* strip off quotation bit */
138: if (ch & 256)
139: {
140: ch &= ~256;
141: qaddch(' ');
142: qaddch('\b');
143: }
144:
145: /* add & echo the char */
146: if (len < bsize - 1)
147: {
148: if (ch == '\t' && !quoted)
149: {
150: widths[len] = *o_tabstop - (tab % *o_tabstop);
151: addstr(" " + 8 - widths[len]);
152: tab += widths[len];
153: }
154: else if (ch > 0 && ch < ' ') /* > 0 by GB */
155: {
156: addch('^');
157: addch(ch + '@');
158: widths[len] = 2;
159: tab += 2;
160: }
161: else if (ch == '\177')
162: {
163: addch('^');
164: addch('?');
165: widths[len] = 2;
166: tab += 2;
167: }
168: else
169: {
170: addch(ch);
171: widths[len] = 1;
172: tab++;
173: }
174: buf[len++] = ch;
175: }
176: else
177: {
178: beep();
179: }
180: quoted = FALSE;
181: }
182: }
183: BreakBreak:
184: refresh();
185: buf[len] = '\0';
186: return len;
187: }
188:
189:
190: static int manymsgs; /* This variable keeps msgs from overwriting each other */
191: static char pmsg[80]; /* previous message (waiting to be displayed) */
192:
193:
194: static int showmsg()
195: {
196: /* if there is no message to show, then don't */
197: if (!manymsgs)
198: return FALSE;
199:
200: /* display the message */
201: move(LINES - 1, 0);
202: if (*pmsg)
203: {
204: standout();
205: qaddch(' ');
206: qaddstr(pmsg);
207: qaddch(' ');
208: standend();
209: }
210: clrtoeol();
211:
212: manymsgs = FALSE;
213: return TRUE;
214: }
215:
216:
217: void endmsgs()
218: {
219: if (manymsgs)
220: {
221: showmsg();
222: addch('\n');
223: }
224: }
225:
226: /* Write a message in an appropriate way. This should really be a varargs
227: * function, but there is no such thing as vwprintw. Hack!!!
228: *
229: * In MODE_EX or MODE_COLON, the message is written immediately, with a
230: * newline at the end.
231: *
232: * In MODE_VI, the message is stored in a character buffer. It is not
233: * displayed until getkey() is called. msg() will call getkey() itself,
234: * if necessary, to prevent messages from being lost.
235: *
236: * msg("") - clears the message line
237: * msg("%s %d", ...) - does a printf onto the message line
238: */
239: #ifdef __STDC__
240: void msg (char *fmt, ...)
241: {
242: va_list ap;
243: va_start (ap, fmt);
244: #else
245: void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
246: char *fmt;
247: long arg1, arg2, arg3, arg4, arg5, arg6, arg7;
248: {
249: #endif
250: if (mode != MODE_VI)
251: {
252: #ifdef __STDC__
253: vsprintf (pmsg, fmt, ap);
254: #else
255: sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
256: #endif
257: qaddstr(pmsg);
258: addch('\n');
259: exrefresh();
260: }
261: else
262: {
263: /* wait for keypress between consecutive msgs */
264: if (manymsgs)
265: {
266: getkey(WHEN_MSG);
267: }
268:
269: /* real message */
270: #ifdef __STDC__
271: vsprintf (pmsg, fmt, ap);
272: #else
273: sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
274: #endif
275: if (*fmt)
276: {
277: manymsgs = TRUE;
278: }
279: }
280: #ifdef __STDC__
281: va_end (ap);
282: #endif
283: }
284:
285:
286: /* This function calls refresh() if the option exrefresh is set */
287: void exrefresh()
288: {
289: char *scan;
290:
291: /* If this ex command wrote ANYTHING set exwrote so vi's : command
292: * can tell that it must wait for a user keystroke before redrawing.
293: */
294: for (scan=kbuf; scan<stdscr; scan++)
295: if (*scan == '\n')
296: exwrote = TRUE;
297:
298: /* now we do the refresh thing */
299: if (*o_exrefresh)
300: {
301: refresh();
302: }
303: else
304: {
305: wqrefresh();
306: }
307: if (mode != MODE_VI)
308: {
309: manymsgs = FALSE;
310: }
311: }
312:
313:
314: /* This structure is used to store maps and abbreviations. The distinction
315: * between them is that maps are stored in the list referenced by the "maps"
316: * pointer, while abbreviations are referenced by the "abbrs" pointer.
317: */
318: typedef struct _map
319: {
320: struct _map *next; /* another abbreviation */
321: short len; /* length of the "rawin" characters */
322: short flags; /* various flags */
323: char *label; /* label of the map/abbr, or NULL */
324: char *rawin; /* the "rawin" characters */
325: char *cooked;/* the "cooked" characters */
326: } MAP;
327:
328: static char keybuf[KEYBUFSIZE];
329: static int cend; /* end of input characters */
330: static int user; /* from user through end are chars typed by user */
331: static int next; /* index of the next character to be returned */
332: static MAP *match; /* the matching map, found by countmatch() */
333: static MAP *maps; /* the map table */
334: #ifndef NO_ABBR
335: static MAP *abbrs; /* the abbreviation table */
336: #endif
337:
338:
339:
340: /* ring the terminal's bell */
341: void beep()
342: {
343: /* do a visible/audible bell */
344: if (*o_flash)
345: {
346: do_VB();
347: refresh();
348: }
349: else if (*o_errorbells)
350: {
351: tputs("\007", 1, faddch);
352: }
353:
354: /* discard any buffered input, and abort macros */
355: next = user = cend;
356: }
357:
358:
359:
360: /* This function replaces a "rawin" character sequence with the "cooked" version,
361: * by modifying the internal type-ahead buffer.
362: */
363:
364: void execmap(rawlen, cookedstr, visual)
365: int rawlen; /* length of rawin text -- string to delete */
366: char *cookedstr; /* the cooked text -- string to insert */
367: int visual; /* boolean -- chars to be executed in visual mode? */
368: {
369: int cookedlen;
370: char *src, *dst;
371: int i;
372:
373: /* find the length of the cooked string */
374: cookedlen = strlen(cookedstr);
375: #ifndef NO_EXTENSIONS
376: if (visual)
377: {
378: cookedlen *= 2;
379: }
380: #endif
381:
382: /* if too big to fit in type-ahead buffer, then don't do it */
383: if (cookedlen + (cend - next) - rawlen > KEYBUFSIZE)
384: {
385: return;
386: }
387:
388: /* shift to make room for cookedstr at the front of keybuf */
389: src = &keybuf[next + rawlen];
390: dst = &keybuf[cookedlen];
391: i = cend - (next + rawlen);
392: if (src >= dst)
393: {
394: while (i-- > 0)
395: {
396: *dst++ = *src++;
397: }
398: }
399: else
400: {
401: src += i;
402: dst += i;
403: while (i-- > 0)
404: {
405: *--dst = *--src;
406: }
407: }
408:
409: /* insert cookedstr, and adjust offsets */
410: cend += cookedlen - rawlen - next;
411: user += cookedlen - rawlen - next;
412: next = 0;
413: for (dst = keybuf, src = cookedstr; *src; )
414: {
415: #ifndef NO_EXTENSIONS
416: if (visual)
417: {
418: *dst++ = ctrl('O');
419: cookedlen--;
420: }
421: #endif
422: *dst++ = *src++;
423: }
424:
425: #ifdef DEBUG2
426: {
427: #include <stdio.h>
428: FILE *debout;
429: int i;
430:
431: debout = fopen("debug.out", "a");
432: fprintf(debout, "After execmap(%d, \"%s\", %d)...\n", rawlen, cookedstr, visual);
433: for (i = 0; i < cend; i++)
434: {
435: if (i == next) fprintf(debout, "(next)");
436: if (i == user) fprintf(debout, "(user)");
437: if (UCHAR(keybuf[i]) < ' ')
438: fprintf(debout, "^%c", keybuf[i] ^ '@');
439: else
440: fprintf(debout, "%c", keybuf[i]);
441: }
442: fprintf(debout, "(end)\n");
443: fclose(debout);
444: }
445: #endif
446: }
447:
448: /* This function calls ttyread(). If necessary, it will also redraw the screen,
449: * change the cursor shape, display the mode, and update the ruler. If the
450: * number of characters read is 0, and we didn't time-out, then it exits because
451: * we've apparently reached the end of an EX script.
452: */
453: static int fillkeybuf(when, timeout)
454: int when; /* mixture of WHEN_XXX flags */
455: int timeout;/* timeout in 1/10 second increments, or 0 */
456: {
457: int nkeys;
458: #ifndef NO_SHOWMODE
459: static int oldwhen; /* "when" from last time */
460: static int oldleft;
461: static long oldtop;
462: static long oldnlines;
463: char *str;
464: #endif
465: #ifndef NO_CURSORSHAPE
466: static int oldcurs;
467: #endif
468:
469: #ifdef DEBUG
470: watch();
471: #endif
472:
473:
474: #ifndef NO_CURSORSHAPE
475: /* make sure the cursor is the right shape */
476: if (has_CQ)
477: {
478: if (when != oldcurs)
479: {
480: switch (when)
481: {
482: case WHEN_EX: do_CX(); break;
483: case WHEN_VICMD: do_CV(); break;
484: case WHEN_VIINP: do_CI(); break;
485: case WHEN_VIREP: do_CR(); break;
486: }
487: oldcurs = when;
488: }
489: }
490: #endif
491:
492: #ifndef NO_SHOWMODE
493: /* if "showmode" then say which mode we're in */
494: if (*o_smd && (when & WHENMASK))
495: {
496: /* redraw the screen before we check to see whether the
497: * "showmode" message needs to be redrawn.
498: */
499: redraw(cursor, !(when & WHEN_VICMD));
500:
501: /* now the "topline" test should be valid */
502: if (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines)
503: {
504: oldwhen = when;
505: oldtop = topline;
506: oldleft = leftcol;
507: oldnlines = nlines;
508:
509: if (when & WHEN_VICMD) str = "Command";
510: else if (when & WHEN_VIINP) str = " Input ";
511: else if (when & WHEN_VIREP) str = "Replace";
512: else if (when & WHEN_REP1) str = " Rep 1 ";
513: else if (when & WHEN_CUT) str = "BufName";
514: else if (when & WHEN_MARK) str = "Mark AZ";
515: else if (when & WHEN_CHAR) str = "Dest Ch";
516: else str = (char *)0;
517:
518: if (str)
519: {
520: move(LINES - 1, COLS - 10);
521: standout();
522: qaddstr(str);
523: standend();
524: }
525: }
526: }
527: #endif
528:
529: #ifndef NO_EXTENSIONS
530: /* maybe display the ruler */
531: if (*o_ruler && (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)))
532: {
533: char buf[20];
534:
535: redraw(cursor, !(when & WHEN_VICMD));
536: pfetch(markline(cursor));
537: sprintf(buf, "%7ld,%-4d", markline(cursor), 1 + idx2col(cursor, ptext, when & (WHEN_VIINP|WHEN_VIREP)));
538: move(LINES - 1, COLS - 22);
539: addstr(buf);
540: }
541: #endif
542:
543: /* redraw, so the cursor is in the right place */
544: if (when & WHENMASK)
545: {
546: redraw(cursor, !(when & (WHENMASK & ~(WHEN_VIREP|WHEN_VIINP))));
547: }
548:
549: /* Okay, now we can finally read the rawin keystrokes */
550: refresh();
551: nkeys = ttyread(keybuf + cend, sizeof keybuf - cend, timeout);
552:
553: /* if nkeys == 0 then we've reached EOF of an ex script. */
554: if (nkeys == 0 && timeout == 0)
555: {
556: tmpabort(TRUE);
557: move(LINES - 1, 0);
558: clrtoeol();
559: refresh();
560: endwin();
561: exit(exitcode);
562: }
563:
564: cend += nkeys;
565: user += nkeys;
566: return nkeys;
567: }
568:
569:
570: /* This function counts the number of maps that could match the characters
571: * between &keybuf[next] and &keybuf[cend], including incomplete matches.
572: * The longest comlete match is remembered via the "match" variable.
573: */
574: static int countmatch(when)
575: int when; /* mixture of WHEN_XXX flags */
576: {
577: MAP *map;
578: int count;
579:
580: /* clear the "match" variable */
581: match = (MAP *)0;
582:
583: /* check every map */
584: for (count = 0, map = maps; map; map = map->next)
585: {
586: /* can't match if wrong mode */
587: if ((map->flags & when) == 0)
588: {
589: continue;
590: }
591:
592: /* would this be a complete match? */
593: if (map->len <= cend - next)
594: {
595: /* Yes, it would be. Now does it really match? */
596: if (!strncmp(map->rawin, &keybuf[next], map->len))
597: {
598: count++;
599:
600: /* if this is the longest complete match,
601: * then remember it.
602: */
603: if (!match || match->len < map->len)
604: {
605: match = map;
606: }
607: }
608: }
609: else
610: {
611: /* No, it wouldn't. But check for partial match */
612: if (!strncmp(map->rawin, &keybuf[next], cend - next))
613: {
614: count++;
615: }
616: }
617: }
618: return count;
619: }
620:
621:
622: #ifndef NO_ABBR
623: /* This function checks to see whether a word is an abbreviation. If it is,
624: * then an appropriate number of backspoace characters is inserted into the
625: * type-ahead buffer, followed by the expanded form of the abbreviation.
626: */
627: static void expandabbr(word, wlen)
628: char *word;
629: int wlen;
630: {
631: MAP *abbr;
632:
633: /* if the next character wouldn't end the word, then don't expand */
634: if (isalnum(keybuf[next]) || keybuf[next] == ctrl('V'))
635: {
636: return;
637: }
638:
639: /* find the abbreviation, if any */
640: for (abbr = abbrs;
641: abbr && (abbr->len != wlen || strncmp(abbr->rawin, word, wlen));
642: abbr = abbr->next)
643: {
644: }
645:
646: /* If an abbreviation was found, then expand it by inserting the long
647: * version into the type-ahead buffer, and then inserting (in front of
648: * the long version) enough backspaces to erase to the short version.
649: */
650: if (abbr)
651: {
652: execmap(0, abbr->cooked, FALSE);
653: while (wlen > 15)
654: {
655: execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", FALSE);
656: wlen -= 15;
657: }
658: if (wlen > 0)
659: {
660: execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + 15 - wlen, FALSE);
661: }
662: }
663: }
664: #endif
665:
666:
667: /* This function calls getabkey() without attempting to expand abbreviations */
668: int getkey(when)
669: int when; /* mixture of WHEN_XXX flags */
670: {
671: return getabkey(when, "", 0);
672: }
673:
674:
675: /* This is it. This function returns keystrokes one-at-a-time, after mapping
676: * and abbreviations have been taken into account.
677: */
678: int getabkey(when, word, wlen)
679: int when; /* mixture of WHEN_XXX flags */
680: char *word; /* a word that may need to be expanded as an abbr */
681: int wlen; /* length of "word" -- since "word" might not have \0 */
682: {
683: int matches;
684:
685: /* if this key is needed for delay between multiple error messages,
686: * then reset the manymsgs flag and abort any mapped key sequence.
687: */
688: if (showmsg())
689: {
690: if (when == WHEN_MSG)
691: {
692: #ifndef CRUNCH
693: if (!*o_more)
694: {
695: refresh();
696: return ' ';
697: }
698: #endif
699: qaddstr("[More...]");
700: refresh();
701: execmap(user, "", FALSE);
702: }
703: }
704:
705: #ifdef DEBUG
706: /* periodically check for screwed up internal tables */
707: watch();
708: #endif
709:
710: /* if buffer empty, read some characters without timeout */
711: if (next >= cend)
712: {
713: next = user = cend = 0;
714: fillkeybuf(when, 0);
715: }
716:
717: /* try to map the key, unless already mapped and not ":set noremap" */
718: if (next >= user || *o_remap)
719: {
720: do
721: {
722: do
723: {
724: matches = countmatch(when);
725: } while (matches > 1 && fillkeybuf(when, *o_keytime) > 0);
726: if (matches == 1)
727: {
728: if (match) {
729: execmap(match->len, match->cooked,
730: (match->flags & WHEN_INMV) != 0
731: && (when & (WHEN_VIINP|WHEN_VIREP)) != 0);
732: } else
733: matches = 0;
734: }
735: } while (*o_remap && matches == 1);
736: }
737:
738: #ifndef NO_ABBR
739: /* try to expand an abbreviation, except in visual command mode */
740: if (wlen > 0 && (mode & (WHEN_EX|WHEN_VIINP|WHEN_VIREP)) != 0)
741: {
742: expandabbr(word, wlen);
743: }
744: #endif
745:
746: /* ERASEKEY should always be mapped to '\b'. */
747: if (keybuf[next] == ERASEKEY)
748: {
749: keybuf[next] = '\b';
750: }
751:
752: /* return the next key */
753: return keybuf[next++];
754: }
755:
756: /* This function maps or unmaps a key */
757: void mapkey(rawin, cooked, when, name)
758: char *rawin; /* the input key sequence, before mapping */
759: char *cooked;/* after mapping -- or NULL to remove map */
760: int when; /* bitmap of when mapping should happen */
761: char *name; /* name of the key, NULL for no name, "abbr" for abbr */
762: {
763: MAP **head; /* head of list of maps or abbreviations */
764: MAP *scan; /* used for scanning through the list */
765: MAP *prev; /* used during deletions */
766:
767: /* Is this a map or an abbreviation? Choose the right list. */
768: #ifndef NO_ABBR
769: head = ((!name || strcmp(name, "abbr")) ? &maps : &abbrs);
770: #else
771: head = &maps;
772: #endif
773:
774: /* try to find the map in the list */
775: for (scan = *head, prev = (MAP *)0;
776: scan && (strcmp(rawin, scan->rawin) ||
777: !(scan->flags & when & (WHEN_EX|WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)));
778: prev = scan, scan = scan->next)
779: {
780: }
781:
782: /* trying to map? (not unmap) */
783: if (cooked && *cooked)
784: {
785: /* if map starts with "visual ", then mark it as a visual map */
786: if (head == &maps && !strncmp(cooked, "visual ", 7))
787: {
788: cooked += 7;
789: when |= WHEN_INMV;
790: }
791:
792: /* "visual" maps always work in input mode */
793: if (when & WHEN_INMV)
794: {
795: when |= WHEN_VIINP|WHEN_VIREP|WHEN_POPUP;
796: }
797:
798: /* if not already in the list, then allocate a new structure */
799: if (!scan)
800: {
801: scan = (MAP *)malloc(sizeof(MAP));
802: scan->len = strlen(rawin);
803: scan->rawin = malloc((unsigned)(scan->len + 1));
804: strcpy(scan->rawin, rawin);
805: scan->flags = when;
806: scan->label = name;
807: if (*head)
808: {
809: prev->next = scan;
810: }
811: else
812: {
813: *head = scan;
814: }
815: scan->next = (MAP *)0;
816: }
817: else /* recycle old structure */
818: {
819: _free_(scan->cooked);
820: }
821: scan->cooked = malloc((unsigned)(strlen(cooked) + 1));
822: strcpy(scan->cooked, cooked);
823: }
824: else /* unmapping */
825: {
826: /* if nothing to unmap, then exit silently */
827: if (!scan)
828: {
829: return;
830: }
831:
832: /* unlink the structure from the list */
833: if (prev)
834: {
835: prev->next = scan->next;
836: }
837: else
838: {
839: *head = scan->next;
840: }
841:
842: /* free it, and the strings that it refers to */
843: _free_(scan->rawin);
844: _free_(scan->cooked);
845: _free_(scan);
846: }
847: }
848:
849:
850: /* This function returns a printable version of a string. It uses tmpblk.c */
851: char *printable(str)
852: char *str; /* the string to convert */
853: {
854: char *build; /* used for building the string */
855:
856: for (build = tmpblk.c; *str; str++)
857: {
858: #if AMIGA
859: if (*str == '\233')
860: {
861: *build++ = '<';
862: *build++ = 'C';
863: *build++ = 'S';
864: *build++ = 'I';
865: *build++ = '>';
866: } else
867: #endif
868: if (UCHAR(*str) < ' ' || *str == '\177')
869: {
870: *build++ = '^';
871: *build++ = *str ^ '@';
872: }
873: else
874: {
875: *build++ = *str;
876: }
877: }
878: *build = '\0';
879: return tmpblk.c;
880: }
881:
882: /* This function displays the contents of either the map table or the
883: * abbreviation table. User commands call this function as follows:
884: * :map dumpkey(WHEN_VICMD, FALSE);
885: * :map! dumpkey(WHEN_VIREP|WHEN_VIINP, FALSE);
886: * :abbr dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE);
887: * :abbr! dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE);
888: */
889: void dumpkey(when, abbr)
890: int when; /* WHEN_XXXX of mappings to be dumped */
891: int abbr; /* boolean: dump abbreviations instead of maps? */
892: {
893: MAP *scan;
894: char *str;
895: int len;
896:
897: #ifndef NO_ABBR
898: for (scan = (abbr ? abbrs : maps); scan; scan = scan->next)
899: #else
900: for (scan = maps; scan; scan = scan->next)
901: #endif
902: {
903: /* skip entries that don't match "when" */
904: if ((scan->flags & when) == 0)
905: {
906: continue;
907: }
908:
909: /* dump the key label, if any */
910: if (!abbr)
911: {
912: len = 8;
913: if (scan->label)
914: {
915: qaddstr(scan->label);
916: len -= strlen(scan->label);
917: }
918: do
919: {
920: qaddch(' ');
921: } while (len-- > 0);
922: }
923:
924: /* dump the rawin version */
925: str = printable(scan->rawin);
926: qaddstr(str);
927: len = strlen(str);
928: do
929: {
930: qaddch(' ');
931: } while (len++ < 8);
932:
933: /* dump the mapped version */
934: #ifndef NO_EXTENSIONS
935: if ((scan->flags & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
936: {
937: qaddstr("visual ");
938: }
939: #endif
940: str = printable(scan->cooked);
941: qaddstr(str);
942: addch('\n');
943: exrefresh();
944: }
945: }
946:
947: #ifndef NO_MKEXRC
948:
949: static void safequote(str)
950: char *str;
951: {
952: char *build;
953:
954: build = tmpblk.c + strlen(tmpblk.c);
955: while (*str)
956: {
957: if (*str <= ' ' && *str >= 1 || *str == '|')
958: {
959: *build++ = ctrl('V');
960: }
961: *build++ = *str++;
962: }
963: *build = '\0';
964: }
965:
966: /* This function saves the contents of either the map table or the
967: * abbreviation table into a file. Both the "bang" and "no bang" versions
968: * are saved.
969: * :map dumpkey(WHEN_VICMD, FALSE);
970: * :map! dumpkey(WHEN_VIREP|WHEN_VIINP, FALSE);
971: * :abbr dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE);
972: * :abbr! dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE);
973: */
974: void
975: savemaps(fd, abbr)
976: int fd; /* file descriptor of an open file to write to */
977: int abbr; /* boolean: do abbr table? (else do map table) */
978: {
979: MAP *scan;
980: int bang;
981: int when;
982:
983: # ifndef NO_ABBR
984: for (scan = (abbr ? abbrs : maps); scan; scan = scan->next)
985: # else
986: for (scan = maps; scan; scan = scan->next)
987: # endif
988: {
989: /* skip maps that have labels, except for function keys */
990: if (scan->label && *scan->label != '#')
991: {
992: continue;
993: }
994:
995: for (bang = 0; bang < 2; bang++)
996: {
997: /* decide which "when" flags we want */
998: # ifndef NO_ABBR
999: if (abbr)
1000: when = (bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP);
1001: else
1002: # endif
1003: when = (bang ? WHEN_VIREP|WHEN_VIINP : WHEN_VICMD);
1004:
1005: /* skip entries that don't match "when" */
1006: if ((scan->flags & when) == 0)
1007: {
1008: continue;
1009: }
1010:
1011: /* write a "map" or "abbr" command name */
1012: # ifndef NO_ABBR
1013: if (abbr)
1014: strcpy(tmpblk.c, "abbr");
1015: else
1016: # endif
1017: strcpy(tmpblk.c, "map");
1018:
1019: /* maybe write a bang. Definitely write a space */
1020: if (bang)
1021: strcat(tmpblk.c, "! ");
1022: else
1023: strcat(tmpblk.c, " ");
1024:
1025: /* write the rawin version */
1026: # ifndef NO_FKEY
1027: if (scan->label)
1028: strcat(tmpblk.c, scan->label);
1029: else
1030: # endif
1031: safequote(scan->rawin);
1032: strcat(tmpblk.c, " ");
1033:
1034: /* dump the mapped version */
1035: # ifndef NO_EXTENSIONS
1036: if ((scan->flags & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
1037: {
1038: strcat(tmpblk.c, "visual ");
1039: }
1040: # endif
1041: safequote(scan->cooked);
1042: strcat(tmpblk.c, "\n");
1043: twrite(fd, tmpblk.c, strlen(tmpblk.c));
1044: }
1045: }
1046: }
1047: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.