1/* $FreeBSD: head/contrib/libreadline/vi_mode.c 136759 2004-10-21 20:10:14Z peter $ */
2
3/* vi_mode.c -- A vi emulation mode for Bash.
4 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
5
6/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
7
8 This file is part of the GNU Readline Library, a library for
9 reading lines of text with interactive input and history editing.
10
11 The GNU Readline Library is free software; you can redistribute it
12 and/or modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2, or
14 (at your option) any later version.
--- 72 unchanged lines hidden (view full) ---
87static char *vi_insert_buffer;
88static int vi_insert_buffer_size;
89
90static int _rl_vi_last_repeat = 1;
91static int _rl_vi_last_arg_sign = 1;
92static int _rl_vi_last_motion;
93#if defined (HANDLE_MULTIBYTE)
94static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
95#else
96static int _rl_vi_last_search_char;
97#endif
98static int _rl_vi_last_replacement;
99
100static int _rl_vi_last_key_before_insert;
101
102static int vi_redoing;
103
104/* Text modification commands. These are the `redoable' commands. */
105static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
106
107/* Arrays for the saved marks. */
108static int vi_mark_chars['z' - 'a' + 1];
109
110static void _rl_vi_stuff_insert PARAMS((int));
111static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
112static int rl_digit_loop1 PARAMS((void));
113
114void
115_rl_vi_initialize_line ()
116{
117 register int i;
118
119 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
120 vi_mark_chars[i] = -1;
121}
122
123void
124_rl_vi_reset_last ()
125{
126 _rl_vi_last_command = 'i';
127 _rl_vi_last_repeat = 1;
128 _rl_vi_last_arg_sign = 1;
--- 539 unchanged lines hidden (view full) ---
668rl_vi_movement_mode (count, key)
669 int count, key;
670{
671 if (rl_point > 0)
672 rl_backward_char (1, key);
673
674 _rl_keymap = vi_movement_keymap;
675 _rl_vi_done_inserting ();
676 return (0);
677}
678
679int
680rl_vi_arg_digit (count, c)
681 int count, c;
682{
683 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
--- 153 unchanged lines hidden (view full) ---
837
838 if (!member (c, vi_motion))
839 {
840 if (_rl_digit_p (c))
841 {
842 save = rl_numeric_arg;
843 rl_numeric_arg = _rl_digit_value (c);
844 rl_explicit_arg = 1;
845 rl_digit_loop1 ();
846 rl_numeric_arg *= save;
847 RL_SETSTATE(RL_STATE_MOREINPUT);
848 c = rl_read_key (); /* real command */
849 RL_UNSETSTATE(RL_STATE_MOREINPUT);
850 *nextkey = c;
851 }
852 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
853 {
--- 56 unchanged lines hidden (view full) ---
910 }
911
912 if (rl_mark < rl_point)
913 SWAP (rl_point, rl_mark);
914
915 return (0);
916}
917
918/* A simplified loop for vi. Don't dispatch key at end.
919 Don't recognize minus sign?
920 Should this do rl_save_prompt/rl_restore_prompt? */
921static int
922rl_digit_loop1 ()
923{
924 int key, c;
925
926 RL_SETSTATE(RL_STATE_NUMERICARG);
927 while (1)
928 {
929 if (rl_numeric_arg > 1000000)
930 {
931 rl_explicit_arg = rl_numeric_arg = 0;
932 rl_ding ();
933 rl_clear_message ();
934 RL_UNSETSTATE(RL_STATE_NUMERICARG);
935 return 1;
936 }
937 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
938 RL_SETSTATE(RL_STATE_MOREINPUT);
939 key = c = rl_read_key ();
940 RL_UNSETSTATE(RL_STATE_MOREINPUT);
941
942 if (c >= 0 && _rl_keymap[c].type == ISFUNC &&
943 _rl_keymap[c].function == rl_universal_argument)
944 {
945 rl_numeric_arg *= 4;
946 continue;
947 }
948
949 c = UNMETA (c);
950 if (_rl_digit_p (c))
951 {
952 if (rl_explicit_arg)
953 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
954 else
955 rl_numeric_arg = _rl_digit_value (c);
956 rl_explicit_arg = 1;
957 }
958 else
959 {
960 rl_clear_message ();
961 rl_stuff_char (key);
962 break;
963 }
964 }
965
966 RL_UNSETSTATE(RL_STATE_NUMERICARG);
967 return (0);
968}
969
970int
971rl_vi_delete_to (count, key)
--- 73 unchanged lines hidden (view full) ---
1045
1046 return (0);
1047}
1048
1049int
1050rl_vi_yank_to (count, key)
1051 int count, key;
1052{
1053 int c, save = rl_point;
1054
1055 if (_rl_uppercase_p (key))
1056 rl_stuff_char ('$');
1057
1058 if (rl_vi_domove (key, &c))
1059 {
1060 rl_ding ();
1061 return -1;
1062 }
--- 8 unchanged lines hidden (view full) ---
1071 rl_end_undo_group ();
1072 rl_do_undo ();
1073 rl_point = save;
1074
1075 return (0);
1076}
1077
1078int
1079rl_vi_delete (count, key)
1080 int count, key;
1081{
1082 int end;
1083
1084 if (rl_end == 0)
1085 {
1086 rl_ding ();
1087 return -1;
1088 }
1089
1090 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1091 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1092 else
1093 end = rl_point + count;
1094
1095 if (end >= rl_end)
1096 end = rl_end;
1097
1098 rl_kill_text (rl_point, end);
1099
1100 if (rl_point > 0 && rl_point == rl_end)
1101 rl_backward_char (1, key);
1102 return (0);
1103}
1104
1105int
1106rl_vi_back_to_indent (count, key)
1107 int count, key;
1108{
1109 rl_beg_of_line (1, key);
--- 4 unchanged lines hidden (view full) ---
1114
1115int
1116rl_vi_first_print (count, key)
1117 int count, key;
1118{
1119 return (rl_vi_back_to_indent (1, key));
1120}
1121
1122int
1123rl_vi_char_search (count, key)
1124 int count, key;
1125{
1126#if defined (HANDLE_MULTIBYTE)
1127 static char *target;
1128 static int mb_len;
1129#else
1130 static char target;
1131#endif
1132 static int orig_dir, dir;
1133
1134 if (key == ';' || key == ',')
1135 dir = key == ';' ? orig_dir : -orig_dir;
1136 else
1137 {
1138 if (vi_redoing)
1139#if defined (HANDLE_MULTIBYTE)
1140 target = _rl_vi_last_search_mbchar;
1141#else
1142 target = _rl_vi_last_search_char;
1143#endif
1144 else
1145 {
1146#if defined (HANDLE_MULTIBYTE)
1147 mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1148 target = _rl_vi_last_search_mbchar;
1149#else
1150 RL_SETSTATE(RL_STATE_MOREINPUT);
1151 _rl_vi_last_search_char = target = rl_read_key ();
1152 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1153#endif
1154 }
1155
1156 switch (key)
1157 {
1158 case 't':
1159 orig_dir = dir = FTO;
1160 break;
1161
1162 case 'T':
1163 orig_dir = dir = BTO;
1164 break;
1165
1166 case 'f':
1167 orig_dir = dir = FFIND;
1168 break;
1169
1170 case 'F':
1171 orig_dir = dir = BFIND;
1172 break;
1173 }
1174 }
1175
1176#if defined (HANDLE_MULTIBYTE)
1177 return (_rl_char_search_internal (count, dir, target, mb_len));
1178#else
1179 return (_rl_char_search_internal (count, dir, target));
1180#endif
1181}
1182
1183/* Match brackets */
1184int
1185rl_vi_match (ignore, key)
1186 int ignore, key;
1187{
1188 int count = 1, brack, pos, tmp, pre;
--- 93 unchanged lines hidden (view full) ---
1282 case '[': return 2;
1283 case ']': return -2;
1284 case '{': return 3;
1285 case '}': return -3;
1286 default: return 0;
1287 }
1288}
1289
1290/* XXX - think about reading an entire mbchar with _rl_read_mbchar and
1291 inserting it in one bunch instead of the loop below (like in
1292 rl_vi_char_search or _rl_vi_change_mbchar_case). Set c to mbchar[0]
1293 for test against 033 or ^C. Make sure that _rl_read_mbchar does
1294 this right. */
1295int
1296rl_vi_change_char (count, key)
1297 int count, key;
1298{
1299 int c, p;
1300
1301 if (vi_redoing)
1302 c = _rl_vi_last_replacement;
1303 else
1304 {
1305 RL_SETSTATE(RL_STATE_MOREINPUT);
1306 _rl_vi_last_replacement = c = rl_read_key ();
1307 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1308 }
1309
1310 if (c == '\033' || c == CTRL ('C'))
1311 return -1;
1312
1313 rl_begin_undo_group ();
1314 while (count-- && rl_point < rl_end)
1315 {
1316 p = rl_point;
1317 rl_vi_delete (1, c);
1318#if defined (HANDLE_MULTIBYTE)
1319 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1320 {
1321 if (rl_point < p) /* Did we retreat at EOL? */
1322 rl_point++;
1323 while (_rl_insert_char (1, c))
1324 {
1325 RL_SETSTATE (RL_STATE_MOREINPUT);
1326 c = rl_read_key ();
1327 RL_UNSETSTATE (RL_STATE_MOREINPUT);
1328 }
1329 }
1330 else
1331#endif
1332 {
1333 if (rl_point < p) /* Did we retreat at EOL? */
1334 rl_point++;
1335 _rl_insert_char (1, c);
1336 }
1337 }
1338 rl_end_undo_group ();
1339
1340 return (0);
1341}
1342
1343int
1344rl_vi_subst (count, key)
1345 int count, key;
1346{
1347 /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1348 if (vi_redoing == 0)
1349 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
1350
1351 return (rl_vi_change_to (count, 'c'));
--- 105 unchanged lines hidden (view full) ---
1457 rl_possible_completions ();
1458 rl_point = save_pos;
1459
1460 return (0);
1461}
1462#endif
1463
1464/* Functions to save and restore marks. */
1465int
1466rl_vi_set_mark (count, key)
1467 int count, key;
1468{
1469 int ch;
1470
1471 RL_SETSTATE(RL_STATE_MOREINPUT);
1472 ch = rl_read_key ();
1473 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1474
1475 if (ch < 'a' || ch > 'z')
1476 {
1477 rl_ding ();
1478 return -1;
1479 }
1480 ch -= 'a';
1481 vi_mark_chars[ch] = rl_point;
1482 return 0;
1483}
1484
1485int
1486rl_vi_goto_mark (count, key)
1487 int count, key;
1488{
1489 int ch;
1490
1491 RL_SETSTATE(RL_STATE_MOREINPUT);
1492 ch = rl_read_key ();
1493 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1494
1495 if (ch == '`')
1496 {
--- 11 unchanged lines hidden (view full) ---
1508 {
1509 rl_ding ();
1510 return -1;
1511 }
1512 rl_point = vi_mark_chars[ch];
1513 return 0;
1514}
1515
1516#endif /* VI_MODE */
2
3/* vi_mode.c -- A vi emulation mode for Bash.
4 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
5
6/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
7
8 This file is part of the GNU Readline Library, a library for
9 reading lines of text with interactive input and history editing.
10
11 The GNU Readline Library is free software; you can redistribute it
12 and/or modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2, or
14 (at your option) any later version.
--- 72 unchanged lines hidden (view full) ---
87static char *vi_insert_buffer;
88static int vi_insert_buffer_size;
89
90static int _rl_vi_last_repeat = 1;
91static int _rl_vi_last_arg_sign = 1;
92static int _rl_vi_last_motion;
93#if defined (HANDLE_MULTIBYTE)
94static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
95#else
96static int _rl_vi_last_search_char;
97#endif
98static int _rl_vi_last_replacement;
99
100static int _rl_vi_last_key_before_insert;
101
102static int vi_redoing;
103
104/* Text modification commands. These are the `redoable' commands. */
105static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
106
107/* Arrays for the saved marks. */
108static int vi_mark_chars['z' - 'a' + 1];
109
110static void _rl_vi_stuff_insert PARAMS((int));
111static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
112static int rl_digit_loop1 PARAMS((void));
113
114void
115_rl_vi_initialize_line ()
116{
117 register int i;
118
119 for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
120 vi_mark_chars[i] = -1;
121}
122
123void
124_rl_vi_reset_last ()
125{
126 _rl_vi_last_command = 'i';
127 _rl_vi_last_repeat = 1;
128 _rl_vi_last_arg_sign = 1;
--- 539 unchanged lines hidden (view full) ---
668rl_vi_movement_mode (count, key)
669 int count, key;
670{
671 if (rl_point > 0)
672 rl_backward_char (1, key);
673
674 _rl_keymap = vi_movement_keymap;
675 _rl_vi_done_inserting ();
676 return (0);
677}
678
679int
680rl_vi_arg_digit (count, c)
681 int count, c;
682{
683 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
--- 153 unchanged lines hidden (view full) ---
837
838 if (!member (c, vi_motion))
839 {
840 if (_rl_digit_p (c))
841 {
842 save = rl_numeric_arg;
843 rl_numeric_arg = _rl_digit_value (c);
844 rl_explicit_arg = 1;
845 rl_digit_loop1 ();
846 rl_numeric_arg *= save;
847 RL_SETSTATE(RL_STATE_MOREINPUT);
848 c = rl_read_key (); /* real command */
849 RL_UNSETSTATE(RL_STATE_MOREINPUT);
850 *nextkey = c;
851 }
852 else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
853 {
--- 56 unchanged lines hidden (view full) ---
910 }
911
912 if (rl_mark < rl_point)
913 SWAP (rl_point, rl_mark);
914
915 return (0);
916}
917
918/* A simplified loop for vi. Don't dispatch key at end.
919 Don't recognize minus sign?
920 Should this do rl_save_prompt/rl_restore_prompt? */
921static int
922rl_digit_loop1 ()
923{
924 int key, c;
925
926 RL_SETSTATE(RL_STATE_NUMERICARG);
927 while (1)
928 {
929 if (rl_numeric_arg > 1000000)
930 {
931 rl_explicit_arg = rl_numeric_arg = 0;
932 rl_ding ();
933 rl_clear_message ();
934 RL_UNSETSTATE(RL_STATE_NUMERICARG);
935 return 1;
936 }
937 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
938 RL_SETSTATE(RL_STATE_MOREINPUT);
939 key = c = rl_read_key ();
940 RL_UNSETSTATE(RL_STATE_MOREINPUT);
941
942 if (c >= 0 && _rl_keymap[c].type == ISFUNC &&
943 _rl_keymap[c].function == rl_universal_argument)
944 {
945 rl_numeric_arg *= 4;
946 continue;
947 }
948
949 c = UNMETA (c);
950 if (_rl_digit_p (c))
951 {
952 if (rl_explicit_arg)
953 rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
954 else
955 rl_numeric_arg = _rl_digit_value (c);
956 rl_explicit_arg = 1;
957 }
958 else
959 {
960 rl_clear_message ();
961 rl_stuff_char (key);
962 break;
963 }
964 }
965
966 RL_UNSETSTATE(RL_STATE_NUMERICARG);
967 return (0);
968}
969
970int
971rl_vi_delete_to (count, key)
--- 73 unchanged lines hidden (view full) ---
1045
1046 return (0);
1047}
1048
1049int
1050rl_vi_yank_to (count, key)
1051 int count, key;
1052{
1053 int c, save = rl_point;
1054
1055 if (_rl_uppercase_p (key))
1056 rl_stuff_char ('$');
1057
1058 if (rl_vi_domove (key, &c))
1059 {
1060 rl_ding ();
1061 return -1;
1062 }
--- 8 unchanged lines hidden (view full) ---
1071 rl_end_undo_group ();
1072 rl_do_undo ();
1073 rl_point = save;
1074
1075 return (0);
1076}
1077
1078int
1079rl_vi_delete (count, key)
1080 int count, key;
1081{
1082 int end;
1083
1084 if (rl_end == 0)
1085 {
1086 rl_ding ();
1087 return -1;
1088 }
1089
1090 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1091 end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1092 else
1093 end = rl_point + count;
1094
1095 if (end >= rl_end)
1096 end = rl_end;
1097
1098 rl_kill_text (rl_point, end);
1099
1100 if (rl_point > 0 && rl_point == rl_end)
1101 rl_backward_char (1, key);
1102 return (0);
1103}
1104
1105int
1106rl_vi_back_to_indent (count, key)
1107 int count, key;
1108{
1109 rl_beg_of_line (1, key);
--- 4 unchanged lines hidden (view full) ---
1114
1115int
1116rl_vi_first_print (count, key)
1117 int count, key;
1118{
1119 return (rl_vi_back_to_indent (1, key));
1120}
1121
1122int
1123rl_vi_char_search (count, key)
1124 int count, key;
1125{
1126#if defined (HANDLE_MULTIBYTE)
1127 static char *target;
1128 static int mb_len;
1129#else
1130 static char target;
1131#endif
1132 static int orig_dir, dir;
1133
1134 if (key == ';' || key == ',')
1135 dir = key == ';' ? orig_dir : -orig_dir;
1136 else
1137 {
1138 if (vi_redoing)
1139#if defined (HANDLE_MULTIBYTE)
1140 target = _rl_vi_last_search_mbchar;
1141#else
1142 target = _rl_vi_last_search_char;
1143#endif
1144 else
1145 {
1146#if defined (HANDLE_MULTIBYTE)
1147 mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1148 target = _rl_vi_last_search_mbchar;
1149#else
1150 RL_SETSTATE(RL_STATE_MOREINPUT);
1151 _rl_vi_last_search_char = target = rl_read_key ();
1152 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1153#endif
1154 }
1155
1156 switch (key)
1157 {
1158 case 't':
1159 orig_dir = dir = FTO;
1160 break;
1161
1162 case 'T':
1163 orig_dir = dir = BTO;
1164 break;
1165
1166 case 'f':
1167 orig_dir = dir = FFIND;
1168 break;
1169
1170 case 'F':
1171 orig_dir = dir = BFIND;
1172 break;
1173 }
1174 }
1175
1176#if defined (HANDLE_MULTIBYTE)
1177 return (_rl_char_search_internal (count, dir, target, mb_len));
1178#else
1179 return (_rl_char_search_internal (count, dir, target));
1180#endif
1181}
1182
1183/* Match brackets */
1184int
1185rl_vi_match (ignore, key)
1186 int ignore, key;
1187{
1188 int count = 1, brack, pos, tmp, pre;
--- 93 unchanged lines hidden (view full) ---
1282 case '[': return 2;
1283 case ']': return -2;
1284 case '{': return 3;
1285 case '}': return -3;
1286 default: return 0;
1287 }
1288}
1289
1290/* XXX - think about reading an entire mbchar with _rl_read_mbchar and
1291 inserting it in one bunch instead of the loop below (like in
1292 rl_vi_char_search or _rl_vi_change_mbchar_case). Set c to mbchar[0]
1293 for test against 033 or ^C. Make sure that _rl_read_mbchar does
1294 this right. */
1295int
1296rl_vi_change_char (count, key)
1297 int count, key;
1298{
1299 int c, p;
1300
1301 if (vi_redoing)
1302 c = _rl_vi_last_replacement;
1303 else
1304 {
1305 RL_SETSTATE(RL_STATE_MOREINPUT);
1306 _rl_vi_last_replacement = c = rl_read_key ();
1307 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1308 }
1309
1310 if (c == '\033' || c == CTRL ('C'))
1311 return -1;
1312
1313 rl_begin_undo_group ();
1314 while (count-- && rl_point < rl_end)
1315 {
1316 p = rl_point;
1317 rl_vi_delete (1, c);
1318#if defined (HANDLE_MULTIBYTE)
1319 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1320 {
1321 if (rl_point < p) /* Did we retreat at EOL? */
1322 rl_point++;
1323 while (_rl_insert_char (1, c))
1324 {
1325 RL_SETSTATE (RL_STATE_MOREINPUT);
1326 c = rl_read_key ();
1327 RL_UNSETSTATE (RL_STATE_MOREINPUT);
1328 }
1329 }
1330 else
1331#endif
1332 {
1333 if (rl_point < p) /* Did we retreat at EOL? */
1334 rl_point++;
1335 _rl_insert_char (1, c);
1336 }
1337 }
1338 rl_end_undo_group ();
1339
1340 return (0);
1341}
1342
1343int
1344rl_vi_subst (count, key)
1345 int count, key;
1346{
1347 /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1348 if (vi_redoing == 0)
1349 rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
1350
1351 return (rl_vi_change_to (count, 'c'));
--- 105 unchanged lines hidden (view full) ---
1457 rl_possible_completions ();
1458 rl_point = save_pos;
1459
1460 return (0);
1461}
1462#endif
1463
1464/* Functions to save and restore marks. */
1465int
1466rl_vi_set_mark (count, key)
1467 int count, key;
1468{
1469 int ch;
1470
1471 RL_SETSTATE(RL_STATE_MOREINPUT);
1472 ch = rl_read_key ();
1473 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1474
1475 if (ch < 'a' || ch > 'z')
1476 {
1477 rl_ding ();
1478 return -1;
1479 }
1480 ch -= 'a';
1481 vi_mark_chars[ch] = rl_point;
1482 return 0;
1483}
1484
1485int
1486rl_vi_goto_mark (count, key)
1487 int count, key;
1488{
1489 int ch;
1490
1491 RL_SETSTATE(RL_STATE_MOREINPUT);
1492 ch = rl_read_key ();
1493 RL_UNSETSTATE(RL_STATE_MOREINPUT);
1494
1495 if (ch == '`')
1496 {
--- 11 unchanged lines hidden (view full) ---
1508 {
1509 rl_ding ();
1510 return -1;
1511 }
1512 rl_point = vi_mark_chars[ch];
1513 return 0;
1514}
1515
1516#endif /* VI_MODE */