source: trunk/minix/commands/elvis/tio.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

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