Home > Blockchain >  Printing sections of a text file with C
Printing sections of a text file with C

Time:08-17

I'm looking for a solution on how to print only relevant sections from a log file where I want to display the code and its contents which spans multiple lines.

The log file is structured like this:

----- start -----
CODE: 1111

DESC: this is some descriptions
      which spans multiple lines.
-----  end  -----

----- start -----
CODE: 2222

DESC: this is some information
      for another code.
-----  end  -----

----- start -----
CODE: 1111

DESC: here is some more info
      for the code again.
-----  end  -----


What I like to achieve if to parse the log file using C, to generate a result similar to this.

----- start -----
CODE: 1111

DESC: this is some descriptions
      which spans multiple lines.
-----  end  -----

----- start -----
CODE: 1111

DESC: here is some more info
      for the code again.
-----  end  -----

I have tried various while loops reading the file into a buffer and compared the strings with strstr() etc. but haven't find any logic with if statements that works for me. I have tried to explore the use of fseek(), fgetpos(), fsetpos() etc. I have searched forums and blogs for answer that can help me forward with little success.

If anyone reading this has a solution to share or any pointer on how I should tackle this, or places to find such information would be much appreciated.

CodePudding user response:

Forget about the "---start---" to begin with. Just look for the target that means an interesting section is beginning. Then output until the "---end---" is encountered.

Here's a sample that works for the sample input you provided. Just uses fgets() until it finds the target string, sets a flag and outputs the preamble (that is given) and loops until it clears the flag. If the current line is neither the start nor the finish, output (or not) is controlled by the flag.

You can adapt this to your particular needs with passing logfile names and target string(s) through command line parameters.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

int main() {
    char buf[ 1024 ];

    FILE *ifp = fopen( "log.txt", "rt" );
    if( ifp == NULL )
        exit( EXIT_FAILURE );

    char *target = "CODE: 1111";
    char *start = "-----  start  -----";
    char *end = "-----  end  -----";
    char *blankrow = "";
    bool inRegion = false;

    while( fgets( buf, sizeof buf, ifp ) ) {
        if( inRegion && strncmp( buf, end, strlen( end ) ) == 0 ) {
            inRegion = false;
            printf( "%s", buf );
        } else if( strncmp( buf, target, strlen( target ) ) == 0 ) {
            inRegion = true;
            printf( "%s%s\n%s", blankrow, start, buf );
            blankrow = "\n";
        } else if( inRegion ) {
            printf( "%s", buf );
        }
    }
    fclose( ifp );

    return 0;
}

CodePudding user response:

In order to solve the problem, you can read until you encounter the line

----- start -----

then read the next line to see if it contains the code that you are looking for. If it does, then you output the log entry, and if it does not, then you read and ignore the rest of the log entry.

Since the end of the log entry is clearly marked with the line

-----  end  -----

you can compare every line inside the log entry with that string.

These steps should be repeated until you encounter end-of-file.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

const char  start_marker[] = "----- start -----";
const char    end_marker[] = "-----  end  -----";
const char target_string[] = "CODE: 1111";

bool read_exactly_one_line( char buffer[], int buffer_size, FILE *fp );

int main( void )
{
    //const size_t start_marker_length = sizeof start_marker - 1;
    //const size_t   end_marker_length = sizeof   end_marker - 1;

    char line[4096];
    bool should_print;

    //read log entries until end-of-file encountered
    for (;;) //infinite loop, equivalent to "while(1)"
    {
        //read until start marker encountered
        for (;;)
        {
           if ( ! read_exactly_one_line( line, sizeof line, stdin ) ) 
            {
                //we are unable to read any further lines due to
                //end-of-file, so wie have finished
                exit( EXIT_SUCCESS );
            }

            //determine whether line is empty
            if ( line[0] == '\0' )
                continue;

            //determine whether line is a start marker
            if ( strcmp( line, start_marker ) == 0 )
                break;

            //line is neither empty nor a start marker, which
            //should not occur
            fprintf( stderr, "Parse error: Unexpected input!\n" );
            exit( EXIT_FAILURE );
        }

        //read the line with the code
        if ( ! read_exactly_one_line( line, sizeof line, stdin ) )
        {
            fprintf( stderr, "Error: Encountered end-of-file inside log entry!\n" );
            exit( EXIT_FAILURE );
        }

        //determine whether the line contains the target string
        if ( strcmp( line, target_string ) == 0 )
        {
            //we should print the log entry
            should_print = true;

            //also print the part that we have already read
            printf( "%s\n%s\n", start_marker, line );
        }
        else
        {
            //do not print the remainder of the log entry
            should_print = false;
        }

        //read until end marker
        for (;;)
        {
            if ( ! read_exactly_one_line( line, sizeof line, stdin ) )
            {
                fprintf( stderr, "Error: Encountered end-of-file inside log entry!\n" );
                exit( EXIT_FAILURE );
            }

            //print the line, if appropriate
            if ( should_print )
                printf( "%s\n", line );

            //determine whether line is the end marker
            if ( strcmp( line, end_marker ) == 0 )
            {
                //add one line of spacing between next log entry
                if ( should_print )
                    printf( "\n" );

                //break out of inner infinite loop
                break;
            }
        }
    }
}

//This function will read exactly one line and remove the newline
//character, if it exists. On success, it will return true. If this
//function is unable to read any further lines due to end-of-file,
//it returns false. If it fails for any other reason, it will not
//return, but will print an error message and call "exit" instead.
bool read_exactly_one_line( char buffer[], int buffer_size, FILE *fp )
{
    char *p;

    if ( fgets( buffer, buffer_size, fp ) == NULL )
    {
        if ( ferror( fp ) )
        {
            fprintf( stderr, "Input error!\n" );
            exit( EXIT_FAILURE );
        }

        return false;
    }

    //make sure that line was not too long for input buffer
    p = strchr( buffer, '\n' );
    if ( p == NULL )
    {
        //a missing newline character is ok on end of file
        if ( !feof(fp) )
        {
            fprintf( stderr, "Line was too long for input buffer!\n" );
            exit( EXIT_FAILURE );
        }
    }
    else
    {
        //remove newline character
        *p = '\0';
    }

    return true;
}

With the input posted in the question, this program has the following output:

----- start -----
CODE: 1111

DESC: this is some descriptions
      which spans multiple lines.
-----  end  -----

----- start -----
CODE: 1111

DESC: here is some more info
      for the code again.
-----  end  -----

  •  Tags:  
  • c
  • Related