Page 165

Modify the pattern finding program of Chapter 5 to take its input from a set of named files or, if no files are named as arguments, from the standard input. Should the file name be printed when a matching line is found?

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define MAXLINE 1000
#define MAXFILES 16
#define STDIN "stdin"

int main(int argc, char *argv[])
{
	char line[MAXLINE];
	long lineno = 0;
	int c, found = 0;
	bool except = false, number = false;

	char *file_names[MAXFILES];
	char **fn = file_names;
	char *pattern = NULL;

	*fn = STDIN;

	if (argc < 2) {
		puts("error: not enough arguments");
		return 1;
	}

	while (--argc > 0) {
		if ((*++argv)[0] == '-') {
			while ((c = *++argv[0])) {
				switch (c) {
				case 'x':
					except = 1;
					break;
				case 'n':
					number = 1;
					break;
				default:
					printf("error: illegal option %c\n", c);
					argc = 0;
					found = -1;
					break;
				}
			}
		} else if (pattern == NULL) {
			pattern = *argv;
		} else {
			*fn++ = *argv;
		}
	}

	FILE *fp;
	int file_count = fn - file_names;
	for (int i = 0; i < file_count; i++) {
		lineno = 0;

		if (strcmp(file_names[i], STDIN) == 0) {
			fp = stdin;
		} else {
			fp = fopen(file_names[i], "r");
		}

		if (fp == NULL) {
			printf("error: unable to read file %s\n",
			       file_names[i]);
		} else {
			while (fgets(line, MAXLINE, fp) != NULL) {
				lineno++;
				if ((strstr(line, pattern) != NULL) != except) {
					if (number) {
						printf("%ld:", lineno);
					}
					printf("%s", line);
					found++;
				}
			}
		}
	}
}