I was remembering today the sfalloc() macro I had defined early on. Some thing like
#define sfalloc( _type, _ptr ) \ (_type *)malloc( sizeof(_ptr) )
The main point of it was to ensure I wrote sizeof(foo) instead of sizeof(int) or some thing. And to get it to compile with a C++ compiler. I was thinking about making a new version of it for one of my header files that would use the cast only if __cplusplus was defined or better yet the new operator instead for use in code I would want to be compatible with both C and C++ but why bother for such a small program? Althouhg it would be a good spot to test it out in if I did hehe. Besides MSVC++ is a pain in the ass any way for compiling C99 code (imho).
My favorite non standard extensions to the C standard library on BSD and GNU systems is deffo err(), errx(), warn(), warnx(), and related routines in err.h namely because they are major time savers imho. Since a unix like system is assumed unistd is included and getopt(3) used for parsing argv rather then doing it manually.
I didn't use the various linked list macros provided by BSD boxes because I wanted to avoid them, in case I ever decided to build the app on Windows or DOS. It also was the first time I ever used a linked list in a C program so I wanted to give it a go hehe. I'm really glad I did to because it was a really good excuse to learn how to use the GNU Debugger at the time ;-)
One of the changes I made today was ensuring it would compile fine without assuming a C99 environment, I also ran it by gcc42 with -std=c89 -ansi and -pedantic-errors in the hopes of catching any thing I might've visually missed.
the 'final' version of the old program
/*- * Copyright (C) 2007 * [my name ]. All rights reserved. * * permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if __STDC_VERSION__ >= 199901L /* inline functions were added in C99 */ #else #define inline /* protect me */ #endif #define MALLOC_FAILED "Unable to initialize memory at __LINE__ \n" /* magic number for debugging read_bottom() and clean_up() */ #define NOMEM ((struct lnpos *)0xDEADBEEF) #include <err.h> #include <errno.h> #include <limits.h> #include <locale.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> /* For storing end of line characters */ typedef struct lnpos { long eol; struct lnpos *next; struct lnpos *prev; } LNPOS; static inline FILE *open_file( char * ); static inline void read_all( FILE *, int ); static void read_top( FILE *, int ); static void read_bottom( FILE *, int ); static inline void clean_up( LNPOS * ); static inline void be_verbose( char * ); static inline void usage( void ); static const char *this_progname; /* * rf - read file to standard out v2.0 -- see changes.log for details */ int main( int argc, char *argv[] ) { char *errp; int b_flag = 0, s_flag = 0, t_flag = 0, v_flag = 0; int ch, f, lncnt = 0; FILE *fp; setlocale( LC_ALL, "" ); this_progname = argv[0]; while ( (ch = getopt( argc, argv, "b:st:v" )) != -1 ) { switch ( ch ) { case 'b': /* Mimic tail(1) -n */ b_flag++; lncnt = strtol( optarg, &errp, 10 ); if ( *errp || lncnt <= 0 ) { errx( EXIT_FAILURE, "Improper line count -- %s\n", optarg ); } break; case 's': /* Suppress -v when given multiple files. */ s_flag++; v_flag = 0; break; case 't': /* Mimic head(1) -n */ t_flag++; lncnt = strtol( optarg, &errp, 10 ); if ( *errp || lncnt <= 0 ) { errx( EXIT_FAILURE, "Improper line count -- %s\n", optarg ); } break; case 'v': /* Append file names -- be_verbose() */ v_flag++; break; case '?': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if ( argc < 1 ) { usage(); } /* Handle multiple files */ for ( f = 0; f < argc; f++ ) { fp = open_file( argv[f] ); if ( (!t_flag) && (!b_flag) ) { read_all( fp, lncnt ); } else if ( t_flag ) { read_top( fp, lncnt ); } else if ( b_flag ) { read_bottom( fp, lncnt ); } else { usage(); /* NOTREACHED */ } if ( (v_flag != 0) || (argc > 1) ) { /* Don't suppress if not set */ if ( s_flag == 0 ) { be_verbose( argv[f] ); v_flag++; } else { v_flag = 0; } } fclose( fp ); } return EXIT_SUCCESS; } /* Simple fopen wrapper to keep the if...else if...else blockage from getting * ugly. Since doing other wise would defeat the purpose of it in this program. * open_file() halts the program if fopen failed. */ static inline FILE * open_file( char *arg ) { FILE *fto; fto = fopen( arg, "r" ); if ( fto == NULL ) { errx( EXIT_FAILURE, "File can not be opened or" " does not exist -- %s\n", arg ); } return fto; } /* * print out an open file to standard output */ static inline void read_all( FILE *fp, int lncnt ) { while ( (lncnt = fgetc( fp )) != EOF ) { printf( "%c", lncnt ); } } /* * Read n lines from the top of the file. */ static void read_top( FILE *fp, int lncnt ) { int c = 0; int f = 0; while ( (c < lncnt) && (f != EOF ) ) { f = fgetc( fp ); printf( "%c", f ); if ( f == '\n') { c++; } } } /* * Read n lines from the bottom of the file */ static void read_bottom( FILE *fp, int lncnt ) { int fin = 0, i; long int eolnum = 0; long int where; struct lnpos *cur = NULL; struct lnpos *root = NULL; struct lnpos *last = NULL; /* initiate the linked list */ root = malloc( sizeof(root) ); root->eol=0; if ( root == NULL ) { err( EXIT_FAILURE, MALLOC_FAILED ); } root->next = NOMEM; root->prev = NOMEM; cur = root; cur->next = malloc( sizeof(cur->next) ); cur->next->eol = 0; if ( cur->next == NULL ) { err( EXIT_FAILURE, MALLOC_FAILED ); } cur->next->prev = cur; cur->next->next = NOMEM; cur = cur->next; /* * read the file, count every end of line and store them in a new * member of our linked list. */ while ( (fin = fgetc( fp )) != EOF ) { if ( fin == '\n' ) { eolnum++; cur->eol = ftell( fp ); cur->next = malloc( sizeof(cur->next) ); cur->next->eol = 0; if ( cur->next == NULL ) { err( EXIT_FAILURE, MALLOC_FAILED ); } cur->next->prev = cur; cur->next->next = NOMEM; cur = cur->next; } } /* double check last nodes prev is up to date before marking the end */ cur->next = malloc( sizeof(cur->next) ); cur->next->eol = 0; if ( cur->next == NULL ) { err( EXIT_FAILURE, MALLOC_FAILED ); } cur->next->prev = cur; cur->next->next = NOMEM; cur = cur->next; last = cur; /* print out the rest of file from the given offset. */ for ( i = 0; i < lncnt; ) { if ( cur->prev != NOMEM ) { if ( cur->eol ) { i++; } cur = cur->prev; } } where = fseek( fp, cur->eol, SEEK_SET ); if ( where != 0 ) { err( EXIT_FAILURE, "Could not seek through the file\n" ); } read_all( fp, lncnt ); clean_up( root ); } static inline void clean_up( LNPOS *root ) { /* Free linked lists memory */ struct lnpos *cur = root; while ( cur->next != NOMEM ) { cur = cur->next; if ( cur->prev != NOMEM ) { free( cur->prev ); cur->prev = NOMEM; } } free( cur ); /* free the end node */ } static inline void be_verbose( char *fname ) { printf( "\n==> %s <==\n", fname ); } static inline void usage( void ) { fprintf( stderr, "usage: %s [-t count | -b count] " "[-v] [file ...]\n", this_progname ); exit( EXIT_FAILURE ); }
The simple makefile compiles it:
gcc -Wall -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion \
-Waggregate-return -Wstrict-prototypes -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Winline -Wnested-externs\
-std=c99 -march=i686
and Makefile.optimize adds the -fforce-mem -fforce-addr -finline-functions -fstrength-reduce -floop-optimize -O3 options for when testing is done, program works fine. FreeBSD's lint implementation also doesn't spew any serious messages.
No comments:
Post a Comment