The C Programming Language

Chapter 7 - Input and Output 7

mmresult 2017. 12. 22. 10:53

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