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?
Solution by Barrett Drawdy
/*
* K&R2 exercise 7-7 By: Barrett Drawdy
*
* Modify the pattern finding program of Chapter 5 (on page 117) 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
* file is found?
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXFILES 10 /* maximum number of files to search in */
#define MAXLINE 1024 /* longest line that can be read at once + 1 for '\0' */
struct file {
FILE *p;
char *name;
};
int main(int argc, char *argv[])
{
struct file files[MAXFILES + 1];
struct file *fp = files;
char **argp;
char *pat;
char line[MAXLINE];
int c;
int found = 0, except = 0, number = 0;
long line_num;
if(argc < 2) {
fprintf(stderr, "usage: %s -x -n [file1] [file2] ... pattern\n",
argv[0]);
exit(-1);
}
/* get pattern */
pat = argv[--argc];
/* open files and read arguments */
for(argp = argv + 1; argp - argv < argc; ++argp) {
/* read arguments */
if(*argp[0] == '-') {
while((c = *++argp[0]))
switch(c) {
case 'x':
except = 1;
break;
case 'n':
number = 1;
break;
default:
fprintf(stderr, "%s: illegal option %c\n",
argv[0], c);
fprintf(stderr,
"usage: %s -x -n [file1] [file2] ... pattern\n",
argv[0]);
exit(-1);
}
}
/* read filenames */
else {
if(fp - files >= MAXFILES) {
fprintf(stderr, "%s: can only open %d files\n", argv[0],
MAXFILES);
exit(-1);
}
if((fp->p = fopen(*argp, "r")) == NULL) {
fprintf(stderr, "%s: error opening %s\n", argv[0], *argp);
exit(-1);
}
else
fp++->name = *argp;
}
}
/* if there were no filenames, read from stdin */
if(fp == files) {
fp++->p = stdin;
}
fp->p = NULL; /* put NULL pointer at end of array */
/* search for pattern in each file */
for(fp = files; fp->p != NULL; ++fp) {
line_num = 0;
while(fgets(line, MAXLINE, fp->p) != NULL) {
++line_num;
if((strstr(line, pat) != NULL) != except) {
if(fp->p != stdin)
printf("%s ", fp->name);
if(number)
printf("%ld", line_num);
if(number || fp->p != stdin)
putchar(':');
puts(line);
++found;
}
}
}
/* clean up */
for(fp = files; fp->p != NULL; ++fp)
fclose(fp->p);
return found;
} /* end of main */
Category 0 Solution by Jose G. López
/* Pattern finding program that takes its input from a set of
file names or, if they aren't passed as arguments, from the standard
input. The file name is shown when a matching line is found.
Note: I've decided to implement the program using a list of structures,
allocating memory when needed.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct file *getinput(int argc, char *argv[]);
void find(char *pattern, int number, int except, struct file *p);
struct file {
FILE *fp;
char *name;
struct file *next;
};
int main(int argc, char *argv[])
{
int c, except = 0, number = 0;
struct file *p;
while (--argc > 0 && (*++argv)[0] == '-') {
while ((c = *++argv[0])) {
switch (c) {
case 'n':
number = 1;
break;
case 'x':
except = 1;
break;
default:
printf("incorrect option '%c'\n", c);
argc = 0;
break;
}
}
}
if (argc < 1)
printf("Usage: find -x -n [FILE]... pattern\n");
else {
p = getinput(argc, argv);
find(argv[argc - 1], number, except, p);
}
return 0;
}
#define MAXLEN 1000 /* max length of any input line */
struct file *getfile(char *filename, struct file *aux);
struct file *falloc(void);
/* getinput: gets passed arguments and returns the first element in the list
created. */
struct file *getinput(int argc, char *argv[])
{
struct file *head, *p, *aux;
aux = NULL;
if (argc > 1) { /* if file names specified */
do { /* we don't have a list without a head */
head = getfile(*argv++, aux);
argc--;
} while (argc > 1 && head == NULL);
aux = head; /* because we can't change its value inside getfile */
while (argc-- > 1) {
if ((p = getfile(*argv++, aux)) != NULL)
aux = p;
}
} else { /* read from input */
if ((head = falloc()) != NULL) {
head->fp = stdin;
head->name = "input";
head->next = NULL;
}
}
return head;
}
/* getfile: with a file name tries to open the file and creates a node with a
pointer to it and its name. */
struct file *getfile(char *filename, struct file *aux)
{
FILE *file;
struct file *p;
p = NULL;
if ((file = fopen(filename, "r")) != NULL) {
if ((p = falloc()) != NULL) {
p->fp = file;
p->name = filename;
p->next = NULL;
if (aux != NULL) {
aux->next = p;
}
}
} else
fprintf(stderr, "Can't opent file %s\n", filename);
return p;
}
/* find: searches the pattern in the list of structures starting from head. */
void find(char *pattern, int number, int except, struct file *p)
{
char line[MAXLEN];
long lineno;
int show_fname;
while (p != NULL) {
lineno = 0;
show_fname = 1;
while (fgets(line, MAXLEN, p->fp) != NULL) {
lineno++;
if ((strstr(line, pattern) != NULL) != except) {
if (show_fname) { /* show file name only once */
printf("%s\n", p->name);
printf("--------------------------\n");
show_fname = 0;
}
if (number)
printf("%ld:", lineno);
printf("%s", line);
}
}
if (!show_fname)
printf("\n");
fclose(p->fp);
p = p->next;
}
}
/* falloc: allocates a new struct file node and returns a pointer to it. */
struct file *falloc(void)
{
return (struct file *)malloc(sizeof(struct file));
}
'The C Programming Language' 카테고리의 다른 글
Chapter 7 - Input and Output 9 (0) | 2017.12.22 |
---|---|
Chapter 7 - Input and Output 8 (0) | 2017.12.22 |
Chapter 7 - Input and Output 6 (0) | 2017.12.22 |
Chapter 7 - Input and Output 5 (0) | 2017.12.22 |
Chapter 7 - Input and Output 4 (0) | 2017.12.22 |