Log in Register Dashboard Temp Share Shortlinks Frames API

HTMLify

wc
Views: 86 | Author: abh
/* wc */

#define POSIX_C_SOURCE 200809L

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <unistd.h>

struct counting {
    int bytes, words, lines, chars; 
    char *filename;
};

struct args {
    bool
    all,
    bytes,
    lines,
    chars,
    words
    ;
} args = {
    true, false, false, false
};

int digit_count(int num) {
    int count = 0;
    if (!num)
        return 1;
    while (num != 0) {
        count++;
        num /= 10;
    }
    return count;
}

struct counting count_file(FILE *file, char *filename) {
    struct counting counting = { 0, 0, 0, 0, filename};
    int byte;
    bool last_space = true;
    while ((byte = getc(file)) != EOF) {
        counting.bytes++;
        if (byte == 10)
            counting.lines++;
        if (isspace((unsigned char)byte)) {
            last_space = true;
        } else {
            if (last_space)
                counting.words++;
            last_space = false;
        }
        if ((byte & 0xC0) != 0x80)
            counting.chars++;
    }
    return counting;
}

int get_span(struct counting counting) {
    int span = 1,
    dc_lines = digit_count(counting.lines),
    dc_words = digit_count(counting.words),
    dc_bytes = digit_count(counting.bytes),
    dc_chars = digit_count(counting.chars)
    ;
    if (args.all) {
        if (dc_lines > span)
            span = dc_lines;
        if (dc_words > span)
            span = dc_words;
        if (dc_bytes > span)
            span = dc_bytes;
        return span;
    }
    if (args.lines + args.words + args.bytes + args.chars == 1)
        return 0;
    if (args.lines)
        if (dc_lines > span)
            span = dc_lines;
    if (args.words)
        if (dc_words > span)
            span = dc_words;
    if (args.bytes)
        if (dc_bytes > span)
            span = dc_bytes;
    if (args.chars)
        if (dc_chars > span)
            span = dc_chars;
    return span;
}

void print_counting(struct counting counting, int span) {
    if (!span)
        span = get_span(counting);
    if (args.all) {
        printf(
            "%*d %*d %*d %s\n",
            span, counting.lines,
            span, counting.words,
            span, counting.bytes, 
            counting.filename
        );
        return;
    }
    if (args.lines)
        printf("%*d ", span, counting.lines);
    if (args.words)
        printf("%*d ", span, counting.words);
    if (args.bytes)
        printf("%*d ", span, counting.bytes);
    if (args.chars)
        printf("%*d ", span, counting.chars);
    printf("%s\n", counting.filename);
}


int main(int argc, char *argv[]) {
    struct counting count, *counts, tcount = { 0, 0, 0, 0, "total" };
    int opt, i, count_count = 0, span = 0, return_code = 0;
    bool has_stdin = false;

    while((opt = getopt(argc, argv, "cmlw")) != -1) {
        switch (opt) {
            case 'c': {
                args.all = false;
                args.bytes = true;
                args.chars = false;
                break;
            }
            case 'l': {
                args.all = false;
                args.lines = true;
                break;
            }
            case 'm': {
                args.all = false;
                args.chars = true;
                args.bytes = false;
                break;
            }
            case 'w': {
                args.all = false;
                args.words = true;
                break;
            }
            default: {
                fprintf(stderr, "Unknown option '-%c'\n", opt);
                return_code = 1;
            }
        }
    }
    argc -= optind;
    argv += optind;

    FILE *file;

    if (argc == 0) {
        struct counting count = count_file(stdin, "");
        print_counting(count, 7);
        return return_code;
    } 

    for (i=0; i<argc; i++) {
        if (!strcmp(argv[i], "-")) {
            file = stdin;
            has_stdin = true;
        } else {
            file = fopen(argv[i], "r");
        }
        if (file == NULL) {
            fprintf(stderr, "wc: %s: No such file or directory\n", argv[i]);
            return_code = 1;
            continue;
        }
        count = count_file(file, argv[i]);
        tcount.bytes += count.bytes;
        tcount.chars += count.chars;
        tcount.words += count.words;
        tcount.lines += count.lines;
        if (get_span(count) > span)
            span = get_span(count);
        counts = realloc(counts, (count_count+1)*sizeof(struct counting));
        counts[count_count] = count;
        count_count++;
    }

    if (argc > 1)
        if (get_span(tcount) > span)
            span = get_span(tcount);

    if (has_stdin)
        span = 7;

    for (i=0; i<count_count; i++) {
        print_counting(counts[i], span);
    }
    if (argc>1)
        print_counting(tcount, span);

    return return_code;
}

Comments