61 |
#include "libbb.h" |
#include "libbb.h" |
62 |
#include "xregex.h" |
#include "xregex.h" |
63 |
|
|
64 |
|
enum { |
65 |
|
OPT_in_place = 1 << 0, |
66 |
|
}; |
67 |
|
|
68 |
/* Each sed command turns into one of these structures. */ |
/* Each sed command turns into one of these structures. */ |
69 |
typedef struct sed_cmd_s { |
typedef struct sed_cmd_s { |
70 |
/* Ordered by alignment requirements: currently 36 bytes on x86 */ |
/* Ordered by alignment requirements: currently 36 bytes on x86 */ |
121 |
int idx; /* Space used */ |
int idx; /* Space used */ |
122 |
int len; /* Space allocated */ |
int len; /* Space allocated */ |
123 |
} pipeline; |
} pipeline; |
124 |
}; |
} FIX_ALIASING; |
125 |
#define G (*(struct globals*)&bb_common_bufsiz1) |
#define G (*(struct globals*)&bb_common_bufsiz1) |
126 |
void BUG_sed_globals_too_big(void); |
struct BUG_G_too_big { |
127 |
|
char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; |
128 |
|
}; |
129 |
#define INIT_G() do { \ |
#define INIT_G() do { \ |
|
if (sizeof(struct globals) > COMMON_BUFSIZE) \ |
|
|
BUG_sed_globals_too_big(); \ |
|
130 |
G.sed_cmd_tail = &G.sed_cmd_head; \ |
G.sed_cmd_tail = &G.sed_cmd_head; \ |
131 |
} while (0) |
} while (0) |
132 |
|
|
389 |
break; |
break; |
390 |
/* Comment */ |
/* Comment */ |
391 |
case '#': |
case '#': |
392 |
while (substr[++idx]) /*skip all*/; |
// while (substr[++idx]) continue; |
393 |
|
idx += strlen(substr + idx); // same |
394 |
/* Fall through */ |
/* Fall through */ |
395 |
/* End of command */ |
/* End of command */ |
396 |
case ';': |
case ';': |
400 |
bb_error_msg_and_die("bad option in substitution expression"); |
bb_error_msg_and_die("bad option in substitution expression"); |
401 |
} |
} |
402 |
} |
} |
403 |
out: |
out: |
404 |
/* compile the match string into a regex */ |
/* compile the match string into a regex */ |
405 |
if (*match != '\0') { |
if (*match != '\0') { |
406 |
/* If match is empty, we use last regex used at runtime */ |
/* If match is empty, we use last regex used at runtime */ |
567 |
/* last part (mandatory) will be a command */ |
/* last part (mandatory) will be a command */ |
568 |
if (!*cmdstr) |
if (!*cmdstr) |
569 |
bb_error_msg_and_die("missing command"); |
bb_error_msg_and_die("missing command"); |
570 |
sed_cmd->cmd = *(cmdstr++); |
sed_cmd->cmd = *cmdstr++; |
571 |
cmdstr = parse_cmd_args(sed_cmd, cmdstr); |
cmdstr = parse_cmd_args(sed_cmd, cmdstr); |
572 |
|
|
573 |
/* Add the command to the command array */ |
/* Add the command to the command array */ |
901 |
|
|
902 |
/* Determine if this command matches this line: */ |
/* Determine if this command matches this line: */ |
903 |
|
|
904 |
|
//bb_error_msg("match1:%d", sed_cmd->in_match); |
905 |
|
//bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line |
906 |
|
// && !sed_cmd->beg_match && !sed_cmd->end_match)); |
907 |
|
//bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 |
908 |
|
// && (sed_cmd->end_line || sed_cmd->end_match |
909 |
|
// ? (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)); |
915 |
|
|
916 |
/* Are we continuing a previous multi-line match? */ |
/* Are we continuing a previous multi-line match? */ |
917 |
sed_cmd->in_match = sed_cmd->in_match |
sed_cmd->in_match = sed_cmd->in_match |
918 |
/* Or is no range necessary? */ |
/* Or is no range necessary? */ |
919 |
|| (!sed_cmd->beg_line && !sed_cmd->end_line |
|| (!sed_cmd->beg_line && !sed_cmd->end_line |
920 |
&& !sed_cmd->beg_match && !sed_cmd->end_match) |
&& !sed_cmd->beg_match && !sed_cmd->end_match) |
921 |
/* Or did we match the start of a numerical range? */ |
/* Or did we match the start of a numerical range? */ |
922 |
|| (sed_cmd->beg_line > 0 && (sed_cmd->beg_line <= linenum)) |
|| (sed_cmd->beg_line > 0 |
923 |
|
&& (sed_cmd->end_line || sed_cmd->end_match |
924 |
|
/* note: even if end is numeric and is < linenum too, |
925 |
|
* GNU sed matches! We match too */ |
926 |
|
? (sed_cmd->beg_line <= linenum) /* N,end */ |
927 |
|
: (sed_cmd->beg_line == linenum) /* N */ |
928 |
|
) |
929 |
|
) |
930 |
/* Or does this line match our begin address regex? */ |
/* Or does this line match our begin address regex? */ |
931 |
|| (beg_match(sed_cmd, pattern_space)) |
|| (beg_match(sed_cmd, pattern_space)) |
932 |
/* Or did we match last line of input? */ |
/* Or did we match last line of input? */ |
942 |
|
|
943 |
if (matched) { |
if (matched) { |
944 |
/* once matched, "n,xxx" range is dead, disabling it */ |
/* once matched, "n,xxx" range is dead, disabling it */ |
945 |
if (sed_cmd->beg_line > 0) |
if (sed_cmd->beg_line > 0 |
946 |
|
&& !(option_mask32 & OPT_in_place) /* but not for -i */ |
947 |
|
) { |
948 |
sed_cmd->beg_line = -2; |
sed_cmd->beg_line = -2; |
949 |
|
} |
950 |
sed_cmd->in_match = !( |
sed_cmd->in_match = !( |
951 |
/* has the ending line come, or is this a single address command? */ |
/* has the ending line come, or is this a single address command? */ |
952 |
(sed_cmd->end_line ? |
(sed_cmd->end_line ? |
992 |
} |
} |
993 |
|
|
994 |
/* actual sedding */ |
/* actual sedding */ |
995 |
|
//bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c", |
996 |
|
//pattern_space, next_line, sed_cmd->cmd); |
997 |
switch (sed_cmd->cmd) { |
switch (sed_cmd->cmd) { |
998 |
|
|
999 |
/* Print line number */ |
/* Print line number */ |
1005 |
case 'P': |
case 'P': |
1006 |
{ |
{ |
1007 |
char *tmp = strchr(pattern_space, '\n'); |
char *tmp = strchr(pattern_space, '\n'); |
|
|
|
1008 |
if (tmp) { |
if (tmp) { |
1009 |
*tmp = '\0'; |
*tmp = '\0'; |
1010 |
/* TODO: explain why '\n' below */ |
/* TODO: explain why '\n' below */ |
1027 |
case 'D': |
case 'D': |
1028 |
{ |
{ |
1029 |
char *tmp = strchr(pattern_space, '\n'); |
char *tmp = strchr(pattern_space, '\n'); |
|
|
|
1030 |
if (tmp) { |
if (tmp) { |
1031 |
tmp = xstrdup(tmp+1); |
overlapping_strcpy(pattern_space, tmp + 1); |
|
free(pattern_space); |
|
|
pattern_space = tmp; |
|
1032 |
goto restart; |
goto restart; |
1033 |
} |
} |
1034 |
} |
} |
1073 |
case 'r': |
case 'r': |
1074 |
{ |
{ |
1075 |
FILE *rfile; |
FILE *rfile; |
|
|
|
1076 |
rfile = fopen_for_read(sed_cmd->string); |
rfile = fopen_for_read(sed_cmd->string); |
1077 |
if (rfile) { |
if (rfile) { |
1078 |
char *line; |
char *line; |
1120 |
{ |
{ |
1121 |
int len; |
int len; |
1122 |
/* If no next line, jump to end of script and exit. */ |
/* If no next line, jump to end of script and exit. */ |
1123 |
|
/* http://www.gnu.org/software/sed/manual/sed.html: |
1124 |
|
* "Most versions of sed exit without printing anything |
1125 |
|
* when the N command is issued on the last line of |
1126 |
|
* a file. GNU sed prints pattern space before exiting |
1127 |
|
* unless of course the -n command switch has been |
1128 |
|
* specified. This choice is by design." |
1129 |
|
*/ |
1130 |
if (next_line == NULL) { |
if (next_line == NULL) { |
1131 |
/* Jump to end of script and exit */ |
//goto discard_line; |
1132 |
free(next_line); |
goto discard_commands; /* GNU behavior */ |
|
next_line = NULL; |
|
|
goto discard_line; |
|
|
/* append next_line, read new next_line. */ |
|
1133 |
} |
} |
1134 |
|
/* Append next_line, read new next_line. */ |
1135 |
len = strlen(pattern_space); |
len = strlen(pattern_space); |
1136 |
pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2); |
pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2); |
1137 |
pattern_space[len] = '\n'; |
pattern_space[len] = '\n'; |
1160 |
case 'y': |
case 'y': |
1161 |
{ |
{ |
1162 |
int i, j; |
int i, j; |
|
|
|
1163 |
for (i = 0; pattern_space[i]; i++) { |
for (i = 0; pattern_space[i]; i++) { |
1164 |
for (j = 0; sed_cmd->string[j]; j += 2) { |
for (j = 0; sed_cmd->string[j]; j += 2) { |
1165 |
if (pattern_space[i] == sed_cmd->string[j]) { |
if (pattern_space[i] == sed_cmd->string[j]) { |
1285 |
int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1286 |
int sed_main(int argc UNUSED_PARAM, char **argv) |
int sed_main(int argc UNUSED_PARAM, char **argv) |
1287 |
{ |
{ |
|
enum { |
|
|
OPT_in_place = 1 << 0, |
|
|
}; |
|
1288 |
unsigned opt; |
unsigned opt; |
1289 |
llist_t *opt_e, *opt_f; |
llist_t *opt_e, *opt_f; |
1290 |
int status = EXIT_SUCCESS; |
int status = EXIT_SUCCESS; |
1304 |
opt_e = opt_f = NULL; |
opt_e = opt_f = NULL; |
1305 |
opt_complementary = "e::f::" /* can occur multiple times */ |
opt_complementary = "e::f::" /* can occur multiple times */ |
1306 |
"nn"; /* count -n */ |
"nn"; /* count -n */ |
1307 |
|
/* -i must be first, to match OPT_in_place definition */ |
1308 |
opt = getopt32(argv, "irne:f:", &opt_e, &opt_f, |
opt = getopt32(argv, "irne:f:", &opt_e, &opt_f, |
1309 |
&G.be_quiet); /* counter for -n */ |
&G.be_quiet); /* counter for -n */ |
1310 |
//argc -= optind; |
//argc -= optind; |
1346 |
if (opt & OPT_in_place) |
if (opt & OPT_in_place) |
1347 |
bb_error_msg_and_die(bb_msg_requires_arg, "-i"); |
bb_error_msg_and_die(bb_msg_requires_arg, "-i"); |
1348 |
add_input_file(stdin); |
add_input_file(stdin); |
|
process_files(); |
|
1349 |
} else { |
} else { |
1350 |
int i; |
int i; |
1351 |
FILE *file; |
FILE *file; |
1377 |
|
|
1378 |
/* Set permissions/owner of output file */ |
/* Set permissions/owner of output file */ |
1379 |
fstat(fileno(file), &statbuf); |
fstat(fileno(file), &statbuf); |
1380 |
|
/* chmod'ing AFTER chown would preserve suid/sgid bits, |
1381 |
|
* but GNU sed 4.2.1 does not preserve them either */ |
1382 |
fchmod(nonstdoutfd, statbuf.st_mode); |
fchmod(nonstdoutfd, statbuf.st_mode); |
1383 |
fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); |
fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); |
1384 |
add_input_file(file); |
add_input_file(file); |
1391 |
free(G.outname); |
free(G.outname); |
1392 |
G.outname = NULL; |
G.outname = NULL; |
1393 |
} |
} |
1394 |
if (G.input_file_count > G.current_input_file) |
/* Here, to handle "sed 'cmds' nonexistent_file" case we did: |
1395 |
process_files(); |
* if (G.current_input_file >= G.input_file_count) |
1396 |
|
* return status; |
1397 |
|
* but it's not needed since process_files() works correctly |
1398 |
|
* in this case too. */ |
1399 |
} |
} |
1400 |
|
process_files(); |
1401 |
|
|
1402 |
return status; |
return status; |
1403 |
} |
} |