/*
 * wc [file ...]
 */

/*)BUILD	$(TKBOPTIONS) = {
			TASK	= ...WCX
		}
*/

#ifdef	DOCUMENTATION

title	wc	Word Count
index		Count Words, Lines, and Bytes in Files

synopsis

	wc [-options] [filename ...]

description

	Count the number of bytes, words, and lines in one or more files.
	wc accepts wild-card file name arguments.

	The following options are defined:

	.lm +8;
 -b	Count bytes in the input files.
 -c	Count characters in the input files - synonym for -b.
 -l	Count lines in the input files.
 -u	Unix-style output; omits the descriptions of the counts (e.g., the
	"bytes" in "5 bytes").
 -w	Count words in the input files.
	.lm -8;

	A word is defined as "optional spaces or tabs" followed by text up to
	the first space, tab, or end of line.

	If no options are given, wc provides all three counts.

	If no file names are given, wc reads from standard input.  All output
	is written to standard output.
diagnostics

	.lm +8
	.s.i -8;"file name": cannot open
	.s.i -8;"file name": illegal file name
	.lm -8

author

	Martin Minow

bugs

#endif
/*
 * Edit history
 * 0.0	??-???-?? MM	Creation
 * 1.0	29-May-85 JSL	Added VMS redirection code, all options, on-line
 *			help.
 */

char	*documentation[]  = {
"wc reads one or more files, counting characters, words and lines.",
"Usage:  wc [-bcluw] [filename ...]",
"",
"Where:",
"",
" -b	Count bytes in the input files.",
" -c	Count characters in the input files - synonym for -b.",
" -l	Count lines in the input files.",
" -u	Unix-style output; omits the descriptions of the counts (e.g., the",
"	\"bytes\" in \"5 bytes\").",
" -w	Count words in the input files.",

"If no options are given, wc provides all three counts.",
"",
"If no file names are given, wc reads from standard input.  All output is",
"written to standard output.",
"",
"A word is defined as \"optional spaces or tabs\" followed by text up to",
"the first space, tab, or end of line.",
"",
0 };

#include <stdio.h>
#ifdef vms
#include		<ssdef.h>
#include		<stsdef.h>
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	SS$_ABORT
#endif
/*
 * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0
#endif
#ifndef	IO_ERROR
#define	IO_ERROR	1
#endif

int	dobytes = 0;		/* Show byte count	*/
int	dowords = 0;		/* Show word count	*/
int	dolines = 0;		/* Show line count	*/
int	ustyle	= 0;		/* Unix-style display	*/
long	twords	= 0;
long	tlines	= 0;
long	tbytes	= 0;
char	file_name[256];

main(argc, argv)
char *argv[];
{
	register int	i, nfiles;
	register FILE	*fp;
	int		nopts,gotcha;

#ifdef vms
	argc = getredirection(argc,argv);
#endif

	if (argc > 1 && argv[1][0] == '?') {
		help();
		exit(IO_ERROR);
	}

	for (nopts = 0, i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {

			case 'b':
			case 'c':
				dobytes++;
				break;
			case 'l':
				dolines++;
				break;
			case 'u':
				ustyle++;
				break;
			case 'w':
				dowords++;
				break;
			default:
				usage();
				exit(IO_ERROR);
			}
			argv[i] = NULL;
			nopts++;
		}
	}

	if (dobytes == 0 && dowords == 0 && dolines == 0)
	{	dobytes++;
		dowords++;
		dolines++;
	}
	nfiles = 0;
	if ((argc-nopts) < 2) {
	    ++nfiles;
	    count(stdin, NULL);
	}
	else {
#ifdef unix
	    for (i = 1; i < argc; ++i) {
		if (argv[i] == NULL)
			continue;
		if ((fp = fopen(argv[i], "r")) == NULL) {
		    perror(argv[i]);
		}
		else {
		    ++nfiles;
		    count(fp, argv[i]);
		    fclose(fp);
		}
	    }
#else
	    for (i = 1; i < argc; ++i) {
		if (argv[i] == NULL)
			continue;
		if ((fp = fwild(argv[i], "r")) == NULL) {
		    perror(argv[i]);
		}
		else {
		    for (gotcha = 0; fnext(fp) != NULL; gotcha++) {
			++nfiles;
			fgetname(fp, file_name);
			count(fp, file_name);
		    }
		    if (gotcha == 0)
			fprintf(stderr, "\"%s\": no matching files\n", argv[i]);
		}
	    }
#endif
	}
	if (nfiles > 1)
		output(tlines, twords, tbytes, "total");
	exit(IO_SUCCESS);
}

count(fp, filename)
FILE		*fp;			/* File pointer			*/
char		*filename;		/* File name string		*/
{
	register int c, inword;
	long lines;
	long words;
	long bytes;

	lines = 0;
	words = 0;
	bytes = 0;
	inword = 0;
	while((c = getc(fp)) != EOF) {
	    ++bytes;
	    if (c == ' ' || c == '\t' || c == '\n') {
		inword = 0;
		if (c == '\n')
		    ++lines;
	    }
	    else if (!inword) {
		++inword;
		++words;
	    }
	}
	twords += words;
	tlines += lines;
	tbytes += bytes;
	output(lines, words, bytes, filename);
}

output(lines, words, bytes, filename)
long		lines;
long		words;
long		bytes;
char		*filename;
{
	if (dolines)
		plural(lines, "line");
	if (dowords)
		plural(words, "word");
	if (dobytes)
		plural(bytes, "byte");
	if (filename != NULL)
	    printf(" %s", filename);
	printf("\n");
}

plural(value, what)
long		value;
char		*what;
{
	if (ustyle)
		printf("%8ld", value);
	else
		printf("%8ld %s%c", value, what, (value == 1) ? ' ' : 's');
}

usage()
/*
 * Give simple-minded help
 */
{
	fprintf(stderr,
 "Usage:  wc [-bcluw] [filename ...]\n"
		);
}

help()
/*
 * Give good help
 */
{
	register char	**dp;

	for (dp = documentation; *dp; dp++)
		printf("%s\n", *dp);
}
