5 * 14407 SW Teal Blvd. #C
11 /* This file contains terminal I/O functions */
18 /* This function reads in a line from the terminal. */
19 int 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 */
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 */
31 int erased
; /* 0, or first char of a digraph */
45 /* read in the line */
53 if (quoted
|| mode
== MODE_EX
)
59 /* maybe expand an abbreviation while getting key */
60 for (word
= len
; --word
>= 0 && isalnum(buf
[word
]); )
64 ch
= getabkey(WHEN_EX
, &buf
[word
], len
- word
);
72 ch
= getkey(quoted
? 0 : WHEN_EX
);
76 /* some special conversions */
77 if (ch
== ctrl('D') && len
== 0)
80 if (*o_digraph
&& erased
!= 0 && ch
!= '\b')
82 ch
= digraph(erased
, ch
);
87 /* inhibit detection of special chars (except ^J) after a ^V */
88 if (quoted
&& ch
!= '\n')
93 /* process the character */
121 for (ch
= widths
[len
]; ch
> 0; ch
--)
136 /* strip off quotation bit */
144 /* add & echo the char */
147 if (ch
== '\t' && !quoted
)
149 widths
[len
] = *o_tabstop
- (tab
% *o_tabstop
);
150 addstr(" " + 8 - widths
[len
]);
153 else if (ch
> 0 && ch
< ' ') /* > 0 by GB */
160 else if (ch
== '\177')
189 static int manymsgs
; /* This variable keeps msgs from overwriting each other */
190 static char pmsg
[80]; /* previous message (waiting to be displayed) */
195 /* if there is no message to show, then don't */
199 /* display the message */
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!!!
228 * In MODE_EX or MODE_COLON, the message is written immediately, with a
229 * newline at the end.
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.
235 * msg("") - clears the message line
236 * msg("%s %d", ...) - does a printf onto the message line
239 void msg(fmt
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
)
241 long arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
;
245 sprintf(pmsg
, fmt
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
);
252 /* wait for keypress between consecutive msgs */
259 sprintf(pmsg
, fmt
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
);
268 /* This function calls refresh() if the option exrefresh is set */
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.
276 for (scan
=kbuf
; scan
<stdscr
; scan
++)
280 /* now we do the refresh thing */
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.
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 */
310 static char keybuf
[KEYBUFSIZE
];
311 static int cend
; /* end of input characters */
312 static int user
; /* from user through end are chars typed by user */
313 static int next
; /* index of the next character to be returned */
314 static MAP
*match
; /* the matching map, found by countmatch() */
315 static MAP
*maps
; /* the map table */
317 static MAP
*abbrs
; /* the abbreviation table */
322 /* ring the terminal's bell */
325 /* do a visible/audible bell */
331 else if (*o_errorbells
)
336 /* discard any buffered input, and abort macros */
342 /* This function replaces a "rawin" character sequence with the "cooked" version,
343 * by modifying the internal type-ahead buffer.
345 void 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? */
354 /* find the length of the cooked string */
355 cookedlen
= strlen(cookedstr
);
356 #ifndef NO_EXTENSIONS
363 /* if too big to fit in type-ahead buffer, then don't do it */
364 if (cookedlen
+ (cend
- next
) - rawlen
> KEYBUFSIZE
)
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
);
390 /* insert cookedstr, and adjust offsets */
391 cend
+= cookedlen
- rawlen
- next
;
392 user
+= cookedlen
- rawlen
- next
;
394 for (dst
= keybuf
, src
= cookedstr
; *src
; )
396 #ifndef NO_EXTENSIONS
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
++)
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
] ^ '@');
421 fprintf(debout
, "%c", keybuf
[i
]);
423 fprintf(debout
, "(end)\n");
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.
434 static int fillkeybuf(when
, timeout
)
435 int when
; /* mixture of WHEN_XXX flags */
436 int timeout
;/* timeout in 1/10 second increments, or 0 */
440 static int oldwhen
; /* "when" from last time */
443 static long oldnlines
;
446 #ifndef NO_CURSORSHAPE
455 #ifndef NO_CURSORSHAPE
456 /* make sure the cursor is the right shape */
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;
474 /* if "showmode" then say which mode we're in */
475 if (*o_smd
&& (when
& WHENMASK
))
477 /* redraw the screen before we check to see whether the
478 * "showmode" message needs to be redrawn.
480 redraw(cursor
, !(when
& WHEN_VICMD
));
482 /* now the "topline" test should be valid */
483 if (when
!= oldwhen
|| topline
!= oldtop
|| leftcol
!= oldleft
|| nlines
!= oldnlines
)
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;
501 move(LINES
- 1, COLS
- 10);
510 #ifndef NO_EXTENSIONS
511 /* maybe display the ruler */
512 if (*o_ruler
&& (when
& (WHEN_VICMD
|WHEN_VIINP
|WHEN_VIREP
)))
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);
524 /* redraw, so the cursor is in the right place */
527 redraw(cursor
, !(when
& (WHENMASK
& ~(WHEN_VIREP
|WHEN_VIINP
))));
530 /* Okay, now we can finally read the rawin keystrokes */
532 nkeys
= ttyread(keybuf
+ cend
, sizeof keybuf
- cend
, timeout
);
534 /* if nkeys == 0 then we've reached EOF of an ex script. */
535 if (nkeys
== 0 && timeout
== 0)
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.
555 static int countmatch(when
)
556 int when
; /* mixture of WHEN_XXX flags */
561 /* clear the "match" variable */
564 /* check every map */
565 for (count
= 0, map
= maps
; map
; map
= map
->next
)
567 /* can't match if wrong mode */
568 if ((map
->flags
& when
) == 0)
573 /* would this be a complete match? */
574 if (map
->len
<= cend
- next
)
576 /* Yes, it would be. Now does it really match? */
577 if (!strncmp(map
->rawin
, &keybuf
[next
], map
->len
))
581 /* if this is the longest complete match,
584 if (!match
|| match
->len
< map
->len
)
592 /* No, it wouldn't. But check for partial match */
593 if (!strncmp(map
->rawin
, &keybuf
[next
], cend
- next
))
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.
608 static void expandabbr(word
, wlen
)
614 /* if the next character wouldn't end the word, then don't expand */
615 if (isalnum(keybuf
[next
]) || keybuf
[next
] == ctrl('V'))
620 /* find the abbreviation, if any */
622 abbr
&& (abbr
->len
!= wlen
|| strncmp(abbr
->rawin
, word
, wlen
));
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.
633 execmap(0, abbr
->cooked
, FALSE
);
636 execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", FALSE
);
641 execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + 15 - wlen
, FALSE
);
648 /* This function calls getabkey() without attempting to expand abbreviations */
650 int when
; /* mixture of WHEN_XXX flags */
652 return getabkey(when
, "", 0);
656 /* This is it. This function returns keystrokes one-at-a-time, after mapping
657 * and abbreviations have been taken into account.
659 int 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 */
666 /* if this key is needed for delay between multiple error messages,
667 * then reset the manymsgs flag and abort any mapped key sequence.
671 if (when
== WHEN_MSG
)
680 qaddstr("[More...]");
682 execmap(user
, "", FALSE
);
687 /* periodically check for screwed up internal tables */
691 /* if buffer empty, read some characters without timeout */
694 next
= user
= cend
= 0;
698 /* try to map the key, unless already mapped and not ":set noremap" */
699 if (next
>= user
|| *o_remap
)
705 matches
= countmatch(when
);
706 } while (matches
> 1 && fillkeybuf(when
, *o_keytime
) > 0);
709 execmap(match
->len
, match
->cooked
,
710 (match
->flags
& WHEN_INMV
) != 0
711 && (when
& (WHEN_VIINP
|WHEN_VIREP
)) != 0);
713 } while (*o_remap
&& matches
== 1);
717 /* try to expand an abbreviation, except in visual command mode */
718 if (wlen
> 0 && (mode
& (WHEN_EX
|WHEN_VIINP
|WHEN_VIREP
)) != 0)
720 expandabbr(word
, wlen
);
724 /* ERASEKEY should always be mapped to '\b'. */
725 if (keybuf
[next
] == ERASEKEY
)
730 /* return the next key */
731 return keybuf
[next
++];
734 /* This function maps or unmaps a key */
735 void 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 */
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 */
745 /* Is this a map or an abbreviation? Choose the right list. */
747 head
= ((!name
|| strcmp(name
, "abbr")) ? &maps
: &abbrs
);
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
)
760 /* trying to map? (not unmap) */
761 if (cooked
&& *cooked
)
763 /* if map starts with "visual ", then mark it as a visual map */
764 if (head
== &maps
&& !strncmp(cooked
, "visual ", 7))
770 /* "visual" maps always work in input mode */
771 if (when
& WHEN_INMV
)
773 when
|= WHEN_VIINP
|WHEN_VIREP
|WHEN_POPUP
;
776 /* if not already in the list, then allocate a new structure */
779 scan
= (MAP
*)malloc(sizeof(MAP
));
780 scan
->len
= strlen(rawin
);
781 scan
->rawin
= malloc(scan
->len
+ 1);
782 strcpy(scan
->rawin
, rawin
);
793 scan
->next
= (MAP
*)0;
795 else /* recycle old structure */
799 scan
->cooked
= malloc(strlen(cooked
) + 1);
800 strcpy(scan
->cooked
, cooked
);
804 /* if nothing to unmap, then exit silently */
810 /* unlink the structure from the list */
813 prev
->next
= scan
->next
;
820 /* free it, and the strings that it refers to */
828 /* This function returns a printable version of a string. It uses tmpblk.c */
830 char *str
; /* the string to convert */
832 char *build
; /* used for building the string */
834 for (build
= tmpblk
.c
; *str
; str
++)
846 if (UCHAR(*str
) < ' ' || *str
== '\177')
849 *build
++ = *str
^ '@';
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);
867 void dumpkey(when
, abbr
)
868 int when
; /* WHEN_XXXX of mappings to be dumped */
869 int abbr
; /* boolean: dump abbreviations instead of maps? */
876 for (scan
= (abbr
? abbrs
: maps
); scan
; scan
= scan
->next
)
878 for (scan
= maps
; scan
; scan
= scan
->next
)
881 /* skip entries that don't match "when" */
882 if ((scan
->flags
& when
) == 0)
887 /* dump the key label, if any */
893 qaddstr(scan
->label
);
894 len
-= strlen(scan
->label
);
902 /* dump the rawin version */
903 str
= printable(scan
->rawin
);
911 /* dump the mapped version */
912 #ifndef NO_EXTENSIONS
913 if ((scan
->flags
& WHEN_INMV
) && (when
& (WHEN_VIINP
|WHEN_VIREP
)))
918 str
= printable(scan
->cooked
);
927 static safequote(str
)
932 build
= tmpblk
.c
+ strlen(tmpblk
.c
);
935 if (*str
<= ' ' && *str
>= 1 || *str
== '|')
937 *build
++ = ctrl('V');
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
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);
953 int fd
; /* file descriptor of an open file to write to */
954 int abbr
; /* boolean: do abbr table? (else do map table) */
963 for (scan
= (abbr
? abbrs
: maps
); scan
; scan
= scan
->next
)
965 for (scan
= maps
; scan
; scan
= scan
->next
)
968 /* skip maps that have labels, except for function keys */
969 if (scan
->label
&& *scan
->label
!= '#')
974 for (bang
= 0; bang
< 2; bang
++)
976 /* decide which "when" flags we want */
979 when
= (bang
? WHEN_EX
|WHEN_VIINP
|WHEN_VIREP
: WHEN_VIINP
|WHEN_VIREP
);
982 when
= (bang
? WHEN_VIREP
|WHEN_VIINP
: WHEN_VICMD
);
984 /* skip entries that don't match "when" */
985 if ((scan
->flags
& when
) == 0)
990 /* write a "map" or "abbr" command name */
993 strcpy(tmpblk
.c
, "abbr");
996 strcpy(tmpblk
.c
, "map");
998 /* maybe write a bang. Definitely write a space */
1000 strcat(tmpblk
.c
, "! ");
1002 strcat(tmpblk
.c
, " ");
1004 /* write the rawin version */
1007 strcat(tmpblk
.c
, scan
->label
);
1010 safequote(scan
->rawin
);
1011 strcat(tmpblk
.c
, " ");
1013 /* dump the mapped version */
1014 # ifndef NO_EXTENSIONS
1015 if ((scan
->flags
& WHEN_INMV
) && (when
& (WHEN_VIINP
|WHEN_VIREP
)))
1017 strcat(tmpblk
.c
, "visual ");
1020 safequote(scan
->cooked
);
1021 strcat(tmpblk
.c
, "\n");
1022 twrite(fd
, tmpblk
.c
, strlen(tmpblk
.c
));