Search code examples
cscanfstdingetlinefileinputstream

Read lines from an input file of varying line sizes


Currently, I am using getline to read lines from a file and I can access individual characters the following way from stdin:

char buffer[1024];
while((lineSize = getline(&line, &len, stdin)) != -1) {
            if (line[0] != 84) {
                // ...
                continue; // continue to next line in file
            }
            if (line[0] == 84){ // (the 'T' character)
                printf("TEST: Line Value: %s\n", line);
                buffer[0] = line[1]; // this is a single digit number in char form
                buffer[1] = '\0';
                // send buffer somewhere
                send(clientSocket, buffer, strlen(buffer), 0);
                // ...
}

A sample file is as follows:

T3
T9
S0
S4
T55
T6

However, as you can see, I run into issues when a number > 9 is given such as the T55 line here. I can only grab the first digit with this method. Therefore, I may have to completely redo the way I read a file. Is there a better and simple way I can read through an input file and check the first character and make the remaining character(s) into an int until the end of a line? (Max the integer can be is 100 btw)


Solution

  • Continuing from my comments, you can use fgets() to read line and then use sscanf() with the format string of " %c%d%n" to extract the first character and converting the next set of digits to an int and finally obtaining to total number of characters consumed by sscanf() in that conversion using the "%n" specifier. You validate that both the character and integer conversion took place and that the first non-whitespace character read was 'T'. You can then use mychar and myint as desired and use mylen as the length to use with send.

    (note: you can scan forward in line to determine if any whitespace was included at the beginning and ignore than in your call to send() -- that is left to you)

    Putting it altogether, you can so something like:

      char line[1024],
           mychar = 0;
      int myint = 0,
          mylen;
      
      /* read using fgets */
      while (fgets (line, sizeof line, stdin)) {
        /* parse with sscanf, validate both conversions and 'T' as 1st char,
         * use "%n" to get number of chars through int conversion
         */
        if (sscanf (line, " %c%d%n", &mychar, &myint, &mylen) != 2 || 
                    mychar != 'T') {
          fputs ("error: invalid format.\n", stderr);
          continue;
        }
        
        send (clientSocket, line, mylen, 0);    /* send mylen chars */
      }
    

    To be more specific, I will need to see your Minimal Complete Reproducible Example to ensure there is nothing outside what you have posted that will impact the code above.


    Adding Example

    Adding a short example to show the result of parsing under expected and unexpected input with the above, and adding the scanning forward to remove leading whitespace in the line, a short program that reads input from stdin and writes to stdout, outputting the lines matching 'T'(int), you could do:

    #include <stdio.h>
    #include <unistd.h>
    #include <ctype.h>
    
    int main (void) {
    
      char line[1024],
           mychar = 0,
           nl = '\n';
      int myint = 0,
          mylen;
      
      /* read using fgets */
      while (fgets (line, sizeof line, stdin)) {
        char *p = line;
        /* parse with sscanf, validate both conversions and 'T' as 1st char,
         * use "%n" to get number of chars through int conversion
         */
        if (sscanf (line, " %c%d%n", &mychar, &myint, &mylen) != 2 || 
            mychar != 'T') {
          fprintf (stderr, "error: invalid format: %s", line);
          continue;
        }
        
        while (isspace (*p)) {    /* reamove leading whitespace */
          p += 1;
          mylen -= 1;
        }
        
        // send (clientSocket, p, mylen, 0);    /* send mylen chars */
        write (STDOUT_FILENO, p, mylen);
        write (STDOUT_FILENO, &nl, 1);
      }
    }
    

    (note: write (STDOUT_FILENO, &nl, 1); is simply included above to output a newline after each output -- it would not be part of what you send() over your socket -- unless the receiving program is using the '\n' as the line termination character)

    Example Input File:

    $ cat dat/charint.txt
    T4
    T44
    T444
     TT
     T3 and more gibberish
    P55
    

    (note: leading whitespace and trailing characters included in last two lines beginning with 'T', including the invalid line format " TT")

    Example Use/Output

    $ ./bin/charandintsend < dat/charint.txt
    T4
    T44
    T444
    error: invalid format:  TT
    T3
    error: invalid format: P55
    

    Let me know if you have questions, or if I misunderstood some aspect of your question.