#include #include #include #include #include #include #include #include #include #include #include #include #include "util/debug.h" #include "util/error.h" #include "util/loop_args.h" #include "util/map.h" #include "util/versie.h" #include "io/read_file.h" static int modeMap; static void usage(FILE *f) { fprintf(f, "Gebruik: toilet [-nchV] [BESTAND]...\n" "\n" "Toon de hoeveelheid regels, woorden en beten for elk BESTAND\n" "\n" " -c Geef het aantal beten weer\n" " -w Geef het aantal woorden weer\n" " -l Geef het aantal regels weer\n" " -h Toon deze hulptekst\n" " -V Toon versienummer\n"); } enum MODE { M_LINES = 1 << 0, M_WORDS = 1 << 1, M_BYTES = 1 << 2, }; // Returns pointer to argument array containing the file names static char** parse_options(int argc, char **argv, int *modeMap) { int opt; while ((opt = getopt(argc, argv, "cwlhV")) != -1) { switch (opt) { case 'c': *modeMap |= M_BYTES; break; case 'w': *modeMap |= M_WORDS; break; case 'l': *modeMap |= M_LINES; break; case 'h': usage(stdout); exit(0); case 'V': drukkedoos_print_versie(stdout); exit(0); case '?': fprintf(stderr, "toilet: Ongeldige optie: -%c\n", optopt); usage(stderr); exit(1); } } return argv + optind; } static size_t count_lines(char *fname, FILE *f) { size_t nlines = 0; { char *line = NULL; size_t linen = 0; while ((errno = 0, getline(&line, &linen, f)) != -1) { nlines++; } free(line); } if (errno != 0) { printf("toilet: fout bij lezen uit bestand '%s'\n", fname); exit(1); } rewind(f); return nlines; } static size_t count_words(FILE *f) { #define BUF_SIZE 4096 size_t nwords = 0; static char buf[BUF_SIZE]; while (!feof(f)) { const size_t n = fread(buf, 1, BUF_SIZE, f); #define IN(i) (i < n) for (size_t i = 0; IN(i);) { size_t previ = i; while (IN(i) && !isspace(buf[i])) i++; nwords += i != previ; while (IN(i) && isspace(buf[i])) i++; } #undef IN } rewind(f); return nwords; #undef BUF_SIZE } static size_t get_count(enum MODE mode, char *fname, FILE *f) { switch (mode) { case M_BYTES: { fseek(f, 0, SEEK_END); long offset = ftell(f); rewind(f); return offset; } case M_WORDS: return count_words(f); case M_LINES: return count_lines(fname, f); default: assert(false); } } static int process(char *fname, bool isstdin) { FILE *f = isstdin ? stdin : fopen(fname, "r"); for (enum MODE mode = 1; mode <= M_BYTES; mode <<= 1) { if (mode & modeMap) { const size_t count = get_count(mode, fname, f); printf("%li ", count); } } printf("%s\n", fname); if (!isstdin) fclose(f); return 0; } int entry_toilet(int argc, char **argv) { modeMap = 0; char **args = parse_options(argc, argv, &modeMap); if (modeMap == 0) { modeMap = INT_MAX; } return loop_args(args, process); }