pcregrep.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:13k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: pcregrep.c,v $
  4.  * PRODUCTION Revision 1000.0  2003/10/29 15:56:36  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R1.1
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*************************************************
  10. *               pcregrep program                 *
  11. *************************************************/
  12. /* This is a grep program that uses the PCRE regular expression library to do
  13. its pattern matching. On a Unix system it can recurse into directories. */
  14. #include <ctype.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <errno.h>
  19. #include "pcre.h"
  20. #include "pcre_config.h"
  21. #define FALSE 0
  22. #define TRUE 1
  23. typedef int BOOL;
  24. #define VERSION "2.0 01-Aug-2001"
  25. #define MAX_PATTERN_COUNT 100
  26. /*************************************************
  27. *               Global variables                 *
  28. *************************************************/
  29. static char *pattern_filename = NULL;
  30. static int  pattern_count = 0;
  31. static pcre **pattern_list;
  32. static pcre_extra **hints_list;
  33. static BOOL count_only = FALSE;
  34. static BOOL filenames = TRUE;
  35. static BOOL filenames_only = FALSE;
  36. static BOOL invert = FALSE;
  37. static BOOL number = FALSE;
  38. static BOOL recurse = FALSE;
  39. static BOOL silent = FALSE;
  40. static BOOL whole_lines = FALSE;
  41. /* Structure for options and list of them */
  42. typedef struct option_item {
  43.   int one_char;
  44.   char *long_name;
  45.   char *help_text;
  46. } option_item;
  47. static option_item optionlist[] = {
  48.   { -1,  "help",         "display this help and exit" },
  49.   { 'c', "count",        "print only a count of matching lines per FILE" },
  50.   { 'h', "no-filename",  "suppress the prefixing filename on output" },
  51.   { 'i', "ignore-case",  "ignore case distinctions" },
  52.   { 'l', "files-with-matches", "print only FILE names containing matches" },
  53.   { 'n', "line-number",  "print line number with output lines" },
  54.   { 'r', "recursive",    "recursively scan sub-directories" },
  55.   { 's', "no-messages",  "suppress error messages" },
  56.   { 'V', "version",      "print version information and exit" },
  57.   { 'v', "invert-match", "select non-matching lines" },
  58.   { 'x', "line-regex",   "force PATTERN to match only whole lines" },
  59.   { 'x', "line-regexp",  "force PATTERN to match only whole lines" },
  60.   { 0,    NULL,           NULL }
  61. };
  62. /*************************************************
  63. *       Functions for directory scanning         *
  64. *************************************************/
  65. /* These functions are defined so that they can be made system specific,
  66. although at present the only ones are for Unix, and for "no directory recursion
  67. support". */
  68. /************* Directory scanning in Unix ***********/
  69. #if defined(NCBI_OS_UNIX)
  70. #include <sys/types.h>
  71. #include <sys/stat.h>
  72. #include <dirent.h>
  73. typedef DIR directory_type;
  74. int
  75. isdirectory(char *filename)
  76. {
  77. struct stat statbuf;
  78. if (stat(filename, &statbuf) < 0)
  79.   return 0;        /* In the expectation that opening as a file will fail */
  80. return ((statbuf.st_mode & S_IFMT) == S_IFDIR)? '/' : 0;
  81. }
  82. directory_type *
  83. opendirectory(char *filename)
  84. {
  85. return opendir(filename);
  86. }
  87. char *
  88. readdirectory(directory_type *dir)
  89. {
  90. for (;;)
  91.   {
  92.   struct dirent *dent = readdir(dir);
  93.   if (dent == NULL) return NULL;
  94.   if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0)
  95.     return dent->d_name;
  96.   }
  97. return NULL;   /* Keep compiler happy; never executed */
  98. }
  99. void
  100. closedirectory(directory_type *dir)
  101. {
  102. closedir(dir);
  103. }
  104. #else
  105. /************* Directory scanning when we can't do it ***********/
  106. /* The type is void, and apart from isdirectory(), the functions do nothing. */
  107. typedef void directory_type;
  108. int isdirectory(char *filename) { return FALSE; }
  109. directory_type * opendirectory(char *filename) { return 0; }
  110. char *readdirectory(directory_type *dir) { return 0; }
  111. void closedirectory(directory_type *dir) {}
  112. #endif
  113. #if ! HAVE_STRERROR
  114. /*************************************************
  115. *     Provide strerror() for non-ANSI libraries  *
  116. *************************************************/
  117. /* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror()
  118. in their libraries, but can provide the same facility by this simple
  119. alternative function. */
  120. extern int   sys_nerr;
  121. extern char *sys_errlist[];
  122. char *
  123. strerror(int n)
  124. {
  125. if (n < 0 || n >= sys_nerr) return "unknown error number";
  126. return sys_errlist[n];
  127. }
  128. #endif /* HAVE_STRERROR */
  129. /*************************************************
  130. *              Grep an individual file           *
  131. *************************************************/
  132. static int
  133. pcregrep(FILE *in, char *name)
  134. {
  135. int rc = 1;
  136. int linenumber = 0;
  137. int count = 0;
  138. int offsets[99];
  139. char buffer[BUFSIZ];
  140. while (fgets(buffer, sizeof(buffer), in) != NULL)
  141.   {
  142.   BOOL match = FALSE;
  143.   int i;
  144.   int length = (int)strlen(buffer);
  145.   if (length > 0 && buffer[length-1] == 'n') buffer[--length] = 0;
  146.   linenumber++;
  147.   for (i = 0; !match && i < pattern_count; i++)
  148.     {
  149.     match = pcre_exec(pattern_list[i], hints_list[i], buffer, length, 0, 0,
  150.       offsets, 99) >= 0;
  151.     if (match && whole_lines && offsets[1] != length) match = FALSE;
  152.     }
  153.   if (match != invert)
  154.     {
  155.     if (count_only) count++;
  156.     else if (filenames_only)
  157.       {
  158.       fprintf(stdout, "%sn", (name == NULL)? "<stdin>" : name);
  159.       return 0;
  160.       }
  161.     else if (silent) return 0;
  162.     else
  163.       {
  164.       if (name != NULL) fprintf(stdout, "%s:", name);
  165.       if (number) fprintf(stdout, "%d:", linenumber);
  166.       fprintf(stdout, "%sn", buffer);
  167.       }
  168.     rc = 0;
  169.     }
  170.   }
  171. if (count_only)
  172.   {
  173.   if (name != NULL) fprintf(stdout, "%s:", name);
  174.   fprintf(stdout, "%dn", count);
  175.   }
  176. return rc;
  177. }
  178. /*************************************************
  179. *     Grep a file or recurse into a directory    *
  180. *************************************************/
  181. static int
  182. grep_or_recurse(char *filename, BOOL recurse, BOOL show_filenames,
  183.   BOOL only_one_at_top)
  184. {
  185. int rc = 1;
  186. int sep;
  187. FILE *in;
  188. /* If the file is a directory and we are recursing, scan each file within it.
  189. The scanning code is localized so it can be made system-specific. */
  190. if ((sep = isdirectory(filename)) != 0 && recurse)
  191.   {
  192.   char buffer[1024];
  193.   char *nextfile;
  194.   directory_type *dir = opendirectory(filename);
  195.   if (dir == NULL)
  196.     {
  197.     fprintf(stderr, "pcregrep: Failed to open directory %s: %sn", filename,
  198.       strerror(errno));
  199.     return 2;
  200.     }
  201.   while ((nextfile = readdirectory(dir)) != NULL)
  202.     {
  203.     int frc;
  204.     sprintf(buffer, "%.512s%c%.128s", filename, sep, nextfile);
  205.     frc = grep_or_recurse(buffer, recurse, TRUE, FALSE);
  206.     if (frc == 0 && rc == 1) rc = 0;
  207.     }
  208.   closedirectory(dir);
  209.   return rc;
  210.   }
  211. /* If the file is not a directory, or we are not recursing, scan it. If this is
  212. the first and only argument at top level, we don't show the file name.
  213. Otherwise, control is via the show_filenames variable. */
  214. in = fopen(filename, "r");
  215. if (in == NULL)
  216.   {
  217.   fprintf(stderr, "pcregrep: Failed to open %s: %sn", filename, strerror(errno));
  218.   return 2;
  219.   }
  220. rc = pcregrep(in, (show_filenames && !only_one_at_top)? filename : NULL);
  221. fclose(in);
  222. return rc;
  223. }
  224. /*************************************************
  225. *                Usage function                  *
  226. *************************************************/
  227. static int
  228. usage(int rc)
  229. {
  230. fprintf(stderr, "Usage: pcregrep [-Vcfhilnrsvx] [long-options] pattern [file] ...n");
  231. fprintf(stderr, "Type `pcregrep --help' for more information.n");
  232. return rc;
  233. }
  234. /*************************************************
  235. *                Help function                   *
  236. *************************************************/
  237. static void
  238. help(void)
  239. {
  240. option_item *op;
  241. printf("Usage: pcregrep [OPTION]... PATTERN [FILE] ...n");
  242. printf("Search for PATTERN in each FILE or standard input.n");
  243. printf("Example: pcregrep -i 'hello.*world' menu.h main.cnn");
  244. printf("Options:n");
  245. for (op = optionlist; op->one_char != 0; op++)
  246.   {
  247.   int n;
  248.   char s[4];
  249.   if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, "   ");
  250.   printf("  %s --%s%n", s, op->long_name, &n);
  251.   n = 30 - n;
  252.   if (n < 1) n = 1;
  253.   printf("%.*s%sn", n, "                    ", op->help_text);
  254.   }
  255. printf("n  -f<filename>  or  --file=<filename>n");
  256. printf("    Read patterns from <filename> instead of using a command line option.n");
  257. printf("    Trailing white space is removed; blanks lines are ignored.n");
  258. printf("    There is a maximum of %d patterns.n", MAX_PATTERN_COUNT);
  259. printf("nWith no FILE, read standard input. If fewer than two FILEs given, assume -h.n");
  260. printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble.n");
  261. }
  262. /*************************************************
  263. *                Handle an option                *
  264. *************************************************/
  265. static int
  266. handle_option(int letter, int options)
  267. {
  268. switch(letter)
  269.   {
  270.   case -1:  help(); exit(0);
  271.   case 'c': count_only = TRUE; break;
  272.   case 'h': filenames = FALSE; break;
  273.   case 'i': options |= PCRE_CASELESS; break;
  274.   case 'l': filenames_only = TRUE;
  275.   case 'n': number = TRUE; break;
  276.   case 'r': recurse = TRUE; break;
  277.   case 's': silent = TRUE; break;
  278.   case 'v': invert = TRUE; break;
  279.   case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break;
  280.   case 'V':
  281.   fprintf(stderr, "pcregrep version %s using ", VERSION);
  282.   fprintf(stderr, "PCRE version %sn", pcre_version());
  283.   exit(0);
  284.   break;
  285.   default:
  286.   fprintf(stderr, "pcregrep: Unknown option -%cn", letter);
  287.   exit(usage(2));
  288.   }
  289. return options;
  290. }
  291. /*************************************************
  292. *                Main program                    *
  293. *************************************************/
  294. int
  295. main(int argc, char **argv)
  296. {
  297. int i, j;
  298. int rc = 1;
  299. int options = 0;
  300. int errptr;
  301. const char *error;
  302. BOOL only_one_at_top;
  303. /* Process the options */
  304. for (i = 1; i < argc; i++)
  305.   {
  306.   if (argv[i][0] != '-') break;
  307.   /* Long name options */
  308.   if (argv[i][1] == '-')
  309.     {
  310.     option_item *op;
  311.     if (strncmp(argv[i]+2, "file=", 5) == 0)
  312.       {
  313.       pattern_filename = argv[i] + 7;
  314.       continue;
  315.       }
  316.     for (op = optionlist; op->one_char != 0; op++)
  317.       {
  318.       if (strcmp(argv[i]+2, op->long_name) == 0)
  319.         {
  320.         options = handle_option(op->one_char, options);
  321.         break;
  322.         }
  323.       }
  324.     if (op->one_char == 0)
  325.       {
  326.       fprintf(stderr, "pcregrep: Unknown option %sn", argv[i]);
  327.       exit(usage(2));
  328.       }
  329.     }
  330.   /* One-char options */
  331.   else
  332.     {
  333.     char *s = argv[i] + 1;
  334.     while (*s != 0)
  335.       {
  336.       if (*s == 'f')
  337.         {
  338.         pattern_filename = s + 1;
  339.         if (pattern_filename[0] == 0)
  340.           {
  341.           if (i >= argc - 1)
  342.             {
  343.             fprintf(stderr, "pcregrep: File name missing after -fn");
  344.             exit(usage(2));
  345.             }
  346.           pattern_filename = argv[++i];
  347.           }
  348.         break;
  349.         }
  350.       else options = handle_option(*s++, options);
  351.       }
  352.     }
  353.   }
  354. pattern_list = malloc(MAX_PATTERN_COUNT * sizeof(pcre *));
  355. hints_list = malloc(MAX_PATTERN_COUNT * sizeof(pcre_extra *));
  356. if (pattern_list == NULL || hints_list == NULL)
  357.   {
  358.   fprintf(stderr, "pcregrep: malloc failedn");
  359.   return 2;
  360.   }
  361. /* Compile the regular expression(s). */
  362. if (pattern_filename != NULL)
  363.   {
  364.   FILE *f = fopen(pattern_filename, "r");
  365.   char buffer[BUFSIZ];
  366.   if (f == NULL)
  367.     {
  368.     fprintf(stderr, "pcregrep: Failed to open %s: %sn", pattern_filename,
  369.       strerror(errno));
  370.     return 2;
  371.     }
  372.   while (fgets(buffer, sizeof(buffer), f) != NULL)
  373.     {
  374.     char *s = buffer + (int)strlen(buffer);
  375.     if (pattern_count >= MAX_PATTERN_COUNT)
  376.       {
  377.       fprintf(stderr, "pcregrep: Too many patterns in file (max %d)n",
  378.         MAX_PATTERN_COUNT);
  379.       return 2;
  380.       }
  381.     while (s > buffer && isspace((unsigned char)(s[-1]))) s--;
  382.     if (s == buffer) continue;
  383.     *s = 0;
  384.     pattern_list[pattern_count] = pcre_compile(buffer, options, &error,
  385.       &errptr, NULL);
  386.     if (pattern_list[pattern_count++] == NULL)
  387.       {
  388.       fprintf(stderr, "pcregrep: Error in regex number %d at offset %d: %sn",
  389.         pattern_count, errptr, error);
  390.       return 2;
  391.       }
  392.     }
  393.   fclose(f);
  394.   }
  395. /* If no file name, a single regex must be given inline */
  396. else
  397.   {
  398.   if (i >= argc) return usage(0);
  399.   pattern_list[0] = pcre_compile(argv[i++], options, &error, &errptr, NULL);
  400.   if (pattern_list[0] == NULL)
  401.     {
  402.     fprintf(stderr, "pcregrep: Error in regex at offset %d: %sn", errptr,
  403.       error);
  404.     return 2;
  405.     }
  406.   pattern_count++;
  407.   }
  408. /* Study the regular expressions, as we will be running them may times */
  409. for (j = 0; j < pattern_count; j++)
  410.   {
  411.   hints_list[j] = pcre_study(pattern_list[j], 0, &error);
  412.   if (error != NULL)
  413.     {
  414.     char s[16];
  415.     if (pattern_count == 1) s[0] = 0; else sprintf(s, " number %d", j);
  416.     fprintf(stderr, "pcregrep: Error while studying regex%s: %sn", s, error);
  417.     return 2;
  418.     }
  419.   }
  420. /* If there are no further arguments, do the business on stdin and exit */
  421. if (i >= argc) return pcregrep(stdin, NULL);
  422. /* Otherwise, work through the remaining arguments as files or directories.
  423. Pass in the fact that there is only one argument at top level - this suppresses
  424. the file name if the argument is not a directory. */
  425. only_one_at_top = (i == argc - 1);
  426. if (filenames_only) filenames = TRUE;
  427. for (; i < argc; i++)
  428.   {
  429.   int frc = grep_or_recurse(argv[i], recurse, filenames, only_one_at_top);
  430.   if (frc == 0 && rc == 1) rc = 0;
  431.   }
  432. return rc;
  433. }
  434. /* End */