view toys/posix/sed.c @ 700:ad6bff0c9169

Refactor touch (cleanup whitespace, brackets, function order), code otherwise same.
author Rob Landley <rob@landley.net>
date Fri, 16 Nov 2012 15:36:01 -0600
parents 786841fdb1e0
children
line wrap: on
line source

/* sed.c - Stream editor.
 *
 * Copyright 2012 Rob Landley <rob@landley.net>
 *
 * See http://opengroup.org/onlinepubs/9699919799/utilities/sed.c

USE_SED(NEWTOY(sed, "irne*", TOYFLAG_BIN))

config SED
  bool "sed"
  default n
  help
    usage: sed [-irn] {command | [-e command]...} [FILE...]

    Stream EDitor, transforms text by appling script of command to each line
    of input.

    -e  Add expression to the command script (if no -e, use first argument)
    -i	Modify file in place
    -n  No default output (p commands only)
    -r  Use extended regular expression syntex
*/

#define FOR_sed
#include "toys.h"
#include "lib/xregcomp.h"

GLOBALS(
  struct arg_list *scripts;
  struct double_list *commands;

  void *parsed;
)

// Digested version of what sed commands can actually tell use to do.


struct sed_command {
  // double_list compatibility (easier to create in-order)
  struct sed_command *next, *prev;

  // data string for (saicytb)
  char c, *data;
  // Regexes for s/match/data/ and /begin/,/end/command
  regex_t *match, *begin, *end;
  // For numeric ranges ala 10,20command
  long lstart, lstop;
  // Which match to replace, 0 for all. s and w commands can write to a file
  int which, outfd;
};

//  Space. Space. Gotta get past space. Spaaaaaaaace! (But not newline.)
void spaceorb(char **s)
{
  while (**s == ' ' || **s == '\t') *s++;
}

void parse_scripts(void)
{
  struct sed_command *commands = 0;
  struct arg_list *script;
  int which = 0;
  long l;

  for (script = TT.scripts; *script; script = script->next) {
    char *str = script->arg, *s;
    struct sed_command *cmd;

    which++;
    for (i=1;;) {
      if (!*str) break;

      cmd = xzalloc(sizeof(struct sed_command));

      // Identify prefix
      for (;;) {
        long l;

        spaceorb(&str);
        if (*str == '$') {
          l = -1;
          str++;
        } else if (isdigit(*str)) l = strtol(str, &str, 10);
        else if (!cmd->lstart) break;
        else goto parse_fail;

        spaceorb(&str);
        if (!cmd->lstart) {
          if (!l) goto parse_fail;
          cmd->lstart = l;
          if (*str != ',') break;
          str++;
          continue;
        }
        cmd->lstop = l;
        break;
      } else if (*str == '/') {
        printf("regex\n");
      }
      l = stridx("{bcdDgGhHlnNpPstwxyrqia= \t#:}", *str);
      if (l == -1) goto parse_fail;


    }
  }

  return;

parse_fail:
  error_exit("bad expression %d@%d: %s", which, i, script->arg+i);
}

void sed_main(void)
{
  char **files=toys.optargs;

  // If no -e, use first argument
  if (!TT.scripts) {
    if (!*files) error_exit("Need script");
    (TT.scripts=xzalloc(sizeof(struct arg_list)))->arg=*(files++);
  }


  {
    struct arg_list *test;

    for (test = TT.commands; test; test = test->next)
      dprintf(2,"command=%s\n",test->arg);
    while (*files) dprintf(2,"file=%s\n", *(files++));
  }
}