All pastes #468555 Raw Edit

rf.c

public c v1 · immutable
·published 2007-05-03 06:17 UTC
rendered paste body
/*- * Copyright (C) 2007 *      Terry M. Poulin. 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. */#include <err.h>#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <locale.h>#include <unistd.h>struct lnpos {	long nl;	struct lnpos *next;};static FILE *open_file( char * );static void read_all( FILE *, int );static void read_top( FILE *, int );static void read_bottom( FILE *, int );static void clean_up( struct lnpos *);static void be_verbose( void );static void usage( void );static const char *this_progname;/* * rf - read file to standard out v1.28 */intmain( int argc, char *argv[] ) {	char *erptr;	int t_flag = 0, b_flag = 0, v_flag = 0;	int ch, lncnt;	FILE *fp;	(void)setlocale( LC_ALL, "" );	this_progname = argv[0];	while ( (ch = getopt(argc, argv, "b:t:v")) != -1 ) {		switch (ch) {		case 'b':			b_flag++;			lncnt = strtol(optarg, &erptr, 10);			if ( *erptr || lncnt <= 0 )				errx( 1, "Improper line count -- %s", optarg );			break;		case 't':			t_flag++;			lncnt = strtol(optarg, &erptr, 10);			if ( *erptr || lncnt <= 0 )				errx( 1, "Improper line count -- %s", optarg );			break;		case 'v':			v_flag++;			break;		case '?':		default:			usage();			/* NOTREACHED */		}	}	/* This is ugly looking  but cleaner then w/o open_file(). */	if ( argv[1] == NULL ) {		usage();	} else if ( (t_flag < 1) && (b_flag < 1) && (v_flag < 1) )  {		fp = open_file( argv[1] );		read_all( fp, lncnt );	} else if ( (v_flag != 0) && (t_flag < 1) && (b_flag < 1) ) {		fp = open_file( argv[2] );		read_all( fp, lncnt );	}  else if ( t_flag > 0 ) {		fp = open_file( argv[3] );		read_top( fp, lncnt );	} else if ( b_flag > 0 ) {		fp = open_file( argv[3] );	    	read_bottom( fp, lncnt );	} else {		usage();		/* NOTREACHED */	}	if ( v_flag != 0 )	    be_verbose();	fclose( fp );	return 0;}/* Simple fopen wrapper to keep the if...else if...else blockage from * getting even uglier. Since doing other wise would defeat the purpose of it. * open_file() halts the program if fopen failed. */static FILE*open_file( char *arg ) {	FILE *fto;	fto = fopen( arg, "r" );	if ( fto == NULL ) 		errx( 1, "File can not be opened or"		      " does not exist -- %s\n", arg );	return fto;}/* * print out an open file to standard output */static voidread_all( FILE *fp, int lncnt ) {	while ( (lncnt = fgetc( fp )) != EOF ) {		printf( "%c", lncnt );	}}/*  * Read n lines from the top of the file. */static voidread_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 voidread_bottom( FILE *fp, int lncnt ) {	int hmany = lncnt;	long nlnum = 0;	long where;	struct lnpos *root = 0;	struct lnpos *cur = 0;	root = malloc( sizeof(struct lnpos) );	if ( root == NULL )		err( 1, "can't init the list" );	root->next = 0;	cur = root;	cur->next = malloc( sizeof(struct lnpos) );	if ( cur->next == NULL )		err( 1, "can't add first node" );	cur = cur->next;	/* read the file, count every '\n' and store them in a new member of	 * our linked list.	 */	while ( (lncnt = fgetc( fp )) != EOF ) {		if ( lncnt == '\n' ) {			nlnum++;			cur->nl = ftell( fp );			cur->next = malloc( sizeof(struct lnpos) );			if ( cur->next == NULL )				err( 1, "can't store line feeds" );			cur = cur->next;		}	}	/* Let's mark the end of the list and move to it */	cur->next = malloc( sizeof(struct lnpos) );	if ( cur->next == NULL )		err( 1, "can't terminate the list" );	cur = cur->next;	cur->next = NULL;	/* rewind our linked-list and seek to b_flag segments. So readall()	 * starts from the correct fseek offset to print till EOF. - This	 * keeps down on unnecessary code here !	 */	cur = root;	while ( hmany < nlnum ) {		cur = cur->next;		nlnum--;	}	where = fseek( fp, cur->nl, SEEK_SET );	if ( where != 0 )		err( 1, "could not seek through the file\n" );	read_all( fp, lncnt );	clean_up( root );}/* Simple destructor - walk the list and free() the memory before the * program exits. */static voidclean_up( struct lnpos *rp ) {	struct lnpos *t = rp;	struct lnpos *atpos = rp;	while ( atpos != NULL ) {		free( t );		atpos = atpos->next;		t = atpos;	}}static voidbe_verbose( void ) {	printf("==> %s <==\n", __FILE__);}static voidusage( void ) {	(void)fprintf( stderr, "usage: %s [-t count | -b count] "		       "[-v] [file ...]\n",		       this_progname );	exit( EXIT_FAILURE );}