#include #include #include #include #include #include "util/map.h" #include "util/versie.h" static void usage(FILE *f) { fprintf(f, "Gebruik: tak [-hV] \n" "\n" "Schakel bestanden aaneen naar standaard uitvoer omgekeerd.\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, "tak"); exit(0); case '?': usage(stderr); exit(1); } } return argv + optind; } struct state { char *buf; size_t sz; }; static void process(struct state state) { char *lstart, *lend; lend = &state.buf[state.sz - 1]; while (lend > state.buf) { if (*lend == '\n') { lend--; } lstart = lend; while (*lstart != '\n' && lstart != state.buf) { lstart--; } if (lstart != state.buf) { lstart++; } fwrite(lstart, 1, lend - lstart + 2, stdout); lend = lstart-1; } } #define CHECK_OOM(ptr) \ if (ptr == NULL) { \ fprintf(stderr, "tak: geheugen is op"); \ /* I think I should free the original memory here, but whatever */ \ return NULL; \ } static char *read_stream(FILE *stream, size_t *sz) { *sz = 0; size_t cap = 4096; char *res = malloc(cap); CHECK_OOM(res); while (!feof(stream)) { if (cap-*sz == 0) { cap *= 2; res = realloc(res, cap); CHECK_OOM(res); } const size_t amount = cap-*sz; const size_t n = fread(res+*sz, 1, amount, stream); *sz += n; if (n != amount && !feof(stream)) { fprintf(stderr, "tak: fout tijdens lezen van standaard invoer.\n"); free(res); return NULL; } } res = realloc(res, *sz); return res; } int handleStream(FILE *stream) { size_t sz = 0; char *data = read_stream(stream, &sz); if (data == NULL) { return 1; } struct state state = { .buf = data, .sz = sz }; process(state); free(data); return 0; } int handleFile(char *fname) { struct map *map = open_map(fname); if (map == NULL) { return 1; } struct state state = { .buf = map->addr, .sz = map->sb.st_size }; process(state); close_map(map); return 0; } int entry_tak(int argc, char **argv) { char **args = parse_options(argc, argv); if (*args == NULL) { handleStream(stdin); return 0; } while (*args != NULL) { if (!strcmp(*args, "-")) { handleStream(stdin); goto next; } if (!handleFile(*args)) { goto next; } FILE *stream = fopen(*args, "rb"); if (handleStream(stream)) { return 1; } fclose(stream); next: args++; } return 0; }