Mercurial > hg > toybox
comparison toys/pending/sed.c @ 1545:b6ff5dc17763 draft
Implement a few sed commands. Not done, and not tested yet.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 08 Nov 2014 01:51:59 -0600 |
parents | ad6b2f0e566b |
children | 2997847aa299 |
comparison
equal
deleted
inserted
replaced
1544:e3aeb7435efe | 1545:b6ff5dc17763 |
---|---|
178 struct arg_list *e; | 178 struct arg_list *e; |
179 | 179 |
180 // processed pattern list | 180 // processed pattern list |
181 struct double_list *pattern; | 181 struct double_list *pattern; |
182 | 182 |
183 char *nextline; | 183 char *nextline, *remember; |
184 long nextlen, count; | 184 void *restart; |
185 long nextlen, rememberlen, count; | |
185 int fdout, noeol; | 186 int fdout, noeol; |
186 ) | 187 ) |
187 | 188 |
188 struct step { | 189 struct step { |
189 struct step *next, *prev; | 190 struct step *next, *prev; |
234 */ | 235 */ |
235 return regexec(preg, string, nmatch, pmatch, eflags); | 236 return regexec(preg, string, nmatch, pmatch, eflags); |
236 | 237 |
237 } | 238 } |
238 | 239 |
240 // Extend allocation to include new string. | |
241 | |
242 static char *extend_string(char **old, char *new, int oldlen, int newlen) | |
243 { | |
244 int newline = newlen < 0; | |
245 char *s; | |
246 | |
247 if (newline) newlen = -newlen; | |
248 s = *old = xrealloc(*old, oldlen+newlen+newline+1); | |
249 if (newline) s[oldlen++] = '\n'; | |
250 memcpy(s+oldlen, new, newlen); | |
251 s[oldlen+newlen] = 0; | |
252 | |
253 return s+oldlen+newlen; | |
254 } | |
255 | |
239 // Apply pattern to line from input file | 256 // Apply pattern to line from input file |
240 static void walk_pattern(char **pline, long plen) | 257 static void walk_pattern(char **pline, long plen) |
241 { | 258 { |
242 char *line = TT.nextline; | 259 char *line = TT.nextline, *append = 0; |
243 long len = TT.nextlen; | 260 long len = TT.nextlen; |
244 struct step *logrus; | 261 struct step *logrus; |
245 int eol = 0; | 262 int eol = 0, tea = 0; |
246 | 263 |
247 // Grab next line for deferred processing (EOF detection, we get a NULL | 264 // Grab next line for deferred processing (EOF detection: we get a NULL |
248 // pline at EOF to flush last line). Note that only end of _last_ input | 265 // pline at EOF to flush last line). Note that only end of _last_ input |
249 // file matches $ (unless we're doing -i). | 266 // file matches $ (unless we're doing -i). |
250 if (pline) { | 267 if (pline) { |
251 TT.nextline = *pline; | 268 TT.nextline = *pline; |
252 TT.nextlen = plen; | 269 TT.nextlen = plen; |
255 | 272 |
256 if (!line || !len) return; | 273 if (!line || !len) return; |
257 if (line[len-1] == '\n') line[--len] = eol++; | 274 if (line[len-1] == '\n') line[--len] = eol++; |
258 TT.count++; | 275 TT.count++; |
259 | 276 |
260 for (logrus = (void *)TT.pattern; logrus; logrus = logrus->next) { | 277 logrus = TT.restart ? TT.restart : (void *)TT.pattern; |
261 char c = logrus->c; | 278 TT.restart = 0; |
279 while (logrus) { | |
280 char *str, c = logrus->c; | |
262 | 281 |
263 // Have we got a matching range for this rule? | 282 // Have we got a matching range for this rule? |
264 if (*logrus->lmatch || *logrus->rmatch) { | 283 if (*logrus->lmatch || *logrus->rmatch) { |
265 int miss = 0; | 284 int miss = 0; |
266 long lm; | 285 long lm; |
303 } | 322 } |
304 // Deferred disable from regex end match | 323 // Deferred disable from regex end match |
305 if (miss) logrus->hit = 0; | 324 if (miss) logrus->hit = 0; |
306 } | 325 } |
307 | 326 |
308 // Process like the wind, bullseye! | 327 // Process command |
309 | 328 |
310 // if (strchr("dDgGhHlnNpPqx=", c)) { | 329 if (c == 'a') { |
311 | 330 long alen = append ? strlen(append) : 0; |
312 | 331 |
313 // if (strchr("abcirstTwy:", c) | 332 str = logrus->arg1+(char *)logrus; |
314 if (c == 'p') { | 333 extend_string(&append, str, alen, -strlen(str)); |
334 } else if (c == 'b') { | |
335 str = logrus->arg1+(char *)logrus; | |
336 | |
337 if (!*str) break; | |
338 for (logrus = (void *)TT.pattern; logrus; logrus = logrus->next) | |
339 if (logrus->c == ':' && !strcmp(logrus->arg1+(char *)logrus, str)) | |
340 break; | |
341 if (!logrus) error_exit("no :%s", str); | |
342 } else if (c == 'd') goto done; | |
343 else if (c == 'D') { | |
344 // Delete up to \n or end of buffer | |
345 for (str = line; !*str || *str == '\n'; str++); | |
346 len -= str - line; | |
347 memmove(line, str, len); | |
348 line[len] = 0; | |
349 | |
350 // restart script | |
351 logrus = (void *)TT.pattern; | |
352 continue; | |
353 } else if (c == 'g') { | |
354 free(line); | |
355 line = xstrdup(TT.remember); | |
356 len = TT.rememberlen; | |
357 } else if (c == 'G') { | |
358 line = xrealloc(line, len+TT.rememberlen+2); | |
359 line[len++] = '\n'; | |
360 memcpy(line+len, TT.remember, TT.rememberlen); | |
361 line[len += TT.rememberlen] = 0; | |
362 } else if (c == 'h') { | |
363 free(TT.remember); | |
364 TT.remember = xstrdup(line); | |
365 TT.rememberlen = len; | |
366 } else if (c == 'H') { | |
367 TT.remember = xrealloc(TT.remember, TT.rememberlen+len+2); | |
368 TT.remember[TT.rememberlen++] = '\n'; | |
369 memcpy(TT.remember+TT.rememberlen, line, len); | |
370 TT.remember[TT.rememberlen += len] = 0; | |
371 } else if (c == 'l') { | |
372 error_exit("todo: l"); | |
373 } else if (c == 'n') { | |
374 TT.restart = logrus->next; | |
375 | |
376 break; | |
377 } else if (c == 'N') { | |
378 if (pline) { | |
379 TT.restart = logrus->next; | |
380 extend_string(&line, TT.nextline, plen, -TT.nextlen); | |
381 free(TT.nextline); | |
382 TT.nextline = line; | |
383 } | |
384 | |
385 goto append; | |
386 } else if (c == 'p') { | |
315 if (emit(line, len, eol)) break; | 387 if (emit(line, len, eol)) break; |
316 } else error_exit("what?"); | 388 } else if (c == 'q') break; |
389 else if (c == 'x') { | |
390 long swap = TT.rememberlen; | |
391 | |
392 str = TT.remember; | |
393 TT.remember = line; | |
394 line = str; | |
395 TT.rememberlen = len; | |
396 len = swap; | |
397 } else if (c == '=') xprintf("%ld\n", TT.count); | |
398 // labcirstTwy | |
399 else if (c != ':') error_exit("todo: %c", c); | |
400 | |
401 logrus = logrus->next; | |
317 } | 402 } |
318 | 403 |
319 if (!(toys.optflags & FLAG_n)) emit(line, len, eol); | 404 if (!(toys.optflags & FLAG_n)) emit(line, len, eol); |
320 | 405 |
406 done: | |
321 free(line); | 407 free(line); |
408 | |
409 append: | |
410 if (append) { | |
411 emit(append, strlen(append), 1); | |
412 free(append); | |
413 } | |
322 } | 414 } |
323 | 415 |
324 // Genericish function, can probably get moved to lib.c | 416 // Genericish function, can probably get moved to lib.c |
325 | 417 |
326 // Iterate over lines in file, calling function. Function can write NULL to | 418 // Iterate over lines in file, calling function. Function can write NULL to |
420 *to = delim; | 512 *to = delim; |
421 } | 513 } |
422 *pstr = from + rc; | 514 *pstr = from + rc; |
423 | 515 |
424 return rc; | 516 return rc; |
425 } | |
426 | |
427 // Extend allocation to include new string. We use offsets instead of | |
428 // pointers so realloc() moving stuff doesn't break things. Do it | |
429 // here instead of toybuf so there's no maximum size. | |
430 | |
431 static char *extend_string(char **old, char *new, int oldlen, int newlen) | |
432 { | |
433 *old = xrealloc(*old, oldlen+newlen+1); | |
434 memcpy(*old+oldlen, new, newlen); | |
435 (*old)[oldlen+newlen] = 0; | |
436 | |
437 return (*old)+oldlen+newlen; | |
438 } | 517 } |
439 | 518 |
440 // Translate primal pattern into walkable form. | 519 // Translate primal pattern into walkable form. |
441 static void jewel_of_judgement(char **pline, long len) | 520 static void jewel_of_judgement(char **pline, long len) |
442 { | 521 { |
634 do_lines(xopen(dworkin->arg, O_RDONLY), dworkin->arg, jewel_of_judgement); | 713 do_lines(xopen(dworkin->arg, O_RDONLY), dworkin->arg, jewel_of_judgement); |
635 dlist_terminate(TT.pattern); | 714 dlist_terminate(TT.pattern); |
636 if (TT.nextlen) error_exit("no }"); | 715 if (TT.nextlen) error_exit("no }"); |
637 | 716 |
638 TT.fdout = 1; | 717 TT.fdout = 1; |
718 TT.remember = xstrdup(""); | |
639 | 719 |
640 // Inflict pattern upon input files | 720 // Inflict pattern upon input files |
641 loopfiles_rw(args, O_RDONLY, 0, 0, do_sed); | 721 loopfiles_rw(args, O_RDONLY, 0, 0, do_sed); |
642 | 722 |
643 if (!(toys.optflags & FLAG_i)) walk_pattern(0, 0); | 723 if (!(toys.optflags & FLAG_i)) walk_pattern(0, 0); |