Linux wc command in C I'm working on my implementaion of the linux wc command. I finally have something that is working properly (with no options yet) but i think it needs a lot of "cleaning". I mean, i highly disrespect the "do not repeat yourself rule" and i want to hear some ideas on how can i polish this up a bit.

Here 's the code:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;getopt.h&gt;
#define BUF_SIZE 1024

typedef struct Total{ //stores the Total count of lines words and bytes
  int lines;
  int words;
  int bytes;
} Total;

Total* new_Total(int lines, int words, int bytes){ //constructor function for Total
  Total* t = (Total*)malloc(sizeof(Total));
  t-&gt;lines = lines;
  t-&gt;words = words;
  t-&gt;bytes = bytes;
  return t;
}

void updateTotal(Total *t, int lines, int words, int bytes){ //updates Total counters
  t-&gt;lines += lines;
  t-&gt;words += words;
  t-&gt;bytes += bytes;
}

void readStdin(Total* t, char c){ //reads from stdin, counts and prints
  int lines = 0, words = 0, bytes = 0, startWord = 0;
  char ch;
  while((ch=fgetc(stdin)) != EOF){//count the bytes, lines and words
    bytes++;
    if (ch == '\n'){
      lines++;
    }
    if (ch != ' ' &amp;&amp; ch != '\n' &amp;&amp; ch != '\r' &amp;&amp; ch != '\t'){ //if there's a visible char, there's a word
      startWord = 1;
    }
    if ((ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t') &amp;&amp; startWord == 1){ //when the word ends
      words++; //increment the word coutner
      startWord = 0; //reset word finder
    }
  }
  updateTotal(t, lines, words, bytes);
  if (c == '\0'){ //if the command was called with no arguments
    printf ("%d %d %d\n", lines, words, bytes);
  }
  else{
    printf ("%d %d %d %c\n", lines, words, bytes, c);
  }
}

void readFile(Total *t, char* filename, FILE* fp){
  int lines = 0, words = 0, bytes = 0, startWord = 0;
  char ch;
  if (fp == NULL){
    printf("%s: No such file or drectory\n", filename);
    exit(1);
  }
  while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
    bytes++;
    if (ch == '\n'){
      lines++;
    }
    if (ch != ' ' &amp;&amp; ch != '\n' &amp;&amp; ch != '\r' &amp;&amp; ch != '\t'){
      startWord = 1;
    }
    if ((ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t') &amp;&amp; startWord == 1){
      words++;
      startWord = 0;
    }
  }
  updateTotal(t, lines, words, bytes);
  printf("%d %d %d %s\n", lines, words, bytes, filename);
}

void readArgs(Total* t, int argc, char* argv[]){
  FILE* fp;
  for (int i=1; i&lt;argc; i++){
    if (*argv[i] == '-'){//if a '-' is found, read from stdin
      readStdin(t, '-');
      clearerr(stdin);
    }
    else { //tries to read the file in argv[i]
      fp = fopen(argv[i], "r");
      readFile(t, argv[i], fp);
      fclose(fp);
    }
  }
  if (argc &gt; 2){ //if there's more than one file, print the total in the end
    printf("%d %d %d total\n", t-&gt;lines, t-&gt;words, t-&gt;bytes);
  }
  else {
    exit(0);
  }
}

int main(int argc, char* argv[]){
  Total* t = new_Total(0,0,0);
  if (argc&lt;2){ //no arguments
    readStdin(t,'\0'); //pass /0 to readstin because as it is the only time it is called, there's no need to append the name of the argument
    return 0;
  }
  readArgs(t, argc, argv);
  free(t);
  return 0;
}


As you can see, both in readStdin() and in readFile() i have the same piece of code that handles the counting. I've tried to make a function out of this using pointers but i gave up. Any suggestion would be much appreciated. Also, if you have any hint that has nothing to do with the problem that i mentioned, shoot it up!
A standard way to do this is to break the function up into smaller 'private' (static) functions, each with one thing to do. One can pass the default to the counting function in case we are not provided the argument. This allows separation of the code which counts and the UI.

Total is always going to be called with (0, 0, 0), it's unnecessary to provide these arguments. In fact, the storage of Total in dynamic memory is probably unnecessary. No need to updateTotal, use of the counters directly is fine. In fact, there is going to be 1 total, might as well make it static.

fgetc returns an int, char ch is not enough to tell EOF, which is -1. You've defined BUF_SIZE, an excellent optimization, but never use it. I'd go from fgetc to fgets. Note that this assumes that the file is text and doesn't contain a '\0' inside, (eg, modified UTF-8.)

You've included getopt and unistd, making your code POSIX C99, but you're not using those. Removing them makes your code more general C99 (now your code will compile on more compilers.)

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;errno.h&gt;

//stores the Total count of lines words and bytes
struct Total {
    size_t lines, words, bytes;
} total;

//count the bytes, lines and words
//gives incorrect results on binary files with embedded 0
//a word is delimited by everything that {isgraph}
//using the unix definition of a text file, {lines = count('\n')}
static int readFile(FILE *fp) {
    char buffer[1024], b;
    int startWord = 1;
    size_t i;
    while(fgets(buffer, (int)sizeof buffer, fp)) {
        i = 0;
        do {
            b = buffer[i++];
            if(b == '\n') {
                /* This will not recognize '\l' in old Mac text files opened
                 with "wb"? Hmm. */
                total.lines++;
                startWord = 1;
            } else if(b == '\0') {
                break;
            } else if(isgraph(b)) {
                //if there's a visible char, there's a word
                if(startWord) total.words++, startWord = 0;
            } else {
                startWord = 1;
            }
        } while(1);
        total.bytes += i;
    }
    return ferror(fp) ? 0 : 1;
}

int main(int argc, char *argv[]) {
    FILE *fp = 0;
    char *fn = "&lt;no file&gt;";
    for(int i = 1; i &lt; argc; i++) {
        fn = argv[i];
        fp = fopen(fn, "r");
        if(!fp || !readFile(fp)) break;
        fclose(fp), fp = 0;
    }
    if(argc &lt;= 1) readFile(stdin);
    if(fp) fclose(fp);
    if(errno) return perror(fn), EXIT_FAILURE;
    /* https://stackoverflow.com/a/2524675/2472827 */
    printf("%zu lines; %zu words; %zu bytes total.\n",
        total.lines, total.words, total.bytes);
    return EXIT_SUCCESS;
}


Some see typedef struct as problematic, and, in my opinion, it's not needed here; see Linux kernel coding style. INT_MAX could be as little as 32,767; it's never going to be less than zero, so I'd prefer unsigned, or size_t in this context. What if there are other chars besides '\n', ' ', '\r', '\t'? I've included &lt;ctype.h&gt; to get rid of the ambiguity. There was a bug counting the word at the end of the line. Now, a line is defined as the number of '\n' (UNIX style.) A word is delimited by isgraph.