view toys/posix/paste.c @ 1008:a55854bde872

su: cleanery * make help message more like others * s/TT\.(.)Argu/TT.\1/g * move environ to toys.h * simplify failure messages * clear password before quit * not check what execve returns * -lc
author Strake <strake888@gmail.com>
date Sat, 17 Aug 2013 02:54:58 -0500
parents b4faf2ae39e8
children
line wrap: on
line source

/* paste.c - Replace newlines
 *
 * Copyright 2012 Felix Janda <felix.janda@posteo.de>
 *
 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/paste.html 
 *
USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_BIN))

config PASTE
  bool "paste"
  default y
  help
    usage: paste [-s] [-d list] [file...]

    Replace newlines in files.

    -d list    list of delimiters to separate lines
    -s         process files sequentially instead of in parallel

    By default print corresponding lines separated by <tab>.
*/
#define FOR_paste
#include "toys.h"

GLOBALS(
  char *delim;
)

void paste_main(void)
{
  char *p, *buf = toybuf, **args = toys.optargs;
  size_t ndelim = 0;
  int i, j, c;

  // Process delimiter list
  // TODO: Handle multibyte characters
  if (!(toys.optflags & FLAG_d)) TT.delim = "\t";
  for (p = TT.delim; *p; p++, buf++, ndelim++) {
    if (*p == '\\') {
      p++;
      if (-1 == (i = stridx("nt\\0", *p)))
        error_exit("bad delimiter: \\%c", *p);
      *buf = "\n\t\\\0"[i];
    } else *buf = *p;
  }
  *buf = 0;

  if (toys.optflags & FLAG_s) { // Sequential
    FILE *f;

    for (; *args; args++) {
      if ((*args)[0] == '-' && !(*args)[1]) f = stdin;
      else if (!(f = fopen(*args, "r"))) perror_exit("%s", *args);
      for (i = 0, c = 0; c != EOF;) {
        switch(c = getc(f)) {
        case '\n':
          putchar(toybuf[i++ % ndelim]);
        case EOF:
          break;
        default:
          putchar(c);
        }
      }
      if (f != stdin) fclose(f);
      putchar('\n');
    }
  } else { // Parallel
    // Need to be careful not to print an extra line at the end
    FILE **files;
    int anyopen = 1;

    files = (FILE**)(buf + 1);
    for (; *args; args++, files++) {
      if ((*args)[0] == '-' && !(*args)[1]) *files = stdin;
      else if (!(*files = fopen(*args, "r"))) perror_exit("%s", *args);
    }
    while (anyopen) {
      anyopen = 0;
      for (i = 0; i < toys.optc; i++) {
        FILE **f = (FILE**)(buf + 1) + i;

        if (*f) for (;;) {
          c = getc(*f);
          if (c != EOF) {
            if (!anyopen++) for (j = 0; j < i; j++) putchar(toybuf[j % ndelim]);
            if (c != '\n') putchar(c);
            else break;
          }
          else {
            if (*f != stdin) fclose(*f);
            *f = 0;
            break;
          }
        }
        if (anyopen) putchar((i + 1 == toys.optc) ? toybuf[i % ndelim] : '\n');
      }
    }
  }
}