Выбрать главу

  1: /* grep.с */

  2:

  3: #include <alloca.h>

  4: #include <ctype.h>

  5: #include <popt.h>

  6: #include <regex.h>

  7: #include <stdio.h>

  8: #include <string.h>

  9: #include <unistd.h>

 10:

 11: #define MODE_REGEXP 1

 12: #define MODE_EXTENDED 2

 13: #define MODE_FIXED 3

 14:

 15: void do_regerror(int errcode, const regex_t *preg) {

 16:  char *errbuf;

 17:  size_t errbuf_size;

 18:

 19:  errbuf_size = regerror(errcode, preg, NULL, 0);

 20:  errbuf = alloca(errbuf_size);

 21:  if (!errbuf) {

 22:   perror("alloca");

 23:   return;

 24:  }

 25:

 26:  regerror(errcode, preg, errbuf, errbuf_size);

 27:  fprintf(stderr, "%s\n", errbuf);

 28: }

 29:

 30: int scanFile(FILE * f, int mode, const void * pattern,

 31:  int ignoreCase, const char * fileName,

 32:  int * maxCountPtr) {

 33:  long lineLength;

 34:  char * line;

 35:  int match;

 36:  int rc;

 37:  char * chptr;

 38:  char * prefix = "";

 39:

 40:  if (fileName) {

 41:   prefix = alloca(strlen(fileName) + 4);

 42:   sprintf(prefix, "%s: ", fileName);

 43:  }

 44:

 45:  lineLength = sysconf(_SC_LINE_MAX);

 46:  line = alloca(lineLength);

 47:

 48:  while (fgets(line, lineLength, f) && (*maxCountPtr)) {

 49:   /* если у нас не будет завершающего символа '\n'

 50:      то мы не сможем получить всю строку целиком */

 51:   if (line [strlen (line) -1] != '\n') {

 52:    fprintf(stderr, " %s line слишком длинная\n", prefix);

 53:    return 1;

 54:   }

 55:

 56:   if (mode == MODE_FIXED) {

 57:    if (ignoreCase) {

 58:     for (chptr = line; *chptr; chptr++) {

 59:      if (isalpha(*chptr)) *chptr = tolower(*chptr);

 60:     }

 61:    }

 62:    match = (strstr(line, pattern) != NULL);

 63:   } else {

 64:    match = 0;

 65:    rc = regexec (pattern, line, 0, NULL, 0);

 66:    if (!rc)

 67:     match = 1;

 68:    else if (rc != REG_NOMATCH)

 69:    do_regerror(match, pattern);

 70:   }

 71:

 72:   if (match) {

 73:    printf("%s%s", prefix, line);

 74:    if (*maxCountPtr > 0)

 75:     (*maxCountPtr)--;

 76:   }

 77:  }

 78:

 79:  return 0;

 80: }

 81:

 82: int main(int argc, const char ** argv) {

 83:  const char * pattern = NULL;

 84:  regex_t regPattern;

 85:  const void * finalPattern;

 86:  int mode = MODE_REGEXP;

 87:  int ignoreCase = 0;

 88:  int maxCount = -1;

 89:  int rc;

 90:  int regFlags;

 91:  const char ** files;

 92:  poptContext optCon;

 93:  FILE * f;

 94:  char * chptr;

 95:  struct poptOption optionsTable[] = {

 96:   { "extended-regexp", 'E', POPT_ARG_VAL,

 97:     &mode, MODE_EXTENDED,

 98:     "шаблоном для соответствия является расширенное регулярное "

 99:     "выражение"},

100:   { "fixed-strings", 'F', POPT_ARG_VAL,

101:     &mode, MODE_FIXED,

102:     "шаблоном для соответствия является базовая строка (не "

103:     "регулярное выражение)", NULL },

104:   { "basic-regexp", 'G', POPT_ARG_VAL,

105:     &mode, MODE_REGEXP,

106:     "шаблоном для соответствия является базовое регулярное выражение" },

107:   { "ignore-case", 'i', POPT_ARG_NONE, &ignoreCase, 0,

108:     "выполнять поиск, чувствительный к регистру", NULL },

109:   { "max-count", 'm', POPT_ARG_INT, &maxCount, 0,

110:     "завершить после получения N. совпадений", "N" },

111:   { "regexp", 'e', POPT_ARG_STRING, &pattern, 0,

112:     "регулярное выражение для поиска", "pattern" },

113:     POPT_AUTOHELP

114:   { NULL, '\0', POPT_ARG_NONE, NULL, 0, NULL, NULL }

115:  };

116:

117:  optCon = poptGetContext("grep", argc, argv, optionsTable, 0);

118:  poptSetOtherOptionHelp(optCon, "<шаблон> <список файлов>");

119:

120:  if ((rc = poptGetNextOpt(optCon)) < -1) {

121:   /* во время обработки параметра возникла ошибка */

122:   fprintf(stderr, "%s: %s\n",

123:    poptBadOption(optCon, POPT_BADOPTION_NOALIAS),

124:   poptStrerror(rc));

125:   return 1;

126:  }

127:

128:  files = poptGetArgs(optCon);

129:  /* если мы не получили шаблон, то он должен быть первым

130:     из оставшихся */

131:  if (!files && !pattern) {

132:   poptPrintUsage(optCon, stdout, 0);

133:   return 1;

134:  }

135:

136:  if (!pattern) {

137:   pattern = files[0];

138:   files++;

139:  }

140:

141:  regFlags = REG_NEWLINE | REG_NOSUB;

142:  if (ignoreCase) {

143:   regFlags |= REG_ICASE;

144:   /* преобразование шаблона в нижний регистр; этого можно не делать,