ela said:
Is there any similar structure in C that I can easily get the strings in a
file like:
Example file
bicycle
bus
ferry
plane
train
so I can print them generically? In Perl, I just read them into an array,
e.g. @vehicle
then get them back by foreach. Thanks for telling me if there's similar
handy function in C
Actually it is very easy in C, you just reserve a buffer of
the appropriate size and then, er, simply read the lines into
the buffer. And you're done!
My attempt follows - written in ISO/IEC 9899:1999 (E) C,
without the need for any additional libraries.
I have the impression that I made a lot of off-by-1 errors,
which I hid under some dirty hacks. There also are still some
redundancies in the code. But I do not have the time for a
code clean-up right now.
However, I would be pleased to read how to improve the
following code.
For the program to be self-contained, it first /writes/ the file
to the path »tmp.txt«.
WARNING: this will overwrite any existing file named »tmp.txt«
in the current directory.
»writelines« is used to create the file.
»getc_count« gets the size of the file to be read.
»readfile« reads the whole file into a buffer.
»getlines« fills in the array of lines.
»printlines« then prints these lines.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getc_count
( const char * const path, size_t * const result )
{ FILE * input = fopen( path, "rb" );
size_t size = 0;
int failed = 1;
int error = 0;
int overflow = 0;
if( input )
{ int ch = getc( input );
while( ch != EOF )
{ if( !++size )overflow = 1, ch = EOF;
else ch = getc( input ); }
if( ferror( input ))error = 1;
if( fclose( input )== 0 && !overflow && !error )failed = 0; }
*result = size;
return failed; }
int writelines
( char const * const path,
char const * const * const source,
size_t const n )
{ FILE * const file = fopen( path, "w" );
int result = -1;
if( file )
{ for( size_t i = 0; i < n; ++i )
if
( strlen( source[ i ])+ 1 !=
( size_t )fprintf( file, "%s\n", source[ i ]))
{ result = 2; break; }
if( fclose( file ))result = 3;
if( result == -1 )result = 0;
else result = 1; }
else result = 19;
return result; }
int readfile2
( char const * const path, char * * const buffer,
size_t * const linecount,
size_t * const size )
{ int result = -1;
char * const buff = *buffer;
char * p = buff;
size_t s = 0;
{ FILE * input = fopen( path, "r" );
if( input )
{ int ch = getc( input );
if( ch == '\n' ){ ch = 0; ++*linecount; }
if( !++s )result = 8, ch = EOF;
else if( s >= *size )result = 13, ch = EOF;
else if( ch != EOF )*p++ = ch;
while( ch != EOF )
{ ch = getc( input );
if( ch == '\n' ){ ch = 0; ++*linecount; }
if( !++s )result = 5, ch = EOF;
else if( s - 1 > *size )result = 6, ch = EOF;
else if( ch != EOF )*p++ = ch; }
if( ferror( input ))result = 7;
if( fclose( input ))result = 9;
if( result == -1 )
{ if( !++s )result = 10;
else if( s - 2 > *size )result = 11;
else
{ *p++ = 0; result = 0;
*size = p - buff; }}}
else result = 12; }
return result; }
int readfile1
( char const * const path, char * * const buffer,
size_t * const linecount,
size_t * const size )
{ int result = -1;
if( *buffer = malloc( *size + 3 ))
{ result = readfile2( path, buffer, linecount, size );
if( result )
{ free(( void * )*buffer ); *buffer = 0; }}
else result = 4;
return result; }
int readfile
( char const * const path, char * * const buffer,
size_t * const size,
size_t * const linecount )
{ int result = -1;
if( !getc_count( path, size ))
{ if( *size + 1 == 0 )result = 14;
else if( *size + 2 == 0 )result = 17;
else if( *size + 3 == 0 )result = 18;
else result = readfile1( path, buffer, linecount, size ); }
return result; }
int getlines
( char * buffer, size_t size,
char const * * * const lines, size_t linecount )
{ int result = -1;
size_t need = sizeof( char const * )* linecount;
size_t test = need / sizeof( char const * );
if( test == linecount )
{ *lines = malloc( need );
if( *lines )
{ char const * p = buffer;
int looping = 1;
size_t i = 0;
char const * * const l = *lines;
while( looping )
{ l[ i++ ]= p;
while( p < buffer + size && *p != 0 )++p;
++p;
if( p < buffer + size + 1 ); else return 15;
if( i == linecount )break; }
result = 0; }
else result = 16; }
else result = 17;
return result; }
int printlines
( size_t const linecount, char const * const * lines )
{ for( size_t i = 0; i < linecount; ++i )
printf( "%s\n", lines[ i ]);
return 0; }
int main( void )
{ char const * const source[] =
{ "bicycle", "bus", "ferry", "plane", "train" };
int const writelinesstatus = writelines
( "tmp.txt", source, sizeof source / sizeof 0[ source ]);
if( writelinesstatus )fprintf( stderr, "%d\n", writelinesstatus );
else
{ char * buffer = 0; size_t linecount = 0; size_t size = 0;
int const readfilestatus =
readfile( "tmp.txt", &buffer, &size, &linecount );
if( readfilestatus )fprintf( stderr, "%d\n", readfilestatus );
else
{ char const * * lines = 0;
int const getlinesstatus =
getlines( buffer, size, &lines, linecount );
if( getlinesstatus )fprintf( stderr, "%d\n", getlinesstatus );
else printlines( linecount, lines );
if( lines ){ free(( void * )lines ); lines = 0; }
if( buffer ){ free(( void * )buffer ); buffer = 0; }}}}