/**************************************************************************** * scan.c Version 1.0 * * 29 December 1990 * Compiled with SAS/C 5.10 * * Copyright © 1990 By Dan Fish * All rights reserved. * * Permission is granted to freely redistribute this program provided * the source code is included in the distribution and this copyright * notice is unchanged. * ****************************************************************************/ #include #include #include #include #include #include #include #include "ansicodes.h" #define BUFFSIZE 2048L /* length of I/O buffer */ #define MAXFILELEN 80 #define SPACEBAR 32 char *key[] = { "NULLS ","^A (SOH) ","^B (STX) ","^C (ETX) ","^D (EOT) ", "^E (ENQ) ","^F (ACK) ","^G (BELL) ","Backspaces","Tabs ", "Line Feeds","Vert Tabs ","Formfeeds ","Returns ","^N (SO) ", "^O (SI) ","^P (DLE) ","^Q (DC1) ","^R (DC2) ","^S (DC3) ", "^T (DC4) ","^U (NAK) ","^V (SYN) ","^W (ETB) ","^X (CAN) ", "^Y (EM) ","^Z (SUB) ","ESC ","^\\ (FS) ","^] (GS) ", "^^ (RS) ","^- (US) ","Spaces " }; char WindowTitle[] = " ASCII HEX Count Character Percent"; char *fname; struct numlist { long ascii; long count; }; struct numlist num[256]; struct numlist *numptr; long temp[256]; long totalchars=0; int diffchars=0, pages, page=1; main (argc,argv) int argc; char *argv[]; { void DisplayData(); void WriteData(); void GetData(); void BooBoo(); void Usage(); extern struct Window *mywindow; /* Console window */ extern short pagelen; char oname[MAXFILELEN+1]; int in; FILE *out; int outfile = FALSE; int sort = FALSE; int loop; numptr=num; /* parse the command line */ if (( argc<2) || (*argv[1] =='?') || argv[1][1] == '?') { Usage(); exit(10); } for (loop = argc-1; loop > 1; --loop) if (!(argv[loop][0] == '-' )) /* then it better be an output filename! */ { if(outfile) BooBoo(3,(char *)NULL); /* already have an outfile! */ else { outfile = TRUE; stccpy(oname,argv[loop],MAXFILELEN); } } for (loop = argc-1; loop > 0; --loop) if(argv[loop][0] == '-') /* options */ { if(strpbrk(argv[loop],"sS") != (char *)NULL) sort = TRUE; } if ((in = open(argv[1], O_RDONLY, NULL)) < 0) BooBoo(1,argv[1]); if(outfile) if ((out = fopen(oname, "w")) == NULL) { close(in); BooBoo(2,oname); } fname=argv[1]; GetData(in,sort); if(outfile) WriteData(out); else DisplayData(); exit(0); } /************************************************************************ * Function : WriteData * * Arguments: fp - pointer to output file structure * * Returns : nothing * * Purpose : Writes the data to an output file instead of the screen * *************************************************************************/ void WriteData(fp) FILE *fp; { char *Line(); int error=0; register j; fprintf(fp," File: %s Total: %-6d Different: %-3d\n\n", fname,totalchars,diffchars); for(j = 0, numptr = num; j < diffchars; j++, numptr++) { error = fputs(Line(),fp); if(error) fprintf(stderr,"Scan: Error during write! Iteration = %3d, Ascii = %3d\n", j,numptr->ascii); error = fputs("\n",fp); } fclose(fp); } /************************************************************************ * Function : GetData * * Arguments: fh - file handle of input file * * sort - TRUE if output is to be sorted by frequency * * Returns : nothing * * Purpose : Creates an array containing the number of each character * * found in the input file. Sorts the array if applicable * *************************************************************************/ void GetData(fh,sort) int fh,sort; /*input file handle */ { int ch; register j=0; int frequency_sort(); while ((ch = Fetch(fh)) != EOF) { temp[ch]++; /* Increment the "temp[]" value that */ /* corresponds to the ASCII value */ /* of the character just read */ totalchars++; /* Running tab on total # of char's */ } /* Create an array of only characters contained in the file by filtering */ /* out all "temps[]" with a value of zero */ while (j < 256) { if (temp[j] != 0) { num[diffchars].ascii = j; num[diffchars].count = temp[j]; diffchars++; } j++; } if (sort) qsort((char *)num,diffchars+1,sizeof(struct numlist),frequency_sort); } /************************************************************************ * Function : DisplayData * * Arguments: none * * Returns : nothing * * Purpose : Handles (or call functions to handle) all outputing of * * data to the screen. * *************************************************************************/ void DisplayData() { void mysetup(); extern short pagelen; void DisplayLine(); void DisplayPage(); int getkey; char quit[] = {'q','Q','\x1b','\003','\0'}; /* Null terminated string of */ /* characters that will end */ /* the program */ mysetup(); /* Initialize the output console */ numptr = num; cursor_off(); if ((diffchars % pagelen)==0) /* the number of different characters will */ pages = diffchars/pagelen; /* exactly fill a given number of pages */ else pages = (diffchars/pagelen)+1;/* gonna need an extra page */ DisplayPage(); /* Display the first "pagelen" lines */ while(strchr(quit, getkey = getchar()) == (char *)NULL) { if (getkey == SPACEBAR && pages > 1) { if(numptr < &num[diffchars]) DisplayPage(); /* display next page */ else { numptr = num; /* go back to first page */ DisplayPage(); } } } return; } /************************************************************************ * Function : DisplayLine * * Arguments: yval-- position on the screen where line is displayed * * Returns : nothing * * Purpose : Output a line to the screen positioned at "yval". If * * "numptr->ascii" is non-printable, the line is highlighted * *************************************************************************/ void DisplayLine(yval) int yval; { char print; char *Line(); put_cursor(1,yval); if(!(print = isprint(numptr->ascii))) setforecolor3(); printf("%s",Line()); if(!print) set_normal(); } /************************************************************************ * Function : *Line * * Arguments: None * * Returns : pointer to buffer containing the formatted line * * Purpose : Format a line of information about character * * "numptr->ascii". This information includes its * * ascii value, hex value, common reference, number of * * occurences and % of total * *************************************************************************/ char *Line() { static char linebuff[80]; char tempbuff[20]; if (numptr->ascii < 33) sprintf(tempbuff,"%10s ",key[numptr->ascii]); /* a more familiar form */ else if(numptr->ascii > 127 && numptr->ascii < 160) sprintf(tempbuff," "); else sprintf(tempbuff,"%-10c ",numptr->ascii); /* the actual character */ sprintf(linebuff," [%3d] [%3x] %7d ",numptr->ascii,numptr->ascii, numptr->count); strcat(linebuff,tempbuff); sprintf(tempbuff,"%6.2f %%", (((float)numptr->count)/((float)totalchars))*100.0); strcat(linebuff,tempbuff); return(linebuff); } /************************************************************************ * Function : DisplayPage * * Arguments: none * * Returns : nothing * * Purpose : Handles the screen formatting and display of an entire * * page of lines formatted by *Line(). Also displays * * filename and totalizer information at the bottom * *************************************************************************/ void DisplayPage() { extern short pagelen; void DisplayLine(); int j; char filnam[29]; for (j=0; j < pagelen; j++) /* 22 lines per page */ { if (numptr > &num[diffchars-1]) /* if this is the last character */ erase_eos(); /* get rid of any old junk left */ else /* from the previous page */ { DisplayLine(j+1); /* display the next line */ printf("\n"); numptr++; /* increment pointer to next non-empty charval */ } } stccpy(filnam,fname,27); /* Ensure filename will fit on */ /* the last line! */ cursor_bot(); set_hilite(); printf(" Page %d of %d ",page,pages); printf(" Total: %-6d ",totalchars); printf(" Different: %-3d ",diffchars); printf(" File: %s ",filnam); set_normal(); page++; if (page > pages) page = 1; } /************************************************************************ * Function : Fetch * * Arguments: fh - file handle of file to read * * Returns : a character (int) or EOF * * Purpose : Performs buffered low-level file reading, refilling * * buffer when last character has been "fetched" * * Returns EOF if no more characters in file * *************************************************************************/ Fetch(fh) int fh; /*input file handle */ { static unsigned char buffer[BUFFSIZE]; /* input buffer */ static short nextch = BUFFSIZE-1; static short lastch = BUFFSIZE-1; if(++nextch >= lastch) /* If buffer used up, */ { /* refill it from file */ lastch = read(fh,buffer,BUFFSIZE); nextch = 0; } if (lastch == 0) /* EOF, close up shop */ { close(fh); return(EOF); } return((int)buffer[nextch]); /* return next character */ } /************************************************************************ * Function : Usage * * Arguments: none * * Returns : nothing * * Purpose : Displays the proper usage format * *************************************************************************/ void Usage() { fprintf(stderr,"\x1b[5m"); fprintf(stderr,"\n\x1b[1;33m Usage: \x1b[0m"); fprintf(stderr,"Scan [outfile] [-s] \x1b[0m\n\n"); } /************************************************************************ * Function : BooBoo * * Arguments: cause - integer for determining the nature of the problem * * string - pointer to a character string for screen output * * Returns : nothing * * Purpose : Displays an error message in the event of problems parsing * * command line arguments or accessing files * *************************************************************************/ void BooBoo(cause,string) int cause; char *string; { void Usage(); fprintf(stderr,"\n\x1b[33m Scan: \x1b[32m"); if (cause == 1) fprintf(stderr,"Can't open \"%s\" for input! \n\n", string); else if(cause == 2) fprintf(stderr,"Can't open \"%s\" for output! \n\n", string); else if(cause == 3) { fprintf(stderr,"Too many file names!\n"); Usage(); } fprintf(stderr,"\x1b[0m"); exit(-cause); } /************************************************************************ * Function : frequency_sort * * Arguments: two pointers to the items being compared * * Purpose : provides the sorting algorithm for qsort() * *************************************************************************/ int frequency_sort(num1,num2) struct numlist *num1,*num2; { if (num1->count < num2->count) return(1); else if (num1->count == num2->count) return(0); else return(-1); }