diff -x CVS -x regex.h -Nur tre/configure.ac prj/widechar-regex/tre/dist/configure.ac --- tre/configure.ac 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/configure.ac 2009-07-21 11:36:06.000000000 +0000 @@ -5,7 +5,7 @@ AC_CANONICAL_TARGET AM_INIT_AUTOMAKE(1.9.0) AC_PREREQ(2.59) -AM_GNU_GETTEXT_VERSION(0.17) +AM_GNU_GETTEXT_VERSION(0.14.6) dnl Checks for programs. AC_PROG_CC @@ -100,6 +100,7 @@ dnl Checks for headers, functions, types, and macros AC_DEFINE(_GNU_SOURCE, 1, [ Define to enable GNU extensions in glibc ]) AC_HEADER_STDC +AC_CHECK_HEADERS([sys/cdefs.h]) AC_ARG_WITH(alloca, AC_HELP_STRING( @@ -513,6 +514,17 @@ AC_SYS_LARGEFILE +if test "$tre_agrep" = "yes"; then + OLD_LIBS="$LIBS" + AC_CHECK_HEADERS([fts.h ftw.h]) + AC_CHECK_HEADERS([termcap.h]) + AC_CHECK_LIB(termcap, tgetent) + AC_CHECK_FUNCS([tputs t_agetstr t_getent t_freent]) + TRE_AGREP_LIBS="$LIBS" + LIBS="$OLD_LIBS" + AC_SUBST(TRE_AGREP_LIBS) +fi + AM_GNU_GETTEXT([external]) AC_LIBTOOL_TAGS([]) AC_LIBTOOL_WIN32_DLL diff -x CVS -x regex.h -Nur tre/doc/agrep.1.in prj/widechar-regex/tre/dist/doc/agrep.1.in --- tre/doc/agrep.1.in 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/doc/agrep.1.in 2009-06-29 10:14:19.000000000 +0000 @@ -89,6 +89,9 @@ .BR \-v ", " \-\^\-invert\-match Select non-matching records instead of matching records. .TP +.BR \-r ", " \-\^\-recursive +Read all files under each directory, recursively. +.TP .BR \-V ", " \-\^\-version Print version information and exit. .TP diff -x CVS -x regex.h -Nur tre/lib/regcomp.c prj/widechar-regex/tre/dist/lib/regcomp.c --- tre/lib/regcomp.c 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/lib/regcomp.c 2009-07-30 12:03:38.000000000 +0000 @@ -19,12 +19,13 @@ #include "xmalloc.h" int -regncomp(regex_t *preg, const char *regex, size_t n, int cflags) +regncomp(regex_t * __restrict preg, const char * __restrict regex, size_t n, + int cflags) { int ret; #if TRE_WCHAR tre_char_t *wregex; - int wlen; + size_t wlen; wregex = xmalloc(sizeof(tre_char_t) * (n + 1)); if (wregex == NULL) @@ -50,7 +51,7 @@ #if TRE_MULTIBYTE else { - int consumed; + size_t consumed; tre_char_t *wcptr = wregex; #ifdef HAVE_MBSTATE_T mbstate_t state; @@ -71,11 +72,11 @@ return REG_BADPAT; } break; - case -1: + case (size_t)-1: DPRINT(("mbrtowc: error %d: %s.\n", errno, strerror(errno))); xfree(wregex); return REG_BADPAT; - case -2: + case (size_t)-2: /* The last character wasn't complete. Let's not call it a fatal error. */ consumed = n; @@ -100,21 +101,35 @@ } int -regcomp(regex_t *preg, const char *regex, int cflags) +regcomp(regex_t * __restrict preg, const char * __restrict regex, int cflags) { +#ifdef _NETBSD_SOURCE + size_t len; + + if (cflags & REG_PEND) + { + if (preg->re_endp >= regex) + len = preg->re_endp - regex; + else + len = 0; + return regncomp(preg, regex, len, cflags); + } + else +#endif /* _NETBSD_SOURCE */ return regncomp(preg, regex, regex ? strlen(regex) : 0, cflags); } #ifdef TRE_WCHAR int -regwncomp(regex_t *preg, const wchar_t *regex, size_t n, int cflags) +regwncomp(regex_t * __restrict preg, const wchar_t * __restrict regex, + size_t n, int cflags) { return tre_compile(preg, regex, n, cflags); } int -regwcomp(regex_t *preg, const wchar_t *regex, int cflags) +regwcomp(regex_t * __restrict preg, const wchar_t * __restrict regex, int cflags) { return tre_compile(preg, regex, regex ? wcslen(regex) : 0, cflags); } diff -x CVS -x regex.h -Nur tre/lib/regerror.c prj/widechar-regex/tre/dist/lib/regerror.c --- tre/lib/regerror.c 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/lib/regerror.c 2009-07-30 12:04:23.000000000 +0000 @@ -33,36 +33,100 @@ /* Error message strings for error codes listed in `regex.h'. This list needs to be in sync with the codes listed there, naturally. */ -static const char *tre_error_messages[] = - { gettext_noop("No error"), /* REG_OK */ - gettext_noop("No match"), /* REG_NOMATCH */ - gettext_noop("Invalid regexp"), /* REG_BADPAT */ - gettext_noop("Unknown collating element"), /* REG_ECOLLATE */ - gettext_noop("Unknown character class name"), /* REG_ECTYPE */ - gettext_noop("Trailing backslash"), /* REG_EESCAPE */ - gettext_noop("Invalid back reference"), /* REG_ESUBREG */ - gettext_noop("Missing ']'"), /* REG_EBRACK */ - gettext_noop("Missing ')'"), /* REG_EPAREN */ - gettext_noop("Missing '}'"), /* REG_EBRACE */ - gettext_noop("Invalid contents of {}"), /* REG_BADBR */ - gettext_noop("Invalid character range"), /* REG_ERANGE */ - gettext_noop("Out of memory"), /* REG_ESPACE */ - gettext_noop("Invalid use of repetition operators") /* REG_BADRPT */ +static const struct { + int err; + const char *string; +} tre_error_messages[] = + { + { REG_OK, gettext_noop("No error") }, + { REG_NOMATCH, gettext_noop("No match") }, + { REG_BADPAT, gettext_noop("Invalid regexp") }, + { REG_ECOLLATE, gettext_noop("Unknown collating element"), }, + { REG_ECTYPE, gettext_noop("Unknown character class name") }, + { REG_EESCAPE, gettext_noop("Trailing backslash") }, + { REG_ESUBREG, gettext_noop("Invalid back reference") }, + { REG_EBRACK, gettext_noop("Missing ']'") }, + { REG_EPAREN, gettext_noop("Missing ')'") }, + { REG_EBRACE, gettext_noop("Missing '}'") }, + { REG_BADBR, gettext_noop("Invalid contents of {}") }, + { REG_ERANGE, gettext_noop("Invalid character range") }, + { REG_ESPACE, gettext_noop("Out of memory") }, + { REG_BADRPT, gettext_noop("Invalid use of repetition operators") } }; +#ifdef _NETBSD_SOURCE +static const struct { + int err; + const char *string; +} tre_error_codes[] = + { + { REG_OK, gettext_noop("REG_OK") }, + { REG_NOMATCH, gettext_noop("REG_NOMATCH") }, + { REG_BADPAT, gettext_noop("REG_BADPAT") }, + { REG_ECOLLATE, gettext_noop("REG_ECOLLATE") }, + { REG_ECTYPE, gettext_noop("REG_ECTYPE") }, + { REG_EESCAPE, gettext_noop("REG_EESCAPE") }, + { REG_ESUBREG, gettext_noop("REG_ESUBREG") }, + { REG_EBRACK, gettext_noop("REG_EBRACK") }, + { REG_EPAREN, gettext_noop("REG_EPAREN") }, + { REG_EBRACE, gettext_noop("REG_EBRACE") }, + { REG_BADBR, gettext_noop("REG_EBADBR") }, + { REG_ERANGE, gettext_noop("REG_ERANGE") }, + { REG_ESPACE, gettext_noop("REG_ESPACE") }, + { REG_BADRPT, gettext_noop("REG_BADRPT") } + }; +#endif /* _NETBSD_SOURCE */ size_t -regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +regerror(int errcode, const regex_t * __restrict preg, char * __restrict errbuf, + size_t errbuf_size) { - const char *err; - size_t err_len; + const char *err = NULL; + size_t err_len, i; /*LINTED*/(void)&preg; - if (errcode >= 0 - && errcode < (int)(sizeof(tre_error_messages) - / sizeof(*tre_error_messages))) - err = gettext(tre_error_messages[errcode]); +#ifdef _NETBSD_SOURCE + if (errcode & REG_ITOA && !(errcode & REG_ATOI)) + { + for (i = 0; i < sizeof(tre_error_codes) / sizeof(tre_error_codes[0]); i++) + if (tre_error_codes[i].err == errcode) + { + err = tre_error_messages[i].string; + break; + } + if (err == NULL) + { + err_len = snprintf(errbuf, errbuf_size, "REG_0x%x", errcode); + return err_len >= errbuf_size ? errbuf_size : err_len + 1; + } + } + else if (errcode & REG_ATOI && !(errcode & REG_ITOA)) + { + for (i = 0; i < sizeof(tre_error_codes) / sizeof(tre_error_codes[0]); i++) + if (strcmp(tre_error_codes[i].string, preg->re_endp) == 0) + { + err_len = snprintf(errbuf, errbuf_size, "%d", + tre_error_messages[i].err); + return err_len >= errbuf_size ? errbuf_size : err_len + 1; + } + } else + { +#endif /* _NETBSD_SOURCE */ + if (errcode >= 0) + { + for (i = 0; i < sizeof(tre_error_messages) / + sizeof(tre_error_messages[0]); i++) + if (tre_error_messages[i].err == errcode) + { + err = gettext(tre_error_messages[errcode].string); + break; + } + } + if (err == NULL || errcode < 0) err = gettext("Unknown error"); +#ifdef _NETBSD_SOURCE + } +#endif /* _NETBSD_SOURCE */ err_len = strlen(err) + 1; if (errbuf_size > 0 && errbuf != NULL) diff -x CVS -x regex.h -Nur tre/lib/regexec.c prj/widechar-regex/tre/dist/lib/regexec.c --- tre/lib/regexec.c 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/lib/regexec.c 2009-07-30 12:03:56.000000000 +0000 @@ -19,8 +19,10 @@ # ifdef _AIX #pragma alloca # else -# ifndef alloca /* predefined by HP cc +Olibcalls */ +# ifndef __NetBSD__ /* NetBSD has alloca in stdlib.h */ +# ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); +# endif # endif # endif # endif @@ -200,8 +202,8 @@ } int -regnexec(const regex_t *preg, const char *str, size_t len, - size_t nmatch, regmatch_t pmatch[], int eflags) +regnexec(const regex_t * __restrict preg, const char * __restrict str, + size_t len, size_t nmatch, regmatch_t pmatch[], int eflags) { tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; tre_str_type_t type = (TRE_MB_CUR_MAX == 1) ? STR_BYTE : STR_MBS; @@ -210,9 +212,20 @@ } int -regexec(const regex_t *preg, const char *str, +regexec(const regex_t * __restrict preg, const char * __restrict str, size_t nmatch, regmatch_t pmatch[], int eflags) { +#ifdef _NETBSD_SOURCE + size_t len; + + if (eflags & REG_STARTEND) + { + len = (str + pmatch[0].rm_eo) - (str + pmatch[0].rm_so); + str += pmatch[0].rm_so; + return regnexec(preg, str, len, nmatch, pmatch, eflags); + } + else +#endif /* _NETBSD_SOURCE */ return regnexec(preg, str, (unsigned)-1, nmatch, pmatch, eflags); } @@ -220,15 +233,15 @@ #ifdef TRE_WCHAR int -regwnexec(const regex_t *preg, const wchar_t *str, size_t len, - size_t nmatch, regmatch_t pmatch[], int eflags) +regwnexec(const regex_t * __restrict preg, const wchar_t * __restrict str, + size_t len, size_t nmatch, regmatch_t pmatch[], int eflags) { tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; return tre_match(tnfa, str, len, STR_WIDE, nmatch, pmatch, eflags); } int -regwexec(const regex_t *preg, const wchar_t *str, +regwexec(const regex_t * __restrict preg, const wchar_t * __restrict str, size_t nmatch, regmatch_t pmatch[], int eflags) { return regwnexec(preg, str, (unsigned)-1, nmatch, pmatch, eflags); @@ -237,7 +250,7 @@ #endif /* TRE_WCHAR */ int -reguexec(const regex_t *preg, const tre_str_source *str, +reguexec(const regex_t * __restrict preg, const tre_str_source * __restrict str, size_t nmatch, regmatch_t pmatch[], int eflags) { tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; @@ -293,8 +306,9 @@ } int -reganexec(const regex_t *preg, const char *str, size_t len, - regamatch_t *match, regaparams_t params, int eflags) +reganexec(const regex_t * __restrict preg, const char * __restrict str, + size_t len, regamatch_t * __restrict match, regaparams_t params, + int eflags) { tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; tre_str_type_t type = (TRE_MB_CUR_MAX == 1) ? STR_BYTE : STR_MBS; @@ -303,8 +317,8 @@ } int -regaexec(const regex_t *preg, const char *str, - regamatch_t *match, regaparams_t params, int eflags) +regaexec(const regex_t * __restrict preg, const char * __restrict str, + regamatch_t * __restrict match, regaparams_t params, int eflags) { return reganexec(preg, str, (unsigned)-1, match, params, eflags); } @@ -312,8 +326,9 @@ #ifdef TRE_WCHAR int -regawnexec(const regex_t *preg, const wchar_t *str, size_t len, - regamatch_t *match, regaparams_t params, int eflags) +regawnexec(const regex_t * __restrict preg, const wchar_t * __restrict str, + size_t len, regamatch_t * __restrict match, regaparams_t params, + int eflags) { tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; return tre_match_approx(tnfa, str, len, STR_WIDE, @@ -321,8 +336,8 @@ } int -regawexec(const regex_t *preg, const wchar_t *str, - regamatch_t *match, regaparams_t params, int eflags) +regawexec(const regex_t * __restrict preg, const wchar_t * __restrict str, + regamatch_t * __restrict match, regaparams_t params, int eflags) { return regawnexec(preg, str, (unsigned)-1, match, params, eflags); } @@ -330,7 +345,7 @@ #endif /* TRE_WCHAR */ void -regaparams_default(regaparams_t *params) +regaparams_default(regaparams_t * __restrict params) { memset(params, 0, sizeof(*params)); params->cost_ins = 1; diff -x CVS -x regex.h -Nur tre/lib/tre-internal.h prj/widechar-regex/tre/dist/lib/tre-internal.h --- tre/lib/tre-internal.h 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/lib/tre-internal.h 2009-07-30 12:05:54.000000000 +0000 @@ -17,6 +17,10 @@ #include #endif /* !HAVE_WCTYPE_H */ +#ifdef HAVE_SYS_CDEFS_H +#include +#endif + #include #include "regex.h" @@ -43,6 +47,33 @@ #endif /* TRE_MULTIBYTE */ #endif /* HAVE_MBSTATE_T */ +#ifdef _NETBSD_SOURCE +#ifdef TRE_WCHAR +typedef wchar_t tre_char_t; +#else /* TRE_WCHAR */ +typedef unsigned char tre_char_t; +#endif /* TRE_WCHAR */ +typedef int reg_errcode_t; +typedef regstr_t tre_str_source; + +int +tre_have_backrefs(const regex_t *preg); +int +tre_have_approx(const regex_t *preg); +int +tre_config(int query, void *result); +char * +tre_version(void); + +enum { + TRE_CONFIG_APPROX, + TRE_CONFIG_WCHAR, + TRE_CONFIG_MULTIBYTE, + TRE_CONFIG_SYSTEM_ABI, + TRE_CONFIG_VERSION +}; +#endif /* _NETBSD_SOURCE */ + /* Define the character types and functions. */ #ifdef TRE_WCHAR @@ -136,6 +167,10 @@ #define MAX(a, b) (((a) >= (b)) ? (a) : (b)) #define MIN(a, b) (((a) <= (b)) ? (a) : (b)) +#ifndef __restrict +#define __restrict +#endif /* !__restrict */ + /* Define STRF to the correct printf formatter for strings. */ #ifdef TRE_WCHAR #define STRF "ls" diff -x CVS -x regex.h -Nur tre/src/Makefile.am prj/widechar-regex/tre/dist/src/Makefile.am --- tre/src/Makefile.am 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/src/Makefile.am 2009-06-18 10:53:22.000000000 +0000 @@ -7,7 +7,7 @@ bin_PROGRAMS = agrep agrep_SOURCES = agrep.c -agrep_LDADD = ../lib/libtre.la $(LTLIBINTL) +agrep_LDADD = ../lib/libtre.la $(LTLIBINTL) $(TRE_AGREP_LIBS) agrep_CFLAGS = -DLOCALEDIR=\"$(localedir)\" if TRE_PROFILE agrep_LDFLAGS = -static diff -x CVS -x regex.h -Nur tre/src/agrep.c prj/widechar-regex/tre/dist/src/agrep.c --- tre/src/agrep.c 2009-07-31 15:57:29.000000000 +0000 +++ prj/widechar-regex/tre/dist/src/agrep.c 2009-07-31 16:33:07.000000000 +0000 @@ -23,6 +23,19 @@ #ifdef HAVE_GETOPT_H #include #endif /* HAVE_GETOPT_H */ +#ifdef HAVE_FTS_H +#include +#else /* HAVE_FTS_H */ +#ifdef HAVE_FTW_H +#include +#include +#else /* HAVE_FTW_H */ +#include +#endif /* HAVE_FTW_H */ +#endif /* HAVE_FTS_H */ +#ifdef HAVE_TERMCAP_H +#include +#endif /* HAVE_TERMCAP_H */ #include "regex.h" #ifdef HAVE_GETTEXT @@ -42,8 +55,10 @@ /* Short options. */ static char const short_options[] = -"cd:e:hiklnqsvwyBD:E:HI:MS:V0123456789-:"; +"cd:e:hiklnqrsvwyBD:E:HI:MS:V0123456789-:"; +/* Recursive search. */ +static int recursive; static int show_help; char *program_name; @@ -76,6 +91,7 @@ {"nothing", no_argument, NULL, 'y'}, {"quiet", no_argument, NULL, 'q'}, {"record-number", no_argument, NULL, 'n'}, + {"recursive", no_argument, &recursive, 'r' }, {"regexp", required_argument, NULL, 'e'}, {"show-cost", no_argument, NULL, 's'}, {"show-position", no_argument, NULL, SHOW_POSITION_OPTION}, @@ -123,6 +139,7 @@ digit between 0 and 9)\n\ \n\ Miscellaneous:\n\ + -r, --recursive enable recursive search\n\ -d, --delimiter=PATTERN set the record delimiter regular expression\n\ -v, --invert-match select non-matching records\n\ -V, --version print version information and exit\n\ @@ -193,9 +210,16 @@ static regaparams_t match_params; -/* The color string used with the --color option. If set, the - environment variable GREP_COLOR overrides this default value. */ -static const char *highlight = "01;31"; +/* The color strings used with the --color option. */ +#ifdef HAVE_T_AGETSTR +static char *highlight_off, *highlight_on; +#else /* HAVE_T_AGETSTR */ +static char highlight_off[32], highlight_on[32]; +#endif /* HAVE_T_AGETSTR */ + +#ifdef HAVE_T_GETENT +static struct tinfo *tinfo; +#endif /* HAVE_T_GETENT */ /* Sets `record' to the next complete record from file `fd', and `record_len' to the length of the record. Returns 1 when there are no more records, @@ -435,10 +459,18 @@ if (color_option && !invert_match) { printf("%.*s", (int)pmatch[0].rm_so, record); - printf("\33[%sm", highlight); +#ifdef HAVE_TPUTS + tputs(highlight_on, 1, putchar); +#else /* HAVE_TPUTS */ + puts(highlight_on); +#endif /* HAVE_TPUTS */ printf("%.*s", (int)(pmatch[0].rm_eo - pmatch[0].rm_so), record + pmatch[0].rm_so); - fputs("\33[00m", stdout); +#ifdef HAVE_TPUTS + tputs(highlight_off, 1, putchar); +#else /* HAVE_TPUTS */ + puts(highlight_off); +#endif /* HAVE_TPUTS */ printf("%.*s", (int)(record_len - pmatch[0].rm_eo), record + pmatch[0].rm_eo); } @@ -463,7 +495,181 @@ return 0; } +#ifdef HAVE_FTS_H +static int +tre_agrep_handle(char **argv) +{ + FTS *ftsp; + FTSENT *entry; + + /* According to fts(3), the result of a fts_open() call is undefined, if an + error occurs and errno indicates an error then. */ + errno = 0; + ftsp = fts_open(argv, FTS_LOGICAL | FTS_NOSTAT, NULL); + if (errno != 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, + _("Cannot open fts handle"), strerror(errno)); + } + for (;;) + { + errno = 0; + entry = fts_read(ftsp); + if (entry == NULL) + { + if (errno != 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, + _("Cannot read fts entry"), strerror(errno)); + return 1; + } + else + { + fprintf(stderr, "%s: %s", program_name, + _("Cannot read fts entry")); + return 1; + } + if (fts_close(ftsp) < 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, + _("Cannot close fts handle"), strerror(errno)); + } + return 1; + } + if (entry->fts_info != FTS_D) + { + if (tre_agrep_handle_file(entry->fts_path) != 0) + { + if (fts_close(ftsp) < 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, + _("Cannot close fts handle"), strerror(errno)); + } + return 1; + } + } + } + if (fts_close(ftsp) < 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, + _("Cannot close fts handle"), strerror(errno)); + return 1; + } + else + return 0; +} +#else /* HAVE_FTS_H */ +#ifdef HAVE_FTW_H +static int +tre_agrep_handle_callback(const char *filename, const struct stat *buf, + int flag) +{ + if (flag == FTW_F) + return tre_agrep_handle_file(filename); + else + return 0; +} +static int +tre_agrep_handle_directory(const char *path) +{ + int ret; + int open_max; + + /* TODO: Is there a reasonable value for the file descriptor limit? */ + open_max = sysconf(_SC_OPEN_MAX); + if (open_max == -1) +#ifdef OPEN_MAX + open_max = OPEN_MAX; +#else + open_max = 256; +#endif /* OPEN_MAX */ + + /* 80:20 rule */ + ret = ftw(path, tre_agrep_handle_callback, open_max * (80 / 100)); + switch (ret) + { + case -1: + fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(errno)); + return 1; + case 0: + return 0; + default: + fprintf(stderr, "%s: %s\n", program_name, + _("Cannot traverse directory.")); + return ret; + } +} +#else +static int tre_agrep_handle(const char *path); + +static int +tre_agrep_handle_directory(const char *path) +{ + DIR *dir; + struct dirent *entry; + char entry_path[PATH_MAX]; + int ret; + + dir = opendir(path); + if (dir == NULL) + { + fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(errno)); + return 1; + } + + for (;;) + { + entry = readdir(dir); + if (entry == NULL) + { + fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(errno)); + return 1; + } + + strncpy(entry_path, path, PATH_MAX - 1); + strncat(entry_path, "/", PATH_MAX - 1); + strncat(entry_path, entry->d_name, PATH_MAX - 1); + + ret = tre_agrep_handle(entry_path); + if (ret != 0) + { + if (closedir(dir) < 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(errno)); + return 1; + } + return ret; + } + } + + if (closedir(dir) < 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(errno)); + return 1; + } + else + return 0; +} +#endif /* HAVE_FTW_H */ + +static int +tre_agrep_handle(const char *path) +{ + struct stat buf; + + if (stat(path, &buf) < 0) + { + fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(errno)); + return 1; + } + + if (S_ISDIR(buf.st_mode)) + return tre_agrep_handle_directory(path); + else + return tre_agrep_handle_file(path); +} +#endif /* HAVE_FTS_H */ int main(int argc, char **argv) @@ -547,6 +753,10 @@ case 'q': be_silent = 1; break; + case 'r': + /* Search directories recursively. */ + recursive = 1; + break; case 's': /* Print match cost of matching record. */ print_cost = 1; @@ -654,7 +864,76 @@ { char *user_highlight = getenv("GREP_COLOR"); if (user_highlight && *user_highlight != '\0') - highlight = user_highlight; + { + sprintf(highlight_on, "\33[%sm", user_highlight); + strcpy(highlight_off, "\33[00m"); + } + else + { +#ifdef HAVE_TERMCAP_H + char *term; +#ifndef HAVE_T_GETENT + char buf[1024]; +#endif /* !HAVE_T_GETENT */ +#ifndef HAVE_T_AGETSTR + char *s, sbuf[32]; +#endif /* HAVE_T_AGETSTR */ + + term = getenv("TERM"); + if (term != NULL) + { +#ifdef HAVE_T_GETENT + if (t_getent(&tinfo, term) < 0) +#else /* HAVE_T_GETENT */ + if (tgetent(&buf, term) < 1) +#endif /* HAVE_T_GETENT */ + color_option = 0; + else + { +#ifdef HAVE_T_AGETSTR + highlight_on = t_agetstr(tinfo, "so"); + if (highlight_on == NULL) + { +#ifdef HAVE_T_FREENT + t_freent(tinfo); +#endif /* HAVE_T_FREENT */ + color_option = 0; + } + else + { + highlight_off = t_agetstr(tinfo, "se"); + if (highlight_off == NULL) + { +#ifdef HAVE_T_FREENT + t_freent(tinfo); +#endif /* HAVE_T_FREENT */ + color_option = 0; + } + } +#else /* HAVE_T_AGETSTR */ + s = tgetstr("so", &sbuf); + if (s == NULL) + color_option = 0; + else + { + strcpy(highlight_on, s); + s = tgetstr("se", &sbuf); + if (s == NULL) + color_option = 0; + else + strcpy(hightligh_off, s); + } +#endif /* HAVE_T_AGETSTR */ + } + } + else + color_option = 0; + } +#else /* HAVE_TERMCAP_H */ + strcpy(highlight_on, "\33[01;31m"); + strcpy(highlight_off, "\33[00m"); + } +#endif /* HAVE_TERMCAP_H */ } /* Get the pattern. */ @@ -796,8 +1075,23 @@ /* Scan all files once without outputting anything, searching for the best matches. */ +#ifdef HAVE_FTS_H + if (recursive) + tre_agrep_handle(argv + optind); + else + { + while (optind < argc) + tre_agrep_handle_file(argv[optind++]); + } +#else /* HAVE_FTS_H */ while (optind < argc) - tre_agrep_handle_file(argv[optind++]); + { + if (recursive) + tre_agrep_handle(argv[optind++]); + else + tre_agrep_handle_file(argv[optind++]); + } +#endif /* HAVE_FTS_H */ /* If there were no matches, bail out now. */ if (best_cost == INT_MAX) @@ -809,15 +1103,49 @@ match_params.max_cost = best_cost; best_match = 2; optind = first_ind; +#ifdef HAVE_FTS_H + if (recursive) + tre_agrep_handle(argv + optind); + else + { + while (optind < argc) + tre_agrep_handle_file(argv[optind++]); + } +#else /* HAVE_FTS_H */ while (optind < argc) - tre_agrep_handle_file(argv[optind++]); + { + if (recursive) + tre_agrep_handle(argv[optind++]); + else + tre_agrep_handle_file(argv[optind++]); + } +#endif /* HAVE_FTS_H */ } else { /* Normal mode. */ +#ifdef HAVE_FTS_H + if (recursive) + tre_agrep_handle(argv + optind); + else + { + while (optind < argc) + tre_agrep_handle_file(argv[optind++]); + } +#else /* HAVE_FTS_H */ while (optind < argc) - tre_agrep_handle_file(argv[optind++]); + { + if (recursive) + tre_agrep_handle(argv[optind++]); + else + tre_agrep_handle_file(argv[optind++]); + } +#endif /* HAVE_FTS_H */ } +#ifdef HAVE_T_FREENT + t_freent(tinfo); +#endif /* HAVE_T_FREENT */ + return have_matches == 0; }