Sunday, March 11, 2007

rf.c

Well I've done some correcting to my little back scratcher, including two bug fixes and changes to the man page.

/*-
 * Copyright (C) 2007
 * Terry *. P*****. 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.
 */


// vim: set noexpandtab ts=8 sw=4 ai :
// vi: set ai nu ts=8 sw=4 :

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>

struct lnpos {
 long nl;
 struct lnpos *next;
};

static void readall( FILE *, int );
static void readtop( FILE *, int );
static void readbottom( FILE *, int );
static void usage( void );

/*
 * rf - read file to standard out v1.1
 */

int
main( int argc, char *argv[] ) {
 
 char *erptr;
 int t_flag = 0, b_flag = 0;
 int ch, lncnt;
 FILE *fp;

 extern char *optarg;
 extern int optind;
 extern int optopt;
 extern int opterr;
 extern int optreset;

 while ( (ch = getopt(argc, argv, "b:t:")) != -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 '?':
  default:
   usage();
   return 1;
  }
 }

 if ( (t_flag < 1) && (b_flag < 1) )  {
  fp = fopen( argv[1], "r" );
  if ( fp == NULL ) 
   errx( 1, "File can not be opened or"
         " does not exist -- %s\n", argv[1] );
  readall( fp, lncnt );
 } else if ( t_flag > 0 ) {
  fp = fopen( argv[3], "r" );
  if ( fp == NULL )
   errx( 1, "File can not be opened or"
         " does not exist -- %s\n", argv[3] );
  readtop( fp, lncnt );
 } else if ( b_flag > 0 ) {
  fp = fopen( argv[3], "r" );
  if ( fp == NULL )
   errx( 1, "File can not be opened or"
         " does not exist -- %s\n", argv[3] );
      readbottom( fp, lncnt );
 } else {
  usage();
  /* NOTREACHED */
 }

 fclose( fp );
 return 0;
}

/*
 * print out an open file to standard output
 */

static void 
readall( FILE *fp, int lncnt ) {

 while ( (lncnt = fgetc( fp )) != EOF ) {
  printf( "%c", lncnt );
 }
}

/* Read n lines from the top of the file.
 * note that it was very inspired by the head(1) implementation of BSD
 */
static void
readtop( FILE *fp, int lncnt ) {

 char *cp;
 size_t error, rlen;
 while ( lncnt && (cp = fgetln( fp, &rlen )) != NULL ) {
  error = fwrite( cp, sizeof(char), rlen, stdout );
  if ( error != rlen )
   err( 1, "stdout" );
  lncnt--;
 }
}


/* Read n lines from the bottom of the file
 */
static void
readbottom( FILE *fp, int lncnt ) {

 int hmany = lncnt;
 long nlnum = 0;
 long where;

 struct lnpos *root;
 struct lnpos *cur;

 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 nodes" );
 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 );
   if ( cur->next != NULL ) 
    cur = cur->next;
   cur->next = malloc( sizeof(struct lnpos) );
   if ( cur->next == NULL )
    err( 1, "can't add nodes" );
   cur = cur->next;
  }
 }

 /* rewind our linked-list and seek to b_flag + 1 segments short of the
  * end of the list _before_ calling readall. So readall _starts_ from
  * the correct fseek offset to print till EOF.
  */
 cur = root->next;
 hmany++;
 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" );

 readall( fp, lncnt );
}

static void
usage( void ) {
 fprintf( stderr, "usage:\n rf file\n "
         "rf [-t number lines from the top] file\n "
  "rf [ -b number of lines from the bottom ] [ file ]\n" );
}


And the manual which writing got me interested in roff, I'll post when I have time to learn more about it. Basically the problem I had was caused by working on it. Originally under the conditions when 2 + 2 = 5 which is not good, because 2 + 2 is really == 4 !!!! I should never do stuff when I'm like that, but if I don't try nothing gets done.

No comments:

Post a Comment