1 /* locate -- search databases for filenames that match patterns
2 Copyright (C) 1994, 1996, 1998, 1999, 2000, 2003,
3 2004, 2005 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 /* Usage: locate [options] pattern...
23 Scan a pathname list for the full pathname of a file, given only
24 a piece of the name (possibly containing shell globbing metacharacters).
25 The list has been processed with front-compression, which reduces
26 the list size by a factor of 4-5.
27 Recognizes two database formats, old and new. The old format is
28 bigram coded, which reduces space by a further 20-25% and uses the
29 following encoding of the database bytes:
31 0-28 likeliest differential counts + offset (14) to make nonnegative
32 30 escape code for out-of-range count to follow in next halfword
33 128-255 bigram codes (the 128 most common, as determined by `updatedb')
34 32-127 single character (printable) ASCII remainder
36 Earlier versions of GNU locate used to use a novel two-tiered
37 string search technique, which was described in Usenix ;login:, Vol
38 8, No 1, February/March, 1983, p. 8.
40 However, latterly code changes to provide additional functionality
41 became dificult to make with the existing reading scheme, and so
42 we no longer perform the matching as efficiently as we used to (that is,
43 we no longer use the same algorithm).
45 The old algorithm was:
47 First, match a metacharacter-free subpattern and a partial
48 pathname BACKWARDS to avoid full expansion of the pathname list.
49 The time savings is 40-50% over forward matching, which cannot
50 efficiently handle overlapped search patterns and compressed
53 Then, match the actual shell glob pattern (if in this form)
54 against the candidate pathnames using the slower shell filename
58 Written by James A. Woods <jwoods@adobe.com>.
59 Modified by David MacKenzie <djm@gnu.org>.
60 Additional work by James Youngman and Bas van Gompel.
66 #include <sys/types.h>
73 /* The presence of unistd.h is assumed by gnulib these days, so we
74 * might as well assume it too.
76 /* We need <unistd.h> for isatty(). */
83 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
105 # include <libintl.h>
106 # define _(Text) gettext (Text)
108 # define _(Text) Text
109 #define textdomain(Domain)
110 #define bindtextdomain(Package, Directory)
113 # define N_(String) gettext_noop (String)
115 /* We used to use (String) instead of just String, but apparentl;y ISO C
116 * doesn't allow this (at least, that's what HP said when someone reported
117 * this as a compiler bug). This is HP case number 1205608192. See
118 * also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11250 (which references
119 * ANSI 3.5.7p14-15). The Intel icc compiler also rejects constructs
120 * like: static const char buf[] = ("string");
122 # define N_(String) String
125 #include "locatedb.h"
127 #include "../gnulib/lib/xalloc.h"
128 #include "../gnulib/lib/error.h"
129 #include "../gnulib/lib/human.h"
131 #include "closeout.h"
132 #include "nextelem.h"
135 #include "quotearg.h"
136 #include "printquoted.h"
139 /* Note that this evaluates C many times. */
141 # define TOUPPER(Ch) toupper (Ch)
142 # define TOLOWER(Ch) tolower (Ch)
144 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
145 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
148 /* typedef enum {false, true} boolean; */
150 /* Warn if a database is older than this. 8 days allows for a weekly
151 update that takes up to a day to perform. */
152 #define WARN_NUMBER_UNITS (8)
153 /* Printable name of units used in WARN_SECONDS */
154 static const char warn_name_units
[] = N_("days");
155 #define SECONDS_PER_UNIT (60 * 60 * 24)
157 #define WARN_SECONDS ((SECONDS_PER_UNIT) * (WARN_NUMBER_UNITS))
161 VISIT_CONTINUE
= 1, /* please call the next visitor */
162 VISIT_ACCEPTED
= 2, /* accepted, call no futher callbacks for this file */
163 VISIT_REJECTED
= 4, /* rejected, process next file. */
164 VISIT_ABORT
= 8 /* rejected, process no more files. */
167 enum ExistenceCheckType
169 ACCEPT_EITHER
, /* Corresponds to lack of -E/-e option */
170 ACCEPT_EXISTING
, /* Corresponds to option -e */
171 ACCEPT_NON_EXISTING
/* Corresponds to option -E */
174 /* Check for existence of files before printing them out? */
175 enum ExistenceCheckType check_existence
= ACCEPT_EITHER
;
177 static int follow_symlinks
= 1;
179 /* What to separate the results with. */
180 static int separator
= '\n';
182 static struct quoting_options
* quote_opts
= NULL
;
183 static bool stdout_is_a_tty
;
184 static bool print_quoted_filename
;
186 /* Read in a 16-bit int, high byte first (network byte order). */
194 x
= (signed char) fgetc (fp
) << 8;
195 x
|= (fgetc (fp
) & 0xff);
199 const char * const metacharacters
= "*?[]\\";
201 /* Return nonzero if S contains any shell glob characters.
204 contains_metacharacter(const char *s
)
206 if (NULL
== strpbrk(s
, metacharacters
))
214 * Read bytes from FP into the buffer at offset OFFSET in (*BUF),
215 * until we reach DELIMITER or end-of-file. We reallocate the buffer
216 * as necessary, altering (*BUF) and (*SIZ) as appropriate. No assumption
217 * is made regarding the content of the data (i.e. the implementation is
218 * 8-bit clean, the only delimiter is DELIMITER).
220 * Written Fri May 23 18:41:16 2003 by James Youngman, because getstr()
221 * has been removed from gnulib.
223 * We call the function locate_read_str() to avoid a name clash with the curses
227 locate_read_str(char **buf
, size_t *siz
, FILE *fp
, int delimiter
, int offs
)
233 nread
= getdelim(&p
, &sz
, delimiter
, fp
);
238 needed
= offs
+ nread
+ 1;
241 char *pnew
= realloc(*buf
, needed
);
244 return -1; /* FAIL */
252 memcpy((*buf
)+offs
, p
, nread
);
260 lc_strcpy(char *dest
, const char *src
)
264 *dest
++ = TOLOWER(*src
);
273 uintmax_t items_accepted
;
275 static struct locate_limits limits
;
280 uintmax_t compressed_bytes
;
281 uintmax_t total_filename_count
;
282 uintmax_t total_filename_length
;
283 uintmax_t whitespace_count
;
284 uintmax_t newline_count
;
285 uintmax_t highbit_filename_count
;
287 static struct locate_stats statistics
;
297 static struct stringbuf casebuf
;
303 struct stringbuf
*pbuf
;
306 struct regular_expression
314 int c
; /* An input byte. */
315 int count
; /* The length of the prefix shared with the previous database entry. */
317 char *original_filename
; /* The current input database entry. */
318 size_t pathsize
; /* Amount allocated for it. */
319 char *munged_filename
; /* path or base_name(path) */
320 FILE *fp
; /* The pathname database. */
321 char *dbfile
; /* Its name, or "<stdin>" */
322 /* for the old database format,
323 the first and second characters of the most common bigrams. */
329 typedef int (*visitfunc
)(struct process_data
*procdata
,
336 struct visitor
*next
;
340 static struct visitor
*inspectors
= NULL
;
341 static struct visitor
*lastinspector
= NULL
;
342 static struct visitor
*past_pat_inspector
= NULL
;
344 /* 0 or 1 pattern(s) */
346 process_simple(struct process_data
*procdata
)
348 int result
= VISIT_CONTINUE
;
349 const struct visitor
*p
= inspectors
;
351 while ( ((VISIT_CONTINUE
| VISIT_ACCEPTED
) & result
) && (NULL
!= p
) )
353 result
= (p
->inspector
)(procdata
, p
->context
);
360 /* Accept if any pattern matches. */
362 process_or (struct process_data
*procdata
)
364 int result
= VISIT_CONTINUE
;
365 const struct visitor
*p
= inspectors
;
367 while ( ((VISIT_CONTINUE
| VISIT_REJECTED
) & result
) && (past_pat_inspector
!= p
) )
369 result
= (p
->inspector
)(procdata
, p
->context
);
373 if (result
== VISIT_CONTINUE
)
374 result
= VISIT_REJECTED
;
375 if (result
& (VISIT_ABORT
| VISIT_REJECTED
))
378 p
= past_pat_inspector
;
379 result
= VISIT_CONTINUE
;
381 while ( (VISIT_CONTINUE
== result
) && (NULL
!= p
) )
383 result
= (p
->inspector
)(procdata
, p
->context
);
387 if (VISIT_CONTINUE
== result
)
388 return VISIT_ACCEPTED
;
393 /* Accept if all pattern match. */
395 process_and (struct process_data
*procdata
)
397 int result
= VISIT_CONTINUE
;
398 const struct visitor
*p
= inspectors
;
400 while ( ((VISIT_CONTINUE
| VISIT_ACCEPTED
) & result
) && (past_pat_inspector
!= p
) )
402 result
= (p
->inspector
)(procdata
, p
->context
);
406 if (result
== VISIT_CONTINUE
)
407 result
= VISIT_REJECTED
;
408 if (result
& (VISIT_ABORT
| VISIT_REJECTED
))
411 p
= past_pat_inspector
;
412 result
= VISIT_CONTINUE
;
414 while ( (VISIT_CONTINUE
== result
) && (NULL
!= p
) )
416 result
= (p
->inspector
)(procdata
, p
->context
);
420 if (VISIT_CONTINUE
== result
)
421 return VISIT_ACCEPTED
;
426 typedef int (*processfunc
)(struct process_data
*procdata
);
428 static processfunc mainprocessor
= NULL
;
431 add_visitor(visitfunc fn
, void *context
)
433 struct visitor
*p
= xmalloc(sizeof(struct visitor
));
435 p
->context
= context
;
438 if (NULL
== lastinspector
)
440 lastinspector
= inspectors
= p
;
444 lastinspector
->next
= p
;
452 visit_justprint_quoted(struct process_data
*procdata
, void *context
)
455 print_quoted (stdout
, quote_opts
, stdout_is_a_tty
,
457 procdata
->original_filename
);
459 return VISIT_CONTINUE
;
463 visit_justprint_unquoted(struct process_data
*procdata
, void *context
)
466 fputs(procdata
->original_filename
, stdout
);
468 return VISIT_CONTINUE
;
472 visit_old_format(struct process_data
*procdata
, void *context
)
477 /* Get the offset in the path where this path info starts. */
478 if (procdata
->c
== LOCATEDB_OLD_ESCAPE
)
479 procdata
->count
+= getw (procdata
->fp
) - LOCATEDB_OLD_OFFSET
;
481 procdata
->count
+= procdata
->c
- LOCATEDB_OLD_OFFSET
;
483 /* Overlay the old path with the remainder of the new. */
484 for (s
= procdata
->original_filename
+ procdata
->count
;
485 (procdata
->c
= getc (procdata
->fp
)) > LOCATEDB_OLD_ESCAPE
;)
486 if (procdata
->c
< 0200)
487 *s
++ = procdata
->c
; /* An ordinary character. */
490 /* Bigram markers have the high bit set. */
492 *s
++ = procdata
->bigram1
[procdata
->c
];
493 *s
++ = procdata
->bigram2
[procdata
->c
];
497 procdata
->munged_filename
= procdata
->original_filename
;
499 return VISIT_CONTINUE
;
504 visit_locate02_format(struct process_data
*procdata
, void *context
)
510 if (procdata
->c
== LOCATEDB_ESCAPE
)
511 procdata
->count
+= (short)get_short (procdata
->fp
);
512 else if (procdata
->c
> 127)
513 procdata
->count
+= procdata
->c
- 256;
515 procdata
->count
+= procdata
->c
;
517 if (procdata
->count
> procdata
->len
|| procdata
->count
< 0)
519 /* This should not happen generally , but since we're
520 * reading in data which is outside our control, we
523 error(1, 0, _("locate database `%s' is corrupt or invalid"), procdata
->dbfile
);
526 /* Overlay the old path with the remainder of the new. */
527 nread
= locate_read_str (&procdata
->original_filename
, &procdata
->pathsize
,
528 procdata
->fp
, 0, procdata
->count
);
531 procdata
->c
= getc (procdata
->fp
);
532 procdata
->len
= procdata
->count
+ nread
;
533 s
= procdata
->original_filename
+ procdata
->len
- 1; /* Move to the last char in path. */
534 assert (s
[0] != '\0');
535 assert (s
[1] == '\0'); /* Our terminator. */
536 assert (s
[2] == '\0'); /* Added by locate_read_str. */
538 procdata
->munged_filename
= procdata
->original_filename
;
540 return VISIT_CONTINUE
;
544 visit_basename(struct process_data
*procdata
, void *context
)
547 procdata
->munged_filename
= base_name(procdata
->original_filename
);
549 return VISIT_CONTINUE
;
554 visit_casefold(struct process_data
*procdata
, void *context
)
556 struct stringbuf
*b
= context
;
558 if (*b
->preqlen
+1 > b
->buffersize
)
560 b
->buffer
= xrealloc(b
->buffer
, *b
->preqlen
+1); /* XXX: consider using extendbuf(). */
561 b
->buffersize
= *b
->preqlen
+1;
563 lc_strcpy(b
->buffer
, procdata
->munged_filename
);
565 return VISIT_CONTINUE
;
568 /* visit_existing_follow implements -L -e */
570 visit_existing_follow(struct process_data
*procdata
, void *context
)
575 /* munged_filename has been converted in some way (to lower case,
576 * or is just the base name of the file), and original_filename has not.
577 * Hence only original_filename is still actually the name of the file
578 * whose existence we would need to check.
580 if (stat(procdata
->original_filename
, &st
) != 0)
582 return VISIT_REJECTED
;
586 return VISIT_CONTINUE
;
590 /* visit_non_existing_follow implements -L -E */
592 visit_non_existing_follow(struct process_data
*procdata
, void *context
)
597 /* munged_filename has been converted in some way (to lower case,
598 * or is just the base name of the file), and original_filename has not.
599 * Hence only original_filename is still actually the name of the file
600 * whose existence we would need to check.
602 if (stat(procdata
->original_filename
, &st
) == 0)
604 return VISIT_REJECTED
;
608 return VISIT_CONTINUE
;
612 /* visit_existing_nofollow implements -P -e */
614 visit_existing_nofollow(struct process_data
*procdata
, void *context
)
619 /* munged_filename has been converted in some way (to lower case,
620 * or is just the base name of the file), and original_filename has not.
621 * Hence only original_filename is still actually the name of the file
622 * whose existence we would need to check.
624 if (lstat(procdata
->original_filename
, &st
) != 0)
626 return VISIT_REJECTED
;
630 return VISIT_CONTINUE
;
634 /* visit_non_existing_nofollow implements -P -E */
636 visit_non_existing_nofollow(struct process_data
*procdata
, void *context
)
641 /* munged_filename has been converted in some way (to lower case,
642 * or is just the base name of the file), and original_filename has not.
643 * Hence only original_filename is still actually the name of the file
644 * whose existence we would need to check.
646 if (lstat(procdata
->original_filename
, &st
) == 0)
648 return VISIT_REJECTED
;
652 return VISIT_CONTINUE
;
657 visit_substring_match_nocasefold(struct process_data
*procdata
, void *context
)
659 const char *pattern
= context
;
661 if (NULL
!= strstr(procdata
->munged_filename
, pattern
))
662 return VISIT_ACCEPTED
;
664 return VISIT_REJECTED
;
668 visit_substring_match_casefold(struct process_data
*procdata
, void *context
)
670 const struct casefolder
* p
= context
;
671 const struct stringbuf
* b
= p
->pbuf
;
674 if (NULL
!= strstr(b
->buffer
, p
->pattern
))
675 return VISIT_ACCEPTED
;
677 return VISIT_REJECTED
;
682 visit_globmatch_nofold(struct process_data
*procdata
, void *context
)
684 const char *glob
= context
;
685 if (fnmatch(glob
, procdata
->munged_filename
, 0) != 0)
686 return VISIT_REJECTED
;
688 return VISIT_ACCEPTED
;
693 visit_globmatch_casefold(struct process_data
*procdata
, void *context
)
695 const char *glob
= context
;
696 if (fnmatch(glob
, procdata
->munged_filename
, FNM_CASEFOLD
) != 0)
697 return VISIT_REJECTED
;
699 return VISIT_ACCEPTED
;
704 visit_regex(struct process_data
*procdata
, void *context
)
706 struct regular_expression
*p
= context
;
708 if (0 == regexec(&p
->re
, procdata
->munged_filename
, 0u, NULL
, 0))
709 return VISIT_ACCEPTED
; /* match */
711 return VISIT_REJECTED
; /* no match */
716 visit_stats(struct process_data
*procdata
, void *context
)
718 struct locate_stats
*p
= context
;
719 size_t len
= strlen(procdata
->original_filename
);
721 int highbit
, whitespace
, newline
;
723 ++(p
->total_filename_count
);
724 p
->total_filename_length
+= len
;
726 highbit
= whitespace
= newline
= 0;
727 for (s
=procdata
->original_filename
; *s
; ++s
)
729 if ( (int)(*s
) & 128 )
733 newline
= whitespace
= 1;
735 else if (isspace((unsigned char)*s
))
742 ++(p
->highbit_filename_count
);
744 ++(p
->whitespace_count
);
746 ++(p
->newline_count
);
748 return VISIT_CONTINUE
;
753 visit_limit(struct process_data
*procdata
, void *context
)
755 struct locate_limits
*p
= context
;
759 if (++p
->items_accepted
>= p
->limit
)
762 return VISIT_CONTINUE
;
766 visit_count(struct process_data
*procdata
, void *context
)
768 struct locate_limits
*p
= context
;
773 return VISIT_CONTINUE
;
776 /* Emit the statistics.
779 print_stats(int argc
, size_t database_file_size
)
781 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
783 printf(_("Locate database size: %s bytes\n"),
784 human_readable ((uintmax_t) database_file_size
,
785 hbuf
, human_ceiling
, 1, 1));
787 printf(_("Filenames: %s "),
788 human_readable (statistics
.total_filename_count
,
789 hbuf
, human_ceiling
, 1, 1));
790 printf(_("with a cumulative length of %s bytes"),
791 human_readable (statistics
.total_filename_length
,
792 hbuf
, human_ceiling
, 1, 1));
794 printf(_("\n\tof which %s contain whitespace, "),
795 human_readable (statistics
.whitespace_count
,
796 hbuf
, human_ceiling
, 1, 1));
797 printf(_("\n\t%s contain newline characters, "),
798 human_readable (statistics
.newline_count
,
799 hbuf
, human_ceiling
, 1, 1));
800 printf(_("\n\tand %s contain characters with the high bit set.\n"),
801 human_readable (statistics
.highbit_filename_count
,
802 hbuf
, human_ceiling
, 1, 1));
805 printf(_("Compression ratio %4.2f%%\n"),
806 100.0 * ((double)statistics
.total_filename_length
807 - (double) database_file_size
)
808 / (double) statistics
.total_filename_length
);
813 /* Print or count the entries in DBFILE that match shell globbing patterns in
814 ARGV. Return the number of entries matched. */
824 struct locate_limits
*plimit
,
829 char *pathpart
; /* A pattern to consider. */
830 int argn
; /* Index to current pattern in argv. */
831 int need_fold
; /* Set when folding and any pattern is non-glob. */
832 int nread
; /* number of bytes read from an entry. */
833 struct process_data procdata
; /* Storage for data shared with visitors. */
835 int old_format
= 0; /* true if reading a bigram-encoded database. */
836 static bool did_stdin
= false; /* Set to prevent rereading stdin. */
837 struct visitor
* pvis
; /* temp for determining past_pat_inspector. */
839 /* To check the age of the database. */
844 procdata
.len
= procdata
.count
= 0;
845 if (!strcmp (dbfile
, "-"))
849 error (0, 0, _("warning: the locate database can only be read from stdin once."));
854 procdata
.dbfile
= "<stdin>";
860 if (stat (dbfile
, &st
) || (procdata
.fp
= fopen (dbfile
, "r")) == NULL
)
862 error (0, errno
, "%s", dbfile
);
866 if (now
- st
.st_mtime
> WARN_SECONDS
)
869 warning: database `fred' is more than 8 days old */
870 error (0, 0, _("warning: database `%s' is more than %d %s old"),
871 dbfile
, WARN_NUMBER_UNITS
, _(warn_name_units
));
873 procdata
.dbfile
= dbfile
;
876 procdata
.pathsize
= 1026; /* Increased as necessary by locate_read_str. */
877 procdata
.original_filename
= xmalloc (procdata
.pathsize
);
879 nread
= fread (procdata
.original_filename
, 1, sizeof (LOCATEDB_MAGIC
),
881 if (nread
!= sizeof (LOCATEDB_MAGIC
)
882 || memcmp (procdata
.original_filename
, LOCATEDB_MAGIC
,
883 sizeof (LOCATEDB_MAGIC
)))
886 /* Read the list of the most common bigrams in the database. */
887 nread
= fread (procdata
.original_filename
+ sizeof (LOCATEDB_MAGIC
), 1,
888 256 - sizeof (LOCATEDB_MAGIC
), procdata
.fp
);
889 for (i
= 0; i
< 128; i
++)
891 procdata
.bigram1
[i
] = procdata
.original_filename
[i
<< 1];
892 procdata
.bigram2
[i
] = procdata
.original_filename
[(i
<< 1) + 1];
897 /* Set up the inspection regime */
899 lastinspector
= NULL
;
900 past_pat_inspector
= NULL
;
903 add_visitor(visit_old_format
, NULL
);
905 add_visitor(visit_locate02_format
, NULL
);
908 add_visitor(visit_basename
, NULL
);
910 /* See if we need fold. */
911 if (ignore_case
&& !regex
)
912 for ( argn
= 0; argn
< argc
; argn
++ )
914 pathpart
= argv
[argn
];
915 if (!contains_metacharacter(pathpart
))
924 add_visitor(visit_casefold
, &casebuf
);
925 casebuf
.preqlen
= &procdata
.pathsize
;
926 casebuf
.soffs
= &procdata
.count
;
929 /* Add an inspector for each pattern we're looking for. */
930 for ( argn
= 0; argn
< argc
; argn
++ )
932 pathpart
= argv
[argn
];
935 struct regular_expression
*p
= xmalloc(sizeof(*p
));
936 int cflags
= REG_EXTENDED
| REG_NOSUB
937 | (ignore_case
? REG_ICASE
: 0);
939 if (0 == regcomp(&p
->re
, pathpart
, cflags
))
941 add_visitor(visit_regex
, p
);
945 error (1, errno
, "Invalid regular expression; %s", pathpart
);
948 else if (contains_metacharacter(pathpart
))
951 add_visitor(visit_globmatch_casefold
, pathpart
);
953 add_visitor(visit_globmatch_nofold
, pathpart
);
957 /* No glob characters used. Hence we match on
958 * _any part_ of the filename, not just the
959 * basename. This seems odd to me, but it is the
960 * traditional behaviour.
961 * James Youngman <jay@gnu.org>
965 struct casefolder
* cf
= xmalloc(sizeof(*cf
));
966 cf
->pattern
= pathpart
;
968 add_visitor(visit_substring_match_casefold
, cf
);
969 /* If we ignore case, convert it to lower now so we don't have to
972 lc_strcpy(pathpart
, pathpart
);
976 add_visitor(visit_substring_match_nocasefold
, pathpart
);
981 pvis
= lastinspector
;
983 /* We add visit_existing_*() as late as possible to reduce the
984 * number of stat() calls.
986 switch (check_existence
)
988 case ACCEPT_EXISTING
:
989 if (follow_symlinks
) /* -L, default */
990 add_visitor(visit_existing_follow
, NULL
);
992 add_visitor(visit_existing_nofollow
, NULL
);
995 case ACCEPT_NON_EXISTING
:
996 if (follow_symlinks
) /* -L, default */
997 add_visitor(visit_non_existing_follow
, NULL
);
999 add_visitor(visit_non_existing_nofollow
, NULL
);
1002 case ACCEPT_EITHER
: /* Default, neither -E nor -e */
1003 /* do nothing; no extra processing. */
1008 add_visitor(visit_stats
, &statistics
);
1012 if (print_quoted_filename
)
1013 add_visitor(visit_justprint_quoted
, NULL
);
1015 add_visitor(visit_justprint_unquoted
, NULL
);
1020 add_visitor(visit_limit
, plimit
);
1022 add_visitor(visit_count
, plimit
);
1027 past_pat_inspector
= pvis
->next
;
1029 mainprocessor
= process_and
;
1031 mainprocessor
= process_or
;
1034 mainprocessor
= process_simple
;
1038 printf(_("Database %s is in the %s format.\n"),
1040 old_format
? _("old") : "LOCATE02");
1044 procdata
.c
= getc (procdata
.fp
);
1045 /* If we are searching for filename patterns, the inspector list
1046 * will contain an entry for each pattern for which we are searching.
1048 while ( (procdata
.c
!= EOF
) &&
1049 (VISIT_ABORT
!= (mainprocessor
)(&procdata
)) )
1051 /* Do nothing; all the work is done in the visitor functions. */
1056 print_stats(argc
, st
.st_size
);
1059 if (ferror (procdata
.fp
))
1061 error (0, errno
, "%s", procdata
.dbfile
);
1064 if (procdata
.fp
!= stdin
&& fclose (procdata
.fp
) == EOF
)
1066 error (0, errno
, "%s", dbfile
);
1070 return plimit
->items_accepted
;
1076 extern char *version_string
;
1078 /* The name this program was run with. */
1082 usage (FILE *stream
)
1084 fprintf (stream
, _("\
1085 Usage: %s [-d path | --database=path] [-e | -E | --[non-]existing]\n\
1086 [-i | --ignore-case] [-w | --wholename] [-b | --basename] \n\
1087 [--limit=N | -l N] [-S | --statistics] [-0 | --null] [-c | --count]\n\
1088 [-P | -H | --nofollow] [-L | --follow] [-m | --mmap ] [ -s | --stdio ]\n\
1089 [-A | --all] [-p | --print] [-r | --regex ] [--version] [--help]\n\
1092 fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream
);
1095 static struct option
const longopts
[] =
1097 {"database", required_argument
, NULL
, 'd'},
1098 {"existing", no_argument
, NULL
, 'e'},
1099 {"non-existing", no_argument
, NULL
, 'E'},
1100 {"ignore-case", no_argument
, NULL
, 'i'},
1101 {"all", no_argument
, NULL
, 'A'},
1102 {"help", no_argument
, NULL
, 'h'},
1103 {"version", no_argument
, NULL
, 'v'},
1104 {"null", no_argument
, NULL
, '0'},
1105 {"count", no_argument
, NULL
, 'c'},
1106 {"wholename", no_argument
, NULL
, 'w'},
1107 {"wholepath", no_argument
, NULL
, 'w'}, /* Synonym. */
1108 {"basename", no_argument
, NULL
, 'b'},
1109 {"print", no_argument
, NULL
, 'p'},
1110 {"stdio", no_argument
, NULL
, 's'},
1111 {"mmap", no_argument
, NULL
, 'm'},
1112 {"limit", required_argument
, NULL
, 'l'},
1113 {"regex", no_argument
, NULL
, 'r'},
1114 {"statistics", no_argument
, NULL
, 'S'},
1115 {"follow", no_argument
, NULL
, 'L'},
1116 {"nofollow", no_argument
, NULL
, 'P'},
1117 {NULL
, no_argument
, NULL
, 0}
1121 main (int argc
, char **argv
)
1124 unsigned long int found
= 0uL;
1126 int ignore_case
= 0;
1129 int basename_only
= 0;
1136 program_name
= argv
[0];
1138 #ifdef HAVE_SETLOCALE
1139 setlocale (LC_ALL
, "");
1141 bindtextdomain (PACKAGE
, LOCALEDIR
);
1142 textdomain (PACKAGE
);
1143 atexit (close_stdout
);
1146 limits
.items_accepted
= 0;
1148 quote_opts
= clone_quoting_options (NULL
);
1149 print_quoted_filename
= true;
1151 dbpath
= getenv ("LOCATE_PATH");
1155 check_existence
= ACCEPT_EITHER
;
1157 while ((optc
= getopt_long (argc
, argv
, "Abcd:eEil:prsm0SwHPL", longopts
, (int *) 0)) != -1)
1162 print_quoted_filename
= false; /* print filename 'raw'. */
1182 check_existence
= ACCEPT_EXISTING
;
1186 check_existence
= ACCEPT_NON_EXISTING
;
1202 printf (_("GNU locate version %s\n"), version_string
);
1218 follow_symlinks
= 1;
1221 /* In find, -P and -H differ in the way they handle paths
1222 * given on the command line. This is not relevant for
1223 * locate, but the -H option is supported because it is
1224 * probably more intuitive to do so.
1228 follow_symlinks
= 0;
1234 strtol_error err
= xstrtoumax(optarg
, &end
, 10, &limits
.limit
, NULL
);
1235 if (LONGINT_OK
!= err
)
1237 STRTOL_FATAL_ERROR(optarg
, _("argument to --limit"), err
);
1243 case 's': /* use stdio */
1244 case 'm': /* use mmap */
1245 /* These options are implemented simply for
1246 * compatibility with FreeBSD
1255 if (!just_count
&& !stats
)
1265 if (!just_count
&& optind
== argc
)
1273 if (1 == isatty(STDOUT_FILENO
))
1274 stdout_is_a_tty
= true;
1276 stdout_is_a_tty
= false;
1278 next_element (dbpath
, 0); /* Initialize. */
1280 /* Bail out early if limit already reached. */
1281 while ((e
= next_element ((char *) NULL
, 0)) != NULL
&&
1282 (!use_limit
|| limits
.limit
> limits
.items_accepted
))
1284 statistics
.compressed_bytes
=
1285 statistics
.total_filename_count
=
1286 statistics
.total_filename_length
=
1287 statistics
.whitespace_count
=
1288 statistics
.newline_count
=
1289 statistics
.highbit_filename_count
= 0u;
1291 if (0 == strlen(e
) || 0 == strcmp(e
, "."))
1293 /* Use the default database name instead (note: we
1294 * don't use 'dbpath' since that might itself contain a
1295 * colon-separated list.
1300 found
= locate (argc
- optind
, &argv
[optind
], e
, ignore_case
, print
, basename_only
, use_limit
, &limits
, stats
, op_and
, regex
);
1305 printf("%ld\n", found
);
1308 if (found
|| (use_limit
&& (limits
.limit
==0)) || stats
)