aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
Diffstat (limited to 'editors')
-rw-r--r--editors/awk.c94
-rw-r--r--editors/patch.c26
-rw-r--r--editors/sed.c84
-rw-r--r--editors/vi.c294
4 files changed, 282 insertions, 216 deletions
diff --git a/editors/awk.c b/editors/awk.c
index 7685546e5..71abca215 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -25,6 +25,7 @@
25 * to perform debug printfs to stderr: */ 25 * to perform debug printfs to stderr: */
26#define debug_printf_walker(...) do {} while (0) 26#define debug_printf_walker(...) do {} while (0)
27#define debug_printf_eval(...) do {} while (0) 27#define debug_printf_eval(...) do {} while (0)
28#define debug_printf_parse(...) do {} while (0)
28 29
29#ifndef debug_printf_walker 30#ifndef debug_printf_walker
30# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) 31# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
@@ -32,6 +33,9 @@
32#ifndef debug_printf_eval 33#ifndef debug_printf_eval
33# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) 34# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
34#endif 35#endif
36#ifndef debug_printf_parse
37# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__))
38#endif
35 39
36 40
37 41
@@ -238,6 +242,9 @@ typedef struct tsplitter_s {
238 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1, 242 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
239 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string 243 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
240 */ 244 */
245#undef P
246#undef PRIMASK
247#undef PRIMASK2
241#define P(x) (x << 24) 248#define P(x) (x << 24)
242#define PRIMASK 0x7F000000 249#define PRIMASK 0x7F000000
243#define PRIMASK2 0x7E000000 250#define PRIMASK2 0x7E000000
@@ -432,13 +439,13 @@ struct globals {
432 smallint nextrec; 439 smallint nextrec;
433 smallint nextfile; 440 smallint nextfile;
434 smallint is_f0_split; 441 smallint is_f0_split;
442 smallint t_rollback;
435}; 443};
436struct globals2 { 444struct globals2 {
437 uint32_t t_info; /* often used */ 445 uint32_t t_info; /* often used */
438 uint32_t t_tclass; 446 uint32_t t_tclass;
439 char *t_string; 447 char *t_string;
440 int t_lineno; 448 int t_lineno;
441 int t_rollback;
442 449
443 var *intvar[NUM_INTERNAL_VARS]; /* often used */ 450 var *intvar[NUM_INTERNAL_VARS]; /* often used */
444 451
@@ -496,11 +503,11 @@ struct globals2 {
496#define nextrec (G1.nextrec ) 503#define nextrec (G1.nextrec )
497#define nextfile (G1.nextfile ) 504#define nextfile (G1.nextfile )
498#define is_f0_split (G1.is_f0_split ) 505#define is_f0_split (G1.is_f0_split )
506#define t_rollback (G1.t_rollback )
499#define t_info (G.t_info ) 507#define t_info (G.t_info )
500#define t_tclass (G.t_tclass ) 508#define t_tclass (G.t_tclass )
501#define t_string (G.t_string ) 509#define t_string (G.t_string )
502#define t_lineno (G.t_lineno ) 510#define t_lineno (G.t_lineno )
503#define t_rollback (G.t_rollback )
504#define intvar (G.intvar ) 511#define intvar (G.intvar )
505#define fsplitter (G.fsplitter ) 512#define fsplitter (G.fsplitter )
506#define rsplitter (G.rsplitter ) 513#define rsplitter (G.rsplitter )
@@ -1008,6 +1015,7 @@ static uint32_t next_token(uint32_t expected)
1008 1015
1009 if (*p == '\0') { 1016 if (*p == '\0') {
1010 tc = TC_EOF; 1017 tc = TC_EOF;
1018 debug_printf_parse("%s: token found: TC_EOF\n", __func__);
1011 1019
1012 } else if (*p == '\"') { 1020 } else if (*p == '\"') {
1013 /* it's a string */ 1021 /* it's a string */
@@ -1023,6 +1031,7 @@ static uint32_t next_token(uint32_t expected)
1023 p++; 1031 p++;
1024 *s = '\0'; 1032 *s = '\0';
1025 tc = TC_STRING; 1033 tc = TC_STRING;
1034 debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string);
1026 1035
1027 } else if ((expected & TC_REGEXP) && *p == '/') { 1036 } else if ((expected & TC_REGEXP) && *p == '/') {
1028 /* it's regexp */ 1037 /* it's regexp */
@@ -1045,6 +1054,7 @@ static uint32_t next_token(uint32_t expected)
1045 p++; 1054 p++;
1046 *s = '\0'; 1055 *s = '\0';
1047 tc = TC_REGEXP; 1056 tc = TC_REGEXP;
1057 debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string);
1048 1058
1049 } else if (*p == '.' || isdigit(*p)) { 1059 } else if (*p == '.' || isdigit(*p)) {
1050 /* it's a number */ 1060 /* it's a number */
@@ -1054,6 +1064,7 @@ static uint32_t next_token(uint32_t expected)
1054 if (*p == '.') 1064 if (*p == '.')
1055 syntax_error(EMSG_UNEXP_TOKEN); 1065 syntax_error(EMSG_UNEXP_TOKEN);
1056 tc = TC_NUMBER; 1066 tc = TC_NUMBER;
1067 debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double);
1057 1068
1058 } else { 1069 } else {
1059 /* search for something known */ 1070 /* search for something known */
@@ -1076,6 +1087,7 @@ static uint32_t next_token(uint32_t expected)
1076 ) { 1087 ) {
1077 /* then this is what we are looking for */ 1088 /* then this is what we are looking for */
1078 t_info = *ti; 1089 t_info = *ti;
1090 debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info);
1079 p += l; 1091 p += l;
1080 goto token_found; 1092 goto token_found;
1081 } 1093 }
@@ -1099,14 +1111,17 @@ static uint32_t next_token(uint32_t expected)
1099 p = skip_spaces(p); 1111 p = skip_spaces(p);
1100 if (*p == '(') { 1112 if (*p == '(') {
1101 tc = TC_FUNCTION; 1113 tc = TC_FUNCTION;
1114 debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string);
1102 } else { 1115 } else {
1103 if (*p == '[') { 1116 if (*p == '[') {
1104 p++; 1117 p++;
1105 tc = TC_ARRAY; 1118 tc = TC_ARRAY;
1106 } 1119 debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string);
1120 } else
1121 debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string);
1107 } 1122 }
1108 token_found: ;
1109 } 1123 }
1124 token_found:
1110 g_pos = p; 1125 g_pos = p;
1111 1126
1112 /* skipping newlines in some cases */ 1127 /* skipping newlines in some cases */
@@ -1178,6 +1193,8 @@ static node *parse_expr(uint32_t iexp)
1178 uint32_t tc, xtc; 1193 uint32_t tc, xtc;
1179 var *v; 1194 var *v;
1180 1195
1196 debug_printf_parse("%s(%x)\n", __func__, iexp);
1197
1181 sn.info = PRIMASK; 1198 sn.info = PRIMASK;
1182 sn.r.n = glptr = NULL; 1199 sn.r.n = glptr = NULL;
1183 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1200 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
@@ -1186,12 +1203,14 @@ static node *parse_expr(uint32_t iexp)
1186 1203
1187 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1204 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
1188 /* input redirection (<) attached to glptr node */ 1205 /* input redirection (<) attached to glptr node */
1206 debug_printf_parse("%s: input redir\n", __func__);
1189 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); 1207 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
1190 cn->a.n = glptr; 1208 cn->a.n = glptr;
1191 xtc = TC_OPERAND | TC_UOPPRE; 1209 xtc = TC_OPERAND | TC_UOPPRE;
1192 glptr = NULL; 1210 glptr = NULL;
1193 1211
1194 } else if (tc & (TC_BINOP | TC_UOPPOST)) { 1212 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1213 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__);
1195 /* for binary and postfix-unary operators, jump back over 1214 /* for binary and postfix-unary operators, jump back over
1196 * previous operators with higher priority */ 1215 * previous operators with higher priority */
1197 vn = cn; 1216 vn = cn;
@@ -1221,6 +1240,7 @@ static node *parse_expr(uint32_t iexp)
1221 vn->a.n = cn; 1240 vn->a.n = cn;
1222 1241
1223 } else { 1242 } else {
1243 debug_printf_parse("%s: other\n", __func__);
1224 /* for operands and prefix-unary operators, attach them 1244 /* for operands and prefix-unary operators, attach them
1225 * to last node */ 1245 * to last node */
1226 vn = cn; 1246 vn = cn;
@@ -1228,12 +1248,14 @@ static node *parse_expr(uint32_t iexp)
1228 cn->a.n = vn; 1248 cn->a.n = vn;
1229 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1249 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1230 if (tc & (TC_OPERAND | TC_REGEXP)) { 1250 if (tc & (TC_OPERAND | TC_REGEXP)) {
1251 debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__);
1231 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; 1252 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
1232 /* one should be very careful with switch on tclass - 1253 /* one should be very careful with switch on tclass -
1233 * only simple tclasses should be used! */ 1254 * only simple tclasses should be used! */
1234 switch (tc) { 1255 switch (tc) {
1235 case TC_VARIABLE: 1256 case TC_VARIABLE:
1236 case TC_ARRAY: 1257 case TC_ARRAY:
1258 debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__);
1237 cn->info = OC_VAR; 1259 cn->info = OC_VAR;
1238 v = hash_search(ahash, t_string); 1260 v = hash_search(ahash, t_string);
1239 if (v != NULL) { 1261 if (v != NULL) {
@@ -1250,6 +1272,7 @@ static node *parse_expr(uint32_t iexp)
1250 1272
1251 case TC_NUMBER: 1273 case TC_NUMBER:
1252 case TC_STRING: 1274 case TC_STRING:
1275 debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__);
1253 cn->info = OC_VAR; 1276 cn->info = OC_VAR;
1254 v = cn->l.v = xzalloc(sizeof(var)); 1277 v = cn->l.v = xzalloc(sizeof(var));
1255 if (tc & TC_NUMBER) 1278 if (tc & TC_NUMBER)
@@ -1259,32 +1282,41 @@ static node *parse_expr(uint32_t iexp)
1259 break; 1282 break;
1260 1283
1261 case TC_REGEXP: 1284 case TC_REGEXP:
1285 debug_printf_parse("%s: TC_REGEXP\n", __func__);
1262 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); 1286 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
1263 break; 1287 break;
1264 1288
1265 case TC_FUNCTION: 1289 case TC_FUNCTION:
1290 debug_printf_parse("%s: TC_FUNCTION\n", __func__);
1266 cn->info = OC_FUNC; 1291 cn->info = OC_FUNC;
1267 cn->r.f = newfunc(t_string); 1292 cn->r.f = newfunc(t_string);
1268 cn->l.n = condition(); 1293 cn->l.n = condition();
1269 break; 1294 break;
1270 1295
1271 case TC_SEQSTART: 1296 case TC_SEQSTART:
1297 debug_printf_parse("%s: TC_SEQSTART\n", __func__);
1272 cn = vn->r.n = parse_expr(TC_SEQTERM); 1298 cn = vn->r.n = parse_expr(TC_SEQTERM);
1299 if (!cn)
1300 syntax_error("Empty sequence");
1273 cn->a.n = vn; 1301 cn->a.n = vn;
1274 break; 1302 break;
1275 1303
1276 case TC_GETLINE: 1304 case TC_GETLINE:
1305 debug_printf_parse("%s: TC_GETLINE\n", __func__);
1277 glptr = cn; 1306 glptr = cn;
1278 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1307 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1279 break; 1308 break;
1280 1309
1281 case TC_BUILTIN: 1310 case TC_BUILTIN:
1311 debug_printf_parse("%s: TC_BUILTIN\n", __func__);
1282 cn->l.n = condition(); 1312 cn->l.n = condition();
1283 break; 1313 break;
1284 } 1314 }
1285 } 1315 }
1286 } 1316 }
1287 } 1317 }
1318
1319 debug_printf_parse("%s() returns %p\n", __func__, sn.r.n);
1288 return sn.r.n; 1320 return sn.r.n;
1289} 1321}
1290 1322
@@ -1353,18 +1385,25 @@ static void chain_group(void)
1353 } while (c & TC_NEWLINE); 1385 } while (c & TC_NEWLINE);
1354 1386
1355 if (c & TC_GRPSTART) { 1387 if (c & TC_GRPSTART) {
1388 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
1356 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { 1389 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
1390 debug_printf_parse("%s: !TC_GRPTERM\n", __func__);
1357 if (t_tclass & TC_NEWLINE) 1391 if (t_tclass & TC_NEWLINE)
1358 continue; 1392 continue;
1359 rollback_token(); 1393 rollback_token();
1360 chain_group(); 1394 chain_group();
1361 } 1395 }
1396 debug_printf_parse("%s: TC_GRPTERM\n", __func__);
1362 } else if (c & (TC_OPSEQ | TC_OPTERM)) { 1397 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1398 debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__);
1363 rollback_token(); 1399 rollback_token();
1364 chain_expr(OC_EXEC | Vx); 1400 chain_expr(OC_EXEC | Vx);
1365 } else { /* TC_STATEMNT */ 1401 } else {
1402 /* TC_STATEMNT */
1403 debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__);
1366 switch (t_info & OPCLSMASK) { 1404 switch (t_info & OPCLSMASK) {
1367 case ST_IF: 1405 case ST_IF:
1406 debug_printf_parse("%s: ST_IF\n", __func__);
1368 n = chain_node(OC_BR | Vx); 1407 n = chain_node(OC_BR | Vx);
1369 n->l.n = condition(); 1408 n->l.n = condition();
1370 chain_group(); 1409 chain_group();
@@ -1379,12 +1418,14 @@ static void chain_group(void)
1379 break; 1418 break;
1380 1419
1381 case ST_WHILE: 1420 case ST_WHILE:
1421 debug_printf_parse("%s: ST_WHILE\n", __func__);
1382 n2 = condition(); 1422 n2 = condition();
1383 n = chain_loop(NULL); 1423 n = chain_loop(NULL);
1384 n->l.n = n2; 1424 n->l.n = n2;
1385 break; 1425 break;
1386 1426
1387 case ST_DO: 1427 case ST_DO:
1428 debug_printf_parse("%s: ST_DO\n", __func__);
1388 n2 = chain_node(OC_EXEC); 1429 n2 = chain_node(OC_EXEC);
1389 n = chain_loop(NULL); 1430 n = chain_loop(NULL);
1390 n2->a.n = n->a.n; 1431 n2->a.n = n->a.n;
@@ -1393,6 +1434,7 @@ static void chain_group(void)
1393 break; 1434 break;
1394 1435
1395 case ST_FOR: 1436 case ST_FOR:
1437 debug_printf_parse("%s: ST_FOR\n", __func__);
1396 next_token(TC_SEQSTART); 1438 next_token(TC_SEQSTART);
1397 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); 1439 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
1398 if (t_tclass & TC_SEQTERM) { /* for-in */ 1440 if (t_tclass & TC_SEQTERM) { /* for-in */
@@ -1418,6 +1460,7 @@ static void chain_group(void)
1418 1460
1419 case OC_PRINT: 1461 case OC_PRINT:
1420 case OC_PRINTF: 1462 case OC_PRINTF:
1463 debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
1421 n = chain_node(t_info); 1464 n = chain_node(t_info);
1422 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); 1465 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1423 if (t_tclass & TC_OUTRDR) { 1466 if (t_tclass & TC_OUTRDR) {
@@ -1429,17 +1472,20 @@ static void chain_group(void)
1429 break; 1472 break;
1430 1473
1431 case OC_BREAK: 1474 case OC_BREAK:
1475 debug_printf_parse("%s: OC_BREAK\n", __func__);
1432 n = chain_node(OC_EXEC); 1476 n = chain_node(OC_EXEC);
1433 n->a.n = break_ptr; 1477 n->a.n = break_ptr;
1434 break; 1478 break;
1435 1479
1436 case OC_CONTINUE: 1480 case OC_CONTINUE:
1481 debug_printf_parse("%s: OC_CONTINUE\n", __func__);
1437 n = chain_node(OC_EXEC); 1482 n = chain_node(OC_EXEC);
1438 n->a.n = continue_ptr; 1483 n->a.n = continue_ptr;
1439 break; 1484 break;
1440 1485
1441 /* delete, next, nextfile, return, exit */ 1486 /* delete, next, nextfile, return, exit */
1442 default: 1487 default:
1488 debug_printf_parse("%s: default\n", __func__);
1443 chain_expr(t_info); 1489 chain_expr(t_info);
1444 } 1490 }
1445 } 1491 }
@@ -1457,19 +1503,24 @@ static void parse_program(char *p)
1457 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | 1503 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
1458 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { 1504 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1459 1505
1460 if (tclass & TC_OPTERM) 1506 if (tclass & TC_OPTERM) {
1507 debug_printf_parse("%s: TC_OPTERM\n", __func__);
1461 continue; 1508 continue;
1509 }
1462 1510
1463 seq = &mainseq; 1511 seq = &mainseq;
1464 if (tclass & TC_BEGIN) { 1512 if (tclass & TC_BEGIN) {
1513 debug_printf_parse("%s: TC_BEGIN\n", __func__);
1465 seq = &beginseq; 1514 seq = &beginseq;
1466 chain_group(); 1515 chain_group();
1467 1516
1468 } else if (tclass & TC_END) { 1517 } else if (tclass & TC_END) {
1518 debug_printf_parse("%s: TC_END\n", __func__);
1469 seq = &endseq; 1519 seq = &endseq;
1470 chain_group(); 1520 chain_group();
1471 1521
1472 } else if (tclass & TC_FUNCDECL) { 1522 } else if (tclass & TC_FUNCDECL) {
1523 debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
1473 next_token(TC_FUNCTION); 1524 next_token(TC_FUNCTION);
1474 g_pos++; 1525 g_pos++;
1475 f = newfunc(t_string); 1526 f = newfunc(t_string);
@@ -1487,22 +1538,27 @@ static void parse_program(char *p)
1487 clear_array(ahash); 1538 clear_array(ahash);
1488 1539
1489 } else if (tclass & TC_OPSEQ) { 1540 } else if (tclass & TC_OPSEQ) {
1541 debug_printf_parse("%s: TC_OPSEQ\n", __func__);
1490 rollback_token(); 1542 rollback_token();
1491 cn = chain_node(OC_TEST); 1543 cn = chain_node(OC_TEST);
1492 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); 1544 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1493 if (t_tclass & TC_GRPSTART) { 1545 if (t_tclass & TC_GRPSTART) {
1546 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
1494 rollback_token(); 1547 rollback_token();
1495 chain_group(); 1548 chain_group();
1496 } else { 1549 } else {
1550 debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
1497 chain_node(OC_PRINT); 1551 chain_node(OC_PRINT);
1498 } 1552 }
1499 cn->r.n = mainseq.last; 1553 cn->r.n = mainseq.last;
1500 1554
1501 } else /* if (tclass & TC_GRPSTART) */ { 1555 } else /* if (tclass & TC_GRPSTART) */ {
1556 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
1502 rollback_token(); 1557 rollback_token();
1503 chain_group(); 1558 chain_group();
1504 } 1559 }
1505 } 1560 }
1561 debug_printf_parse("%s: TC_EOF\n", __func__);
1506} 1562}
1507 1563
1508 1564
@@ -2627,7 +2683,7 @@ static var *evaluate(node *op, var *res)
2627 rsm = iF; 2683 rsm = iF;
2628 } 2684 }
2629 2685
2630 if (!rsm->F) { 2686 if (!rsm || !rsm->F) {
2631 setvar_i(intvar[ERRNO], errno); 2687 setvar_i(intvar[ERRNO], errno);
2632 setvar_i(res, -1); 2688 setvar_i(res, -1);
2633 break; 2689 break;
@@ -2961,7 +3017,7 @@ static rstream *next_input_file(void)
2961#define rsm (G.next_input_file__rsm) 3017#define rsm (G.next_input_file__rsm)
2962#define files_happen (G.next_input_file__files_happen) 3018#define files_happen (G.next_input_file__files_happen)
2963 3019
2964 FILE *F = NULL; 3020 FILE *F;
2965 const char *fname, *ind; 3021 const char *fname, *ind;
2966 3022
2967 if (rsm.F) 3023 if (rsm.F)
@@ -2969,19 +3025,21 @@ static rstream *next_input_file(void)
2969 rsm.F = NULL; 3025 rsm.F = NULL;
2970 rsm.pos = rsm.adv = 0; 3026 rsm.pos = rsm.adv = 0;
2971 3027
2972 do { 3028 for (;;) {
2973 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { 3029 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
2974 if (files_happen) 3030 if (files_happen)
2975 return NULL; 3031 return NULL;
2976 fname = "-"; 3032 fname = "-";
2977 F = stdin; 3033 F = stdin;
2978 } else { 3034 break;
2979 ind = getvar_s(incvar(intvar[ARGIND]));
2980 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
2981 if (fname && *fname && !is_assignment(fname))
2982 F = xfopen_stdin(fname);
2983 } 3035 }
2984 } while (!F); 3036 ind = getvar_s(incvar(intvar[ARGIND]));
3037 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
3038 if (fname && *fname && !is_assignment(fname)) {
3039 F = xfopen_stdin(fname);
3040 break;
3041 }
3042 }
2985 3043
2986 files_happen = TRUE; 3044 files_happen = TRUE;
2987 setvar_s(intvar[FILENAME], fname); 3045 setvar_s(intvar[FILENAME], fname);
@@ -2995,7 +3053,7 @@ int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2995int awk_main(int argc, char **argv) 3053int awk_main(int argc, char **argv)
2996{ 3054{
2997 unsigned opt; 3055 unsigned opt;
2998 char *opt_F, *opt_W; 3056 char *opt_F;
2999 llist_t *list_v = NULL; 3057 llist_t *list_v = NULL;
3000 llist_t *list_f = NULL; 3058 llist_t *list_f = NULL;
3001 int i, j; 3059 int i, j;
@@ -3057,7 +3115,7 @@ int awk_main(int argc, char **argv)
3057 } 3115 }
3058 } 3116 }
3059 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ 3117 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
3060 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W); 3118 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL);
3061 argv += optind; 3119 argv += optind;
3062 argc -= optind; 3120 argc -= optind;
3063 if (opt & 0x1) 3121 if (opt & 0x1)
@@ -3091,7 +3149,7 @@ int awk_main(int argc, char **argv)
3091 parse_program(*argv++); 3149 parse_program(*argv++);
3092 } 3150 }
3093 if (opt & 0x8) // -W 3151 if (opt & 0x8) // -W
3094 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); 3152 bb_error_msg("warning: option -W is ignored");
3095 3153
3096 /* fill in ARGV array */ 3154 /* fill in ARGV array */
3097 setvar_i(intvar[ARGC], argc); 3155 setvar_i(intvar[ARGC], argc);
diff --git a/editors/patch.c b/editors/patch.c
index ec5b8e7ad..13785ef46 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -70,8 +70,7 @@ struct double_list {
70 70
71// Free all the elements of a linked list 71// Free all the elements of a linked list
72// Call freeit() on each element before freeing it. 72// Call freeit() on each element before freeing it.
73static 73static void dlist_free(struct double_list *list, void (*freeit)(void *data))
74void dlist_free(struct double_list *list, void (*freeit)(void *data))
75{ 74{
76 while (list) { 75 while (list) {
77 void *pop = list; 76 void *pop = list;
@@ -83,8 +82,7 @@ void dlist_free(struct double_list *list, void (*freeit)(void *data))
83} 82}
84 83
85// Add an entry before "list" element in (circular) doubly linked list 84// Add an entry before "list" element in (circular) doubly linked list
86static 85static struct double_list *dlist_add(struct double_list **list, char *data)
87struct double_list *dlist_add(struct double_list **list, char *data)
88{ 86{
89 struct double_list *llist; 87 struct double_list *llist;
90 struct double_list *line = xmalloc(sizeof(*line)); 88 struct double_list *line = xmalloc(sizeof(*line));
@@ -232,7 +230,7 @@ static int apply_one_hunk(void)
232 else matcheof = 0; 230 else matcheof = 0;
233 if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); 231 if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data);
234 } 232 }
235 matcheof = matcheof < TT.context; 233 matcheof = !matcheof || matcheof < TT.context;
236 234
237 if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); 235 if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
238 236
@@ -476,19 +474,21 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
476 474
477 // We're deleting oldname if new file is /dev/null (before -p) 475 // We're deleting oldname if new file is /dev/null (before -p)
478 // or if new hunk is empty (zero context) after patching 476 // or if new hunk is empty (zero context) after patching
479 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) 477 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) {
480 {
481 name = reverse ? newname : oldname; 478 name = reverse ? newname : oldname;
482 empty++; 479 empty++;
483 } 480 }
484 481
485 // handle -p path truncation. 482 // handle -p path truncation.
486 for (i=0, s = name; *s;) { 483 for (i = 0, s = name; *s;) {
487 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; 484 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i)
488 if (*(s++)=='/') { 485 break;
489 name = s; 486 if (*s++ != '/')
490 i++; 487 continue;
491 } 488 while (*s == '/')
489 s++;
490 i++;
491 name = s;
492 } 492 }
493 493
494 if (empty) { 494 if (empty) {
diff --git a/editors/sed.c b/editors/sed.c
index 5c4e9cc3b..c8bb503ea 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -26,7 +26,7 @@
26 * add_input_file() adds a FILE* to the list of input files. We need to 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. 27 * know all input sources ahead of time to find the last line for the $ match.
28 * 28 *
29 * process_files() does actual sedding, reading data lines from each input FILE * 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 30 * (which could be stdin) and applying the sed command list (sed_cmd_head) to
31 * each of the resulting lines. 31 * each of the resulting lines.
32 * 32 *
@@ -57,7 +57,8 @@
57 */ 57 */
58 58
59//usage:#define sed_trivial_usage 59//usage:#define sed_trivial_usage
60//usage: "[-efinr] SED_CMD [FILE]..." 60//usage: "[-inr] [-f FILE]... [-e CMD]... [FILE]...\n"
61//usage: "or: sed [-inr] CMD [FILE]..."
61//usage:#define sed_full_usage "\n\n" 62//usage:#define sed_full_usage "\n\n"
62//usage: " -e CMD Add CMD to sed commands to be executed" 63//usage: " -e CMD Add CMD to sed commands to be executed"
63//usage: "\n -f FILE Add FILE contents to sed commands to be executed" 64//usage: "\n -f FILE Add FILE contents to sed commands to be executed"
@@ -75,6 +76,13 @@
75#include "libbb.h" 76#include "libbb.h"
76#include "xregex.h" 77#include "xregex.h"
77 78
79#if 0
80# define dbg(...) bb_error_msg(__VA_ARGS__)
81#else
82# define dbg(...) ((void)0)
83#endif
84
85
78enum { 86enum {
79 OPT_in_place = 1 << 0, 87 OPT_in_place = 1 << 0,
80}; 88};
@@ -89,6 +97,7 @@ typedef struct sed_cmd_s {
89 regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */ 97 regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
90 regex_t *sub_match; /* For 's/sub_match/string/' */ 98 regex_t *sub_match; /* For 's/sub_match/string/' */
91 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ 99 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */
100 int beg_line_orig; /* copy of the above, needed for -i */
92 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ 101 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
93 102
94 FILE *sw_file; /* File (sw) command writes to, -1 for none. */ 103 FILE *sw_file; /* File (sw) command writes to, -1 for none. */
@@ -123,7 +132,7 @@ struct globals {
123 regex_t *previous_regex_ptr; 132 regex_t *previous_regex_ptr;
124 133
125 /* linked list of sed commands */ 134 /* linked list of sed commands */
126 sed_cmd_t sed_cmd_head, *sed_cmd_tail; 135 sed_cmd_t *sed_cmd_head, **sed_cmd_tail;
127 136
128 /* Linked list of append lines */ 137 /* Linked list of append lines */
129 llist_t *append_head; 138 llist_t *append_head;
@@ -148,7 +157,7 @@ struct BUG_G_too_big {
148#if ENABLE_FEATURE_CLEAN_UP 157#if ENABLE_FEATURE_CLEAN_UP
149static void sed_free_and_close_stuff(void) 158static void sed_free_and_close_stuff(void)
150{ 159{
151 sed_cmd_t *sed_cmd = G.sed_cmd_head.next; 160 sed_cmd_t *sed_cmd = G.sed_cmd_head;
152 161
153 llist_free(G.append_head, free); 162 llist_free(G.append_head, free);
154 163
@@ -599,6 +608,7 @@ static void add_cmd(const char *cmdstr)
599 608
600 /* first part (if present) is an address: either a '$', a number or a /regex/ */ 609 /* first part (if present) is an address: either a '$', a number or a /regex/ */
601 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); 610 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
611 sed_cmd->beg_line_orig = sed_cmd->beg_line;
602 612
603 /* second part (if present) will begin with a comma */ 613 /* second part (if present) will begin with a comma */
604 if (*cmdstr == ',') { 614 if (*cmdstr == ',') {
@@ -630,8 +640,8 @@ static void add_cmd(const char *cmdstr)
630 cmdstr = parse_cmd_args(sed_cmd, cmdstr); 640 cmdstr = parse_cmd_args(sed_cmd, cmdstr);
631 641
632 /* Add the command to the command array */ 642 /* Add the command to the command array */
633 G.sed_cmd_tail->next = sed_cmd; 643 *G.sed_cmd_tail = sed_cmd;
634 G.sed_cmd_tail = G.sed_cmd_tail->next; 644 G.sed_cmd_tail = &sed_cmd->next;
635 } 645 }
636 646
637 /* If we glued multiple lines together, free the memory. */ 647 /* If we glued multiple lines together, free the memory. */
@@ -777,7 +787,7 @@ static sed_cmd_t *branch_to(char *label)
777{ 787{
778 sed_cmd_t *sed_cmd; 788 sed_cmd_t *sed_cmd;
779 789
780 for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { 790 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
781 if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) { 791 if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
782 return sed_cmd; 792 return sed_cmd;
783 } 793 }
@@ -953,24 +963,24 @@ static void process_files(void)
953 963
954 /* For every line, go through all the commands */ 964 /* For every line, go through all the commands */
955 restart: 965 restart:
956 for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { 966 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
957 int old_matched, matched; 967 int old_matched, matched;
958 968
959 old_matched = sed_cmd->in_match; 969 old_matched = sed_cmd->in_match;
960 970
961 /* Determine if this command matches this line: */ 971 /* Determine if this command matches this line: */
962 972
963 //bb_error_msg("match1:%d", sed_cmd->in_match); 973 dbg("match1:%d", sed_cmd->in_match);
964 //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line 974 dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
965 // && !sed_cmd->beg_match && !sed_cmd->end_match)); 975 && !sed_cmd->beg_match && !sed_cmd->end_match));
966 //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 976 dbg("match3:%d", (sed_cmd->beg_line > 0
967 // && (sed_cmd->end_line || sed_cmd->end_match 977 && (sed_cmd->end_line || sed_cmd->end_match
968 // ? (sed_cmd->beg_line <= linenum) 978 ? (sed_cmd->beg_line <= linenum)
969 // : (sed_cmd->beg_line == linenum) 979 : (sed_cmd->beg_line == linenum)
970 // ) 980 )
971 // ) 981 ));
972 //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space))); 982 dbg("match4:%d", (beg_match(sed_cmd, pattern_space)));
973 //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); 983 dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));
974 984
975 /* Are we continuing a previous multi-line match? */ 985 /* Are we continuing a previous multi-line match? */
976 sed_cmd->in_match = sed_cmd->in_match 986 sed_cmd->in_match = sed_cmd->in_match
@@ -981,7 +991,14 @@ static void process_files(void)
981 || (sed_cmd->beg_line > 0 991 || (sed_cmd->beg_line > 0
982 && (sed_cmd->end_line || sed_cmd->end_match 992 && (sed_cmd->end_line || sed_cmd->end_match
983 /* note: even if end is numeric and is < linenum too, 993 /* note: even if end is numeric and is < linenum too,
984 * GNU sed matches! We match too */ 994 * GNU sed matches! We match too, therefore we don't
995 * check here that linenum <= end.
996 * Example:
997 * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p'
998 * first three input lines are deleted;
999 * 4th line is matched and printed
1000 * by "2,3" (!) and by "4" ranges
1001 */
985 ? (sed_cmd->beg_line <= linenum) /* N,end */ 1002 ? (sed_cmd->beg_line <= linenum) /* N,end */
986 : (sed_cmd->beg_line == linenum) /* N */ 1003 : (sed_cmd->beg_line == linenum) /* N */
987 ) 1004 )
@@ -994,16 +1011,14 @@ static void process_files(void)
994 /* Snapshot the value */ 1011 /* Snapshot the value */
995 matched = sed_cmd->in_match; 1012 matched = sed_cmd->in_match;
996 1013
997 //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", 1014 dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
998 //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); 1015 sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);
999 1016
1000 /* Is this line the end of the current match? */ 1017 /* Is this line the end of the current match? */
1001 1018
1002 if (matched) { 1019 if (matched) {
1003 /* once matched, "n,xxx" range is dead, disabling it */ 1020 /* once matched, "n,xxx" range is dead, disabling it */
1004 if (sed_cmd->beg_line > 0 1021 if (sed_cmd->beg_line > 0) {
1005 && !(option_mask32 & OPT_in_place) /* but not for -i */
1006 ) {
1007 sed_cmd->beg_line = -2; 1022 sed_cmd->beg_line = -2;
1008 } 1023 }
1009 sed_cmd->in_match = !( 1024 sed_cmd->in_match = !(
@@ -1017,7 +1032,8 @@ static void process_files(void)
1017 /* or does this line matches our last address regex */ 1032 /* or does this line matches our last address regex */
1018 || (sed_cmd->end_match && old_matched 1033 || (sed_cmd->end_match && old_matched
1019 && (regexec(sed_cmd->end_match, 1034 && (regexec(sed_cmd->end_match,
1020 pattern_space, 0, NULL, 0) == 0)) 1035 pattern_space, 0, NULL, 0) == 0)
1036 )
1021 ); 1037 );
1022 } 1038 }
1023 1039
@@ -1407,11 +1423,12 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1407 add_input_file(stdin); 1423 add_input_file(stdin);
1408 } else { 1424 } else {
1409 int i; 1425 int i;
1410 FILE *file;
1411 1426
1412 for (i = 0; argv[i]; i++) { 1427 for (i = 0; argv[i]; i++) {
1413 struct stat statbuf; 1428 struct stat statbuf;
1414 int nonstdoutfd; 1429 int nonstdoutfd;
1430 FILE *file;
1431 sed_cmd_t *sed_cmd;
1415 1432
1416 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { 1433 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
1417 add_input_file(stdin); 1434 add_input_file(stdin);
@@ -1423,11 +1440,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1423 status = EXIT_FAILURE; 1440 status = EXIT_FAILURE;
1424 continue; 1441 continue;
1425 } 1442 }
1443 add_input_file(file);
1426 if (!(opt & OPT_in_place)) { 1444 if (!(opt & OPT_in_place)) {
1427 add_input_file(file);
1428 continue; 1445 continue;
1429 } 1446 }
1430 1447
1448 /* -i: process each FILE separately: */
1449
1431 G.outname = xasprintf("%sXXXXXX", argv[i]); 1450 G.outname = xasprintf("%sXXXXXX", argv[i]);
1432 nonstdoutfd = xmkstemp(G.outname); 1451 nonstdoutfd = xmkstemp(G.outname);
1433 G.nonstdout = xfdopen_for_write(nonstdoutfd); 1452 G.nonstdout = xfdopen_for_write(nonstdoutfd);
@@ -1438,15 +1457,20 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1438 * but GNU sed 4.2.1 does not preserve them either */ 1457 * but GNU sed 4.2.1 does not preserve them either */
1439 fchmod(nonstdoutfd, statbuf.st_mode); 1458 fchmod(nonstdoutfd, statbuf.st_mode);
1440 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); 1459 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);
1441 add_input_file(file); 1460
1442 process_files(); 1461 process_files();
1443 fclose(G.nonstdout); 1462 fclose(G.nonstdout);
1444
1445 G.nonstdout = stdout; 1463 G.nonstdout = stdout;
1464
1446 /* unlink(argv[i]); */ 1465 /* unlink(argv[i]); */
1447 xrename(G.outname, argv[i]); 1466 xrename(G.outname, argv[i]);
1448 free(G.outname); 1467 free(G.outname);
1449 G.outname = NULL; 1468 G.outname = NULL;
1469
1470 /* Re-enable disabled range matches */
1471 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
1472 sed_cmd->beg_line = sed_cmd->beg_line_orig;
1473 }
1450 } 1474 }
1451 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: 1475 /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
1452 * if (G.current_input_file >= G.input_file_count) 1476 * if (G.current_input_file >= G.input_file_count)
diff --git a/editors/vi.c b/editors/vi.c
index 9708679b4..d6d926e35 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3072,7 +3072,6 @@ static void refresh(int full_screen)
3072//----- Execute a Vi Command ----------------------------------- 3072//----- Execute a Vi Command -----------------------------------
3073static void do_cmd(int c) 3073static void do_cmd(int c)
3074{ 3074{
3075 const char *msg = msg; // for compiler
3076 char *p, *q, *save_dot; 3075 char *p, *q, *save_dot;
3077 char buf[12]; 3076 char buf[12];
3078 int dir; 3077 int dir;
@@ -3081,8 +3080,8 @@ static void do_cmd(int c)
3081 3080
3082// c1 = c; // quiet the compiler 3081// c1 = c; // quiet the compiler
3083// cnt = yf = 0; // quiet the compiler 3082// cnt = yf = 0; // quiet the compiler
3084// msg = p = q = save_dot = buf; // quiet the compiler 3083// p = q = save_dot = buf; // quiet the compiler
3085 memset(buf, '\0', 12); 3084 memset(buf, '\0', sizeof(buf));
3086 3085
3087 show_status_line(); 3086 show_status_line();
3088 3087
@@ -3198,19 +3197,18 @@ static void do_cmd(int c)
3198 case KEYCODE_LEFT: // cursor key Left 3197 case KEYCODE_LEFT: // cursor key Left
3199 case 8: // ctrl-H- move left (This may be ERASE char) 3198 case 8: // ctrl-H- move left (This may be ERASE char)
3200 case 0x7f: // DEL- move left (This may be ERASE char) 3199 case 0x7f: // DEL- move left (This may be ERASE char)
3201 if (--cmdcnt > 0) { 3200 do {
3202 do_cmd(c); 3201 dot_left();
3203 } 3202 } while (--cmdcnt > 0);
3204 dot_left();
3205 break; 3203 break;
3206 case 10: // Newline ^J 3204 case 10: // Newline ^J
3207 case 'j': // j- goto next line, same col 3205 case 'j': // j- goto next line, same col
3208 case KEYCODE_DOWN: // cursor key Down 3206 case KEYCODE_DOWN: // cursor key Down
3209 if (--cmdcnt > 0) { 3207 do {
3210 do_cmd(c); 3208 dot_next(); // go to next B-o-l
3211 } 3209 // try stay in same col
3212 dot_next(); // go to next B-o-l 3210 dot = move_to_col(dot, ccol + offset);
3213 dot = move_to_col(dot, ccol + offset); // try stay in same col 3211 } while (--cmdcnt > 0);
3214 break; 3212 break;
3215 case 12: // ctrl-L force redraw whole screen 3213 case 12: // ctrl-L force redraw whole screen
3216 case 18: // ctrl-R force redraw 3214 case 18: // ctrl-R force redraw
@@ -3223,11 +3221,10 @@ static void do_cmd(int c)
3223 break; 3221 break;
3224 case 13: // Carriage Return ^M 3222 case 13: // Carriage Return ^M
3225 case '+': // +- goto next line 3223 case '+': // +- goto next line
3226 if (--cmdcnt > 0) { 3224 do {
3227 do_cmd(c); 3225 dot_next();
3228 } 3226 dot_skip_over_ws();
3229 dot_next(); 3227 } while (--cmdcnt > 0);
3230 dot_skip_over_ws();
3231 break; 3228 break;
3232 case 21: // ctrl-U scroll up half screen 3229 case 21: // ctrl-U scroll up half screen
3233 dot_scroll((rows - 2) / 2, -1); 3230 dot_scroll((rows - 2) / 2, -1);
@@ -3245,10 +3242,9 @@ static void do_cmd(int c)
3245 case ' ': // move right 3242 case ' ': // move right
3246 case 'l': // move right 3243 case 'l': // move right
3247 case KEYCODE_RIGHT: // Cursor Key Right 3244 case KEYCODE_RIGHT: // Cursor Key Right
3248 if (--cmdcnt > 0) { 3245 do {
3249 do_cmd(c); 3246 dot_right();
3250 } 3247 } while (--cmdcnt > 0);
3251 dot_right();
3252 break; 3248 break;
3253#if ENABLE_FEATURE_VI_YANKMARK 3249#if ENABLE_FEATURE_VI_YANKMARK
3254 case '"': // "- name a register to use for Delete/Yank 3250 case '"': // "- name a register to use for Delete/Yank
@@ -3330,11 +3326,12 @@ static void do_cmd(int c)
3330#endif /* FEATURE_VI_YANKMARK */ 3326#endif /* FEATURE_VI_YANKMARK */
3331 case '$': // $- goto end of line 3327 case '$': // $- goto end of line
3332 case KEYCODE_END: // Cursor Key End 3328 case KEYCODE_END: // Cursor Key End
3333 if (--cmdcnt > 0) { 3329 for (;;) {
3330 dot = end_line(dot);
3331 if (--cmdcnt > 0)
3332 break;
3334 dot_next(); 3333 dot_next();
3335 do_cmd(c);
3336 } 3334 }
3337 dot = end_line(dot);
3338 break; 3335 break;
3339 case '%': // %- find matching char of pair () [] {} 3336 case '%': // %- find matching char of pair () [] {}
3340 for (q = dot; q < end && *q != '\n'; q++) { 3337 for (q = dot; q < end && *q != '\n'; q++) {
@@ -3359,38 +3356,35 @@ static void do_cmd(int c)
3359 // 3356 //
3360 //**** fall through to ... ';' 3357 //**** fall through to ... ';'
3361 case ';': // ;- look at rest of line for last forward char 3358 case ';': // ;- look at rest of line for last forward char
3362 if (--cmdcnt > 0) { 3359 do {
3363 do_cmd(';'); 3360 if (last_forward_char == 0)
3364 } 3361 break;
3365 if (last_forward_char == 0) 3362 q = dot + 1;
3366 break; 3363 while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
3367 q = dot + 1; 3364 q++;
3368 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 3365 }
3369 q++; 3366 if (*q == last_forward_char)
3370 } 3367 dot = q;
3371 if (*q == last_forward_char) 3368 } while (--cmdcnt > 0);
3372 dot = q;
3373 break; 3369 break;
3374 case ',': // repeat latest 'f' in opposite direction 3370 case ',': // repeat latest 'f' in opposite direction
3375 if (--cmdcnt > 0) {
3376 do_cmd(',');
3377 }
3378 if (last_forward_char == 0) 3371 if (last_forward_char == 0)
3379 break; 3372 break;
3380 q = dot - 1; 3373 do {
3381 while (q >= text && *q != '\n' && *q != last_forward_char) { 3374 q = dot - 1;
3382 q--; 3375 while (q >= text && *q != '\n' && *q != last_forward_char) {
3383 } 3376 q--;
3384 if (q >= text && *q == last_forward_char) 3377 }
3385 dot = q; 3378 if (q >= text && *q == last_forward_char)
3379 dot = q;
3380 } while (--cmdcnt > 0);
3386 break; 3381 break;
3387 3382
3388 case '-': // -- goto prev line 3383 case '-': // -- goto prev line
3389 if (--cmdcnt > 0) { 3384 do {
3390 do_cmd(c); 3385 dot_prev();
3391 } 3386 dot_skip_over_ws();
3392 dot_prev(); 3387 } while (--cmdcnt > 0);
3393 dot_skip_over_ws();
3394 break; 3388 break;
3395#if ENABLE_FEATURE_VI_DOT_CMD 3389#if ENABLE_FEATURE_VI_DOT_CMD
3396 case '.': // .- repeat the last modifying command 3390 case '.': // .- repeat the last modifying command
@@ -3422,9 +3416,6 @@ static void do_cmd(int c)
3422 // user changed mind and erased the "/"- do nothing 3416 // user changed mind and erased the "/"- do nothing
3423 break; 3417 break;
3424 case 'N': // N- backward search for last pattern 3418 case 'N': // N- backward search for last pattern
3425 if (--cmdcnt > 0) {
3426 do_cmd(c);
3427 }
3428 dir = BACK; // assume BACKWARD search 3419 dir = BACK; // assume BACKWARD search
3429 p = dot - 1; 3420 p = dot - 1;
3430 if (last_search_pattern[0] == '?') { 3421 if (last_search_pattern[0] == '?') {
@@ -3436,41 +3427,41 @@ static void do_cmd(int c)
3436 case 'n': // n- repeat search for last pattern 3427 case 'n': // n- repeat search for last pattern
3437 // search rest of text[] starting at next char 3428 // search rest of text[] starting at next char
3438 // if search fails return orignal "p" not the "p+1" address 3429 // if search fails return orignal "p" not the "p+1" address
3439 if (--cmdcnt > 0) { 3430 do {
3440 do_cmd(c); 3431 const char *msg;
3441 }
3442 dc3: 3432 dc3:
3443 dir = FORWARD; // assume FORWARD search 3433 dir = FORWARD; // assume FORWARD search
3444 p = dot + 1; 3434 p = dot + 1;
3445 if (last_search_pattern[0] == '?') { 3435 if (last_search_pattern[0] == '?') {
3446 dir = BACK; 3436 dir = BACK;
3447 p = dot - 1; 3437 p = dot - 1;
3448 } 3438 }
3449 dc4: 3439 dc4:
3450 q = char_search(p, last_search_pattern + 1, dir, FULL); 3440 q = char_search(p, last_search_pattern + 1, dir, FULL);
3451 if (q != NULL) { 3441 if (q != NULL) {
3452 dot = q; // good search, update "dot" 3442 dot = q; // good search, update "dot"
3453 msg = ""; 3443 msg = NULL;
3454 goto dc2; 3444 goto dc2;
3455 } 3445 }
3456 // no pattern found between "dot" and "end"- continue at top 3446 // no pattern found between "dot" and "end"- continue at top
3457 p = text; 3447 p = text;
3458 if (dir == BACK) {
3459 p = end - 1;
3460 }
3461 q = char_search(p, last_search_pattern + 1, dir, FULL);
3462 if (q != NULL) { // found something
3463 dot = q; // found new pattern- goto it
3464 msg = "search hit BOTTOM, continuing at TOP";
3465 if (dir == BACK) { 3448 if (dir == BACK) {
3466 msg = "search hit TOP, continuing at BOTTOM"; 3449 p = end - 1;
3450 }
3451 q = char_search(p, last_search_pattern + 1, dir, FULL);
3452 if (q != NULL) { // found something
3453 dot = q; // found new pattern- goto it
3454 msg = "search hit BOTTOM, continuing at TOP";
3455 if (dir == BACK) {
3456 msg = "search hit TOP, continuing at BOTTOM";
3457 }
3458 } else {
3459 msg = "Pattern not found";
3467 } 3460 }
3468 } else {
3469 msg = "Pattern not found";
3470 }
3471 dc2: 3461 dc2:
3472 if (*msg) 3462 if (msg)
3473 status_line_bold("%s", msg); 3463 status_line_bold("%s", msg);
3464 } while (--cmdcnt > 0);
3474 break; 3465 break;
3475 case '{': // {- move backward paragraph 3466 case '{': // {- move backward paragraph
3476 q = char_search(dot, "\n\n", BACK, FULL); 3467 q = char_search(dot, "\n\n", BACK, FULL);
@@ -3589,18 +3580,17 @@ static void do_cmd(int c)
3589 case 'B': // B- back a blank-delimited Word 3580 case 'B': // B- back a blank-delimited Word
3590 case 'E': // E- end of a blank-delimited word 3581 case 'E': // E- end of a blank-delimited word
3591 case 'W': // W- forward a blank-delimited word 3582 case 'W': // W- forward a blank-delimited word
3592 if (--cmdcnt > 0) {
3593 do_cmd(c);
3594 }
3595 dir = FORWARD; 3583 dir = FORWARD;
3596 if (c == 'B') 3584 if (c == 'B')
3597 dir = BACK; 3585 dir = BACK;
3598 if (c == 'W' || isspace(dot[dir])) { 3586 do {
3599 dot = skip_thing(dot, 1, dir, S_TO_WS); 3587 if (c == 'W' || isspace(dot[dir])) {
3600 dot = skip_thing(dot, 2, dir, S_OVER_WS); 3588 dot = skip_thing(dot, 1, dir, S_TO_WS);
3601 } 3589 dot = skip_thing(dot, 2, dir, S_OVER_WS);
3602 if (c != 'W') 3590 }
3603 dot = skip_thing(dot, 1, dir, S_BEFORE_WS); 3591 if (c != 'W')
3592 dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
3593 } while (--cmdcnt > 0);
3604 break; 3594 break;
3605 case 'C': // C- Change to e-o-l 3595 case 'C': // C- Change to e-o-l
3606 case 'D': // D- delete to e-o-l 3596 case 'D': // D- delete to e-o-l
@@ -3651,20 +3641,19 @@ static void do_cmd(int c)
3651 case 'i': // i- insert before current char 3641 case 'i': // i- insert before current char
3652 case KEYCODE_INSERT: // Cursor Key Insert 3642 case KEYCODE_INSERT: // Cursor Key Insert
3653 dc_i: 3643 dc_i:
3654 cmd_mode = 1; // start insrting 3644 cmd_mode = 1; // start inserting
3655 break; 3645 break;
3656 case 'J': // J- join current and next lines together 3646 case 'J': // J- join current and next lines together
3657 if (--cmdcnt > 1) { 3647 do {
3658 do_cmd(c); 3648 dot_end(); // move to NL
3659 } 3649 if (dot < end - 1) { // make sure not last char in text[]
3660 dot_end(); // move to NL 3650 *dot++ = ' '; // replace NL with space
3661 if (dot < end - 1) { // make sure not last char in text[] 3651 file_modified++;
3662 *dot++ = ' '; // replace NL with space 3652 while (isblank(*dot)) { // delete leading WS
3663 file_modified++; 3653 dot_delete();
3664 while (isblank(*dot)) { // delete leading WS 3654 }
3665 dot_delete();
3666 } 3655 }
3667 } 3656 } while (--cmdcnt > 0);
3668 end_cmd_q(); // stop adding to q 3657 end_cmd_q(); // stop adding to q
3669 break; 3658 break;
3670 case 'L': // L- goto bottom line on screen 3659 case 'L': // L- goto bottom line on screen
@@ -3708,20 +3697,19 @@ static void do_cmd(int c)
3708 case 'X': // X- delete char before dot 3697 case 'X': // X- delete char before dot
3709 case 'x': // x- delete the current char 3698 case 'x': // x- delete the current char
3710 case 's': // s- substitute the current char 3699 case 's': // s- substitute the current char
3711 if (--cmdcnt > 0) {
3712 do_cmd(c);
3713 }
3714 dir = 0; 3700 dir = 0;
3715 if (c == 'X') 3701 if (c == 'X')
3716 dir = -1; 3702 dir = -1;
3717 if (dot[dir] != '\n') { 3703 do {
3718 if (c == 'X') 3704 if (dot[dir] != '\n') {
3719 dot--; // delete prev char 3705 if (c == 'X')
3720 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char 3706 dot--; // delete prev char
3721 } 3707 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char
3722 if (c == 's') 3708 }
3723 goto dc_i; // start insrting 3709 } while (--cmdcnt > 0);
3724 end_cmd_q(); // stop adding to q 3710 end_cmd_q(); // stop adding to q
3711 if (c == 's')
3712 goto dc_i; // start inserting
3725 break; 3713 break;
3726 case 'Z': // Z- if modified, {write}; exit 3714 case 'Z': // Z- if modified, {write}; exit
3727 // ZZ means to save file (if necessary), then exit 3715 // ZZ means to save file (if necessary), then exit
@@ -3752,23 +3740,22 @@ static void do_cmd(int c)
3752 break; 3740 break;
3753 case 'b': // b- back a word 3741 case 'b': // b- back a word
3754 case 'e': // e- end of word 3742 case 'e': // e- end of word
3755 if (--cmdcnt > 0) {
3756 do_cmd(c);
3757 }
3758 dir = FORWARD; 3743 dir = FORWARD;
3759 if (c == 'b') 3744 if (c == 'b')
3760 dir = BACK; 3745 dir = BACK;
3761 if ((dot + dir) < text || (dot + dir) > end - 1) 3746 do {
3762 break; 3747 if ((dot + dir) < text || (dot + dir) > end - 1)
3763 dot += dir; 3748 break;
3764 if (isspace(*dot)) { 3749 dot += dir;
3765 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); 3750 if (isspace(*dot)) {
3766 } 3751 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
3767 if (isalnum(*dot) || *dot == '_') { 3752 }
3768 dot = skip_thing(dot, 1, dir, S_END_ALNUM); 3753 if (isalnum(*dot) || *dot == '_') {
3769 } else if (ispunct(*dot)) { 3754 dot = skip_thing(dot, 1, dir, S_END_ALNUM);
3770 dot = skip_thing(dot, 1, dir, S_END_PUNCT); 3755 } else if (ispunct(*dot)) {
3771 } 3756 dot = skip_thing(dot, 1, dir, S_END_PUNCT);
3757 }
3758 } while (--cmdcnt > 0);
3772 break; 3759 break;
3773 case 'c': // c- change something 3760 case 'c': // c- change something
3774 case 'd': // d- delete something 3761 case 'd': // d- delete something
@@ -3853,11 +3840,10 @@ static void do_cmd(int c)
3853 } 3840 }
3854 case 'k': // k- goto prev line, same col 3841 case 'k': // k- goto prev line, same col
3855 case KEYCODE_UP: // cursor key Up 3842 case KEYCODE_UP: // cursor key Up
3856 if (--cmdcnt > 0) { 3843 do {
3857 do_cmd(c); 3844 dot_prev();
3858 } 3845 dot = move_to_col(dot, ccol + offset); // try stay in same col
3859 dot_prev(); 3846 } while (--cmdcnt > 0);
3860 dot = move_to_col(dot, ccol + offset); // try stay in same col
3861 break; 3847 break;
3862 case 'r': // r- replace the current char with user input 3848 case 'r': // r- replace the current char with user input
3863 c1 = get_one_char(); // get the replacement char 3849 c1 = get_one_char(); // get the replacement char
@@ -3875,19 +3861,18 @@ static void do_cmd(int c)
3875 last_forward_char = 0; 3861 last_forward_char = 0;
3876 break; 3862 break;
3877 case 'w': // w- forward a word 3863 case 'w': // w- forward a word
3878 if (--cmdcnt > 0) { 3864 do {
3879 do_cmd(c); 3865 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM
3880 } 3866 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
3881 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3867 } else if (ispunct(*dot)) { // we are on PUNCT
3882 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); 3868 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
3883 } else if (ispunct(*dot)) { // we are on PUNCT 3869 }
3884 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); 3870 if (dot < end - 1)
3885 } 3871 dot++; // move over word
3886 if (dot < end - 1) 3872 if (isspace(*dot)) {
3887 dot++; // move over word 3873 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
3888 if (isspace(*dot)) { 3874 }
3889 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); 3875 } while (--cmdcnt > 0);
3890 }
3891 break; 3876 break;
3892 case 'z': // z- 3877 case 'z': // z-
3893 c1 = get_one_char(); // get the replacement char 3878 c1 = get_one_char(); // get the replacement char
@@ -3903,17 +3888,16 @@ static void do_cmd(int c)
3903 dot = move_to_col(dot, cmdcnt - 1); // try to move to column 3888 dot = move_to_col(dot, cmdcnt - 1); // try to move to column
3904 break; 3889 break;
3905 case '~': // ~- flip the case of letters a-z -> A-Z 3890 case '~': // ~- flip the case of letters a-z -> A-Z
3906 if (--cmdcnt > 0) { 3891 do {
3907 do_cmd(c); 3892 if (islower(*dot)) {
3908 } 3893 *dot = toupper(*dot);
3909 if (islower(*dot)) { 3894 file_modified++;
3910 *dot = toupper(*dot); 3895 } else if (isupper(*dot)) {
3911 file_modified++; 3896 *dot = tolower(*dot);
3912 } else if (isupper(*dot)) { 3897 file_modified++;
3913 *dot = tolower(*dot); 3898 }
3914 file_modified++; 3899 dot_right();
3915 } 3900 } while (--cmdcnt > 0);
3916 dot_right();
3917 end_cmd_q(); // stop adding to q 3901 end_cmd_q(); // stop adding to q
3918 break; 3902 break;
3919 //----- The Cursor and Function Keys ----------------------------- 3903 //----- The Cursor and Function Keys -----------------------------