/* Program HEAD -- prints first 'n' lines of files */
/* (C) Copyright John S. Simonson 1985, 1986 All Rights Reserved. */
/* Version (major.minor) 1.4    --revised 1-6-86                  */
/* Version 2.1 Microsoft C version    --  1-17-86                 */
#include <types.h>
#include <stat.h>
#include <stdio.h>
#include <ctype.h>
#define TRANS 1
#define HEDR  2
#define LINES 3
#define NUMBR 4
#define DUD   6
#define FSPEC 0
#define TRUE  1
#define FALSE 0
#define DASH '-'
#define SLASH '/'
#define DEFAULT 5
#define MARKLEN 7
#define FEED 5
#define MAXSTR 255
#define MAJOR 2
#define MINOR 1
short i,k,j,m; 
unsigned short nlin;  /* this will be the Number of LINes to print     */
char a[MAXSTR];
char mark[MARKLEN]; /* array to hold options switch settings */
char *x;
short nbad;
char told;
char cpyrite[80];

main(ac,av)
unsigned ac;   /* argument count */
char *av[];    /* argument vector -- array of pointers to args */

{
strcpy(cpyrite,"(C)Copyright 1985 by John S. Simonson. All rights reserved.");
nbad=0;          /* set # of bad arguments to zero */
told=FALSE;      /* we haven't told user of errors */
for(i=0;i<MARKLEN;i++)
  mark[i] = FALSE; /* set all option switches to off */
if(ac>1)
  {
  i=1;  /*get first true argument (not prog name)*/
  while(i<ac)
    {
    strcpy(a,av[i]);
    x=a;  /* set pointer x to array a so can pass to isnumbr easily */
    if(((a[0]==DASH)||(a[0]==SLASH))&&(strlen(a)>1))
      {
      for(k=1;k<strlen(a);k++)
        {
        a[k]=tolower(a[k]); /* convert args to lower case */
        if(a[k]=='t')
          mark[TRANS]=TRUE;   /*drop ascii > 127d to printable form*/
        else
          if(a[k]=='l')
            mark[LINES]=TRUE;   /*print line number selected*/
          else
            if(a[k]=='h')
              mark[HEDR]=TRUE;  /*print file name header selected */
            else
              if(a[k]=='n')
                mark[FEED]=TRUE; /*add a newline to end of string*/
              else
                if(isdigit(a[k]))
                  {
                  x=x+k; /*set *x equal to start of num string*/
                  j=getlenn(x); /*find num. string length*/
                  if(j>0) m=getnmbr(j,x);
                  else nlin=DEFAULT; /*if not a num str, use default*/
                  if(m==0) m=DEFAULT;
                  if(m<0) nlin=m*(-1); /*ensure we have a posnum*/
                    else  nlin=m;
                  mark[NUMBR]=TRUE; /*indicate we did reset value*/
                  k=k+j-1;
                  x=a; /*restore x pointer to a[0]*/
                  }
                else
                  {
                  nbad++;           /* increment n of bad args */
                  mark[DUD]=i;     /*not a number, so unknown option*/
                  }
            }
        }
        else
          mark[FSPEC]++;  /*no leading dash, so must be a file name*/
       i++;
       }
    }
  else
    if(!told)
      {
      usage();
      told=TRUE;
      }
  if(ac>1)
  {
  if(!mark[NUMBR])
    nlin=DEFAULT;   /*if not set, set to default # of lines*/
  if(mark[DUD])
    {
    printf("\nUnknown option %s ignored.",av[(mark[DUD])]);
    printf("\n%d unknown options detected.\n",nbad);
    }
  if(mark[FSPEC])
    crunchit(ac,av);
  else
    printf("\nUsage: HEAD filespec [options] --no filespec given!");
  }
  else
    if(!told)
     {
     usage();
     told=TRUE;
     }
} /* End of Main Procedure */

usage()
/* this just displays how to use the program correctly */
{
 printf("\nUsage: HEAD filespec [-t -h -l -n -#] or [-thln#]\n");
 printf("t = Translate down 128 (decimal) ascii chars over 127d\n");
 printf("h = print a file Header before each file's output\n");
 printf("l = print Line numbers with each line\n");
 printf("n = terminate each output string with a Newline\n");
 printf("# = set number of lines to print from each file to #,\n");
 printf("where # is a positive integer (e.g. -10 to print ten lines)\n");
 printf("\n%s Version %d.%d\n",cpyrite,MAJOR,MINOR);
}

getlenn(s)
char *s;
/* ---------------------------------------------- */
/* finds the length of s substring of numeric vals*/
/* i.e., number of consecutive digits in a string */
/* since the first char MUST be a digit for this  */
/* to be called, we wont do error checking..and j,*/
/* the return value, must be at least 1           */
/*  getlenn(s) s is a pointer of type char        */
/*  and j, the return value is type short         */
/* ---------------------------------------------- */
{
char b;
short j,n,m;
n=strlen(s); /*get possible length of numeric string*/
j=0;         /* set initial values*/
m=1;
b=*s;        /*char b is current char of string*/
while((m<=n)&&(isdigit(b)))
  {
  if(isdigit(b)) j++;  /*incr length of digit chars*/
  m++;  /*incr pointer to next char*/
  if(m<=n) b=*(++s); /*if past possible length we stop*/
  else b=32; /* set b to bogus value so its not stuck as a digit*/
  }
return j; 
}

getnmbr(l,s)
short l;
char *s;
/* --------------------------------------------- */
/* extracts and converts a numeric substring from*/
/* a string.  The integer result is returned in  */
/* the type short variable "result".             */
/* getnumbr(l,s) l is type short, must be >1, and*/
/* less than the length of the passed string, s  */
/* s is a pointer of type char.                  */
/* --------------------------------------------- */
{
char *y;
char hold[256];
short result;
strncpy(hold,s,l);    /*extract the portion of s we need*/
y=hold;               /*let y point to our new string*/
result=atoi(y);       /*convert to an integer*/
return result;
}

crunchit(ac,av)
/*                                                   */
/*---------------------------------------------------*/
/* cant really think of a good name for this routine */
/* this is the actual get-down-and-get-dirty section */
/* that expands the file specs (if there are wild    */
/* cards) and processes each matching file.          */
/* The options (-t,-l,-#,-h,and file name should all */
/* be available to this routine.                     */
/* John Simonson 12/10/85                            */
/* Microsoft C ver. 3.00 using SLIBC libarary        */
/* 01/21/86                                          */
/*---------------------------------------------------*/
/* Note: command parsing and error checking (with the*/
/*       exception that file name validity hasnt been*/
/*       checked) should be done prior to entry.     */
/*---------------------------------------------------*/
/*                                                   */
unsigned ac;
char *av[];
{
extern FILE *fopen();
FILE *ptr;
char *next;
char *first;
char works[MAXSTR];          /* this is a string work area           */
unsigned char ubuf[4096];    /* this is a HUGE string buffer */
unsigned int buflen;
int how=0;
int result=0;
int ii=0;
unsigned short lineno=1;
unsigned short blen=0;
unsigned short retval=0;
unsigned short bufptr=0;
struct stat buf;             /* this needs stuff in STAT.H */

  buflen = 4096; /* now set buffer length  */
  for(ii=1;ii<ac;ii++)
    {
    strcpy(works,av[ii]);
    next=works;
    if(works[0]!=DASH&&works[0]!=SLASH)
      {
      result=stat(next,&buf);
      if(result==-1)
        printf("HEAD: Could not find any file %s\n",next);
      else
      if(buf.st_mode & S_IFREG)
      {
      if (mark[HEDR])
        {
        printf("\n\n====================> "); /*file header requested*/
        printf("%s",next);
        printf(" <====================\n");
        }
      ptr = fopen(next,"r");  /* open the current file for read only */
      if(!ptr)
        {
        printf("HEAD: file opening failure for %s\n",next);
        how = fclose(ptr);   /* make sure file closed properly */
        clearerr(ptr);       /*and clear the error condition*/
        }
      else
        {
        for(lineno=1;lineno<=nlin;lineno++)
           {
           first=ubuf;
           first=fgets(ubuf,buflen,ptr); /*put some stuff in the buffer*/
           retval=feof(ptr);  /* end-of-file ? */
           if(!retval)
             {
             if(mark[TRANS])
               {
               blen=strlen(ubuf);
               for(bufptr=0;bufptr<=blen;bufptr++)
                 if(ubuf[bufptr]>127)
                   ubuf[bufptr]=ubuf[bufptr]-128;  /* shift down */
               }
             if(mark[LINES])
               printf("%04d: ",lineno);
             if(mark[FEED])
               printf("%s\n",ubuf); /* print line with newline */
             else 
             printf("%s",ubuf); /*print line w/o newline */
             }
           else
           lineno=nlin+1; /*EOF, so end looping now*/
           }
           if(ptr) 
            {
            how=fclose(ptr);      /* be sure to close file */
            clearerr(ptr);        /*and clear any error condition*/
            }
         }
       }
    }
 }
 return;
}