#include #include #include #include #include #include "util/versie.h" #include "util/error.h" #include "util/debug.h" static void usage(FILE *f) { fprintf(f, "Gebruik: omd [-hV] \n" "\n" "Draai alle regels om\n" "\n" " -h Toon deze hulptekst\n" " -V Toon versienummer\n"); } // Returns pointer to argument array containing the file names static char** parse_options(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "hV")) != -1) { switch (opt) { case 'h': usage(stdout); exit(0); case 'V': drukkedoos_print_versie(stdout, "omd"); exit(0); case '?': usage(stderr); exit(1); } } return argv + optind; } static void reverse_in_place(char *buf, size_t len) { for (size_t i = 0, j = len - 1; i < len / 2; i++, j--) { char c = buf[i]; buf[i] = buf[j]; buf[j] = c; } } static void process(const char *fname, FILE *f) { size_t cap = 4096; char *buffer = malloc(cap); if (!buffer) print_error_nomem("omd"); size_t cursor = 0; while (true) { DEBUG("cursor=%zu\n", cursor); // read a line size_t linelen = 0; while (true) { // grow buffer when small if (cap - cursor < 1024) { cap *= 2; if (cap == 0) { fprintf(stderr, "omd: Regel te lang\n"); exit(1); } DEBUG("realloc to cap %zu\n", cap); buffer = realloc(buffer, cap); if (!buffer) print_error_nomem("omd"); } size_t nr = fread(buffer + cursor, 1, cap - cursor, f); DEBUG("nr=%zu\n", nr); if (nr == 0) { if (feof(f)) { if (cursor == 0) return; linelen = cursor; break; } if (fname) fprintf(stderr, "omd: Fout bij lezen van bestand '%s'\n", fname); else fprintf(stderr, "omd: Fout bij lezen van standaardinvoer\n"); exit(1); } char *p = memchr(buffer + cursor, '\n', nr); cursor += nr; if (p != NULL) { linelen = p - buffer; break; } } DEBUG("line with len %zu (cursor=%zu)\n", linelen, cursor); // we have a newline at cursor+linelen; print all lines that we already have in full size_t linestart = 0; while (true) { reverse_in_place(buffer + linestart, linelen); if (linestart + linelen < cap && buffer[linestart + linelen] == '\n') { size_t nw = fwrite(buffer + linestart, 1, linelen + 1, stdout); if (nw < linelen + 1) exit(1); } else { size_t nw = fwrite(buffer + linestart, 1, linelen, stdout); if (nw < linelen) exit(1); putchar('\n'); // no newline in the buffer but nevertheless a completed line means that input is at EOF goto cleanup; } linestart += linelen + 1; char *p = memchr(buffer + linestart, '\n', cursor - linestart); if (p == NULL) { DEBUG("no more newlines, moving back from %zu len %zu\n", linestart, cursor - linestart); // move back whatever we have left memmove(buffer, buffer + linestart, cursor - linestart); cursor -= linestart; break; } linelen = p - (buffer + linestart); DEBUG("next line from %zu len %zu\n", linestart, linelen); } } cleanup: free(buffer); } int entry_omd(int argc, char **argv) { char **args = parse_options(argc, argv); if (*args == NULL) { process(NULL, stdin); } else { while (*args != NULL) { FILE *f = fopen(*args, "r"); if (!f) { fprintf(stderr, "omd: Kon bestand '%s' niet openen\n", *args); return 1; } process(*args, f); fclose(f); args++; } } return 0; }