単純なgrepコマンド

単純なgrep。引数で与えられた文字列にHITすると印字する。ただし-xオプションが与えられていれば逆に印字しない。また-nオプションでHITした行番号も印字する。オプションは-nxの書式も許可する。


以下はK&Rから。ただし分かりづらかったのでwhile文はfor文に変更した。

#include 
#include 

#define MAXLINE 1000

int getline(char *, int);


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



     /* オプション処理用のループ。
      * 外側でコマンドラインの引数をインクリメントする。
      * 内側でその引数の文字列処理を行う。
      */
     for (--argc, ++argv; argc > 0 && (*argv)[0] == '-'; --argc, ++argv) {
          for (++argv[0]; (c = *argv[0]); ++argv[0])
               switch (c) {
               case 'x':
                    except = 1;
                    break;
               case 'n':
                    number = 1;
                    break;
               default:
                    printf("find: illegal optinon %c\n", c);
                    argc = 0;
                    break;
               }
     }

     /* 引数が不正なら終了 */
     if (argc != 1) {
          printf("Usage: find -x -n pattern\n");
          return -1;
     }

     /* 印字処理用のループ。*/
     for (lineno=1; getline(line, MAXLINE) > 0; ++lineno) {
          if ((strstr(line, *argv) != NULL) != except) {    /* この処理はややこしい。
                                                             * 1. 文字列がHITし、かつexceptが0である
                                                             * 2. 文字列がHITせず、かつexceptが1である
                                                             * 上記2つの場合にprintする。*/
               if (number) {
                    printf("%ld:", lineno);
               }
               printf("%s", line);
               found++;
          }
     }
     return found;
}

しかし、MAXLINEは1000なのに、linenoをlongで宣言しているのは何故だろう? 博士たちのご乱心かしら。

シンタックスシュガー

argv[i]は*(argv+i)のシンタックスシュガーで有ることを利用し、以下のように書き換えた。こちらの方が分かりやすいと思うのだけれど。

#include 
#include 

#define MAXLINE 1000

int getline(char *, int);


int main(int argc, char *argv[])
{
     char line[MAXLINE];
     long lineno;
     int c, i, j;
     int except, number, found;


     except = number = 0;
     for (--argc, i=1; argc > 0 && argv[i][0] == '-'; --argc, i++) {
          for (j=1; c = argv[i][j]; j++)
               switch (c) {
               case 'x':
                    except = 1;
                    break;
               case 'n':
                    number = 1;
                    break;
               default:
                    printf("find: illegal optinon %c\n", c);
                    argc = 0;
                    break;
               }
     }

     if (argc != 1) {
          printf("Usage: find -x -n pattern\n");
          return -1;
     }

     found = 0;
     for (lineno = 1; getline(line, MAXLINE) > 0; lineno++) {
          if ((strstr(line, argv[i]) != NULL) != except) {
               if (number) {
                    printf("%ld:", lineno);
               }
               printf("%s", line);
               found++;
          }
     }
     return found;
}