You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
3.0 KiB
C
194 lines
3.0 KiB
C
/* wc.c -- program to count and display the number of lines, words and one of bytes or characters in the named files */
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
#include "support.h"
|
|
|
|
|
|
/* Parameters */
|
|
enum
|
|
{
|
|
W,
|
|
L,
|
|
CM
|
|
};
|
|
|
|
/* States */
|
|
enum {
|
|
OUTWORD,
|
|
INWORD
|
|
};
|
|
|
|
/* Category names for count[] and result[] */
|
|
enum {
|
|
/* character or byte */
|
|
LINES,
|
|
WORDS,
|
|
COB
|
|
};
|
|
|
|
|
|
int wc(FILE *fd, int *results)
|
|
{
|
|
char state;
|
|
int c;
|
|
|
|
state = OUTWORD;
|
|
c = 0;
|
|
|
|
|
|
for(c = 0; (c = fgetc(fd)) != EOF;)
|
|
{
|
|
if(!(isblank(c) || c == '\n'))
|
|
{
|
|
if(state == OUTWORD)
|
|
{
|
|
results[WORDS]++;
|
|
}
|
|
|
|
state = INWORD;
|
|
}
|
|
else
|
|
{
|
|
if(c == '\n')
|
|
{
|
|
results[LINES]++;
|
|
}
|
|
|
|
state = OUTWORD;
|
|
}
|
|
|
|
results[COB]++;
|
|
}
|
|
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* if a particular pars element is non-zero, print the corresponding total element. */
|
|
/* if pars is NULL, print everything */
|
|
/* if total is NULL, throw an error */
|
|
int printres(int *total, char *filepath, char *pars)
|
|
{
|
|
int i;
|
|
|
|
i = 0;
|
|
|
|
|
|
if(!total)
|
|
{
|
|
throw(MISC_FAIL, "printres: total is null");
|
|
}
|
|
|
|
|
|
for(i = 0; i <= 2; i++)
|
|
{
|
|
if(pars == NULL || pars[i])
|
|
{
|
|
printf("%d ", total[i]);
|
|
}
|
|
}
|
|
|
|
if(filepath)
|
|
{
|
|
if(!strcmp("-", filepath))
|
|
{
|
|
printf("stdin");
|
|
}
|
|
else
|
|
{
|
|
printf("%s", filepath);
|
|
}
|
|
}
|
|
putchar('\n');
|
|
|
|
|
|
return(0);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
/* haspar == 0 means we pass NULL to printres for default POSIX behavior */
|
|
char haspar;
|
|
int c, i;
|
|
int current[3] = {0};
|
|
int results[3] = {0};
|
|
|
|
char pars[3] = {0};
|
|
FILE *fd;
|
|
|
|
haspar = 0;
|
|
/* c value is arbitrary but is non-NULL for safety reasons; i is used to ensure the program does not open itself */
|
|
c = i = 1;
|
|
|
|
fd = 0;
|
|
|
|
|
|
/* process our parameters */
|
|
for(; (c = getopt(argc, argv, "cmlw")) != -1; c = 0)
|
|
{
|
|
switch(c)
|
|
{
|
|
case 'c': pars[CM] = 1;
|
|
haspar = 1;
|
|
break;
|
|
case 'm': pars[CM] = -1;
|
|
haspar = 1;
|
|
break;
|
|
case 'l': pars[L] = 1;
|
|
haspar = 1;
|
|
break;
|
|
case 'w': pars[W] = 1;
|
|
haspar = 1;
|
|
break;
|
|
/* Fall-through to default from ':' */
|
|
case ':':
|
|
case '?':
|
|
default: throw(NEEDARG_FAIL, mastrcat(argv[0], " [-c|-m] [-lw] [file ...]"));
|
|
break;
|
|
}
|
|
}
|
|
i = optind;
|
|
|
|
/* do-while allows easy opening of stdin */
|
|
do
|
|
{
|
|
/* open file */
|
|
fd = file_open(argv[i], "r");
|
|
|
|
/* process file */
|
|
wc(fd, current);
|
|
|
|
/* print results */
|
|
if(haspar)
|
|
{
|
|
printres(current, argv[i], pars);
|
|
}
|
|
else
|
|
{
|
|
printres(current, argv[i], NULL);
|
|
}
|
|
|
|
/* add results to global count */
|
|
results[WORDS] += current[WORDS];
|
|
results[LINES] += current[LINES];
|
|
results[COB] += current[COB];
|
|
|
|
/* reset count and file descriptor */
|
|
current[WORDS] = 0;
|
|
current[LINES] = 0;
|
|
current[COB] = 0;
|
|
|
|
fclose(fd);
|
|
}
|
|
/* this would normally be a pre-increment, but that can be confusing, so we use a more explicit approach here */
|
|
while((i+=1) < argc);
|
|
|
|
|
|
exit(0);
|
|
}
|