/* Copyright (C) 2003, 2004 Dave Bayer. Subject to the terms and conditions of the MIT License. */ #include "root.h" #include "file.h" /*. fileOpen */ FILE *fileOpen( const char* fileName, char *mode, BOOL abort ) { FILE *fp; fp = fopen( fileName, mode ); if ( fp == 0 ) { fprintf( stderr, "fileOpen: error opening file \"%s\" with mode \"%s\"\n", fileName, mode ); executionError( 0, abort ); } return fp; } /*. fileClose */ BOOL fileClose( FILE *fp, BOOL abort ) { if ( fclose( fp ) == EOF ) { executionError( "fileClose: error closing file", abort ); return NO; } return YES; } /*. checkEOF */ BOOL checkEOF( FILE *fin, BOOL abort ) { if ( !feof( fin )) { executionError( "checkEOF: error reading file", abort ); return NO; } return YES; } /*. lineAlloc */ line *lineAlloc( unsigned max ) { char *s; line *l; s = malloc( (max + 1) * sizeof( *s )); *s = '\0'; l = malloc( sizeof( *l )); l->next = 0; l->len = 0; l->max = max; l->s = s; l->data = 0; return l; } /*. lineFree */ void lineFree( line *l, lineFreeFn freedata ) { free( l->s ); if ( freedata ) freedata( l->data ); free( l ); } /*. lineListFree */ void lineListFree( line *l, lineFreeFn freedata ) { line *p; while ( l != 0 ) { p = l->next; lineFree( l, freedata ); l = p; } } /*. lineCopy */ line *lineCopy( line *l, unsigned max ) { line *p; unsigned len; assert( l->len == strlen( l->s )); len = l->len; p = lineAlloc( MAX( max, len )); p->len = len; strncpy( p->s, l->s, len+1 ); p->data = l->data; return p; } /*. lineReset */ void lineReset( line *l, lineFreeFn freedata ) { l->next = 0; l->len = 0; *l->s = '\0'; if ( freedata ) freedata( l->data ); l->data = 0; } /*. lineFromStr */ line *lineFromStr( const char *s ) { line *l; unsigned len; len = strlen( s ); l = lineAlloc( len ); l->len = len; strncpy( l->s, s, len+1 ); return l; } /* pointers to handles */ /*. lineAdvance */ void lineAdvance( line ***ppl ) { line *l; l = **ppl; if ( l != 0 ) *ppl = &l->next; } /*. lineInsert */ void lineInsert( line *l, line ***ppl ) { l->next = **ppl; **ppl = l; *ppl = &l->next; } /*. lineListInsert */ void lineListInsert( line *l, line **pl, line ***ppl) { assert( l != 0 ); *pl = **ppl; **ppl = l; *ppl = pl; } /*. lineRemove */ void lineRemove( line **pl ) { line *l; l = *pl; *pl = l->next; l->next = 0; } /*. lineListRemove */ void lineListRemove( line **pl, line ***ppm ) { assert( *pl != **ppm ); *pl = **ppm; **ppm = 0; *ppm = pl; } /*. lineDelete */ void lineDelete( line **pl, lineFreeFn freedata ) { line *l; l = *pl; *pl = l->next; lineFree( l, freedata ); } /*. lineListCopy */ line *lineListCopy( line *l, unsigned max ) { line *p, *m, **pm; m = 0; pm = &m; for ( p=l; p!=0; p=p->next ) { *pm = lineCopy( p, max ); lineAdvance( &pm ); } return m; } /*. lineRead */ BOOL lineRead( FILE *fin, line *l, unsigned detab ) { int c, n; char *s; for ( n=0, s=l->s; nmax; ++n ) { c = getc( fin ); switch( c ) { case EOF: checkEOF( fin, YES ); if ( n == 0 ) return NO; goto end; /* accept Unix, Mac, DOS line breaks: \n, \r, \r\n */ case '\r': c = getc( fin ); if ( c != '\n' ) ungetc( c, fin ); case '\n': goto end; /* tabs fall through to default unless detab is nonzero */ case '\t': if ( detab ) { *s++ = ' '; while (( n + 1 ) % detab != 0 ) ++n, *s++ = ' '; break; } default: *s++ = c; break; } } executionError( "lineRead: line length exceeded", YES ); end: /* lineRead end */ for ( --s; n > 0 && isspace( *s ); --n, --s ) {} *++s = '\n'; *++s = '\0'; l->len = n+1; return YES; } /*. lineWrite */ void lineWrite( FILE *fout, line *l ) { assert( l->len == strlen( l->s )); if ( fputs( l->s, fout ) == EOF ) executionError( "lineWrite: error writing file", YES ); } /*. fileRead */ line *fileRead( FILE *fin, lineFilter *pfilter, unsigned detab ) { line *buf1, *buf2, *swap, *m, **pm; lineFilter *pf; buf1 = lineAlloc( BUFLEN ); buf2 = pfilter != 0 ? lineAlloc( BUFLEN ) : 0; m = 0; pm = &m; while ( lineRead( fin, buf1, detab )) { for ( pf = pfilter; pf != 0; pf=pf->next ) { lineReset( buf2, 0 ); pf->filt( buf1, buf2, pf->data ); assert( buf2->len <= buf2->max && buf2->len == strlen( buf2->s )); swap = buf2; buf2 = buf1; buf1 = swap; } *pm = lineCopy( buf1, 0 ); lineAdvance( &pm ); } lineFree( buf1, 0 ); if ( pfilter != 0 ) lineFree( buf2, 0 ); return m; } /*. fileWrite */ void fileWrite( FILE *fout, line *l, lineFilter *pfilter ) { line *p, *p1, *p2, *swap, *buf1, *buf2; lineFilter *pf; if ( pfilter != 0 ) { buf1 = lineAlloc( BUFLEN ); buf2 = lineAlloc( BUFLEN ); } else buf1 = buf2 = 0; for ( p=l; p!=0; p=p->next ) { /* juggle buffers with care */ p1 = p; p2 = buf1; swap = buf2; for ( pf = pfilter; pf != 0; pf=pf->next ) { lineReset( p2, 0 ); pf->filt( p1, p2, pf->data ); assert( p2->len <= p2->max && p2->len == strlen( p2->s )); p1 = p2; p2 = swap; swap = p1; } lineWrite( fout, p1 ); } if ( pfilter != 0 ) { lineFree( buf1, 0 ); lineFree( buf2, 0 ); } } /*. lineListFilter */ line *lineListFilter( line *l, lineFilter *pfilter ) { line *p, *p1, *p2, *swap, *buf1, *buf2, *m, **pm; lineFilter *pf; buf1 = lineAlloc( BUFLEN ); buf2 = lineAlloc( BUFLEN ); m = 0; pm = &m; for ( p=l; p!=0; p=p->next ) { p1 = p; p2 = buf1; swap = buf2; for ( pf = pfilter; pf != 0; pf=pf->next ) { lineReset( p2, 0 ); pf->filt( p1, p2, pf->data ); assert( p2->len <= p2->max && p2->len == strlen( p2->s )); p1 = p2; p2 = swap; swap = p1; } *pm = lineCopy( p1, 0 ); lineAdvance( &pm ); } lineFree( buf1, 0 ); lineFree( buf2, 0 ); return m; } /* test code */ #ifdef TESTCODE /*. identityLineFilter */ static void identityLineFilter( line *buf1, line *buf2, void *data ) { strncpy( buf2->s, buf1->s, buf1->len+1 ); buf2->len = buf1->len; } /*. fileTest */ void fileTest( void ) { line *l, *m; FILE *fin, *fout; lineFilter filter, filter2, filter3; const char name[] = "TempFileTest"; const char text[] = "Sample line\n" "\n" "Another sample line\n" ; fout = fileOpen( name, "w", YES ); fputs( text, fout ); fileClose( fout, YES ); filter.filt = identityLineFilter; filter.next = &filter2; filter.data = 0; filter2.filt = identityLineFilter; filter2.next = &filter3; filter2.data = 0; filter3.filt = identityLineFilter; filter3.next = 0; filter3.data = 0; fin = fileOpen( name, "r", YES ); l = fileRead( fin, &filter, 0 ); m = lineListFilter( l, &filter ); lineListFree( l, 0 ); fileWrite( stdout, m, &filter ); lineListFree( m, 0 ); fileClose( fin, YES ); } #endif