Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/editors
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- Location:
- branches/3.2/mindi-busybox/editors
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/editors/Config.src
r2725 r3232 68 68 or input from a pipeline. 69 69 70 config VI71 bool "vi"72 default y73 help74 'vi' is a text editor. More specifically, it is the One True75 text editor <grin>. It does, however, have a rather steep76 learning curve. If you are not already comfortable with 'vi'77 you may wish to use something else.78 79 config FEATURE_VI_MAX_LEN80 int "Maximum screen width in vi"81 range 256 1638482 default 409683 depends on VI84 help85 Contrary to what you may think, this is not eating much.86 Make it smaller than 4k only if you are very limited on memory.87 88 config FEATURE_VI_8BIT89 bool "Allow vi to display 8-bit chars (otherwise shows dots)"90 default n91 depends on VI92 help93 If your terminal can display characters with high bit set,94 you may want to enable this. Note: vi is not Unicode-capable.95 If your terminal combines several 8-bit bytes into one character96 (as in Unicode mode), this will not work properly.97 98 config FEATURE_VI_COLON99 bool "Enable \":\" colon commands (no \"ex\" mode)"100 default y101 depends on VI102 help103 Enable a limited set of colon commands for vi. This does not104 provide an "ex" mode.105 106 config FEATURE_VI_YANKMARK107 bool "Enable yank/put commands and mark cmds"108 default y109 depends on VI110 help111 This will enable you to use yank and put, as well as mark in112 busybox vi.113 114 config FEATURE_VI_SEARCH115 bool "Enable search and replace cmds"116 default y117 depends on VI118 help119 Select this if you wish to be able to do search and replace in120 busybox vi.121 122 config FEATURE_VI_USE_SIGNALS123 bool "Catch signals"124 default y125 depends on VI126 help127 Selecting this option will make busybox vi signal aware. This will128 make busybox vi support SIGWINCH to deal with Window Changes, catch129 Ctrl-Z and Ctrl-C and alarms.130 131 config FEATURE_VI_DOT_CMD132 bool "Remember previous cmd and \".\" cmd"133 default y134 depends on VI135 help136 Make busybox vi remember the last command and be able to repeat it.137 138 config FEATURE_VI_READONLY139 bool "Enable -R option and \"view\" mode"140 default y141 depends on VI142 help143 Enable the read-only command line option, which allows the user to144 open a file in read-only mode.145 146 config FEATURE_VI_SETOPTS147 bool "Enable set-able options, ai ic showmatch"148 default y149 depends on VI150 help151 Enable the editor to set some (ai, ic, showmatch) options.152 153 config FEATURE_VI_SET154 bool "Support for :set"155 default y156 depends on VI157 help158 Support for ":set".159 160 config FEATURE_VI_WIN_RESIZE161 bool "Handle window resize"162 default y163 depends on VI164 help165 Make busybox vi behave nicely with terminals that get resized.166 167 config FEATURE_VI_ASK_TERMINAL168 bool "Use 'tell me cursor position' ESC sequence to measure window"169 default y170 depends on VI171 help172 If terminal size can't be retrieved and $LINES/$COLUMNS are not set,173 this option makes vi perform a last-ditch effort to find it:174 vi positions cursor to 999,999 and asks terminal to report real175 cursor position using "ESC [ 6 n" escape sequence, then reads stdin.176 177 This is not clean but helps a lot on serial lines and such.178 179 config FEATURE_VI_OPTIMIZE_CURSOR180 bool "Optimize cursor movement"181 default y182 depends on VI183 help184 This will make the cursor movement faster, but requires more memory185 and it makes the applet a tiny bit larger.186 187 70 config FEATURE_ALLOW_EXEC 188 71 bool "Allow vi and awk to execute shell commands" -
branches/3.2/mindi-busybox/editors/Kbuild.src
r2725 r3232 13 13 lib-$(CONFIG_ED) += ed.o 14 14 lib-$(CONFIG_SED) += sed.o 15 lib-$(CONFIG_VI) += vi.o -
branches/3.2/mindi-busybox/editors/awk.c
r2725 r3232 8 8 */ 9 9 10 //usage:#define awk_trivial_usage 11 //usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..." 12 //usage:#define awk_full_usage "\n\n" 13 //usage: " -v VAR=VAL Set variable" 14 //usage: "\n -F SEP Use SEP as field separator" 15 //usage: "\n -f FILE Read program from FILE" 16 10 17 #include "libbb.h" 11 18 #include "xregex.h" … … 19 26 #define debug_printf_walker(...) do {} while (0) 20 27 #define debug_printf_eval(...) do {} while (0) 28 #define debug_printf_parse(...) do {} while (0) 21 29 22 30 #ifndef debug_printf_walker … … 25 33 #ifndef debug_printf_eval 26 34 # define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) 35 #endif 36 #ifndef debug_printf_parse 37 # define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) 27 38 #endif 28 39 … … 145 156 /* simple token classes */ 146 157 /* Order and hex values are very important!!! See next_token() */ 147 #define TC_SEQSTART 1/* ( */158 #define TC_SEQSTART 1 /* ( */ 148 159 #define TC_SEQTERM (1 << 1) /* ) */ 149 160 #define TC_REGEXP (1 << 2) /* /.../ */ … … 232 243 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string 233 244 */ 245 #undef P 246 #undef PRIMASK 247 #undef PRIMASK2 234 248 #define P(x) (x << 24) 235 249 #define PRIMASK 0x7F000000 … … 426 440 smallint nextfile; 427 441 smallint is_f0_split; 442 smallint t_rollback; 428 443 }; 429 444 struct globals2 { … … 432 447 char *t_string; 433 448 int t_lineno; 434 int t_rollback;435 449 436 450 var *intvar[NUM_INTERNAL_VARS]; /* often used */ … … 490 504 #define nextfile (G1.nextfile ) 491 505 #define is_f0_split (G1.is_f0_split ) 506 #define t_rollback (G1.t_rollback ) 492 507 #define t_info (G.t_info ) 493 508 #define t_tclass (G.t_tclass ) 494 509 #define t_string (G.t_string ) 495 510 #define t_lineno (G.t_lineno ) 496 #define t_rollback (G.t_rollback )497 511 #define intvar (G.intvar ) 498 512 #define fsplitter (G.fsplitter ) … … 683 697 if (c == '\\') 684 698 c = bb_process_escape_sequence((const char**)s); 699 /* Example awk statement: 700 * s = "abc\"def" 701 * we must treat \" as " 702 */ 685 703 if (c == '\\' && *s == pps) { /* unrecognized \z? */ 686 704 c = *(*s); /* yes, fetch z */ … … 689 707 } 690 708 return c; 709 } 710 711 /* TODO: merge with strcpy_and_process_escape_sequences()? 712 */ 713 static void unescape_string_in_place(char *s1) 714 { 715 char *s = s1; 716 while ((*s1 = nextchar(&s)) != '\0') 717 s1++; 691 718 } 692 719 … … 1002 1029 if (*p == '\0') { 1003 1030 tc = TC_EOF; 1031 debug_printf_parse("%s: token found: TC_EOF\n", __func__); 1004 1032 1005 1033 } else if (*p == '\"') { … … 1017 1045 *s = '\0'; 1018 1046 tc = TC_STRING; 1047 debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string); 1019 1048 1020 1049 } else if ((expected & TC_REGEXP) && *p == '/') { … … 1039 1068 *s = '\0'; 1040 1069 tc = TC_REGEXP; 1070 debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string); 1041 1071 1042 1072 } else if (*p == '.' || isdigit(*p)) { … … 1048 1078 syntax_error(EMSG_UNEXP_TOKEN); 1049 1079 tc = TC_NUMBER; 1080 debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double); 1050 1081 1051 1082 } else { … … 1070 1101 /* then this is what we are looking for */ 1071 1102 t_info = *ti; 1103 debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info); 1072 1104 p += l; 1073 1105 goto token_found; … … 1093 1125 if (*p == '(') { 1094 1126 tc = TC_FUNCTION; 1127 debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string); 1095 1128 } else { 1096 1129 if (*p == '[') { 1097 1130 p++; 1098 1131 tc = TC_ARRAY; 1099 } 1100 } 1101 token_found: ; 1102 } 1132 debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string); 1133 } else 1134 debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string); 1135 } 1136 } 1137 token_found: 1103 1138 g_pos = p; 1104 1139 … … 1172 1207 var *v; 1173 1208 1209 debug_printf_parse("%s(%x)\n", __func__, iexp); 1210 1174 1211 sn.info = PRIMASK; 1175 1212 sn.r.n = glptr = NULL; … … 1180 1217 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1181 1218 /* input redirection (<) attached to glptr node */ 1219 debug_printf_parse("%s: input redir\n", __func__); 1182 1220 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); 1183 1221 cn->a.n = glptr; … … 1186 1224 1187 1225 } else if (tc & (TC_BINOP | TC_UOPPOST)) { 1226 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); 1188 1227 /* for binary and postfix-unary operators, jump back over 1189 1228 * previous operators with higher priority */ … … 1215 1254 1216 1255 } else { 1256 debug_printf_parse("%s: other\n", __func__); 1217 1257 /* for operands and prefix-unary operators, attach them 1218 1258 * to last node */ … … 1222 1262 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1223 1263 if (tc & (TC_OPERAND | TC_REGEXP)) { 1264 debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); 1224 1265 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; 1225 1266 /* one should be very careful with switch on tclass - … … 1228 1269 case TC_VARIABLE: 1229 1270 case TC_ARRAY: 1271 debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__); 1230 1272 cn->info = OC_VAR; 1231 1273 v = hash_search(ahash, t_string); … … 1244 1286 case TC_NUMBER: 1245 1287 case TC_STRING: 1288 debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); 1246 1289 cn->info = OC_VAR; 1247 1290 v = cn->l.v = xzalloc(sizeof(var)); … … 1253 1296 1254 1297 case TC_REGEXP: 1298 debug_printf_parse("%s: TC_REGEXP\n", __func__); 1255 1299 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); 1256 1300 break; 1257 1301 1258 1302 case TC_FUNCTION: 1303 debug_printf_parse("%s: TC_FUNCTION\n", __func__); 1259 1304 cn->info = OC_FUNC; 1260 1305 cn->r.f = newfunc(t_string); … … 1263 1308 1264 1309 case TC_SEQSTART: 1310 debug_printf_parse("%s: TC_SEQSTART\n", __func__); 1265 1311 cn = vn->r.n = parse_expr(TC_SEQTERM); 1312 if (!cn) 1313 syntax_error("Empty sequence"); 1266 1314 cn->a.n = vn; 1267 1315 break; 1268 1316 1269 1317 case TC_GETLINE: 1318 debug_printf_parse("%s: TC_GETLINE\n", __func__); 1270 1319 glptr = cn; 1271 1320 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; … … 1273 1322 1274 1323 case TC_BUILTIN: 1324 debug_printf_parse("%s: TC_BUILTIN\n", __func__); 1275 1325 cn->l.n = condition(); 1276 1326 break; … … 1279 1329 } 1280 1330 } 1331 1332 debug_printf_parse("%s() returns %p\n", __func__, sn.r.n); 1281 1333 return sn.r.n; 1282 1334 } … … 1347 1399 1348 1400 if (c & TC_GRPSTART) { 1401 debug_printf_parse("%s: TC_GRPSTART\n", __func__); 1349 1402 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { 1403 debug_printf_parse("%s: !TC_GRPTERM\n", __func__); 1350 1404 if (t_tclass & TC_NEWLINE) 1351 1405 continue; … … 1353 1407 chain_group(); 1354 1408 } 1409 debug_printf_parse("%s: TC_GRPTERM\n", __func__); 1355 1410 } else if (c & (TC_OPSEQ | TC_OPTERM)) { 1411 debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__); 1356 1412 rollback_token(); 1357 1413 chain_expr(OC_EXEC | Vx); 1358 } else { /* TC_STATEMNT */ 1414 } else { 1415 /* TC_STATEMNT */ 1416 debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__); 1359 1417 switch (t_info & OPCLSMASK) { 1360 1418 case ST_IF: 1419 debug_printf_parse("%s: ST_IF\n", __func__); 1361 1420 n = chain_node(OC_BR | Vx); 1362 1421 n->l.n = condition(); … … 1373 1432 1374 1433 case ST_WHILE: 1434 debug_printf_parse("%s: ST_WHILE\n", __func__); 1375 1435 n2 = condition(); 1376 1436 n = chain_loop(NULL); … … 1379 1439 1380 1440 case ST_DO: 1441 debug_printf_parse("%s: ST_DO\n", __func__); 1381 1442 n2 = chain_node(OC_EXEC); 1382 1443 n = chain_loop(NULL); … … 1387 1448 1388 1449 case ST_FOR: 1450 debug_printf_parse("%s: ST_FOR\n", __func__); 1389 1451 next_token(TC_SEQSTART); 1390 1452 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); … … 1412 1474 case OC_PRINT: 1413 1475 case OC_PRINTF: 1476 debug_printf_parse("%s: OC_PRINT[F]\n", __func__); 1414 1477 n = chain_node(t_info); 1415 1478 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); … … 1423 1486 1424 1487 case OC_BREAK: 1488 debug_printf_parse("%s: OC_BREAK\n", __func__); 1425 1489 n = chain_node(OC_EXEC); 1426 1490 n->a.n = break_ptr; … … 1428 1492 1429 1493 case OC_CONTINUE: 1494 debug_printf_parse("%s: OC_CONTINUE\n", __func__); 1430 1495 n = chain_node(OC_EXEC); 1431 1496 n->a.n = continue_ptr; … … 1434 1499 /* delete, next, nextfile, return, exit */ 1435 1500 default: 1501 debug_printf_parse("%s: default\n", __func__); 1436 1502 chain_expr(t_info); 1437 1503 } … … 1451 1517 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { 1452 1518 1453 if (tclass & TC_OPTERM) 1519 if (tclass & TC_OPTERM) { 1520 debug_printf_parse("%s: TC_OPTERM\n", __func__); 1454 1521 continue; 1522 } 1455 1523 1456 1524 seq = &mainseq; 1457 1525 if (tclass & TC_BEGIN) { 1526 debug_printf_parse("%s: TC_BEGIN\n", __func__); 1458 1527 seq = &beginseq; 1459 1528 chain_group(); 1460 1529 1461 1530 } else if (tclass & TC_END) { 1531 debug_printf_parse("%s: TC_END\n", __func__); 1462 1532 seq = &endseq; 1463 1533 chain_group(); 1464 1534 1465 1535 } else if (tclass & TC_FUNCDECL) { 1536 debug_printf_parse("%s: TC_FUNCDECL\n", __func__); 1466 1537 next_token(TC_FUNCTION); 1467 1538 g_pos++; … … 1481 1552 1482 1553 } else if (tclass & TC_OPSEQ) { 1554 debug_printf_parse("%s: TC_OPSEQ\n", __func__); 1483 1555 rollback_token(); 1484 1556 cn = chain_node(OC_TEST); 1485 1557 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); 1486 1558 if (t_tclass & TC_GRPSTART) { 1559 debug_printf_parse("%s: TC_GRPSTART\n", __func__); 1487 1560 rollback_token(); 1488 1561 chain_group(); 1489 1562 } else { 1563 debug_printf_parse("%s: !TC_GRPSTART\n", __func__); 1490 1564 chain_node(OC_PRINT); 1491 1565 } … … 1493 1567 1494 1568 } else /* if (tclass & TC_GRPSTART) */ { 1569 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__); 1495 1570 rollback_token(); 1496 1571 chain_group(); 1497 1572 } 1498 1573 } 1574 debug_printf_parse("%s: TC_EOF\n", __func__); 1499 1575 } 1500 1576 … … 1737 1813 1738 1814 } else if (v == intvar[FS]) { 1815 /* 1816 * The POSIX-2008 standard says that changing FS should have no effect on the 1817 * current input line, but only on the next one. The language is: 1818 * 1819 * > Before the first reference to a field in the record is evaluated, the record 1820 * > shall be split into fields, according to the rules in Regular Expressions, 1821 * > using the value of FS that was current at the time the record was read. 1822 * 1823 * So, split up current line before assignment to FS: 1824 */ 1825 split_f0(); 1826 1739 1827 mk_splitter(getvar_s(v), &fsplitter); 1740 1828 … … 2621 2709 } 2622 2710 2623 if (!rsm ->F) {2711 if (!rsm || !rsm->F) { 2624 2712 setvar_i(intvar[ERRNO], errno); 2625 2713 setvar_i(res, -1); … … 2930 3018 static int is_assignment(const char *expr) 2931 3019 { 2932 char *exprc, *val , *s, *s1;3020 char *exprc, *val; 2933 3021 2934 3022 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { … … 2940 3028 *val++ = '\0'; 2941 3029 2942 s = s1 = val; 2943 while ((*s1 = nextchar(&s)) != '\0') 2944 s1++; 2945 3030 unescape_string_in_place(val); 2946 3031 setvar_u(newvar(exprc), val); 2947 3032 free(exprc); … … 2955 3040 #define files_happen (G.next_input_file__files_happen) 2956 3041 2957 FILE *F = NULL;3042 FILE *F; 2958 3043 const char *fname, *ind; 2959 3044 … … 2963 3048 rsm.pos = rsm.adv = 0; 2964 3049 2965 do{3050 for (;;) { 2966 3051 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { 2967 3052 if (files_happen) … … 2969 3054 fname = "-"; 2970 3055 F = stdin; 2971 } else { 2972 ind = getvar_s(incvar(intvar[ARGIND])); 2973 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); 2974 if (fname && *fname && !is_assignment(fname)) 2975 F = xfopen_stdin(fname); 2976 } 2977 } while (!F); 3056 break; 3057 } 3058 ind = getvar_s(incvar(intvar[ARGIND])); 3059 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); 3060 if (fname && *fname && !is_assignment(fname)) { 3061 F = xfopen_stdin(fname); 3062 break; 3063 } 3064 } 2978 3065 2979 3066 files_happen = TRUE; … … 2989 3076 { 2990 3077 unsigned opt; 2991 char *opt_F , *opt_W;3078 char *opt_F; 2992 3079 llist_t *list_v = NULL; 2993 3080 llist_t *list_f = NULL; … … 3051 3138 } 3052 3139 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ 3053 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);3140 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); 3054 3141 argv += optind; 3055 3142 argc -= optind; 3056 if (opt & 0x1) 3057 setvar_s(intvar[FS], opt_F); // -F 3143 if (opt & 0x1) { /* -F */ 3144 unescape_string_in_place(opt_F); 3145 setvar_s(intvar[FS], opt_F); 3146 } 3058 3147 while (list_v) { /* -v */ 3059 3148 if (!is_assignment(llist_pop(&list_v))) … … 3085 3174 } 3086 3175 if (opt & 0x8) // -W 3087 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);3176 bb_error_msg("warning: option -W is ignored"); 3088 3177 3089 3178 /* fill in ARGV array */ -
branches/3.2/mindi-busybox/editors/cmp.c
r2725 r3232 10 10 /* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */ 11 11 /* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */ 12 13 //usage:#define cmp_trivial_usage 14 //usage: "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" 15 //usage:#define cmp_full_usage "\n\n" 16 //usage: "Compare FILE1 with FILE2 (or stdin)\n" 17 //usage: "\n -l Write the byte numbers (decimal) and values (octal)" 18 //usage: "\n for all differing bytes" 19 //usage: "\n -s Quiet" 12 20 13 21 #include "libbb.h" -
branches/3.2/mindi-busybox/editors/diff.c
r2725 r3232 77 77 */ 78 78 79 //usage:#define diff_trivial_usage 80 //usage: "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" 81 //usage:#define diff_full_usage "\n\n" 82 //usage: "Compare files line by line and output the differences between them.\n" 83 //usage: "This implementation supports unified diffs only.\n" 84 //usage: "\n -a Treat all files as text" 85 //usage: "\n -b Ignore changes in the amount of whitespace" 86 //usage: "\n -B Ignore changes whose lines are all blank" 87 //usage: "\n -d Try hard to find a smaller set of changes" 88 //usage: "\n -i Ignore case differences" 89 //usage: "\n -L Use LABEL instead of the filename in the unified header" 90 //usage: "\n -N Treat absent files as empty" 91 //usage: "\n -q Output only whether files differ" 92 //usage: "\n -r Recurse" 93 //usage: "\n -S Start with FILE when comparing directories" 94 //usage: "\n -T Make tabs line up by prefixing a tab when necessary" 95 //usage: "\n -s Report when two files are the same" 96 //usage: "\n -t Expand tabs to spaces in output" 97 //usage: "\n -U Output LINES lines of context" 98 //usage: "\n -w Ignore all whitespace" 99 79 100 #include "libbb.h" 80 101 81 102 #if 0 82 //#define dbg_error_msg(...) bb_error_msg(__VA_ARGS__)103 # define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) 83 104 #else 84 # define dbg_error_msg(...) ((void)0)105 # define dbg_error_msg(...) ((void)0) 85 106 #endif 86 107 … … 673 694 static int diffreg(char *file[2]) 674 695 { 675 FILE *fp[2] = { stdin, stdin };696 FILE *fp[2]; 676 697 bool binary = false, differ = false; 677 698 int status = STATUS_SAME, i; 678 699 700 fp[0] = stdin; 701 fp[1] = stdin; 679 702 for (i = 0; i < 2; i++) { 680 703 int fd = open_or_warn_stdin(file[i]); … … 795 818 if (r != 0 || !S_ISDIR(osb.st_mode)) { 796 819 /* other dir doesn't have similarly named 797 * directory, don't recurse */ 820 * directory, don't recurse; return 1 upon 821 * exit, just like diffutils' diff */ 822 exit_status |= 1; 798 823 return SKIP; 799 824 } … … 819 844 list[i].len = strlen(p[i]); 820 845 recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS, 821 846 add_to_dirlist, skip_dir, &list[i], 0); 822 847 /* Sort dl alphabetically. 823 848 * GNU diff does this ignoring any number of trailing dots. … … 847 872 pos = !dp[0] ? 1 : (!dp[1] ? -1 : strcmp(dp[0], dp[1])); 848 873 k = pos > 0; 849 if (pos && !(option_mask32 & FLAG(N))) 874 if (pos && !(option_mask32 & FLAG(N))) { 850 875 printf("Only in %s: %s\n", p[k], dp[k]); 851 else { 876 exit_status |= 1; 877 } else { 852 878 char *fullpath[2], *path[2]; /* if -N */ 853 879 … … 950 976 bb_error_msg_and_die("can't compare stdin to a directory"); 951 977 978 /* Compare metadata to check if the files are the same physical file. 979 * 980 * Comment from diffutils source says: 981 * POSIX says that two files are identical if st_ino and st_dev are 982 * the same, but many file systems incorrectly assign the same (device, 983 * inode) pair to two distinct files, including: 984 * GNU/Linux NFS servers that export all local file systems as a 985 * single NFS file system, if a local device number (st_dev) exceeds 986 * 255, or if a local inode number (st_ino) exceeds 16777215. 987 */ 988 if (ENABLE_DESKTOP 989 && stb[0].st_ino == stb[1].st_ino 990 && stb[0].st_dev == stb[1].st_dev 991 && stb[0].st_size == stb[1].st_size 992 && stb[0].st_mtime == stb[1].st_mtime 993 && stb[0].st_ctime == stb[1].st_ctime 994 && stb[0].st_mode == stb[1].st_mode 995 && stb[0].st_nlink == stb[1].st_nlink 996 && stb[0].st_uid == stb[1].st_uid 997 && stb[0].st_gid == stb[1].st_gid 998 ) { 999 /* files are physically the same; no need to compare them */ 1000 return STATUS_SAME; 1001 } 1002 952 1003 if (S_ISDIR(stb[0].st_mode) && S_ISDIR(stb[1].st_mode)) { 953 1004 #if ENABLE_FEATURE_DIFF_DIR -
branches/3.2/mindi-busybox/editors/ed.c
r2725 r3232 7 7 * The "ed" built-in command (much simplified) 8 8 */ 9 10 //usage:#define ed_trivial_usage "" 11 //usage:#define ed_full_usage "" 9 12 10 13 #include "libbb.h" … … 130 133 * >0 length of input string, including terminating '\n' 131 134 */ 132 len = read_line_input( ": ", buf, sizeof(buf), NULL);135 len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); 133 136 if (len <= 0) 134 137 return; … … 228 231 if (!dirty) 229 232 return; 230 len = read_line_input( "Really quit? ", buf, 16, NULL);233 len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); 231 234 /* read error/EOF - no way to continue */ 232 235 if (len < 0) … … 452 455 /* 453 456 * The new string is larger, so allocate a new line 454 * structure and use that. Link it in inplace of457 * structure and use that. Link it in place of 455 458 * the old line structure. 456 459 */ … … 542 545 * >0 length of input string, including terminating '\n' 543 546 */ 544 len = read_line_input( "", buf, sizeof(buf), NULL);547 len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); 545 548 if (len <= 0) { 546 549 /* Previously, ctrl-C was exiting to shell. -
branches/3.2/mindi-busybox/editors/patch.c
r2725 r3232 16 16 * -o outfile output here instead of in place 17 17 * -r rejectfile write rejected hunks to this file 18 * --dry-run (regression!) 18 19 * 19 20 * -f force (no questions asked) … … 22 23 */ 23 24 24 //applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP))25 26 //kbuild:lib-$(CONFIG_PATCH) += patch.o27 28 25 //config:config PATCH 29 26 //config: bool "patch" … … 31 28 //config: help 32 29 //config: Apply a unified diff formatted patch. 30 31 //applet:IF_PATCH(APPLET(patch, BB_DIR_USR_BIN, BB_SUID_DROP)) 32 33 //kbuild:lib-$(CONFIG_PATCH) += patch.o 33 34 34 35 //usage:#define patch_trivial_usage … … 40 41 //usage: "\n -R,--reverse Reverse patch" 41 42 //usage: "\n -N,--forward Ignore already applied patches" 42 / /usage: "\n --dry-run Don't actually change files"43 /*usage: "\n --dry-run Don't actually change files" - TODO */ 43 44 //usage: "\n -E,--remove-empty-files Remove output files if they become empty" 44 45 //usage: ) … … 50 51 //usage: "\n -E Remove output files if they become empty" 51 52 //usage: ) 53 /* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */ 54 /* -x "debug" is supported but does nothing */ 52 55 //usage: 53 56 //usage:#define patch_example_usage … … 68 71 // Free all the elements of a linked list 69 72 // Call freeit() on each element before freeing it. 70 static 71 void dlist_free(struct double_list *list, void (*freeit)(void *data)) 73 static void dlist_free(struct double_list *list, void (*freeit)(void *data)) 72 74 { 73 75 while (list) { … … 81 83 82 84 // Add an entry before "list" element in (circular) doubly linked list 83 static 84 struct double_list *dlist_add(struct double_list **list, char *data) 85 static struct double_list *dlist_add(struct double_list **list, char *data) 85 86 { 86 87 struct double_list *llist; … … 131 132 #define FLAG_IGNORE (1 << 4) 132 133 #define FLAG_RMEMPTY (1 << 5) 133 / /non-standard:134 #define FLAG_DEBUG ( 1<< 6)134 /* Enable this bit and use -x for debug output: */ 135 #define FLAG_DEBUG (0 << 6) 135 136 136 137 // Dispose of a line of input, either by writing it out or discarding it. … … 230 231 if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); 231 232 } 232 matcheof = matcheof < TT.context;233 matcheof = !matcheof || matcheof < TT.context; 233 234 234 235 if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); … … 239 240 plist = TT.current_hunk; 240 241 buf = NULL; 241 if ( TT.context) for (;;) {242 char *data = xmalloc_reads(TT.filein, NULL , NULL);242 if (reverse ? TT.oldlen : TT.newlen) for (;;) { 243 char *data = xmalloc_reads(TT.filein, NULL); 243 244 244 245 TT.linenum++; … … 353 354 char *oldname = NULL, *newname = NULL; 354 355 char *opt_p, *opt_i; 356 long oldlen = oldlen; /* for compiler */ 357 long newlen = newlen; /* for compiler */ 355 358 356 359 INIT_TT(); … … 392 395 dlist_add(&TT.current_hunk, patchline); 393 396 394 if (*patchline != '+') TT.oldlen--;395 if (*patchline != '-') TT.newlen--;397 if (*patchline != '+') oldlen--; 398 if (*patchline != '-') newlen--; 396 399 397 400 // Context line? … … 401 404 // If we've consumed all expected hunk lines, apply the hunk. 402 405 403 if (! TT.oldlen && !TT.newlen) state = apply_one_hunk();406 if (!oldlen && !newlen) state = apply_one_hunk(); 404 407 continue; 405 408 } … … 448 451 // Read oldline[,oldlen] +newline[,newlen] 449 452 450 TT.oldlen = TT.newlen = 1;453 TT.oldlen = oldlen = TT.newlen = newlen = 1; 451 454 TT.oldline = strtol(s, &s, 10); 452 if (*s == ',') TT.oldlen =strtol(s+1, &s, 10);455 if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10); 453 456 TT.newline = strtol(s+2, &s, 10); 454 if (*s == ',') TT.newlen = strtol(s+1, &s, 10); 457 if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10); 458 459 if (oldlen < 1 && newlen < 1) 460 bb_error_msg_and_die("Really? %s", patchline); 455 461 456 462 TT.context = 0; … … 462 468 char *name; 463 469 464 oldsum = TT.oldline + TT.oldlen;465 newsum = TT.newline + TT.newlen;470 oldsum = TT.oldline + oldlen; 471 newsum = TT.newline + newlen; 466 472 467 473 name = reverse ? oldname : newname; … … 469 475 // We're deleting oldname if new file is /dev/null (before -p) 470 476 // or if new hunk is empty (zero context) after patching 471 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) 472 { 477 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) { 473 478 name = reverse ? newname : oldname; 474 479 empty++; … … 476 481 477 482 // handle -p path truncation. 478 for (i=0, s = name; *s;) { 479 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; 480 if (*(s++)=='/') { 481 name = s; 482 i++; 483 } 483 for (i = 0, s = name; *s;) { 484 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) 485 break; 486 if (*s++ != '/') 487 continue; 488 while (*s == '/') 489 s++; 490 i++; 491 name = s; 484 492 } 485 493 -
branches/3.2/mindi-busybox/editors/sed.c
r2725 r3232 15 15 16 16 /* Code overview. 17 18 Files are laid out to avoid unnecessary function declarations. So for 19 example, every function add_cmd calls occurs before add_cmd in this file. 20 21 add_cmd() is called on each line of sed command text (from a file or from 22 the command line). It calls get_address() and parse_cmd_args(). The 23 resulting sed_cmd_t structures are appended to a linked list 24 (G.sed_cmd_head/G.sed_cmd_tail). 25 26 add_input_file() adds a FILE* to the list of input files. We need to 27 know all input sources ahead of time to find the last line for the $ match. 28 29 process_files() does actual sedding, reading data lines from each input FILE * 30 (which could be stdin) and applying the sed command list (sed_cmd_head) to 31 each of the resulting lines. 32 33 sed_main() is where external code calls into this, with a command line. 34 */ 35 36 37 /* 38 Supported features and commands in this version of sed: 39 40 - comments ('#') 41 - address matching: num|/matchstr/[,num|/matchstr/|$]command 42 - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) 43 - edit commands: (a)ppend, (i)nsert, (c)hange 44 - file commands: (r)ead 45 - backreferences in substitution expressions (\0, \1, \2...\9) 46 - grouped commands: {cmd1;cmd2} 47 - transliteration (y/source-chars/dest-chars/) 48 - pattern space hold space storing / swapping (g, h, x) 49 - labels / branching (: label, b, t, T) 50 51 (Note: Specifying an address (range) to match is *optional*; commands 52 default to the whole pattern space if no specific address match was 53 requested.) 54 55 Todo: 56 - Create a wrapper around regex to make libc's regex conform with sed 57 58 Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html 59 */ 17 * 18 * Files are laid out to avoid unnecessary function declarations. So for 19 * example, every function add_cmd calls occurs before add_cmd in this file. 20 * 21 * add_cmd() is called on each line of sed command text (from a file or from 22 * the command line). It calls get_address() and parse_cmd_args(). The 23 * resulting sed_cmd_t structures are appended to a linked list 24 * (G.sed_cmd_head/G.sed_cmd_tail). 25 * 26 * add_input_file() adds a FILE* to the list of input files. We need to 27 * know all input sources ahead of time to find the last line for the $ match. 28 * 29 * process_files() does actual sedding, reading data lines from each input FILE* 30 * (which could be stdin) and applying the sed command list (sed_cmd_head) to 31 * each of the resulting lines. 32 * 33 * sed_main() is where external code calls into this, with a command line. 34 */ 35 36 /* Supported features and commands in this version of sed: 37 * 38 * - comments ('#') 39 * - address matching: num|/matchstr/[,num|/matchstr/|$]command 40 * - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) 41 * - edit commands: (a)ppend, (i)nsert, (c)hange 42 * - file commands: (r)ead 43 * - backreferences in substitution expressions (\0, \1, \2...\9) 44 * - grouped commands: {cmd1;cmd2} 45 * - transliteration (y/source-chars/dest-chars/) 46 * - pattern space hold space storing / swapping (g, h, x) 47 * - labels / branching (: label, b, t, T) 48 * 49 * (Note: Specifying an address (range) to match is *optional*; commands 50 * default to the whole pattern space if no specific address match was 51 * requested.) 52 * 53 * Todo: 54 * - Create a wrapper around regex to make libc's regex conform with sed 55 * 56 * Reference 57 * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html 58 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html 59 */ 60 61 //usage:#define sed_trivial_usage 62 //usage: "[-inr] [-f FILE]... [-e CMD]... [FILE]...\n" 63 //usage: "or: sed [-inr] CMD [FILE]..." 64 //usage:#define sed_full_usage "\n\n" 65 //usage: " -e CMD Add CMD to sed commands to be executed" 66 //usage: "\n -f FILE Add FILE contents to sed commands to be executed" 67 //usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" 68 //usage: "\n Optionally back files up, appending SFX" 69 //usage: "\n -n Suppress automatic printing of pattern space" 70 //usage: "\n -r Use extended regex syntax" 71 //usage: "\n" 72 //usage: "\nIf no -e or -f, the first non-option argument is the sed command string." 73 //usage: "\nRemaining arguments are input files (stdin if none)." 74 //usage: 75 //usage:#define sed_example_usage 76 //usage: "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n" 77 //usage: "bar\n" 60 78 61 79 #include "libbb.h" 62 80 #include "xregex.h" 81 82 #if 0 83 # define dbg(...) bb_error_msg(__VA_ARGS__) 84 #else 85 # define dbg(...) ((void)0) 86 #endif 87 63 88 64 89 enum { … … 76 101 regex_t *sub_match; /* For 's/sub_match/string/' */ 77 102 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ 103 int beg_line_orig; /* copy of the above, needed for -i */ 78 104 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ 79 105 … … 110 136 111 137 /* linked list of sed commands */ 112 sed_cmd_t sed_cmd_head,*sed_cmd_tail;138 sed_cmd_t *sed_cmd_head, **sed_cmd_tail; 113 139 114 140 /* Linked list of append lines */ … … 125 151 #define G (*(struct globals*)&bb_common_bufsiz1) 126 152 struct BUG_G_too_big { 127 153 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 128 154 }; 129 155 #define INIT_G() do { \ … … 135 161 static void sed_free_and_close_stuff(void) 136 162 { 137 sed_cmd_t *sed_cmd = G.sed_cmd_head .next;163 sed_cmd_t *sed_cmd = G.sed_cmd_head; 138 164 139 165 llist_free(G.append_head, free); … … 201 227 static char *copy_parsing_escapes(const char *string, int len) 202 228 { 229 const char *s; 203 230 char *dest = xmalloc(len + 1); 204 231 205 parse_escapes(dest, string, len, 'n', '\n'); 206 /* GNU sed also recognizes \t */ 207 parse_escapes(dest, dest, strlen(dest), 't', '\t'); 232 /* sed recognizes \n */ 233 /* GNU sed also recognizes \t and \r */ 234 for (s = "\nn\tt\rr"; *s; s += 2) { 235 parse_escapes(dest, string, len, s[1], s[0]); 236 string = dest; 237 len = strlen(dest); 238 } 208 239 return dest; 209 240 } … … 228 259 } 229 260 230 for (; (ch = str[idx]) ; idx++) {261 for (; (ch = str[idx]) != '\0'; idx++) { 231 262 if (bracket >= 0) { 232 if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2 233 && str[idx - 1] == '^'))) 263 if (ch == ']' 264 && !(bracket == idx - 1 || (bracket == idx - 2 && str[idx - 1] == '^')) 265 ) { 234 266 bracket = -1; 267 } 235 268 } else if (escaped) 236 269 escaped = 0; … … 253 286 { 254 287 const char *cmdstr_ptr = cmdstr; 255 char delimiter;288 unsigned char delimiter; 256 289 int idx = 0; 257 290 … … 268 301 /* save the replacement string */ 269 302 cmdstr_ptr += idx + 1; 270 idx = index_of_next_unescaped_regexp_delim(- delimiter, cmdstr_ptr);303 idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); 271 304 *replace = copy_parsing_escapes(cmdstr_ptr, idx); 272 305 … … 293 326 294 327 delimiter = '/'; 295 if (*my_str == '\\') delimiter = *++pos; 328 if (*my_str == '\\') 329 delimiter = *++pos; 296 330 next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); 297 331 temp = copy_parsing_escapes(pos, next); 298 *regex = x malloc(sizeof(regex_t));332 *regex = xzalloc(sizeof(regex_t)); 299 333 xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); 300 334 free(temp); … … 405 439 if (*match != '\0') { 406 440 /* If match is empty, we use last regex used at runtime */ 407 sed_cmd->sub_match = xmalloc(sizeof(regex_t)); 441 sed_cmd->sub_match = xzalloc(sizeof(regex_t)); 442 dbg("xregcomp('%s',%x)", match, cflags); 408 443 xregcomp(sed_cmd->sub_match, match, cflags); 444 dbg("regcomp ok"); 409 445 } 410 446 free(match); … … 418 454 static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) 419 455 { 456 static const char cmd_letters[] = "saicrw:btTydDgGhHlnNpPqx={}"; 457 enum { 458 IDX_s = 0, 459 IDX_a, 460 IDX_i, 461 IDX_c, 462 IDX_r, 463 IDX_w, 464 IDX_colon, 465 IDX_b, 466 IDX_t, 467 IDX_T, 468 IDX_y, 469 IDX_d, 470 IDX_D, 471 IDX_g, 472 IDX_G, 473 IDX_h, 474 IDX_H, 475 IDX_l, 476 IDX_n, 477 IDX_N, 478 IDX_p, 479 IDX_P, 480 IDX_q, 481 IDX_x, 482 IDX_equal, 483 IDX_lbrace, 484 IDX_rbrace, 485 IDX_nul 486 }; 487 struct chk { char chk[sizeof(cmd_letters)-1 == IDX_nul ? 1 : -1]; }; 488 489 unsigned idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters; 490 420 491 /* handle (s)ubstitution command */ 421 if ( sed_cmd->cmd == 's')492 if (idx == IDX_s) { 422 493 cmdstr += parse_subst_cmd(sed_cmd, cmdstr); 494 } 423 495 /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ 424 else if (strchr("aic", sed_cmd->cmd)) { 425 if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') 426 bb_error_msg_and_die("only a beginning address can be specified for edit commands"); 496 else if (idx <= IDX_c) { /* a,i,c */ 497 if (idx < IDX_c) { /* a,i */ 498 if (sed_cmd->end_line || sed_cmd->end_match) 499 bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); 500 } 427 501 for (;;) { 428 502 if (*cmdstr == '\n' || *cmdstr == '\\') { … … 438 512 parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0'); 439 513 cmdstr += strlen(cmdstr); 514 } 440 515 /* handle file cmds: (r)ead */ 441 } else if (strchr("rw", sed_cmd->cmd)) { 442 if (sed_cmd->end_line || sed_cmd->end_match) 443 bb_error_msg_and_die("command only uses one address"); 516 else if (idx <= IDX_w) { /* r,w */ 517 if (idx < IDX_w) { /* r */ 518 if (sed_cmd->end_line || sed_cmd->end_match) 519 bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); 520 } 444 521 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); 445 522 if (sed_cmd->cmd == 'w') { … … 447 524 sed_cmd->sw_last_char = '\n'; 448 525 } 526 } 449 527 /* handle branch commands */ 450 } else if (strchr(":btT", sed_cmd->cmd)) {528 else if (idx <= IDX_T) { /* :,b,t,T */ 451 529 int length; 452 530 … … 459 537 } 460 538 /* translation command */ 461 else if ( sed_cmd->cmd == 'y') {539 else if (idx == IDX_y) { 462 540 char *match, *replace; 463 541 int i = cmdstr[0]; … … 479 557 * then it must be an invalid command. 480 558 */ 481 else if ( strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {559 else if (idx >= IDX_nul) { /* not d,D,g,G,h,H,l,n,N,p,P,q,x,=,{,} */ 482 560 bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd); 483 561 } … … 541 619 /* first part (if present) is an address: either a '$', a number or a /regex/ */ 542 620 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); 621 sed_cmd->beg_line_orig = sed_cmd->beg_line; 543 622 544 623 /* second part (if present) will begin with a comma */ … … 572 651 573 652 /* Add the command to the command array */ 574 G.sed_cmd_tail->next= sed_cmd;575 G.sed_cmd_tail = G.sed_cmd_tail->next;653 *G.sed_cmd_tail = sed_cmd; 654 G.sed_cmd_tail = &sed_cmd->next; 576 655 } 577 656 … … 601 680 /* go through the replacement string */ 602 681 for (i = 0; replace[i]; i++) { 603 /* if we find a backreference (\1, \2, etc.) print the backref'ed *text */682 /* if we find a backreference (\1, \2, etc.) print the backref'ed text */ 604 683 if (replace[i] == '\\') { 605 684 unsigned backref = replace[++i] - '0'; … … 635 714 { 636 715 char *line = *line_p; 637 int altered = 0;638 716 unsigned match_count = 0; 717 bool altered = 0; 718 bool prev_match_empty = 1; 719 bool tried_at_eol = 0; 639 720 regex_t *current_regex; 640 721 … … 649 730 650 731 /* Find the first match */ 651 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) 732 dbg("matching '%s'", line); 733 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) { 734 dbg("no match"); 652 735 return 0; 736 } 737 dbg("match"); 653 738 654 739 /* Initialize temporary output buffer. */ … … 659 744 /* Now loop through, substituting for matches */ 660 745 do { 746 int start = G.regmatch[0].rm_so; 747 int end = G.regmatch[0].rm_eo; 661 748 int i; 662 749 663 /* Work around bug in glibc regexec, demonstrated by:664 echo " a.b" | busybox sed 's [^ .]* x g'665 The match_count check is so not to break666 echo "hi" | busybox sed 's/^/!/g' */667 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {668 pipe_putc(*line++);669 continue;670 }671 672 750 match_count++; 673 751 674 752 /* If we aren't interested in this match, output old line to 675 753 * end of match and continue */ 676 754 if (sed_cmd->which_match 677 755 && (sed_cmd->which_match != match_count) 678 756 ) { 679 for (i = 0; i < G.regmatch[0].rm_eo; i++)757 for (i = 0; i < end; i++) 680 758 pipe_putc(*line++); 681 continue; 682 } 683 684 /* print everything before the match */ 685 for (i = 0; i < G.regmatch[0].rm_so; i++) 759 /* Null match? Print one more char */ 760 if (start == end && *line) 761 pipe_putc(*line++); 762 goto next; 763 } 764 765 /* Print everything before the match */ 766 for (i = 0; i < start; i++) 686 767 pipe_putc(line[i]); 687 768 688 /* then print the substitution string */ 689 do_subst_w_backrefs(line, sed_cmd->string); 690 691 /* advance past the match */ 692 line += G.regmatch[0].rm_eo; 693 /* flag that something has changed */ 694 altered++; 769 /* Then print the substitution string, 770 * unless we just matched empty string after non-empty one. 771 * Example: string "cccd", pattern "c*", repl "R": 772 * result is "RdR", not "RRdR": first match "ccc", 773 * second is "" before "d", third is "" after "d". 774 * Second match is NOT replaced! 775 */ 776 if (prev_match_empty || start != 0 || start != end) { 777 //dbg("%d %d %d", prev_match_empty, start, end); 778 dbg("inserting replacement at %d in '%s'", start, line); 779 do_subst_w_backrefs(line, sed_cmd->string); 780 /* Flag that something has changed */ 781 altered = 1; 782 } else { 783 dbg("NOT inserting replacement at %d in '%s'", start, line); 784 } 785 786 /* If matched string is empty (f.e. "c*" pattern), 787 * copy verbatim one char after it before attempting more matches 788 */ 789 prev_match_empty = (start == end); 790 if (prev_match_empty) { 791 if (!line[end]) { 792 tried_at_eol = 1; 793 } else { 794 pipe_putc(line[end]); 795 end++; 796 } 797 } 798 799 /* Advance past the match */ 800 dbg("line += %d", end); 801 line += end; 695 802 696 803 /* if we're not doing this globally, get out now */ 697 if (sed_cmd->which_match) 698 break; 699 700 //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? 701 } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); 804 if (sed_cmd->which_match != 0) 805 break; 806 next: 807 /* Exit if we are at EOL and already tried matching at it */ 808 if (*line == '\0') { 809 if (tried_at_eol) 810 break; 811 tried_at_eol = 1; 812 } 813 814 //maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? 815 } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); 702 816 703 817 /* Copy rest of string into output pipeline */ … … 719 833 sed_cmd_t *sed_cmd; 720 834 721 for (sed_cmd = G.sed_cmd_head .next; sed_cmd; sed_cmd = sed_cmd->next) {835 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { 722 836 if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) { 723 837 return sed_cmd; … … 895 1009 /* For every line, go through all the commands */ 896 1010 restart: 897 for (sed_cmd = G.sed_cmd_head .next; sed_cmd; sed_cmd = sed_cmd->next) {1011 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { 898 1012 int old_matched, matched; 899 1013 … … 902 1016 /* Determine if this command matches this line: */ 903 1017 904 //bb_error_msg("match1:%d", sed_cmd->in_match);905 //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line906 //&& !sed_cmd->beg_match && !sed_cmd->end_match));907 //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0908 //&& (sed_cmd->end_line || sed_cmd->end_match909 //? (sed_cmd->beg_line <= linenum)910 //: (sed_cmd->beg_line == linenum)911 //)912 // )913 //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space)));914 //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));1018 dbg("match1:%d", sed_cmd->in_match); 1019 dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line 1020 && !sed_cmd->beg_match && !sed_cmd->end_match)); 1021 dbg("match3:%d", (sed_cmd->beg_line > 0 1022 && (sed_cmd->end_line || sed_cmd->end_match 1023 ? (sed_cmd->beg_line <= linenum) 1024 : (sed_cmd->beg_line == linenum) 1025 ) 1026 )); 1027 dbg("match4:%d", (beg_match(sed_cmd, pattern_space))); 1028 dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); 915 1029 916 1030 /* Are we continuing a previous multi-line match? */ … … 923 1037 && (sed_cmd->end_line || sed_cmd->end_match 924 1038 /* note: even if end is numeric and is < linenum too, 925 * GNU sed matches! We match too */ 1039 * GNU sed matches! We match too, therefore we don't 1040 * check here that linenum <= end. 1041 * Example: 1042 * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p' 1043 * first three input lines are deleted; 1044 * 4th line is matched and printed 1045 * by "2,3" (!) and by "4" ranges 1046 */ 926 1047 ? (sed_cmd->beg_line <= linenum) /* N,end */ 927 1048 : (sed_cmd->beg_line == linenum) /* N */ … … 936 1057 matched = sed_cmd->in_match; 937 1058 938 //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",939 //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);1059 dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", 1060 sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); 940 1061 941 1062 /* Is this line the end of the current match? */ … … 943 1064 if (matched) { 944 1065 /* once matched, "n,xxx" range is dead, disabling it */ 945 if (sed_cmd->beg_line > 0 946 && !(option_mask32 & OPT_in_place) /* but not for -i */ 947 ) { 1066 if (sed_cmd->beg_line > 0) { 948 1067 sed_cmd->beg_line = -2; 949 1068 } 950 1069 sed_cmd->in_match = !( 951 1070 /* has the ending line come, or is this a single address command? */ 952 (sed_cmd->end_line ?953 sed_cmd->end_line == -1 ?954 !next_line1071 (sed_cmd->end_line 1072 ? sed_cmd->end_line == -1 1073 ? !next_line 955 1074 : (sed_cmd->end_line <= linenum) 956 1075 : !sed_cmd->end_match … … 959 1078 || (sed_cmd->end_match && old_matched 960 1079 && (regexec(sed_cmd->end_match, 961 pattern_space, 0, NULL, 0) == 0)) 1080 pattern_space, 0, NULL, 0) == 0) 1081 ) 962 1082 ); 963 1083 } … … 993 1113 994 1114 /* actual sedding */ 995 //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c",996 //pattern_space, next_line, sed_cmd->cmd);1115 dbg("pattern_space:'%s' next_line:'%s' cmd:%c", 1116 pattern_space, next_line, sed_cmd->cmd); 997 1117 switch (sed_cmd->cmd) { 998 1118 … … 1041 1161 if (!do_subst_command(sed_cmd, &pattern_space)) 1042 1162 break; 1163 dbg("do_subst_command succeeded:'%s'", pattern_space); 1043 1164 substituted |= 1; 1044 1165 … … 1288 1409 unsigned opt; 1289 1410 llist_t *opt_e, *opt_f; 1411 char *opt_i; 1412 1413 #if ENABLE_LONG_OPTS 1414 static const char sed_longopts[] ALIGN1 = 1415 /* name has_arg short */ 1416 "in-place\0" Optional_argument "i" 1417 "regexp-extended\0" No_argument "r" 1418 "quiet\0" No_argument "n" 1419 "silent\0" No_argument "n" 1420 "expression\0" Required_argument "e" 1421 "file\0" Required_argument "f"; 1422 #endif 1423 1290 1424 int status = EXIT_SUCCESS; 1291 1425 … … 1296 1430 1297 1431 /* Lie to autoconf when it starts asking stupid questions. */ 1298 if (argv[1] && !strcmp(argv[1], "--version")) {1432 if (argv[1] && strcmp(argv[1], "--version") == 0) { 1299 1433 puts("This is not GNU sed version 4.0"); 1300 1434 return 0; … … 1303 1437 /* do normal option parsing */ 1304 1438 opt_e = opt_f = NULL; 1439 opt_i = NULL; 1305 1440 opt_complementary = "e::f::" /* can occur multiple times */ 1306 1441 "nn"; /* count -n */ 1442 1443 IF_LONG_OPTS(applet_long_options = sed_longopts); 1444 1307 1445 /* -i must be first, to match OPT_in_place definition */ 1308 opt = getopt32(argv, "i rne:f:", &opt_e, &opt_f,1446 opt = getopt32(argv, "i::rne:f:", &opt_i, &opt_e, &opt_f, 1309 1447 &G.be_quiet); /* counter for -n */ 1310 1448 //argc -= optind; … … 1349 1487 } else { 1350 1488 int i; 1351 FILE *file;1352 1489 1353 1490 for (i = 0; argv[i]; i++) { 1354 1491 struct stat statbuf; 1355 1492 int nonstdoutfd; 1493 FILE *file; 1494 sed_cmd_t *sed_cmd; 1356 1495 1357 1496 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { … … 1365 1504 continue; 1366 1505 } 1506 add_input_file(file); 1367 1507 if (!(opt & OPT_in_place)) { 1368 add_input_file(file);1369 1508 continue; 1370 1509 } 1510 1511 /* -i: process each FILE separately: */ 1371 1512 1372 1513 G.outname = xasprintf("%sXXXXXX", argv[i]); … … 1380 1521 fchmod(nonstdoutfd, statbuf.st_mode); 1381 1522 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); 1382 add_input_file(file); 1523 1383 1524 process_files(); 1384 1525 fclose(G.nonstdout); 1385 1386 1526 G.nonstdout = stdout; 1387 /* unlink(argv[i]); */ 1388 xrename(G.outname, argv[i]); 1527 1528 if (opt_i) { 1529 char *backupname = xasprintf("%s%s", argv[i], opt_i); 1530 xrename(argv[i], backupname); 1531 free(backupname); 1532 } 1533 /* else unlink(argv[i]); - rename below does this */ 1534 xrename(G.outname, argv[i]); //TODO: rollback backup on error? 1389 1535 free(G.outname); 1390 1536 G.outname = NULL; 1537 1538 /* Re-enable disabled range matches */ 1539 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { 1540 sed_cmd->beg_line = sed_cmd->beg_line_orig; 1541 } 1391 1542 } 1392 1543 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: -
branches/3.2/mindi-busybox/editors/vi.c
r2725 r3232 15 15 * :map macros 16 16 * if mark[] values were line numbers rather than pointers 17 * 17 * it would be easier to change the mark when add/delete lines 18 18 * More intelligence in refresh() 19 19 * ":r !cmd" and "!cmd" to filter text through an external command … … 22 22 */ 23 23 24 //config:config VI 25 //config: bool "vi" 26 //config: default y 27 //config: help 28 //config: 'vi' is a text editor. More specifically, it is the One True 29 //config: text editor <grin>. It does, however, have a rather steep 30 //config: learning curve. If you are not already comfortable with 'vi' 31 //config: you may wish to use something else. 32 //config: 33 //config:config FEATURE_VI_MAX_LEN 34 //config: int "Maximum screen width in vi" 35 //config: range 256 16384 36 //config: default 4096 37 //config: depends on VI 38 //config: help 39 //config: Contrary to what you may think, this is not eating much. 40 //config: Make it smaller than 4k only if you are very limited on memory. 41 //config: 42 //config:config FEATURE_VI_8BIT 43 //config: bool "Allow vi to display 8-bit chars (otherwise shows dots)" 44 //config: default n 45 //config: depends on VI 46 //config: help 47 //config: If your terminal can display characters with high bit set, 48 //config: you may want to enable this. Note: vi is not Unicode-capable. 49 //config: If your terminal combines several 8-bit bytes into one character 50 //config: (as in Unicode mode), this will not work properly. 51 //config: 52 //config:config FEATURE_VI_COLON 53 //config: bool "Enable \":\" colon commands (no \"ex\" mode)" 54 //config: default y 55 //config: depends on VI 56 //config: help 57 //config: Enable a limited set of colon commands for vi. This does not 58 //config: provide an "ex" mode. 59 //config: 60 //config:config FEATURE_VI_YANKMARK 61 //config: bool "Enable yank/put commands and mark cmds" 62 //config: default y 63 //config: depends on VI 64 //config: help 65 //config: This will enable you to use yank and put, as well as mark in 66 //config: busybox vi. 67 //config: 68 //config:config FEATURE_VI_SEARCH 69 //config: bool "Enable search and replace cmds" 70 //config: default y 71 //config: depends on VI 72 //config: help 73 //config: Select this if you wish to be able to do search and replace in 74 //config: busybox vi. 75 //config: 76 //config:config FEATURE_VI_REGEX_SEARCH 77 //config: bool "Enable regex in search and replace" 78 //config: default n # Uses GNU regex, which may be unavailable. FIXME 79 //config: depends on FEATURE_VI_SEARCH 80 //config: help 81 //config: Use extended regex search. 82 //config: 83 //config:config FEATURE_VI_USE_SIGNALS 84 //config: bool "Catch signals" 85 //config: default y 86 //config: depends on VI 87 //config: help 88 //config: Selecting this option will make busybox vi signal aware. This will 89 //config: make busybox vi support SIGWINCH to deal with Window Changes, catch 90 //config: Ctrl-Z and Ctrl-C and alarms. 91 //config: 92 //config:config FEATURE_VI_DOT_CMD 93 //config: bool "Remember previous cmd and \".\" cmd" 94 //config: default y 95 //config: depends on VI 96 //config: help 97 //config: Make busybox vi remember the last command and be able to repeat it. 98 //config: 99 //config:config FEATURE_VI_READONLY 100 //config: bool "Enable -R option and \"view\" mode" 101 //config: default y 102 //config: depends on VI 103 //config: help 104 //config: Enable the read-only command line option, which allows the user to 105 //config: open a file in read-only mode. 106 //config: 107 //config:config FEATURE_VI_SETOPTS 108 //config: bool "Enable set-able options, ai ic showmatch" 109 //config: default y 110 //config: depends on VI 111 //config: help 112 //config: Enable the editor to set some (ai, ic, showmatch) options. 113 //config: 114 //config:config FEATURE_VI_SET 115 //config: bool "Support for :set" 116 //config: default y 117 //config: depends on VI 118 //config: help 119 //config: Support for ":set". 120 //config: 121 //config:config FEATURE_VI_WIN_RESIZE 122 //config: bool "Handle window resize" 123 //config: default y 124 //config: depends on VI 125 //config: help 126 //config: Make busybox vi behave nicely with terminals that get resized. 127 //config: 128 //config:config FEATURE_VI_ASK_TERMINAL 129 //config: bool "Use 'tell me cursor position' ESC sequence to measure window" 130 //config: default y 131 //config: depends on VI 132 //config: help 133 //config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, 134 //config: this option makes vi perform a last-ditch effort to find it: 135 //config: position cursor to 999,999 and ask terminal to report real 136 //config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. 137 //config: 138 //config: This is not clean but helps a lot on serial lines and such. 139 140 //applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) 141 142 //kbuild:lib-$(CONFIG_VI) += vi.o 143 144 //usage:#define vi_trivial_usage 145 //usage: "[OPTIONS] [FILE]..." 146 //usage:#define vi_full_usage "\n\n" 147 //usage: "Edit FILE\n" 148 //usage: IF_FEATURE_VI_COLON( 149 //usage: "\n -c CMD Initial command to run ($EXINIT also available)" 150 //usage: ) 151 //usage: IF_FEATURE_VI_READONLY( 152 //usage: "\n -R Read-only" 153 //usage: ) 154 //usage: "\n -H List available features" 155 24 156 #include "libbb.h" 157 /* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ 158 #if ENABLE_FEATURE_VI_REGEX_SEARCH 159 # include <regex.h> 160 #endif 25 161 26 162 /* the CRASHME code is unmaintained, and doesn't currently build */ … … 41 177 /* 0x9b is Meta-ESC */ 42 178 #if ENABLE_FEATURE_VI_8BIT 43 # define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b)179 # define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) 44 180 #else 45 # define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f)181 # define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) 46 182 #endif 47 183 … … 59 195 }; 60 196 61 /* vt102 typical ESC sequence */ 62 /* terminal standout start/normal ESC sequence */ 63 #define SOs "\033[7m" 64 #define SOn "\033[0m" 65 /* terminal bell sequence */ 66 #define bell "\007" 67 /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 68 #define Ceol "\033[K" 69 #define Ceos "\033[J" 70 /* Cursor motion arbitrary destination ESC sequence */ 71 #define CMrc "\033[%u;%uH" 72 /* Cursor motion up and down ESC sequence */ 73 #define CMup "\033[A" 74 #define CMdown "\n" 197 /* VT102 ESC sequences. 198 * See "Xterm Control Sequences" 199 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 200 */ 201 /* Inverse/Normal text */ 202 #define ESC_BOLD_TEXT "\033[7m" 203 #define ESC_NORM_TEXT "\033[0m" 204 /* Bell */ 205 #define ESC_BELL "\007" 206 /* Clear-to-end-of-line */ 207 #define ESC_CLEAR2EOL "\033[K" 208 /* Clear-to-end-of-screen. 209 * (We use default param here. 210 * Full sequence is "ESC [ <num> J", 211 * <num> is 0/1/2 = "erase below/above/all".) 212 */ 213 #define ESC_CLEAR2EOS "\033[J" 214 /* Cursor to given coordinate (1,1: top left) */ 215 #define ESC_SET_CURSOR_POS "\033[%u;%uH" 216 //UNUSED 217 ///* Cursor up and down */ 218 //#define ESC_CURSOR_UP "\033[A" 219 //#define ESC_CURSOR_DOWN "\n" 75 220 76 221 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK … … 135 280 int file_modified; // buffer contents changed (counter, not flag!) 136 281 int last_file_modified; // = -1; 137 int fn_start; // index of first cmd line file name138 282 int save_argc; // how many file names on cmd line 139 283 int cmdcnt; // repetition count … … 161 305 char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 162 306 #endif 163 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR164 int last_row; // where the cursor was last moved to165 #endif166 307 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 167 308 int my_pid; … … 220 361 #define file_modified (G.file_modified ) 221 362 #define last_file_modified (G.last_file_modified ) 222 #define fn_start (G.fn_start )223 363 #define save_argc (G.save_argc ) 224 364 #define cmdcnt (G.cmdcnt ) … … 248 388 #define ioq (G.ioq ) 249 389 #define ioq_start (G.ioq_start ) 250 #define last_row (G.last_row )251 390 #define my_pid (G.my_pid ) 252 391 #define last_search_pattern (G.last_search_pattern) … … 329 468 static int file_insert(const char *, char *, int); 330 469 static int file_write(char *, char *, char *); 331 #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 332 #define place_cursor(a, b, optimize) place_cursor(a, b) 333 #endif 334 static void place_cursor(int, int, int); 470 static void place_cursor(int, int); 335 471 static void screen_erase(void); 336 472 static void clear_to_eol(void); … … 355 491 #if ENABLE_FEATURE_VI_SEARCH 356 492 static char *char_search(char *, const char *, int, int); // search for pattern starting at p 357 static int mycmp(const char *, const char *, int); // string cmp based in "ignorecase"358 493 #endif 359 494 #if ENABLE_FEATURE_VI_COLON … … 418 553 #endif 419 554 420 vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; 555 // autoindent is not default in vim 7.3 556 vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE; 421 557 // 1- process $HOME/.exrc file (not inplemented yet) 422 558 // 2- process EXINIT variable from environment … … 444 580 case 'c': // cmd line vi command 445 581 if (*optarg) 446 initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN);582 initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); 447 583 break; 448 584 #endif … … 457 593 458 594 // The argv array can be used by the ":next" and ":rewind" commands 459 // save optind. 460 fn_start = optind; // remember first file name for :next and :rew 595 argv += optind; 596 argc -= optind; 597 598 //----- This is the main file handling loop -------------- 461 599 save_argc = argc; 462 463 //----- This is the main file handling loop -------------- 600 optind = 0; 601 // "Save cursor, use alternate screen buffer, clear screen" 602 write1("\033[?1049h"); 464 603 while (1) { 465 604 edit_file(argv[optind]); /* param might be NULL */ … … 467 606 break; 468 607 } 608 // "Use normal screen buffer, restore cursor" 609 write1("\033[?1049l"); 469 610 //----------------------------------------------------------- 470 611 … … 524 665 #endif 525 666 int c; 526 int size;527 667 #if ENABLE_FEATURE_VI_USE_SIGNALS 528 668 int sig; … … 533 673 rows = 24; 534 674 columns = 80; 535 size = 0;536 675 IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); 537 676 #if ENABLE_FEATURE_VI_ASK_TERMINAL … … 881 1020 // don't edit, if the current file has been modified 882 1021 if (file_modified && !useforce) { 883 status_line_bold("No write since last change (: edit! overrides)");1022 status_line_bold("No write since last change (:%s! overrides)", cmd); 884 1023 goto ret; 885 1024 } … … 900 1039 901 1040 #if ENABLE_FEATURE_VI_YANKMARK 902 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {1041 if (Ureg >= 0 && Ureg < 28) { 903 1042 free(reg[Ureg]); // free orig line reg- for 'U' 904 reg[Ureg] = 0;905 } 906 if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {1043 reg[Ureg] = NULL; 1044 } 1045 if (YDreg >= 0 && YDreg < 28) { 907 1046 free(reg[YDreg]); // free default yank/delete register 908 reg[YDreg] = 0;1047 reg[YDreg] = NULL; 909 1048 } 910 1049 #endif … … 971 1110 } else if (strncmp(cmd, "quit", i) == 0 // quit 972 1111 || strncmp(cmd, "next", i) == 0 // edit next file 1112 || strncmp(cmd, "prev", i) == 0 // edit previous file 973 1113 ) { 974 1114 int n; 975 1115 if (useforce) { 976 // force end of argv list977 1116 if (*cmd == 'q') { 1117 // force end of argv list 978 1118 optind = save_argc; 979 1119 } … … 983 1123 // don't exit if the file been modified 984 1124 if (file_modified) { 985 status_line_bold("No write since last change (:%s! overrides)", 986 (*cmd == 'q' ? "quit" : "next")); 1125 status_line_bold("No write since last change (:%s! overrides)", cmd); 987 1126 goto ret; 988 1127 } … … 996 1135 status_line_bold("No more files to edit"); 997 1136 goto ret; 1137 } 1138 if (*cmd == 'p') { 1139 // are there previous files to edit 1140 if (optind < 1) { 1141 status_line_bold("No previous files to edit"); 1142 goto ret; 1143 } 1144 optind -= 2; 998 1145 } 999 1146 editing = 0; … … 1032 1179 } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args 1033 1180 if (file_modified && !useforce) { 1034 status_line_bold("No write since last change (: rewind! overrides)");1181 status_line_bold("No write since last change (:%s! overrides)", cmd); 1035 1182 } else { 1036 1183 // reset the filenames to edit 1037 optind = fn_start - 1;1184 optind = -1; /* start from 0th file */ 1038 1185 editing = 0; 1039 1186 } … … 1044 1191 #endif 1045 1192 i = 0; // offset into args 1046 // only blank is regarded as args del miter. What about tab '\t'?1193 // only blank is regarded as args delimiter. What about tab '\t'? 1047 1194 if (!args[0] || strcasecmp(args, "all") == 0) { 1048 1195 // print out values of all options … … 1085 1232 #if ENABLE_FEATURE_VI_SEARCH 1086 1233 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern 1087 char *ls, *F, *R; 1088 int gflag; 1234 char *F, *R, *flags; 1235 size_t len_F, len_R; 1236 int gflag; // global replace flag 1089 1237 1090 1238 // F points to the "find" pattern 1091 1239 // R points to the "replace" pattern 1092 // replace the cmd line delimiters "/" with NULLs 1093 gflag = 0; // global replace flag 1240 // replace the cmd line delimiters "/" with NULs 1094 1241 c = orig_buf[1]; // what is the delimiter 1095 1242 F = orig_buf + 2; // start of "find" … … 1097 1244 if (!R) 1098 1245 goto colon_s_fail; 1246 len_F = R - F; 1099 1247 *R++ = '\0'; // terminate "find" 1100 buf1= strchr(R, c);1101 if (! buf1)1248 flags = strchr(R, c); 1249 if (!flags) 1102 1250 goto colon_s_fail; 1103 *buf1++ = '\0'; // terminate "replace" 1104 if (*buf1 == 'g') { // :s/foo/bar/g 1105 buf1++; 1106 gflag++; // turn on gflag 1107 } 1251 len_R = flags - R; 1252 *flags++ = '\0'; // terminate "replace" 1253 gflag = *flags; 1254 1108 1255 q = begin_line(q); 1109 1256 if (b < 0) { // maybe :s/foo/bar/ 1110 q = begin_line(dot); 1111 b = count_lines(text, q); 1257 q = begin_line(dot); // start with cur line 1258 b = count_lines(text, q); // cur line number 1112 1259 } 1113 1260 if (e < 0) 1114 1261 e = b; // maybe :.s/foo/bar/ 1262 1115 1263 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 1116 ls = q; // orig line start 1264 char *ls = q; // orig line start 1265 char *found; 1117 1266 vc4: 1118 buf1= char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"1119 if ( buf1) {1267 found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" 1268 if (found) { 1120 1269 uintptr_t bias; 1121 1270 // we found the "find" pattern - delete it 1122 text_hole_delete( buf1, buf1 + strlen(F)- 1);1271 text_hole_delete(found, found + len_F - 1); 1123 1272 // inset the "replace" patern 1124 bias = string_insert( buf1, R); // insert the string1125 buf1+= bias;1273 bias = string_insert(found, R); // insert the string 1274 found += bias; 1126 1275 ls += bias; 1127 1276 /*q += bias; - recalculated anyway */ 1128 1277 // check for "global" :s/foo/bar/g 1129 if (gflag == 1) {1130 if (( buf1 + strlen(R)) < end_line(ls)) {1131 q = buf1 + strlen(R);1278 if (gflag == 'g') { 1279 if ((found + len_R) < end_line(ls)) { 1280 q = found + len_R; 1132 1281 goto vc4; // don't let q move past cur line 1133 1282 } … … 1552 1701 1553 1702 #if ENABLE_FEATURE_VI_SEARCH 1554 static int mycmp(const char *s1, const char *s2, int len) 1555 { 1556 if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { 1557 return strncasecmp(s1, s2, len); 1558 } 1559 return strncmp(s1, s2, len); 1560 } 1703 1704 # if ENABLE_FEATURE_VI_REGEX_SEARCH 1561 1705 1562 1706 // search for pattern starting at p 1563 1707 static char *char_search(char *p, const char *pat, int dir, int range) 1564 1708 { 1565 #ifndef REGEX_SEARCH1566 char *start, *stop;1567 int len;1568 1569 len = strlen(pat);1570 if (dir == FORWARD) {1571 stop = end - 1; // assume range is p - end-11572 if (range == LIMITED)1573 stop = next_line(p); // range is to next line1574 for (start = p; start < stop; start++) {1575 if (mycmp(start, pat, len) == 0) {1576 return start;1577 }1578 }1579 } else if (dir == BACK) {1580 stop = text; // assume range is text - p1581 if (range == LIMITED)1582 stop = prev_line(p); // range is to prev line1583 for (start = p - len; start >= stop; start--) {1584 if (mycmp(start, pat, len) == 0) {1585 return start;1586 }1587 }1588 }1589 // pattern not found1590 return NULL;1591 #else /* REGEX_SEARCH */1592 1709 char *q; 1593 1710 struct re_pattern_buffer preg; 1594 1711 int i; 1595 int size , range;1712 int size; 1596 1713 1597 1714 re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; … … 1616 1733 range = q - p; 1617 1734 1618 q = re_compile_pattern(pat, strlen(pat),&preg);1735 q = (char *)re_compile_pattern(pat, strlen(pat), (struct re_pattern_buffer *)&preg); 1619 1736 if (q != 0) { 1620 1737 // The pattern was not compiled … … 1650 1767 } 1651 1768 return p; 1652 #endif /* REGEX_SEARCH */ 1653 } 1769 } 1770 1771 # else 1772 1773 # if ENABLE_FEATURE_VI_SETOPTS 1774 static int mycmp(const char *s1, const char *s2, int len) 1775 { 1776 if (ignorecase) { 1777 return strncasecmp(s1, s2, len); 1778 } 1779 return strncmp(s1, s2, len); 1780 } 1781 # else 1782 # define mycmp strncmp 1783 # endif 1784 1785 static char *char_search(char *p, const char *pat, int dir, int range) 1786 { 1787 char *start, *stop; 1788 int len; 1789 1790 len = strlen(pat); 1791 if (dir == FORWARD) { 1792 stop = end - 1; // assume range is p - end-1 1793 if (range == LIMITED) 1794 stop = next_line(p); // range is to next line 1795 for (start = p; start < stop; start++) { 1796 if (mycmp(start, pat, len) == 0) { 1797 return start; 1798 } 1799 } 1800 } else if (dir == BACK) { 1801 stop = text; // assume range is text - p 1802 if (range == LIMITED) 1803 stop = prev_line(p); // range is to prev line 1804 for (start = p - len; start >= stop; start--) { 1805 if (mycmp(start, pat, len) == 0) { 1806 return start; 1807 } 1808 } 1809 } 1810 // pattern not found 1811 return NULL; 1812 } 1813 1814 # endif 1815 1654 1816 #endif /* FEATURE_VI_SEARCH */ 1655 1817 … … 1678 1840 } 1679 1841 } else { 1842 #if ENABLE_FEATURE_VI_SETOPTS 1680 1843 // insert a char into text[] 1681 1844 char *sp; // "save p" 1845 #endif 1682 1846 1683 1847 if (c == 13) 1684 1848 c = '\n'; // translate \r to \n 1849 #if ENABLE_FEATURE_VI_SETOPTS 1685 1850 sp = p; // remember addr of insert 1851 #endif 1686 1852 p += 1 + stupid_insert(p, c); // insert the char 1687 1853 #if ENABLE_FEATURE_VI_SETOPTS … … 1764 1930 q = dot; 1765 1931 } else { 1766 1767 1768 1769 1770 1932 // nothing -- this causes any other values of c to 1933 // represent the one-character range under the 1934 // cursor. this is correct for ' ' and 'l', but 1935 // perhaps no others. 1936 // 1771 1937 } 1772 1938 if (q < p) { … … 1916 2082 end += bias; 1917 2083 p += bias; 2084 #if ENABLE_FEATURE_VI_YANKMARK 2085 { 2086 int i; 2087 for (i = 0; i < ARRAY_SIZE(mark); i++) 2088 if (mark[i]) 2089 mark[i] += bias; 2090 } 2091 #endif 1918 2092 text = new_text; 1919 2093 } … … 2002 2176 #endif 2003 2177 #if ENABLE_FEATURE_VI_DOT_CMD 2004 "\n\tLast command repeat with \'.\'"2178 "\n\tLast command repeat with ." 2005 2179 #endif 2006 2180 #if ENABLE_FEATURE_VI_YANKMARK … … 2009 2183 #endif 2010 2184 #if ENABLE_FEATURE_VI_READONLY 2011 "\n\tReadonly if vi is called as \"view\""2012 "\n\tReadonly with -R command line arg"2185 //not implemented: "\n\tReadonly if vi is called as \"view\"" 2186 //redundant: usage text says this too: "\n\tReadonly with -R command line arg" 2013 2187 #endif 2014 2188 #if ENABLE_FEATURE_VI_SET 2015 "\n\tSome colon mode commands with \':\'"2189 "\n\tSome colon mode commands with :" 2016 2190 #endif 2017 2191 #if ENABLE_FEATURE_VI_SETOPTS … … 2147 2321 tcgetattr(0, &term_orig); 2148 2322 term_vi = term_orig; 2149 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's2323 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's 2150 2324 term_vi.c_iflag &= (~IXON & ~ICRNL); 2151 2325 term_vi.c_oflag &= (~ONLCR); … … 2418 2592 2419 2593 //----- Move the cursor to row x col (count from 0, not 1) ------- 2420 static void place_cursor(int row, int col, int optimize) 2421 { 2422 char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; 2423 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2424 enum { 2425 SZ_UP = sizeof(CMup), 2426 SZ_DN = sizeof(CMdown), 2427 SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN, 2428 }; 2429 char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size 2430 #endif 2431 char *cm; 2594 static void place_cursor(int row, int col) 2595 { 2596 char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2]; 2432 2597 2433 2598 if (row < 0) row = 0; … … 2436 2601 if (col >= columns) col = columns - 1; 2437 2602 2438 //----- 1. Try the standard terminal ESC sequence 2439 sprintf(cm1, CMrc, row + 1, col + 1); 2440 cm = cm1; 2441 2442 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2443 if (optimize && col < 16) { 2444 char *screenp; 2445 int Rrow = last_row; 2446 int diff = Rrow - row; 2447 2448 if (diff < -5 || diff > 5) 2449 goto skip; 2450 2451 //----- find the minimum # of chars to move cursor ------------- 2452 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 2453 cm2[0] = '\0'; 2454 2455 // move to the correct row 2456 while (row < Rrow) { 2457 // the cursor has to move up 2458 strcat(cm2, CMup); 2459 Rrow--; 2460 } 2461 while (row > Rrow) { 2462 // the cursor has to move down 2463 strcat(cm2, CMdown); 2464 Rrow++; 2465 } 2466 2467 // now move to the correct column 2468 strcat(cm2, "\r"); // start at col 0 2469 // just send out orignal source char to get to correct place 2470 screenp = &screen[row * columns]; // start of screen line 2471 strncat(cm2, screenp, col); 2472 2473 // pick the shortest cursor motion to send out 2474 if (strlen(cm2) < strlen(cm)) { 2475 cm = cm2; 2476 } 2477 skip: ; 2478 } 2479 last_row = row; 2480 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2481 write1(cm); 2603 sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1); 2604 write1(cm1); 2482 2605 } 2483 2606 … … 2485 2608 static void clear_to_eol(void) 2486 2609 { 2487 write1( Ceol); // Erase from cursor to end of line2610 write1(ESC_CLEAR2EOL); 2488 2611 } 2489 2612 2490 2613 static void go_bottom_and_clear_to_eol(void) 2491 2614 { 2492 place_cursor(rows - 1, 0 , FALSE); // go to bottom of screen2493 clear_to_eol(); // erase to end of line2615 place_cursor(rows - 1, 0); 2616 clear_to_eol(); 2494 2617 } 2495 2618 … … 2497 2620 static void clear_to_eos(void) 2498 2621 { 2499 write1( Ceos); // Erase from cursor to end of screen2622 write1(ESC_CLEAR2EOS); 2500 2623 } 2501 2624 2502 2625 //----- Start standout mode ------------------------------------ 2503 static void standout_start(void) // send "start reverse video" sequence2504 { 2505 write1( SOs); // Start reverse video mode2626 static void standout_start(void) 2627 { 2628 write1(ESC_BOLD_TEXT); 2506 2629 } 2507 2630 2508 2631 //----- End standout mode -------------------------------------- 2509 static void standout_end(void) // send "end reverse video" sequence2510 { 2511 write1( SOn); // End reverse video mode2632 static void standout_end(void) 2633 { 2634 write1(ESC_NORM_TEXT); 2512 2635 } 2513 2636 … … 2515 2638 static void flash(int h) 2516 2639 { 2517 standout_start(); // send "start reverse video" sequence2640 standout_start(); 2518 2641 redraw(TRUE); 2519 2642 mysleep(h); 2520 standout_end(); // send "end reverse video" sequence2643 standout_end(); 2521 2644 redraw(TRUE); 2522 2645 } … … 2529 2652 #endif 2530 2653 if (!err_method) { 2531 write1( bell); // send out a bell character2654 write1(ESC_BELL); 2532 2655 } else { 2533 2656 flash(10); … … 2575 2698 have_status_msg = 0; 2576 2699 } 2577 place_cursor(crow, ccol , FALSE);// put cursor back in correct place2700 place_cursor(crow, ccol); // put cursor back in correct place 2578 2701 } 2579 2702 fflush_all(); … … 2587 2710 2588 2711 va_start(args, format); 2589 strcpy(status_buffer, SOs); // Terminal standout mode on2590 vsprintf(status_buffer + sizeof( SOs)-1, format, args);2591 strcat(status_buffer, SOn); // Terminal standout mode off2712 strcpy(status_buffer, ESC_BOLD_TEXT); 2713 vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args); 2714 strcat(status_buffer, ESC_NORM_TEXT); 2592 2715 va_end(args); 2593 2716 2594 have_status_msg = 1 + sizeof( SOs) + sizeof(SOn) - 2;2717 have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; 2595 2718 } 2596 2719 … … 2624 2747 c_is_no_print = (c & 0x80) && !Isprint(c); 2625 2748 if (c_is_no_print) { 2626 strcpy(d, SOn);2627 d += sizeof( SOn)-1;2749 strcpy(d, ESC_NORM_TEXT); 2750 d += sizeof(ESC_NORM_TEXT)-1; 2628 2751 c = '.'; 2629 2752 } … … 2637 2760 *d = '\0'; 2638 2761 if (c_is_no_print) { 2639 strcpy(d, SOs);2640 d += sizeof( SOs)-1;2762 strcpy(d, ESC_BOLD_TEXT); 2763 d += sizeof(ESC_BOLD_TEXT)-1; 2641 2764 } 2642 2765 if (*s == '\n') { … … 2720 2843 static void redraw(int full_screen) 2721 2844 { 2722 place_cursor(0, 0 , FALSE); // put cursor in correct place2723 clear_to_eos(); // tell terminal to erase display2845 place_cursor(0, 0); 2846 clear_to_eos(); 2724 2847 screen_erase(); // erase the internal screen buffer 2725 2848 last_status_cksum = 0; // force status update … … 2861 2984 // copy changed part of buffer to virtual screen 2862 2985 memcpy(sp+cs, out_buf+cs, ce-cs+1); 2863 2864 // move cursor to column of first change 2865 //if (offset != old_offset) { 2866 // // place_cursor is still too stupid 2867 // // to handle offsets correctly 2868 // place_cursor(li, cs, FALSE); 2869 //} else { 2870 place_cursor(li, cs, TRUE); 2871 //} 2872 2986 place_cursor(li, cs); 2873 2987 // write line out to terminal 2874 2988 fwrite(&sp[cs], ce - cs + 1, 1, stdout); … … 2876 2990 } 2877 2991 2878 place_cursor(crow, ccol , TRUE);2992 place_cursor(crow, ccol); 2879 2993 2880 2994 old_offset = offset; … … 2906 3020 static void do_cmd(int c) 2907 3021 { 2908 const char *msg = msg; // for compiler2909 3022 char *p, *q, *save_dot; 2910 3023 char buf[12]; … … 2915 3028 // c1 = c; // quiet the compiler 2916 3029 // cnt = yf = 0; // quiet the compiler 2917 // msg =p = q = save_dot = buf; // quiet the compiler2918 memset(buf, '\0', 12);3030 // p = q = save_dot = buf; // quiet the compiler 3031 memset(buf, '\0', sizeof(buf)); 2919 3032 2920 3033 show_status_line(); … … 3032 3145 case 8: // ctrl-H- move left (This may be ERASE char) 3033 3146 case 0x7f: // DEL- move left (This may be ERASE char) 3034 if (--cmdcnt > 0) { 3035 do_cmd(c); 3036 } 3037 dot_left(); 3147 do { 3148 dot_left(); 3149 } while (--cmdcnt > 0); 3038 3150 break; 3039 3151 case 10: // Newline ^J 3040 3152 case 'j': // j- goto next line, same col 3041 3153 case KEYCODE_DOWN: // cursor key Down 3042 if (--cmdcnt > 0){3043 do _cmd(c);3044 }3045 dot_next(); // go to next B-o-l3046 dot = move_to_col(dot, ccol + offset); // try stay in same col3154 do { 3155 dot_next(); // go to next B-o-l 3156 // try stay in same col 3157 dot = move_to_col(dot, ccol + offset); 3158 } while (--cmdcnt > 0); 3047 3159 break; 3048 3160 case 12: // ctrl-L force redraw whole screen 3049 3161 case 18: // ctrl-R force redraw 3050 place_cursor(0, 0 , FALSE); // put cursor in correct place3051 clear_to_eos(); // tel terminal to erase display3052 mysleep(10);3162 place_cursor(0, 0); 3163 clear_to_eos(); 3164 //mysleep(10); // why??? 3053 3165 screen_erase(); // erase the internal screen buffer 3054 3166 last_status_cksum = 0; // force status update … … 3057 3169 case 13: // Carriage Return ^M 3058 3170 case '+': // +- goto next line 3059 if (--cmdcnt > 0) { 3060 do_cmd(c); 3061 } 3062 dot_next(); 3063 dot_skip_over_ws(); 3171 do { 3172 dot_next(); 3173 dot_skip_over_ws(); 3174 } while (--cmdcnt > 0); 3064 3175 break; 3065 3176 case 21: // ctrl-U scroll up half screen … … 3079 3190 case 'l': // move right 3080 3191 case KEYCODE_RIGHT: // Cursor Key Right 3081 if (--cmdcnt > 0) { 3082 do_cmd(c); 3083 } 3084 dot_right(); 3192 do { 3193 dot_right(); 3194 } while (--cmdcnt > 0); 3085 3195 break; 3086 3196 #if ENABLE_FEATURE_VI_YANKMARK … … 3152 3262 break; 3153 3263 case 'U': // U- Undo; replace current line with original version 3154 if (reg[Ureg] != 0) {3264 if (reg[Ureg] != NULL) { 3155 3265 p = begin_line(dot); 3156 3266 q = end_line(dot); … … 3164 3274 case '$': // $- goto end of line 3165 3275 case KEYCODE_END: // Cursor Key End 3166 if (--cmdcnt > 0) { 3276 for (;;) { 3277 dot = end_line(dot); 3278 if (--cmdcnt <= 0) 3279 break; 3167 3280 dot_next(); 3168 do_cmd(c); 3169 } 3170 dot = end_line(dot); 3281 } 3171 3282 break; 3172 3283 case '%': // %- find matching char of pair () [] {} … … 3193 3304 //**** fall through to ... ';' 3194 3305 case ';': // ;- look at rest of line for last forward char 3195 if (--cmdcnt > 0) { 3196 do_cmd(';'); 3197 } 3306 do { 3307 if (last_forward_char == 0) 3308 break; 3309 q = dot + 1; 3310 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 3311 q++; 3312 } 3313 if (*q == last_forward_char) 3314 dot = q; 3315 } while (--cmdcnt > 0); 3316 break; 3317 case ',': // repeat latest 'f' in opposite direction 3198 3318 if (last_forward_char == 0) 3199 3319 break; 3200 q = dot + 1; 3201 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 3202 q++; 3203 } 3204 if (*q == last_forward_char) 3205 dot = q; 3206 break; 3207 case ',': // repeat latest 'f' in opposite direction 3208 if (--cmdcnt > 0) { 3209 do_cmd(','); 3210 } 3211 if (last_forward_char == 0) 3212 break; 3213 q = dot - 1; 3214 while (q >= text && *q != '\n' && *q != last_forward_char) { 3215 q--; 3216 } 3217 if (q >= text && *q == last_forward_char) 3218 dot = q; 3320 do { 3321 q = dot - 1; 3322 while (q >= text && *q != '\n' && *q != last_forward_char) { 3323 q--; 3324 } 3325 if (q >= text && *q == last_forward_char) 3326 dot = q; 3327 } while (--cmdcnt > 0); 3219 3328 break; 3220 3329 3221 3330 case '-': // -- goto prev line 3222 if (--cmdcnt > 0) { 3223 do_cmd(c); 3224 } 3225 dot_prev(); 3226 dot_skip_over_ws(); 3331 do { 3332 dot_prev(); 3333 dot_skip_over_ws(); 3334 } while (--cmdcnt > 0); 3227 3335 break; 3228 3336 #if ENABLE_FEATURE_VI_DOT_CMD … … 3256 3364 break; 3257 3365 case 'N': // N- backward search for last pattern 3258 if (--cmdcnt > 0) {3259 do_cmd(c);3260 }3261 3366 dir = BACK; // assume BACKWARD search 3262 3367 p = dot - 1; … … 3270 3375 // search rest of text[] starting at next char 3271 3376 // if search fails return orignal "p" not the "p+1" address 3272 if (--cmdcnt > 0) { 3273 do_cmd(c); 3274 } 3377 do { 3378 const char *msg; 3275 3379 dc3: 3276 dir = FORWARD; // assume FORWARD search3277 p = dot + 1;3278 if (last_search_pattern[0] == '?') {3279 dir = BACK;3280 p = dot - 1;3281 }3380 dir = FORWARD; // assume FORWARD search 3381 p = dot + 1; 3382 if (last_search_pattern[0] == '?') { 3383 dir = BACK; 3384 p = dot - 1; 3385 } 3282 3386 dc4: 3283 q = char_search(p, last_search_pattern + 1, dir, FULL); 3284 if (q != NULL) { 3285 dot = q; // good search, update "dot" 3286 msg = ""; 3287 goto dc2; 3288 } 3289 // no pattern found between "dot" and "end"- continue at top 3290 p = text; 3291 if (dir == BACK) { 3292 p = end - 1; 3293 } 3294 q = char_search(p, last_search_pattern + 1, dir, FULL); 3295 if (q != NULL) { // found something 3296 dot = q; // found new pattern- goto it 3297 msg = "search hit BOTTOM, continuing at TOP"; 3387 q = char_search(p, last_search_pattern + 1, dir, FULL); 3388 if (q != NULL) { 3389 dot = q; // good search, update "dot" 3390 msg = NULL; 3391 goto dc2; 3392 } 3393 // no pattern found between "dot" and "end"- continue at top 3394 p = text; 3298 3395 if (dir == BACK) { 3299 msg = "search hit TOP, continuing at BOTTOM"; 3300 } 3301 } else { 3302 msg = "Pattern not found"; 3303 } 3396 p = end - 1; 3397 } 3398 q = char_search(p, last_search_pattern + 1, dir, FULL); 3399 if (q != NULL) { // found something 3400 dot = q; // found new pattern- goto it 3401 msg = "search hit BOTTOM, continuing at TOP"; 3402 if (dir == BACK) { 3403 msg = "search hit TOP, continuing at BOTTOM"; 3404 } 3405 } else { 3406 msg = "Pattern not found"; 3407 } 3304 3408 dc2: 3305 if (*msg) 3306 status_line_bold("%s", msg); 3409 if (msg) 3410 status_line_bold("%s", msg); 3411 } while (--cmdcnt > 0); 3307 3412 break; 3308 3413 case '{': // {- move backward paragraph … … 3349 3454 ) { 3350 3455 if (file_modified && p[1] != '!') { 3351 status_line_bold("No write since last change (: quit! overrides)");3456 status_line_bold("No write since last change (:%s! overrides)", p); 3352 3457 } else { 3353 3458 editing = 0; … … 3423 3528 case 'E': // E- end of a blank-delimited word 3424 3529 case 'W': // W- forward a blank-delimited word 3425 if (--cmdcnt > 0) {3426 do_cmd(c);3427 }3428 3530 dir = FORWARD; 3429 3531 if (c == 'B') 3430 3532 dir = BACK; 3431 if (c == 'W' || isspace(dot[dir])) { 3432 dot = skip_thing(dot, 1, dir, S_TO_WS); 3433 dot = skip_thing(dot, 2, dir, S_OVER_WS); 3434 } 3435 if (c != 'W') 3436 dot = skip_thing(dot, 1, dir, S_BEFORE_WS); 3533 do { 3534 if (c == 'W' || isspace(dot[dir])) { 3535 dot = skip_thing(dot, 1, dir, S_TO_WS); 3536 dot = skip_thing(dot, 2, dir, S_OVER_WS); 3537 } 3538 if (c != 'W') 3539 dot = skip_thing(dot, 1, dir, S_BEFORE_WS); 3540 } while (--cmdcnt > 0); 3437 3541 break; 3438 3542 case 'C': // C- Change to e-o-l … … 3485 3589 case KEYCODE_INSERT: // Cursor Key Insert 3486 3590 dc_i: 3487 cmd_mode = 1; // start ins rting3591 cmd_mode = 1; // start inserting 3488 3592 break; 3489 3593 case 'J': // J- join current and next lines together 3490 if (--cmdcnt > 1) { 3491 do_cmd(c); 3492 } 3493 dot_end(); // move to NL 3494 if (dot < end - 1) { // make sure not last char in text[] 3495 *dot++ = ' '; // replace NL with space 3496 file_modified++; 3497 while (isblank(*dot)) { // delete leading WS 3498 dot_delete(); 3499 } 3500 } 3594 do { 3595 dot_end(); // move to NL 3596 if (dot < end - 1) { // make sure not last char in text[] 3597 *dot++ = ' '; // replace NL with space 3598 file_modified++; 3599 while (isblank(*dot)) { // delete leading WS 3600 dot_delete(); 3601 } 3602 } 3603 } while (--cmdcnt > 0); 3501 3604 end_cmd_q(); // stop adding to q 3502 3605 break; … … 3542 3645 case 'x': // x- delete the current char 3543 3646 case 's': // s- substitute the current char 3544 if (--cmdcnt > 0) {3545 do_cmd(c);3546 }3547 3647 dir = 0; 3548 3648 if (c == 'X') 3549 3649 dir = -1; 3550 if (dot[dir] != '\n') { 3551 if (c == 'X') 3552 dot--; // delete prev char 3553 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char 3554 } 3650 do { 3651 if (dot[dir] != '\n') { 3652 if (c == 'X') 3653 dot--; // delete prev char 3654 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char 3655 } 3656 } while (--cmdcnt > 0); 3657 end_cmd_q(); // stop adding to q 3555 3658 if (c == 's') 3556 goto dc_i; // start insrting 3557 end_cmd_q(); // stop adding to q 3659 goto dc_i; // start inserting 3558 3660 break; 3559 3661 case 'Z': // Z- if modified, {write}; exit … … 3586 3688 case 'b': // b- back a word 3587 3689 case 'e': // e- end of word 3588 if (--cmdcnt > 0) {3589 do_cmd(c);3590 }3591 3690 dir = FORWARD; 3592 3691 if (c == 'b') 3593 3692 dir = BACK; 3594 if ((dot + dir) < text || (dot + dir) > end - 1) 3595 break; 3596 dot += dir; 3597 if (isspace(*dot)) { 3598 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); 3599 } 3600 if (isalnum(*dot) || *dot == '_') { 3601 dot = skip_thing(dot, 1, dir, S_END_ALNUM); 3602 } else if (ispunct(*dot)) { 3603 dot = skip_thing(dot, 1, dir, S_END_PUNCT); 3604 } 3693 do { 3694 if ((dot + dir) < text || (dot + dir) > end - 1) 3695 break; 3696 dot += dir; 3697 if (isspace(*dot)) { 3698 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); 3699 } 3700 if (isalnum(*dot) || *dot == '_') { 3701 dot = skip_thing(dot, 1, dir, S_END_ALNUM); 3702 } else if (ispunct(*dot)) { 3703 dot = skip_thing(dot, 1, dir, S_END_PUNCT); 3704 } 3705 } while (--cmdcnt > 0); 3605 3706 break; 3606 3707 case 'c': // c- change something … … 3687 3788 case 'k': // k- goto prev line, same col 3688 3789 case KEYCODE_UP: // cursor key Up 3689 if (--cmdcnt > 0) { 3690 do_cmd(c); 3691 } 3692 dot_prev(); 3693 dot = move_to_col(dot, ccol + offset); // try stay in same col 3790 do { 3791 dot_prev(); 3792 dot = move_to_col(dot, ccol + offset); // try stay in same col 3793 } while (--cmdcnt > 0); 3694 3794 break; 3695 3795 case 'r': // r- replace the current char with user input … … 3709 3809 break; 3710 3810 case 'w': // w- forward a word 3711 if (--cmdcnt > 0) { 3712 do_cmd(c); 3713 } 3714 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3715 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); 3716 } else if (ispunct(*dot)) { // we are on PUNCT 3717 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); 3718 } 3719 if (dot < end - 1) 3720 dot++; // move over word 3721 if (isspace(*dot)) { 3722 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); 3723 } 3811 do { 3812 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3813 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); 3814 } else if (ispunct(*dot)) { // we are on PUNCT 3815 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); 3816 } 3817 if (dot < end - 1) 3818 dot++; // move over word 3819 if (isspace(*dot)) { 3820 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); 3821 } 3822 } while (--cmdcnt > 0); 3724 3823 break; 3725 3824 case 'z': // z- … … 3737 3836 break; 3738 3837 case '~': // ~- flip the case of letters a-z -> A-Z 3739 if (--cmdcnt > 0) { 3740 do_cmd(c); 3741 } 3742 if (islower(*dot)) { 3743 *dot = toupper(*dot); 3744 file_modified++; 3745 } else if (isupper(*dot)) { 3746 *dot = tolower(*dot); 3747 file_modified++; 3748 } 3749 dot_right(); 3838 do { 3839 if (islower(*dot)) { 3840 *dot = toupper(*dot); 3841 file_modified++; 3842 } else if (isupper(*dot)) { 3843 *dot = tolower(*dot); 3844 file_modified++; 3845 } 3846 dot_right(); 3847 } while (--cmdcnt > 0); 3750 3848 end_cmd_q(); // stop adding to q 3751 3849 break; … … 3983 4081 if (msg[0]) { 3984 4082 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", 3985 totalcmds, last_input_char, msg, SOs, SOn);4083 totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT); 3986 4084 fflush_all(); 3987 4085 while (safe_read(STDIN_FILENO, d, 1) > 0) {
Note:
See TracChangeset
for help on using the changeset viewer.