/* * Break the input stream into lines based on some delimiter. * * Dan Cross */ #include #include #include #include #include typedef struct Ring Ring; struct Ring { FILE *fp; size_t size; size_t start, cur, end; char data[]; }; static void spliton(FILE *fp, const char *separator); static int separates(FILE *fp, const char *separator, Ring *ring); static const char *basename(const char *argv0); static void usage(const char *prog); const char *prog; int main(int argc, char *argv[]) { FILE *fp; char *filename, *separator; int ch; prog = basename(argv[0]); separator = " "; while ((ch = getopt(argc, argv, "s:?")) != -1) { switch (ch) { case 's': separator = optarg; break; case '?': default: usage(prog); break; } } argc -= optind; argv += optind; if (argc == 0) { spliton(stdin, separator); } else while ((filename = *argv++) != NULL) { if (strcmp(filename, "-") == 0) { spliton(stdin, separator); continue; } fp = fopen(filename, "rb"); if (fp == NULL) { perror(filename); continue; } spliton(fp, separator); fclose(fp); } return(EXIT_SUCCESS); } static Ring * mkfifo(FILE *fp, size_t size) { Ring *buf; buf = calloc(1, sizeof(Ring) + size + 1); if (buf == NULL) { perror("malloc"); exit(EXIT_FAILURE); } buf->fp = fp; buf->size = size + 1; return buf; } static int nextfifo(Ring *buf) { int ch = buf->data[buf->cur]; if (buf->cur == buf->end) { ch = fgetc(buf->fp); if (ch == EOF) return -1; buf->data[buf->cur] = ch; buf->end = (buf->end + 1) % buf->size; } buf->cur = (buf->cur + 1) % buf->size; return ch; } static int outfifo(Ring *buf) { int ch = buf->data[buf->start]; if (buf->start == buf->cur) buf->cur = (buf->cur + 1) % buf->size; buf->start = (buf->start + 1) % buf->size; return ch; } static void rewindfifo(Ring *buf) { buf->cur = buf->start; } static void ffwdfifo(Ring *buf) { buf->start = buf->cur; } static int emptyfifo(Ring *buf) { return buf->start == buf->end; } static void spliton(FILE *fp, const char *separator) { int ch; Ring *buf; buf = mkfifo(fp, strlen(separator)); while ((ch = nextfifo(buf)) != -1) { if (ch == *separator) { if (separates(fp, separator + 1, buf)) { fputc('\n', stdout); ffwdfifo(buf); continue; } } fputc(outfifo(buf), stdout); rewindfifo(buf); } while (!emptyfifo(buf)) fputc(outfifo(buf), stdout); free(buf); } static int separates(FILE *fp, const char *sep, Ring *buf) { while (*sep != '\0') { int ch = nextfifo(buf); if (ch == -1 || ch != *sep) return 0; sep++; } return 1; } static const char * basename(const char *argv0) { const char *p; if (argv0 == NULL) argv0 = "spliton"; return ((p = strrchr(argv0, '/')) == NULL) ? argv0 : p + 1; } static void usage(const char *prog) { fprintf(stderr, "Usage: %s [ -s separator ] [ file[s] ].\n", prog); exit(EXIT_FAILURE); }