sed.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. /* sed.c - stream editor. Thing that does s/// and other stuff.
  2. *
  3. * Copyright 2014 Rob Landley <rob@landley.net>
  4. *
  5. * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
  6. *
  7. * TODO: lines > 2G could wrap signed int length counters. Not just getline()
  8. * but N and s///
  9. * TODO: make y// handle unicode, unicode delimiters
  10. * TODO: handle error return from emit(), error_msg/exit consistently
  11. * What's the right thing to do for -i when write fails? Skip to next?
  12. * test '//q' with no previous regex, also repeat previous regex?
  13. *
  14. * Deviations from POSIX: allow extended regular expressions with -r,
  15. * editing in place with -i, separate with -s, NUL-separated input with -z,
  16. * printf escapes in text, line continuations, semicolons after all commands,
  17. * 2-address anywhere an address is allowed, "T" command, multiline
  18. * continuations for [abc], \; to end [abc] argument before end of line.
  19. USE_SED(NEWTOY(sed, "(help)(version)e*f*i:;nErz(null-data)s[+Er]", TOYFLAG_BIN|TOYFLAG_LOCALE|TOYFLAG_NOHELP))
  20. config SED
  21. bool "sed"
  22. default y
  23. help
  24. usage: sed [-inrszE] [-e SCRIPT]...|SCRIPT [-f SCRIPT_FILE]... [FILE...]
  25. Stream editor. Apply editing SCRIPTs to lines of input.
  26. -e Add SCRIPT to list
  27. -f Add contents of SCRIPT_FILE to list
  28. -i Edit each file in place (-iEXT keeps backup file with extension EXT)
  29. -n No default output (use the p command to output matched lines)
  30. -r Use extended regular expression syntax
  31. -E POSIX alias for -r
  32. -s Treat input files separately (implied by -i)
  33. -z Use \0 rather than \n as input line separator
  34. A SCRIPT is one or more COMMANDs separated by newlines or semicolons.
  35. All -e SCRIPTs are combined as if separated by newlines, followed by all -f
  36. SCRIPT_FILEs. If no -e or -f then first argument is the SCRIPT.
  37. COMMANDs apply to every line unless prefixed with an ADDRESS of the form:
  38. [ADDRESS[,ADDRESS]][!]COMMAND
  39. ADDRESS is a line number (starting at 1), a /REGULAR EXPRESSION/, or $ for
  40. last line (-s or -i makes it last line of each file). One address matches one
  41. line, ADDRESS,ADDRESS matches from first to second inclusive. Two regexes can
  42. match multiple ranges. ADDRESS,+N ends N lines later. ! inverts the match.
  43. REGULAR EXPRESSIONS start and end with the same character (anything but
  44. backslash or newline). To use the delimiter in the regex escape it with a
  45. backslash, and printf escapes (\abcefnrtv and octal, hex, and unicode) work.
  46. An empty regex repeats the previous one. ADDRESS regexes require any
  47. first delimiter except / to be \escaped to distinguish it from COMMANDs.
  48. Sed reads each line of input, processes it, and writes it out or discards it
  49. before reading the next. Sed can remember one additional line in a separate
  50. buffer (the h, H, g, G, and x commands), and can read the next line of input
  51. early (the n and N commands), but otherwise operates on individual lines.
  52. Each COMMAND starts with a single character. Commands with no arguments are:
  53. ! Run this command when the ADDRESS _didn't_ match.
  54. { Start new command block, continuing until a corresponding "}".
  55. Command blocks nest and can have ADDRESSes applying to the whole block.
  56. } End command block (this COMMAND cannot have an address)
  57. d Delete this line and move on to the next one
  58. (ignores remaining COMMANDs)
  59. D Delete one line of input and restart command SCRIPT (same as "d"
  60. unless you've glued lines together with "N" or similar)
  61. g Get remembered line (overwriting current line)
  62. G Get remembered line (appending to current line)
  63. h Remember this line (overwriting remembered line)
  64. H Remember this line (appending to remembered line, if any)
  65. l Print line escaping \abfrtv (but not \n), octal escape other nonprintng
  66. chars, wrap lines to terminal width with \, append $ to end of line.
  67. n Print default output and read next line over current line (quit at EOF)
  68. N Append \n and next line of input to this line. Quit at EOF without
  69. default output. Advances line counter for ADDRESS and "=".
  70. p Print this line
  71. P Print this line up to first newline (from "N")
  72. q Quit (print default output, no more commands processed or lines read)
  73. x Exchange this line with remembered line (overwrite in both directions)
  74. = Print the current line number (plus newline)
  75. # Comment, ignores rest of this line of SCRIPT (until newline)
  76. Commands that take an argument:
  77. : LABEL Target for jump commands
  78. a TEXT Append text to output before reading next line
  79. b LABEL Branch, jumps to :LABEL (with no LABEL to end of SCRIPT)
  80. c TEXT Delete matching ADDRESS range and output TEXT instead
  81. i TEXT Insert text (output immediately)
  82. r FILE Append contents of FILE to output before reading next line.
  83. s/S/R/F Search for regex S replace match with R using flags F. Delimiter
  84. is anything but \n or \, escape with \ to use in S or R. Printf
  85. escapes work. Unescaped & in R becomes full matched text, \1
  86. through \9 = parenthetical subexpression from S. \ at end of
  87. line appends next line of SCRIPT. The flags in F are:
  88. [0-9] A number N, substitute only Nth match
  89. g Global, substitute all matches
  90. i/I Ignore case when matching
  91. p Print resulting line when match found and replaced
  92. w [file] Write (append) line to file when match replaced
  93. t LABEL Test, jump if s/// command matched this line since last test
  94. T LABEL Test false, jump to :LABEL only if no s/// found a match
  95. w FILE Write (append) line to file
  96. y/old/new/ Change each character in 'old' to corresponding character
  97. in 'new' (with standard backslash escapes, delimiter can be
  98. any repeated character except \ or \n)
  99. The TEXT arguments (to a c i) may end with an unescaped "\" to append
  100. the next line (leading whitespace is not skipped), and treat ";" as a
  101. literal character (use "\;" instead).
  102. */
  103. #define FOR_sed
  104. #include "toys.h"
  105. GLOBALS(
  106. char *i;
  107. struct arg_list *f, *e;
  108. // processed pattern list
  109. struct double_list *pattern;
  110. char *nextline, *remember;
  111. void *restart, *lastregex;
  112. long nextlen, rememberlen, count;
  113. int fdout, noeol;
  114. unsigned xx;
  115. char delim;
  116. )
  117. // Linked list of parsed sed commands. Offset fields indicate location where
  118. // regex or string starts, ala offset+(char *)struct, because we remalloc()
  119. // these to expand them for multiline inputs, and pointers would have to be
  120. // individually adjusted.
  121. struct sedcmd {
  122. struct sedcmd *next, *prev;
  123. // Begin and end of each match
  124. long lmatch[2]; // line number of match
  125. int rmatch[2]; // offset of regex struct for prefix matches (/abc/,/def/p)
  126. int arg1, arg2, w; // offset of two arguments per command, plus s//w filename
  127. unsigned not, hit;
  128. unsigned sflags; // s///flag bits: i=1, g=2, p=4, x=8
  129. char c; // action
  130. };
  131. // Write out line with potential embedded NUL, handling eol/noeol
  132. static int emit(char *line, long len, int eol)
  133. {
  134. int l, old = line[len];
  135. if (TT.noeol && !writeall(TT.fdout, "\n", 1)) return 1;
  136. TT.noeol = !eol;
  137. if (eol) line[len++] = '\n';
  138. if (!len) return 0;
  139. l = writeall(TT.fdout, line, len);
  140. if (eol) line[len-1] = old;
  141. if (l != len) {
  142. if (TT.fdout != 1) perror_msg("short write");
  143. return 1;
  144. }
  145. return 0;
  146. }
  147. // Extend allocation to include new string, with newline between if newlen<0
  148. static char *extend_string(char **old, char *new, int oldlen, int newlen)
  149. {
  150. int newline = newlen < 0;
  151. char *s;
  152. if (newline) newlen = -newlen;
  153. s = *old = xrealloc(*old, oldlen+newlen+newline+1);
  154. if (newline) s[oldlen++] = '\n';
  155. memcpy(s+oldlen, new, newlen);
  156. s[oldlen+newlen] = 0;
  157. return s+oldlen+newlen+1;
  158. }
  159. // An empty regex repeats the previous one
  160. static void *get_regex(void *command, int offset)
  161. {
  162. if (!offset) {
  163. if (!TT.lastregex) error_exit("no previous regex");
  164. return TT.lastregex;
  165. }
  166. return TT.lastregex = offset+(char *)command;
  167. }
  168. // Apply pattern to line from input file
  169. static void sed_line(char **pline, long plen)
  170. {
  171. struct append {
  172. struct append *next, *prev;
  173. int file;
  174. char *str;
  175. } *append = 0;
  176. char *line = TT.nextline;
  177. long len = TT.nextlen;
  178. struct sedcmd *command;
  179. int eol = 0, tea = 0;
  180. // Ignore EOF for all files before last unless -i
  181. if (!pline && !FLAG(i) && !FLAG(s)) return;
  182. // Grab next line for deferred processing (EOF detection: we get a NULL
  183. // pline at EOF to flush last line). Note that only end of _last_ input
  184. // file matches $ (unless we're doing -i).
  185. TT.nextline = 0;
  186. TT.nextlen = 0;
  187. if (pline) {
  188. TT.nextline = *pline;
  189. TT.nextlen = plen;
  190. *pline = 0;
  191. }
  192. if (!line || !len) return;
  193. if (line[len-1] == '\n') line[--len] = eol++;
  194. TT.count++;
  195. // The restart-1 is because we added one to make sure it wasn't NULL,
  196. // otherwise N as last command would restart script
  197. command = TT.restart ? ((struct sedcmd *)TT.restart)-1 : (void *)TT.pattern;
  198. TT.restart = 0;
  199. while (command) {
  200. char *str, c = command->c;
  201. // Have we got a line or regex matching range for this rule?
  202. if (*command->lmatch || *command->rmatch) {
  203. int miss = 0;
  204. long lm;
  205. // In a match that might end?
  206. if (command->hit) {
  207. if (!(lm = command->lmatch[1])) {
  208. if (!command->rmatch[1]) command->hit = 0;
  209. else {
  210. void *rm = get_regex(command, command->rmatch[1]);
  211. // regex match end includes matching line, so defer deactivation
  212. if (line && !regexec0(rm, line, len, 0, 0, 0)) miss = 1;
  213. }
  214. } else if (lm > 0 && lm < TT.count) command->hit = 0;
  215. else if (lm < -1 && TT.count == command->hit+(-lm-1)) command->hit = 0;
  216. // Start a new match?
  217. } else {
  218. if (!(lm = *command->lmatch)) {
  219. void *rm = get_regex(command, *command->rmatch);
  220. if (line && !regexec0(rm, line, len, 0, 0, 0))
  221. command->hit = TT.count;
  222. } else if (lm == TT.count || (lm == -1 && !pline))
  223. command->hit = TT.count;
  224. if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
  225. }
  226. // Didn't match?
  227. lm = !(command->not^!!command->hit);
  228. // Deferred disable from regex end match
  229. if (miss || command->lmatch[1] == TT.count) command->hit = 0;
  230. if (lm) {
  231. // Handle skipping curly bracket command group
  232. if (c == '{') {
  233. int curly = 1;
  234. while (curly) {
  235. command = command->next;
  236. if (command->c == '{') curly++;
  237. if (command->c == '}') curly--;
  238. }
  239. }
  240. command = command->next;
  241. continue;
  242. }
  243. }
  244. // A deleted line can still update line match state for later commands
  245. if (!line) {
  246. command = command->next;
  247. continue;
  248. }
  249. // Process command
  250. if (c=='a' || c=='r') {
  251. struct append *a = xzalloc(sizeof(struct append));
  252. if (command->arg1) a->str = command->arg1+(char *)command;
  253. a->file = c=='r';
  254. dlist_add_nomalloc((void *)&append, (void *)a);
  255. } else if (c=='b' || c=='t' || c=='T') {
  256. int t = tea;
  257. if (c != 'b') tea = 0;
  258. if (c=='b' || t^(c=='T')) {
  259. if (!command->arg1) break;
  260. str = command->arg1+(char *)command;
  261. for (command = (void *)TT.pattern; command; command = command->next)
  262. if (command->c == ':' && !strcmp(command->arg1+(char *)command, str))
  263. break;
  264. if (!command) error_exit("no :%s", str);
  265. }
  266. } else if (c=='c') {
  267. str = command->arg1+(char *)command;
  268. if (!command->hit) emit(str, strlen(str), 1);
  269. free(line);
  270. line = 0;
  271. continue;
  272. } else if (c=='d') {
  273. free(line);
  274. line = 0;
  275. continue;
  276. } else if (c=='D') {
  277. // Delete up to \n or end of buffer
  278. str = line;
  279. while ((str-line)<len) if (*(str++) == '\n') break;
  280. len -= str - line;
  281. memmove(line, str, len);
  282. // if "delete" blanks line, disable further processing
  283. // otherwise trim and restart script
  284. if (!len) {
  285. free(line);
  286. line = 0;
  287. } else {
  288. line[len] = 0;
  289. command = (void *)TT.pattern;
  290. }
  291. continue;
  292. } else if (c=='g') {
  293. free(line);
  294. line = xstrdup(TT.remember);
  295. len = TT.rememberlen;
  296. } else if (c=='G') {
  297. line = xrealloc(line, len+TT.rememberlen+2);
  298. line[len++] = '\n';
  299. memcpy(line+len, TT.remember, TT.rememberlen);
  300. line[len += TT.rememberlen] = 0;
  301. } else if (c=='h') {
  302. free(TT.remember);
  303. TT.remember = xstrdup(line);
  304. TT.rememberlen = len;
  305. } else if (c=='H') {
  306. TT.remember = xrealloc(TT.remember, TT.rememberlen+len+2);
  307. TT.remember[TT.rememberlen++] = '\n';
  308. memcpy(TT.remember+TT.rememberlen, line, len);
  309. TT.remember[TT.rememberlen += len] = 0;
  310. } else if (c=='i') {
  311. str = command->arg1+(char *)command;
  312. emit(str, strlen(str), 1);
  313. } else if (c=='l') {
  314. int i, x, off;
  315. if (!TT.xx) {
  316. terminal_size(&TT.xx, 0);
  317. if (!TT.xx) TT.xx = 80;
  318. if (TT.xx > sizeof(toybuf)-10) TT.xx = sizeof(toybuf)-10;
  319. if (TT.xx > 4) TT.xx -= 4;
  320. }
  321. for (i = off = 0; i<len; i++) {
  322. if (off >= TT.xx) {
  323. toybuf[off++] = '\\';
  324. emit(toybuf, off, 1);
  325. off = 0;
  326. }
  327. x = stridx("\\\a\b\f\r\t\v", line[i]);
  328. if (x != -1) {
  329. toybuf[off++] = '\\';
  330. toybuf[off++] = "\\abfrtv"[x];
  331. } else if (line[i] >= ' ') toybuf[off++] = line[i];
  332. else off += sprintf(toybuf+off, "\\%03o", line[i]);
  333. }
  334. toybuf[off++] = '$';
  335. emit(toybuf, off, 1);
  336. } else if (c=='n') {
  337. TT.restart = command->next+1;
  338. break;
  339. } else if (c=='N') {
  340. // Can't just grab next line because we could have multiple N and
  341. // we need to actually read ahead to get N;$p EOF detection right.
  342. if (pline) {
  343. TT.restart = command->next+1;
  344. extend_string(&line, TT.nextline, len, -TT.nextlen);
  345. free(TT.nextline);
  346. TT.nextline = line;
  347. TT.nextlen += len + 1;
  348. line = 0;
  349. }
  350. // Pending append goes out right after N
  351. goto done;
  352. } else if (c=='p' || c=='P') {
  353. char *l = (c=='P') ? strchr(line, '\n') : 0;
  354. if (emit(line, l ? l-line : len, eol)) break;
  355. } else if (c=='q' || c=='Q') {
  356. if (pline) *pline = (void *)1;
  357. free(TT.nextline);
  358. if (!toys.exitval && command->arg1)
  359. toys.exitval = atoi(command->arg1+(char *)command);
  360. TT.nextline = 0;
  361. TT.nextlen = 0;
  362. if (c=='Q') line = 0;
  363. break;
  364. } else if (c=='s') {
  365. char *rline = line, *new = command->arg2 + (char *)command, *l2 = 0;
  366. regmatch_t *match = (void *)toybuf;
  367. regex_t *reg = get_regex(command, command->arg1);
  368. int mflags = 0, count = 0, l2used = 0, zmatch = 1, l2l = len, l2old = 0,
  369. mlen, off, newlen;
  370. // Loop finding match in remaining line (up to remaining len)
  371. while (!regexec0(reg, rline, len-(rline-line), 10, match, mflags)) {
  372. mflags = REG_NOTBOL;
  373. // Zero length matches don't count immediately after a previous match
  374. mlen = match[0].rm_eo-match[0].rm_so;
  375. if (!mlen && !zmatch) {
  376. if (rline-line == len) break;
  377. l2[l2used++] = *rline++;
  378. zmatch++;
  379. continue;
  380. } else zmatch = 0;
  381. // If we're replacing only a specific match, skip if this isn't it
  382. off = command->sflags>>4;
  383. if (off && off != ++count) {
  384. if (l2) memcpy(l2+l2used, rline, match[0].rm_eo);
  385. l2used += match[0].rm_eo;
  386. rline += match[0].rm_eo;
  387. continue;
  388. }
  389. // The fact getline() can allocate unbounded amounts of memory is
  390. // a bigger issue, but while we're here check for integer overflow
  391. if (match[0].rm_eo > INT_MAX) perror_exit(0);
  392. // newlen = strlen(new) but with \1 and & and printf escapes
  393. for (off = newlen = 0; new[off]; off++) {
  394. int cc = -1;
  395. if (new[off] == '&') cc = 0;
  396. else if (new[off] == '\\') cc = new[++off] - '0';
  397. if (cc < 0 || cc > 9) {
  398. newlen++;
  399. continue;
  400. }
  401. newlen += match[cc].rm_eo-match[cc].rm_so;
  402. }
  403. // Copy changed data to new string
  404. // Adjust allocation size of new string, copy data we know we'll keep
  405. l2l += newlen-mlen;
  406. if ((l2l|0xfff) > l2old) l2 = xrealloc(l2, l2old = (l2l|0xfff)+1);
  407. if (match[0].rm_so) {
  408. memcpy(l2+l2used, rline, match[0].rm_so);
  409. l2used += match[0].rm_so;
  410. }
  411. // copy in new replacement text
  412. for (off = mlen = 0; new[off]; off++) {
  413. int cc = 0, ll;
  414. if (new[off] == '\\') {
  415. cc = new[++off] - '0';
  416. if (cc<0 || cc>9) {
  417. if (!(l2[l2used+mlen++] = unescape(new[off])))
  418. l2[l2used+mlen-1] = new[off];
  419. continue;
  420. } else if (cc > reg->re_nsub) error_exit("no s//\\%d/", cc);
  421. } else if (new[off] != '&') {
  422. l2[l2used+mlen++] = new[off];
  423. continue;
  424. }
  425. if (match[cc].rm_so != -1) {
  426. ll = match[cc].rm_eo-match[cc].rm_so;
  427. memcpy(l2+l2used+mlen, rline+match[cc].rm_so, ll);
  428. mlen += ll;
  429. }
  430. }
  431. l2used += newlen;
  432. rline += match[0].rm_eo;
  433. // Stop after first substitution unless we have flag g
  434. if (!(command->sflags & 2)) break;
  435. }
  436. // If we made any changes, finish off l2 and swap it for line
  437. if (l2) {
  438. // grab trailing unmatched data and null terminator, swap with original
  439. mlen = len-(rline-line);
  440. memcpy(l2+l2used, rline, mlen+1);
  441. len = l2used + mlen;
  442. free(line);
  443. line = l2;
  444. }
  445. if (mflags) {
  446. // flag p
  447. if (command->sflags & 4) emit(line, len, eol);
  448. tea = 1;
  449. if (command->w) goto writenow;
  450. }
  451. } else if (c=='w') {
  452. int fd, noeol;
  453. char *name;
  454. writenow:
  455. // Swap out emit() context
  456. fd = TT.fdout;
  457. noeol = TT.noeol;
  458. // We save filehandle and newline status before filename
  459. name = command->w + (char *)command;
  460. memcpy(&TT.fdout, name, 4);
  461. name += 4;
  462. TT.noeol = *(name++);
  463. // write, then save/restore context
  464. if (emit(line, len, eol))
  465. perror_exit("w '%s'", command->arg1+(char *)command);
  466. *(--name) = TT.noeol;
  467. TT.noeol = noeol;
  468. TT.fdout = fd;
  469. } else if (c=='x') {
  470. long swap = TT.rememberlen;
  471. str = TT.remember;
  472. TT.remember = line;
  473. line = str;
  474. TT.rememberlen = len;
  475. len = swap;
  476. } else if (c=='y') {
  477. char *from, *to = (char *)command;
  478. int i, j;
  479. from = to+command->arg1;
  480. to += command->arg2;
  481. for (i = 0; i < len; i++) {
  482. j = stridx(from, line[i]);
  483. if (j != -1) line[i] = to[j];
  484. }
  485. } else if (c=='=') {
  486. sprintf(toybuf, "%ld", TT.count);
  487. if (emit(toybuf, strlen(toybuf), 1)) break;
  488. }
  489. command = command->next;
  490. }
  491. if (line && !FLAG(n)) emit(line, len, eol);
  492. done:
  493. if (dlist_terminate(append)) while (append) {
  494. struct append *a = append->next;
  495. if (append->file) {
  496. int fd = open(append->str, O_RDONLY);
  497. // Force newline if noeol pending
  498. if (fd != -1) {
  499. if (TT.noeol) xwrite(TT.fdout, "\n", 1);
  500. TT.noeol = 0;
  501. xsendfile(fd, TT.fdout);
  502. close(fd);
  503. }
  504. } else if (append->str) emit(append->str, strlen(append->str), 1);
  505. else emit(line, 0, 0);
  506. free(append);
  507. append = a;
  508. }
  509. free(line);
  510. }
  511. // Callback called on each input file
  512. static void do_sed_file(int fd, char *name)
  513. {
  514. char *tmp, *s;
  515. if (FLAG(i)) {
  516. if (!fd) return error_msg("-i on stdin");
  517. TT.fdout = copy_tempfile(fd, name, &tmp);
  518. }
  519. if (FLAG(i) || FLAG(s)) {
  520. struct sedcmd *command;
  521. TT.count = 0;
  522. for (command = (void *)TT.pattern; command; command = command->next)
  523. command->hit = 0;
  524. }
  525. do_lines(fd, TT.delim, sed_line);
  526. if (FLAG(i)) {
  527. if (TT.i && *TT.i) {
  528. xrename(name, s = xmprintf("%s%s", name, TT.i));
  529. free(s);
  530. }
  531. replace_tempfile(-1, TT.fdout, &tmp);
  532. TT.fdout = 1;
  533. }
  534. if (FLAG(i) || FLAG(s)) {
  535. TT.nextline = 0;
  536. TT.nextlen = TT.noeol = 0;
  537. }
  538. }
  539. // Copy chunk of string between two delimiters, converting printf escapes.
  540. // returns processed copy of string (0 if error), *pstr advances to next
  541. // unused char. if delim (or *delim) is 0 uses/saves starting char as delimiter
  542. // if regxex, ignore delimiter in [ranges]
  543. static char *unescape_delimited_string(char **pstr, char *delim)
  544. {
  545. char *to, *from, mode = 0, d;
  546. // Grab leading delimiter (if necessary), allocate space for new string
  547. from = *pstr;
  548. if (!delim || !*delim) {
  549. if (!(d = *(from++))) return 0;
  550. if (d == '\\') d = *(from++);
  551. if (!d || d == '\\') return 0;
  552. if (delim) *delim = d;
  553. } else d = *delim;
  554. to = delim = xmalloc(strlen(*pstr)+1);
  555. while (mode || *from != d) {
  556. if (!*from) return 0;
  557. // delimiter in regex character range doesn't count
  558. if (*from == '[') {
  559. if (!mode) {
  560. mode = ']';
  561. if (from[1]=='-' || from[1]==']') *(to++) = *(from++);
  562. } else if (mode == ']' && strchr(".=:", from[1])) {
  563. *(to++) = *(from++);
  564. mode = *from;
  565. }
  566. } else if (*from == mode) {
  567. if (mode == ']') mode = 0;
  568. else {
  569. *(to++) = *(from++);
  570. mode = ']';
  571. }
  572. // Length 1 range (X-X with same X) is "undefined" and makes regcomp err,
  573. // but the perl build does it, so we need to filter it out.
  574. } else if (mode && *from == '-' && from[-1] == from[1]) {
  575. from+=2;
  576. continue;
  577. } else if (*from == '\\') {
  578. if (!from[1]) return 0;
  579. // Check escaped end delimiter before printf style escapes.
  580. if (from[1] == d) from++;
  581. else if (from[1]=='\\') *(to++) = *(from++);
  582. else {
  583. char c = unescape(from[1]);
  584. if (c) {
  585. *(to++) = c;
  586. from+=2;
  587. continue;
  588. } else if (!mode) *(to++) = *(from++);
  589. }
  590. }
  591. *(to++) = *(from++);
  592. }
  593. *to = 0;
  594. *pstr = from+1;
  595. return delim;
  596. }
  597. // Translate pattern strings into command structures. Each command structure
  598. // is a single allocation (which requires some math and remalloc at times).
  599. static void parse_pattern(char **pline, long len)
  600. {
  601. struct sedcmd *command = (void *)TT.pattern;
  602. char *line, *reg, c, *errstart;
  603. int i;
  604. line = errstart = pline ? *pline : "";
  605. if (len && line[len-1]=='\n') line[--len] = 0;
  606. // Append this line to previous multiline command? (hit indicates type.)
  607. // During parsing "hit" stores data about line continuations, but in
  608. // sed_line() it means the match range attached to this command
  609. // is active, so processing the continuation must zero it again.
  610. if (command && command->prev->hit) {
  611. // Remove half-finished entry from list so remalloc() doesn't confuse it
  612. TT.pattern = TT.pattern->prev;
  613. command = dlist_pop(&TT.pattern);
  614. c = command->c;
  615. reg = (char *)command;
  616. reg += command->arg1 + strlen(reg + command->arg1);
  617. // Resume parsing for 'a' or 's' command. (Only two that can do this.)
  618. // TODO: using 256 to indicate 'a' means our s/// delimiter can't be
  619. // a unicode character.
  620. if (command->hit < 256) goto resume_s;
  621. else goto resume_a;
  622. }
  623. // Loop through commands in this line.
  624. command = 0;
  625. for (;;) {
  626. if (command) dlist_add_nomalloc(&TT.pattern, (void *)command);
  627. // If there's no more data on this line, return.
  628. for (;;) {
  629. while (isspace(*line) || *line == ';') line++;
  630. if (*line == '#') while (*line && *line != '\n') line++;
  631. else break;
  632. }
  633. if (!*line) return;
  634. // Start by writing data into toybuf.
  635. errstart = line;
  636. memset(toybuf, 0, sizeof(struct sedcmd));
  637. command = (void *)toybuf;
  638. reg = toybuf + sizeof(struct sedcmd);
  639. // Parse address range (if any)
  640. for (i = 0; i < 2; i++) {
  641. if (*line == ',') line++;
  642. else if (i) break;
  643. if (i && *line == '+' && isdigit(line[1])) {
  644. line++;
  645. command->lmatch[i] = -2-strtol(line, &line, 0);
  646. } else if (isdigit(*line)) command->lmatch[i] = strtol(line, &line, 0);
  647. else if (*line == '$') {
  648. command->lmatch[i] = -1;
  649. line++;
  650. } else if (*line == '/' || *line == '\\') {
  651. char *s = line;
  652. if (!(s = unescape_delimited_string(&line, 0))) goto error;
  653. if (!*s) command->rmatch[i] = 0;
  654. else {
  655. xregcomp((void *)reg, s, REG_EXTENDED*!!FLAG(r));
  656. command->rmatch[i] = reg-toybuf;
  657. reg += sizeof(regex_t);
  658. }
  659. free(s);
  660. } else break;
  661. }
  662. while (isspace(*line)) line++;
  663. if (!*line) break;
  664. if (*line == '!') {
  665. command->not = 1;
  666. line++;
  667. }
  668. while (isspace(*line)) line++;
  669. if (!*line) break;
  670. c = command->c = *(line++);
  671. if (strchr("}:", c) && i) break;
  672. if (strchr("aiqQr=", c) && i>1) break;
  673. // Allocate memory and copy out of toybuf now that we know how big it is
  674. command = xmemdup(toybuf, reg-toybuf);
  675. reg = (reg-toybuf) + (char *)command;
  676. // Parse arguments by command type
  677. if (c == '{') TT.nextlen++;
  678. else if (c == '}') {
  679. if (!TT.nextlen--) break;
  680. } else if (c == 's') {
  681. char *end, delim = 0;
  682. int flags;
  683. // s/pattern/replacement/flags
  684. // line continuations use arg1 (back at the start of the function),
  685. // so let's fill out arg2 first (since the regex part can't be multiple
  686. // lines) and swap them back later.
  687. // get pattern (just record, we parse it later)
  688. command->arg2 = reg - (char *)command;
  689. if (!(TT.remember = unescape_delimited_string(&line, &delim)))
  690. goto error;
  691. reg += sizeof(regex_t);
  692. command->arg1 = reg-(char *)command;
  693. command->hit = delim;
  694. resume_s:
  695. // get replacement - don't replace escapes yet because \1 and \& need
  696. // processing later, after we replace \\ with \ we can't tell \\1 from \1
  697. end = line;
  698. while (*end != command->hit) {
  699. if (!*end) goto error;
  700. if (*end++ == '\\') {
  701. if (!*end || *end == '\n') {
  702. end[-1] = '\n';
  703. break;
  704. }
  705. end++;
  706. }
  707. }
  708. reg = extend_string((void *)&command, line, reg-(char *)command,end-line);
  709. line = end;
  710. // line continuation? (note: '\n' can't be a valid delim).
  711. if (*line == command->hit) command->hit = 0;
  712. else {
  713. if (!*line) continue;
  714. reg--;
  715. line++;
  716. goto resume_s;
  717. }
  718. // swap arg1/arg2 so they're back in order arguments occur.
  719. i = command->arg1;
  720. command->arg1 = command->arg2;
  721. command->arg2 = i;
  722. // get flags
  723. for (line++; *line; line++) {
  724. long l;
  725. if (isspace(*line) && *line != '\n') continue;
  726. if (0 <= (l = stridx("igpx", *line))) command->sflags |= 1<<l;
  727. else if (*line == 'I') command->sflags |= 1<<0;
  728. else if (!(command->sflags>>4) && 0<(l = strtol(line, &line, 10))) {
  729. command->sflags |= l << 4;
  730. line--;
  731. } else break;
  732. }
  733. flags = (FLAG(r) || (command->sflags&8)) ? REG_EXTENDED : 0;
  734. if (command->sflags&1) flags |= REG_ICASE;
  735. // We deferred actually parsing the regex until we had the s///i flag
  736. // allocating the space was done by extend_string() above
  737. if (!*TT.remember) command->arg1 = 0;
  738. else xregcomp((void *)(command->arg1+(char *)command),TT.remember,flags);
  739. free(TT.remember);
  740. TT.remember = 0;
  741. if (*line == 'w') {
  742. line++;
  743. goto writenow;
  744. }
  745. } else if (c == 'w') {
  746. int fd, delim;
  747. char *cc;
  748. // Since s/// uses arg1 and arg2, and w needs a persistent filehandle and
  749. // eol status, and to retain the filename for error messages, we'd need
  750. // to go up to arg5 just for this. Compromise: dynamically allocate the
  751. // filehandle and eol status.
  752. writenow:
  753. while (isspace(*line)) line++;
  754. if (!*line) goto error;
  755. for (cc = line; *cc; cc++) if (*cc == '\\' && cc[1] == ';') break;
  756. delim = *cc;
  757. *cc = 0;
  758. fd = xcreate(line, O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0644);
  759. *cc = delim;
  760. command->w = reg - (char *)command;
  761. command = xrealloc(command, command->w+(cc-line)+6);
  762. reg = command->w + (char *)command;
  763. memcpy(reg, &fd, 4);
  764. reg += 4;
  765. *(reg++) = 0;
  766. memcpy(reg, line, delim);
  767. reg += delim;
  768. *(reg++) = 0;
  769. line = cc;
  770. if (delim) line += 2;
  771. } else if (c == 'y') {
  772. char *s, delim = 0;
  773. int len;
  774. if (!(s = unescape_delimited_string(&line, &delim))) goto error;
  775. command->arg1 = reg-(char *)command;
  776. len = strlen(s);
  777. reg = extend_string((void *)&command, s, reg-(char *)command, len);
  778. free(s);
  779. command->arg2 = reg-(char *)command;
  780. if (!(s = unescape_delimited_string(&line, &delim))) goto error;
  781. if (len != strlen(s)) goto error;
  782. reg = extend_string((void *)&command, s, reg-(char*)command, len);
  783. free(s);
  784. } else if (strchr("abcirtTqQw:", c)) {
  785. int end;
  786. // trim leading spaces
  787. while (isspace(*line) && *line != '\n') line++;
  788. // Resume logic differs from 's' case because we don't add a newline
  789. // unless it's after something, so we add it on return instead.
  790. resume_a:
  791. command->hit = 0;
  792. // btTqQ: end with space or semicolon, aicrw continue to newline.
  793. if (!(end = strcspn(line, strchr(":btTqQ", c) ? "}; \t\r\n\v\f" : "\n"))){
  794. // Argument's optional for btTqQ
  795. if (strchr("btTqQ", c)) continue;
  796. else if (!command->arg1) break;
  797. }
  798. // Error checking: qQ can only have digits after them
  799. if (c=='q' || c=='Q') {
  800. for (i = 0; i<end && isdigit(line[i]); i++);
  801. if (i != end) {
  802. line += i;
  803. break;
  804. }
  805. }
  806. // Extend allocation to include new string. We use offsets instead of
  807. // pointers so realloc() moving stuff doesn't break things. Ok to write
  808. // \n over NUL terminator because call to extend_string() adds it back.
  809. if (!command->arg1) command->arg1 = reg - (char*)command;
  810. else if (*(command->arg1+(char *)command)) *(reg++) = '\n';
  811. else if (!pline) {
  812. command->arg1 = 0;
  813. continue;
  814. }
  815. reg = extend_string((void *)&command, line, reg - (char *)command, end);
  816. // Recopy data to remove escape sequences and handle line continuation.
  817. if (strchr("aci", c)) {
  818. reg -= end+1;
  819. for (i = end; i; i--) {
  820. if ((*reg++ = *line++)=='\\') {
  821. // escape at end of line: resume if -e escaped literal newline,
  822. // else request callback and resume with next line
  823. if (!--i) {
  824. *--reg = 0;
  825. if (*line) {
  826. line++;
  827. goto resume_a;
  828. }
  829. command->hit = 256;
  830. break;
  831. }
  832. if (!(reg[-1] = unescape(*line))) reg[-1] = *line;
  833. line++;
  834. }
  835. }
  836. *reg = 0;
  837. } else line += end;
  838. // Commands that take no arguments
  839. } else if (!strchr("{dDgGhHlnNpPx=", c)) break;
  840. }
  841. error:
  842. error_exit("bad pattern '%s'@%ld (%c)", errstart, line-errstart+1L, *line);
  843. }
  844. void sed_main(void)
  845. {
  846. struct arg_list *al;
  847. char **args = toys.optargs;
  848. if (!FLAG(z)) TT.delim = '\n';
  849. // Lie to autoconf when it asks stupid questions, so configure regexes
  850. // that look for "GNU sed version %f" greater than some old buggy number
  851. // don't fail us for not matching their narrow expectations.
  852. if (FLAG(version)) {
  853. xprintf("This is not GNU sed version 9.0\n");
  854. return;
  855. }
  856. // Handling our own --version means we handle our own --help too.
  857. if (FLAG(help)) help_exit(0);
  858. // Parse pattern into commands.
  859. // If no -e or -f, first argument is the pattern.
  860. if (!TT.e && !TT.f) {
  861. if (!*toys.optargs) error_exit("no pattern");
  862. (TT.e = xzalloc(sizeof(struct arg_list)))->arg = *(args++);
  863. }
  864. // Option parsing infrastructure can't interlace "-e blah -f blah -e blah"
  865. // so handle all -e, then all -f. (At least the behavior's consistent.)
  866. for (al = TT.e; al; al = al->next) parse_pattern(&al->arg, strlen(al->arg));
  867. parse_pattern(0, 0);
  868. for (al = TT.f; al; al = al->next)
  869. do_lines(xopenro(al->arg), TT.delim, parse_pattern);
  870. dlist_terminate(TT.pattern);
  871. if (TT.nextlen) error_exit("no }");
  872. TT.fdout = 1;
  873. TT.remember = xstrdup("");
  874. // Inflict pattern upon input files. Long version because !O_CLOEXEC
  875. loopfiles_rw(args, O_RDONLY|WARN_ONLY, 0, do_sed_file);
  876. // Provide EOF flush at end of cumulative input for non-i mode.
  877. if (!FLAG(i) && !FLAG(s)) {
  878. toys.optflags |= FLAG_s;
  879. sed_line(0, 0);
  880. }
  881. // todo: need to close fd when done for TOYBOX_FREE?
  882. }