Linux wc command in C





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







2












$begingroup$


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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#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->lines = lines;
t->words = words;
t->bytes = bytes;
return t;
}

void updateTotal(Total *t, int lines, int words, int bytes){ //updates Total counters
t->lines += lines;
t->words += words;
t->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 != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
startWord = 1;
}
if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){ //when the word ends
words++; //increment the word coutner
startWord = 0; //reset word finder
}
}
updateTotal(t, lines, words, bytes);
if (c == ''){ //if the command was called with no arguments
printf ("%d %d %dn", lines, words, bytes);
}
else{
printf ("%d %d %d %cn", 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 drectoryn", filename);
exit(1);
}
while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
bytes++;
if (ch == 'n'){
lines++;
}
if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){
startWord = 1;
}
if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){
words++;
startWord = 0;
}
}
updateTotal(t, lines, words, bytes);
printf("%d %d %d %sn", lines, words, bytes, filename);
}

void readArgs(Total* t, int argc, char* argv){
FILE* fp;
for (int i=1; i<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 > 2){ //if there's more than one file, print the total in the end
printf("%d %d %d totaln", t->lines, t->words, t->bytes);
}
else {
exit(0);
}
}

int main(int argc, char* argv){
Total* t = new_Total(0,0,0);
if (argc<2){ //no arguments
readStdin(t,''); //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!










share|improve this question









New contributor




userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$



















    2












    $begingroup$


    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 <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <getopt.h>
    #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->lines = lines;
    t->words = words;
    t->bytes = bytes;
    return t;
    }

    void updateTotal(Total *t, int lines, int words, int bytes){ //updates Total counters
    t->lines += lines;
    t->words += words;
    t->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 != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
    startWord = 1;
    }
    if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){ //when the word ends
    words++; //increment the word coutner
    startWord = 0; //reset word finder
    }
    }
    updateTotal(t, lines, words, bytes);
    if (c == ''){ //if the command was called with no arguments
    printf ("%d %d %dn", lines, words, bytes);
    }
    else{
    printf ("%d %d %d %cn", 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 drectoryn", filename);
    exit(1);
    }
    while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
    bytes++;
    if (ch == 'n'){
    lines++;
    }
    if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){
    startWord = 1;
    }
    if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){
    words++;
    startWord = 0;
    }
    }
    updateTotal(t, lines, words, bytes);
    printf("%d %d %d %sn", lines, words, bytes, filename);
    }

    void readArgs(Total* t, int argc, char* argv){
    FILE* fp;
    for (int i=1; i<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 > 2){ //if there's more than one file, print the total in the end
    printf("%d %d %d totaln", t->lines, t->words, t->bytes);
    }
    else {
    exit(0);
    }
    }

    int main(int argc, char* argv){
    Total* t = new_Total(0,0,0);
    if (argc<2){ //no arguments
    readStdin(t,''); //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!










    share|improve this question









    New contributor




    userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$















      2












      2








      2


      1



      $begingroup$


      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 <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <getopt.h>
      #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->lines = lines;
      t->words = words;
      t->bytes = bytes;
      return t;
      }

      void updateTotal(Total *t, int lines, int words, int bytes){ //updates Total counters
      t->lines += lines;
      t->words += words;
      t->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 != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
      startWord = 1;
      }
      if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){ //when the word ends
      words++; //increment the word coutner
      startWord = 0; //reset word finder
      }
      }
      updateTotal(t, lines, words, bytes);
      if (c == ''){ //if the command was called with no arguments
      printf ("%d %d %dn", lines, words, bytes);
      }
      else{
      printf ("%d %d %d %cn", 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 drectoryn", filename);
      exit(1);
      }
      while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
      bytes++;
      if (ch == 'n'){
      lines++;
      }
      if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){
      startWord = 1;
      }
      if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){
      words++;
      startWord = 0;
      }
      }
      updateTotal(t, lines, words, bytes);
      printf("%d %d %d %sn", lines, words, bytes, filename);
      }

      void readArgs(Total* t, int argc, char* argv){
      FILE* fp;
      for (int i=1; i<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 > 2){ //if there's more than one file, print the total in the end
      printf("%d %d %d totaln", t->lines, t->words, t->bytes);
      }
      else {
      exit(0);
      }
      }

      int main(int argc, char* argv){
      Total* t = new_Total(0,0,0);
      if (argc<2){ //no arguments
      readStdin(t,''); //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!










      share|improve this question









      New contributor




      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      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 <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <getopt.h>
      #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->lines = lines;
      t->words = words;
      t->bytes = bytes;
      return t;
      }

      void updateTotal(Total *t, int lines, int words, int bytes){ //updates Total counters
      t->lines += lines;
      t->words += words;
      t->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 != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
      startWord = 1;
      }
      if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){ //when the word ends
      words++; //increment the word coutner
      startWord = 0; //reset word finder
      }
      }
      updateTotal(t, lines, words, bytes);
      if (c == ''){ //if the command was called with no arguments
      printf ("%d %d %dn", lines, words, bytes);
      }
      else{
      printf ("%d %d %d %cn", 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 drectoryn", filename);
      exit(1);
      }
      while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
      bytes++;
      if (ch == 'n'){
      lines++;
      }
      if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){
      startWord = 1;
      }
      if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && startWord == 1){
      words++;
      startWord = 0;
      }
      }
      updateTotal(t, lines, words, bytes);
      printf("%d %d %d %sn", lines, words, bytes, filename);
      }

      void readArgs(Total* t, int argc, char* argv){
      FILE* fp;
      for (int i=1; i<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 > 2){ //if there's more than one file, print the total in the end
      printf("%d %d %d totaln", t->lines, t->words, t->bytes);
      }
      else {
      exit(0);
      }
      }

      int main(int argc, char* argv){
      Total* t = new_Total(0,0,0);
      if (argc<2){ //no arguments
      readStdin(t,''); //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!







      c strings reinventing-the-wheel io






      share|improve this question









      New contributor




      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 57 mins ago









      200_success

      131k17157422




      131k17157422






      New contributor




      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 6 hours ago









      userUSeruseruserUSeruser

      434




      434




      New contributor




      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          2 Answers
          2






          active

          oldest

          votes


















          2












          $begingroup$

          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 '' 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 <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          #include <ctype.h>
          #include <errno.h>

          //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 == '') {
          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 = "<no file>";
          for(int i = 1; i < argc; i++) {
          fn = argv[i];
          fp = fopen(fn, "r");
          if(!fp || !readFile(fp)) break;
          fclose(fp), fp = 0;
          }
          if(argc <= 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 <ctype.h> 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.






          share|improve this answer











          $endgroup$





















            0












            $begingroup$

            Well, i actually did it on my own so, if anyone's interested, here's the code:



            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            #include <unistd.h>
            #include <getopt.h>
            #define BUF_SIZE 1024

            typedef struct Counter{ //stores the count of lines, words, bytes and the value of starword
            int lines;
            int words;
            int bytes;
            int wordFlag; //when counting words, if one is found, set to 1. when digested, reset.
            } Counter;

            Counter* new_Counter(int lines, int words, int bytes, int wordFlag){ //constructor function for Counter
            Counter* t = (Counter*)malloc(sizeof(Counter));
            t->lines = lines;
            t->words = words;
            t->bytes = bytes;
            t->wordFlag = wordFlag;
            return t;
            }

            void updateTotal(Counter *t, int lines, int words, int bytes){ //updates the total counter
            t->lines += lines;
            t->words += words;
            t->bytes += bytes;
            }

            void count(char ch, Counter* cnt){//counts the bytes, lines and words
            cnt->bytes++; //if a char is passed, count it
            if (ch == 'n'){ //count each line
            cnt->lines++;
            }
            if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
            cnt->wordFlag = 1;
            }
            if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && cnt->wordFlag == 1){ //when the word ends
            cnt->words++; //increment the word counter
            cnt->wordFlag = 0; //reset the flag
            }
            }

            void readStdin(Counter* t, char c){ //reads from stdin and prints
            Counter* cnt = new_Counter(0,0,0,0);
            char ch;
            while((ch=fgetc(stdin)) != EOF){
            count(ch, cnt);
            }
            updateTotal(t, cnt->lines, cnt->words, cnt->bytes);

            if (c == ''){ //if the command was called with no arguments
            printf ("%d %d %dn", cnt->lines, cnt->words, cnt->bytes);
            }
            else{
            printf ("%d %d %d %cn", cnt->lines, cnt->words, cnt->bytes, c);
            }
            free(cnt);
            }

            void readFile(Counter *t, char* filename, FILE* fp){
            Counter* cnt = new_Counter(0,0,0,0);
            char ch;
            if (fp == NULL){
            fprintf(stderr, "./my_wc: %s: No such file or directoryn", filename);
            exit(1);
            }
            while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
            count(ch, cnt);
            }
            updateTotal(t, cnt->lines, cnt->words, cnt->bytes);
            printf("%d %d %d %sn", cnt->lines, cnt->words, cnt->bytes, filename);
            }

            void readArgs(Counter* t, int argc, char* argv){
            FILE* fp;
            for (int i=1; i<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 > 2){ //if there's more than one file, print the Counter in the end
            printf("%d %d %d totaln", t->lines, t->words, t->bytes);
            }
            else {
            exit(0);
            }
            }

            int main(int argc, char* argv){
            Counter* t = new_Counter(0,0,0,0); //pointer to the total counter
            if (argc<2){ //no arguments
            readStdin(t,''); //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, i renamed the struct to Counter and i used it to store, not only the total counter, but also every temporary counter, then i implemented the function count() that does with the temporary counter values what those if statements in readStdin and readFile do.
            If you still have any suggestions, please do not hesitate.






            share|improve this answer










            New contributor




            userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
            Check out our Code of Conduct.






            $endgroup$














              Your Answer





              StackExchange.ifUsing("editor", function () {
              return StackExchange.using("mathjaxEditing", function () {
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              });
              });
              }, "mathjax-editing");

              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "196"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });






              userUSeruser is a new contributor. Be nice, and check out our Code of Conduct.










              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217099%2flinux-wc-command-in-c%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              2












              $begingroup$

              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 '' 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 <stdio.h>
              #include <stdlib.h>
              #include <string.h>
              #include <ctype.h>
              #include <errno.h>

              //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 == '') {
              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 = "<no file>";
              for(int i = 1; i < argc; i++) {
              fn = argv[i];
              fp = fopen(fn, "r");
              if(!fp || !readFile(fp)) break;
              fclose(fp), fp = 0;
              }
              if(argc <= 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 <ctype.h> 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.






              share|improve this answer











              $endgroup$


















                2












                $begingroup$

                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 '' 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 <stdio.h>
                #include <stdlib.h>
                #include <string.h>
                #include <ctype.h>
                #include <errno.h>

                //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 == '') {
                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 = "<no file>";
                for(int i = 1; i < argc; i++) {
                fn = argv[i];
                fp = fopen(fn, "r");
                if(!fp || !readFile(fp)) break;
                fclose(fp), fp = 0;
                }
                if(argc <= 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 <ctype.h> 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.






                share|improve this answer











                $endgroup$
















                  2












                  2








                  2





                  $begingroup$

                  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 '' 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 <stdio.h>
                  #include <stdlib.h>
                  #include <string.h>
                  #include <ctype.h>
                  #include <errno.h>

                  //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 == '') {
                  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 = "<no file>";
                  for(int i = 1; i < argc; i++) {
                  fn = argv[i];
                  fp = fopen(fn, "r");
                  if(!fp || !readFile(fp)) break;
                  fclose(fp), fp = 0;
                  }
                  if(argc <= 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 <ctype.h> 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.






                  share|improve this answer











                  $endgroup$



                  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 '' 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 <stdio.h>
                  #include <stdlib.h>
                  #include <string.h>
                  #include <ctype.h>
                  #include <errno.h>

                  //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 == '') {
                  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 = "<no file>";
                  for(int i = 1; i < argc; i++) {
                  fn = argv[i];
                  fp = fopen(fn, "r");
                  if(!fp || !readFile(fp)) break;
                  fclose(fp), fp = 0;
                  }
                  if(argc <= 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 <ctype.h> 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.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 2 hours ago

























                  answered 3 hours ago









                  Neil EdelmanNeil Edelman

                  337110




                  337110

























                      0












                      $begingroup$

                      Well, i actually did it on my own so, if anyone's interested, here's the code:



                      #include <stdio.h>
                      #include <stdlib.h>
                      #include <string.h>
                      #include <unistd.h>
                      #include <getopt.h>
                      #define BUF_SIZE 1024

                      typedef struct Counter{ //stores the count of lines, words, bytes and the value of starword
                      int lines;
                      int words;
                      int bytes;
                      int wordFlag; //when counting words, if one is found, set to 1. when digested, reset.
                      } Counter;

                      Counter* new_Counter(int lines, int words, int bytes, int wordFlag){ //constructor function for Counter
                      Counter* t = (Counter*)malloc(sizeof(Counter));
                      t->lines = lines;
                      t->words = words;
                      t->bytes = bytes;
                      t->wordFlag = wordFlag;
                      return t;
                      }

                      void updateTotal(Counter *t, int lines, int words, int bytes){ //updates the total counter
                      t->lines += lines;
                      t->words += words;
                      t->bytes += bytes;
                      }

                      void count(char ch, Counter* cnt){//counts the bytes, lines and words
                      cnt->bytes++; //if a char is passed, count it
                      if (ch == 'n'){ //count each line
                      cnt->lines++;
                      }
                      if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
                      cnt->wordFlag = 1;
                      }
                      if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && cnt->wordFlag == 1){ //when the word ends
                      cnt->words++; //increment the word counter
                      cnt->wordFlag = 0; //reset the flag
                      }
                      }

                      void readStdin(Counter* t, char c){ //reads from stdin and prints
                      Counter* cnt = new_Counter(0,0,0,0);
                      char ch;
                      while((ch=fgetc(stdin)) != EOF){
                      count(ch, cnt);
                      }
                      updateTotal(t, cnt->lines, cnt->words, cnt->bytes);

                      if (c == ''){ //if the command was called with no arguments
                      printf ("%d %d %dn", cnt->lines, cnt->words, cnt->bytes);
                      }
                      else{
                      printf ("%d %d %d %cn", cnt->lines, cnt->words, cnt->bytes, c);
                      }
                      free(cnt);
                      }

                      void readFile(Counter *t, char* filename, FILE* fp){
                      Counter* cnt = new_Counter(0,0,0,0);
                      char ch;
                      if (fp == NULL){
                      fprintf(stderr, "./my_wc: %s: No such file or directoryn", filename);
                      exit(1);
                      }
                      while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
                      count(ch, cnt);
                      }
                      updateTotal(t, cnt->lines, cnt->words, cnt->bytes);
                      printf("%d %d %d %sn", cnt->lines, cnt->words, cnt->bytes, filename);
                      }

                      void readArgs(Counter* t, int argc, char* argv){
                      FILE* fp;
                      for (int i=1; i<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 > 2){ //if there's more than one file, print the Counter in the end
                      printf("%d %d %d totaln", t->lines, t->words, t->bytes);
                      }
                      else {
                      exit(0);
                      }
                      }

                      int main(int argc, char* argv){
                      Counter* t = new_Counter(0,0,0,0); //pointer to the total counter
                      if (argc<2){ //no arguments
                      readStdin(t,''); //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, i renamed the struct to Counter and i used it to store, not only the total counter, but also every temporary counter, then i implemented the function count() that does with the temporary counter values what those if statements in readStdin and readFile do.
                      If you still have any suggestions, please do not hesitate.






                      share|improve this answer










                      New contributor




                      userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                      Check out our Code of Conduct.






                      $endgroup$


















                        0












                        $begingroup$

                        Well, i actually did it on my own so, if anyone's interested, here's the code:



                        #include <stdio.h>
                        #include <stdlib.h>
                        #include <string.h>
                        #include <unistd.h>
                        #include <getopt.h>
                        #define BUF_SIZE 1024

                        typedef struct Counter{ //stores the count of lines, words, bytes and the value of starword
                        int lines;
                        int words;
                        int bytes;
                        int wordFlag; //when counting words, if one is found, set to 1. when digested, reset.
                        } Counter;

                        Counter* new_Counter(int lines, int words, int bytes, int wordFlag){ //constructor function for Counter
                        Counter* t = (Counter*)malloc(sizeof(Counter));
                        t->lines = lines;
                        t->words = words;
                        t->bytes = bytes;
                        t->wordFlag = wordFlag;
                        return t;
                        }

                        void updateTotal(Counter *t, int lines, int words, int bytes){ //updates the total counter
                        t->lines += lines;
                        t->words += words;
                        t->bytes += bytes;
                        }

                        void count(char ch, Counter* cnt){//counts the bytes, lines and words
                        cnt->bytes++; //if a char is passed, count it
                        if (ch == 'n'){ //count each line
                        cnt->lines++;
                        }
                        if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
                        cnt->wordFlag = 1;
                        }
                        if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && cnt->wordFlag == 1){ //when the word ends
                        cnt->words++; //increment the word counter
                        cnt->wordFlag = 0; //reset the flag
                        }
                        }

                        void readStdin(Counter* t, char c){ //reads from stdin and prints
                        Counter* cnt = new_Counter(0,0,0,0);
                        char ch;
                        while((ch=fgetc(stdin)) != EOF){
                        count(ch, cnt);
                        }
                        updateTotal(t, cnt->lines, cnt->words, cnt->bytes);

                        if (c == ''){ //if the command was called with no arguments
                        printf ("%d %d %dn", cnt->lines, cnt->words, cnt->bytes);
                        }
                        else{
                        printf ("%d %d %d %cn", cnt->lines, cnt->words, cnt->bytes, c);
                        }
                        free(cnt);
                        }

                        void readFile(Counter *t, char* filename, FILE* fp){
                        Counter* cnt = new_Counter(0,0,0,0);
                        char ch;
                        if (fp == NULL){
                        fprintf(stderr, "./my_wc: %s: No such file or directoryn", filename);
                        exit(1);
                        }
                        while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
                        count(ch, cnt);
                        }
                        updateTotal(t, cnt->lines, cnt->words, cnt->bytes);
                        printf("%d %d %d %sn", cnt->lines, cnt->words, cnt->bytes, filename);
                        }

                        void readArgs(Counter* t, int argc, char* argv){
                        FILE* fp;
                        for (int i=1; i<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 > 2){ //if there's more than one file, print the Counter in the end
                        printf("%d %d %d totaln", t->lines, t->words, t->bytes);
                        }
                        else {
                        exit(0);
                        }
                        }

                        int main(int argc, char* argv){
                        Counter* t = new_Counter(0,0,0,0); //pointer to the total counter
                        if (argc<2){ //no arguments
                        readStdin(t,''); //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, i renamed the struct to Counter and i used it to store, not only the total counter, but also every temporary counter, then i implemented the function count() that does with the temporary counter values what those if statements in readStdin and readFile do.
                        If you still have any suggestions, please do not hesitate.






                        share|improve this answer










                        New contributor




                        userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.






                        $endgroup$
















                          0












                          0








                          0





                          $begingroup$

                          Well, i actually did it on my own so, if anyone's interested, here's the code:



                          #include <stdio.h>
                          #include <stdlib.h>
                          #include <string.h>
                          #include <unistd.h>
                          #include <getopt.h>
                          #define BUF_SIZE 1024

                          typedef struct Counter{ //stores the count of lines, words, bytes and the value of starword
                          int lines;
                          int words;
                          int bytes;
                          int wordFlag; //when counting words, if one is found, set to 1. when digested, reset.
                          } Counter;

                          Counter* new_Counter(int lines, int words, int bytes, int wordFlag){ //constructor function for Counter
                          Counter* t = (Counter*)malloc(sizeof(Counter));
                          t->lines = lines;
                          t->words = words;
                          t->bytes = bytes;
                          t->wordFlag = wordFlag;
                          return t;
                          }

                          void updateTotal(Counter *t, int lines, int words, int bytes){ //updates the total counter
                          t->lines += lines;
                          t->words += words;
                          t->bytes += bytes;
                          }

                          void count(char ch, Counter* cnt){//counts the bytes, lines and words
                          cnt->bytes++; //if a char is passed, count it
                          if (ch == 'n'){ //count each line
                          cnt->lines++;
                          }
                          if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
                          cnt->wordFlag = 1;
                          }
                          if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && cnt->wordFlag == 1){ //when the word ends
                          cnt->words++; //increment the word counter
                          cnt->wordFlag = 0; //reset the flag
                          }
                          }

                          void readStdin(Counter* t, char c){ //reads from stdin and prints
                          Counter* cnt = new_Counter(0,0,0,0);
                          char ch;
                          while((ch=fgetc(stdin)) != EOF){
                          count(ch, cnt);
                          }
                          updateTotal(t, cnt->lines, cnt->words, cnt->bytes);

                          if (c == ''){ //if the command was called with no arguments
                          printf ("%d %d %dn", cnt->lines, cnt->words, cnt->bytes);
                          }
                          else{
                          printf ("%d %d %d %cn", cnt->lines, cnt->words, cnt->bytes, c);
                          }
                          free(cnt);
                          }

                          void readFile(Counter *t, char* filename, FILE* fp){
                          Counter* cnt = new_Counter(0,0,0,0);
                          char ch;
                          if (fp == NULL){
                          fprintf(stderr, "./my_wc: %s: No such file or directoryn", filename);
                          exit(1);
                          }
                          while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
                          count(ch, cnt);
                          }
                          updateTotal(t, cnt->lines, cnt->words, cnt->bytes);
                          printf("%d %d %d %sn", cnt->lines, cnt->words, cnt->bytes, filename);
                          }

                          void readArgs(Counter* t, int argc, char* argv){
                          FILE* fp;
                          for (int i=1; i<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 > 2){ //if there's more than one file, print the Counter in the end
                          printf("%d %d %d totaln", t->lines, t->words, t->bytes);
                          }
                          else {
                          exit(0);
                          }
                          }

                          int main(int argc, char* argv){
                          Counter* t = new_Counter(0,0,0,0); //pointer to the total counter
                          if (argc<2){ //no arguments
                          readStdin(t,''); //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, i renamed the struct to Counter and i used it to store, not only the total counter, but also every temporary counter, then i implemented the function count() that does with the temporary counter values what those if statements in readStdin and readFile do.
                          If you still have any suggestions, please do not hesitate.






                          share|improve this answer










                          New contributor




                          userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






                          $endgroup$



                          Well, i actually did it on my own so, if anyone's interested, here's the code:



                          #include <stdio.h>
                          #include <stdlib.h>
                          #include <string.h>
                          #include <unistd.h>
                          #include <getopt.h>
                          #define BUF_SIZE 1024

                          typedef struct Counter{ //stores the count of lines, words, bytes and the value of starword
                          int lines;
                          int words;
                          int bytes;
                          int wordFlag; //when counting words, if one is found, set to 1. when digested, reset.
                          } Counter;

                          Counter* new_Counter(int lines, int words, int bytes, int wordFlag){ //constructor function for Counter
                          Counter* t = (Counter*)malloc(sizeof(Counter));
                          t->lines = lines;
                          t->words = words;
                          t->bytes = bytes;
                          t->wordFlag = wordFlag;
                          return t;
                          }

                          void updateTotal(Counter *t, int lines, int words, int bytes){ //updates the total counter
                          t->lines += lines;
                          t->words += words;
                          t->bytes += bytes;
                          }

                          void count(char ch, Counter* cnt){//counts the bytes, lines and words
                          cnt->bytes++; //if a char is passed, count it
                          if (ch == 'n'){ //count each line
                          cnt->lines++;
                          }
                          if (ch != ' ' && ch != 'n' && ch != 'r' && ch != 't'){ //if there's a visible char, there's a word
                          cnt->wordFlag = 1;
                          }
                          if ((ch == ' ' || ch == 'n' || ch == 'r' || ch == 't') && cnt->wordFlag == 1){ //when the word ends
                          cnt->words++; //increment the word counter
                          cnt->wordFlag = 0; //reset the flag
                          }
                          }

                          void readStdin(Counter* t, char c){ //reads from stdin and prints
                          Counter* cnt = new_Counter(0,0,0,0);
                          char ch;
                          while((ch=fgetc(stdin)) != EOF){
                          count(ch, cnt);
                          }
                          updateTotal(t, cnt->lines, cnt->words, cnt->bytes);

                          if (c == ''){ //if the command was called with no arguments
                          printf ("%d %d %dn", cnt->lines, cnt->words, cnt->bytes);
                          }
                          else{
                          printf ("%d %d %d %cn", cnt->lines, cnt->words, cnt->bytes, c);
                          }
                          free(cnt);
                          }

                          void readFile(Counter *t, char* filename, FILE* fp){
                          Counter* cnt = new_Counter(0,0,0,0);
                          char ch;
                          if (fp == NULL){
                          fprintf(stderr, "./my_wc: %s: No such file or directoryn", filename);
                          exit(1);
                          }
                          while ((ch=fgetc(fp)) != EOF){ //count the bytes, lines and words
                          count(ch, cnt);
                          }
                          updateTotal(t, cnt->lines, cnt->words, cnt->bytes);
                          printf("%d %d %d %sn", cnt->lines, cnt->words, cnt->bytes, filename);
                          }

                          void readArgs(Counter* t, int argc, char* argv){
                          FILE* fp;
                          for (int i=1; i<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 > 2){ //if there's more than one file, print the Counter in the end
                          printf("%d %d %d totaln", t->lines, t->words, t->bytes);
                          }
                          else {
                          exit(0);
                          }
                          }

                          int main(int argc, char* argv){
                          Counter* t = new_Counter(0,0,0,0); //pointer to the total counter
                          if (argc<2){ //no arguments
                          readStdin(t,''); //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, i renamed the struct to Counter and i used it to store, not only the total counter, but also every temporary counter, then i implemented the function count() that does with the temporary counter values what those if statements in readStdin and readFile do.
                          If you still have any suggestions, please do not hesitate.







                          share|improve this answer










                          New contributor




                          userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.









                          share|improve this answer



                          share|improve this answer








                          edited 4 hours ago





















                          New contributor




                          userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.









                          answered 4 hours ago









                          userUSeruseruserUSeruser

                          434




                          434




                          New contributor




                          userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.





                          New contributor





                          userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






                          userUSeruser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






















                              userUSeruser is a new contributor. Be nice, and check out our Code of Conduct.










                              draft saved

                              draft discarded


















                              userUSeruser is a new contributor. Be nice, and check out our Code of Conduct.













                              userUSeruser is a new contributor. Be nice, and check out our Code of Conduct.












                              userUSeruser is a new contributor. Be nice, and check out our Code of Conduct.
















                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217099%2flinux-wc-command-in-c%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Сан-Квентин

                              8-я гвардейская общевойсковая армия

                              Алькесар