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"
137 #include "regextype.h"
140 /* Note that this evaluates C many times. */
142 # define TOUPPER(Ch) toupper (Ch)
143 # define TOLOWER(Ch) tolower (Ch)
145 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
146 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
149 /* typedef enum {false, true} boolean; */
151 /* Warn if a database is older than this. 8 days allows for a weekly
152 update that takes up to a day to perform. */
153 #define WARN_NUMBER_UNITS (8)
154 /* Printable name of units used in WARN_SECONDS */
155 static const char warn_name_units
[] = N_("days");
156 #define SECONDS_PER_UNIT (60 * 60 * 24)
158 #define WARN_SECONDS ((SECONDS_PER_UNIT) * (WARN_NUMBER_UNITS))
162 VISIT_CONTINUE
= 1, /* please call the next visitor */
163 VISIT_ACCEPTED
= 2, /* accepted, call no futher callbacks for this file */
164 VISIT_REJECTED
= 4, /* rejected, process next file. */
165 VISIT_ABORT
= 8 /* rejected, process no more files. */
168 enum ExistenceCheckType
170 ACCEPT_EITHER
, /* Corresponds to lack of -E/-e option */
171 ACCEPT_EXISTING
, /* Corresponds to option -e */
172 ACCEPT_NON_EXISTING
/* Corresponds to option -E */
175 /* Check for existence of files before printing them out? */
176 enum ExistenceCheckType check_existence
= ACCEPT_EITHER
;
178 static int follow_symlinks
= 1;
180 /* What to separate the results with. */
181 static int separator
= '\n';
183 static struct quoting_options
* quote_opts
= NULL
;
184 static bool stdout_is_a_tty
;
185 static bool print_quoted_filename
;
187 /* Read in a 16-bit int, high byte first (network byte order). */
195 x
= (signed char) fgetc (fp
) << 8;
196 x
|= (fgetc (fp
) & 0xff);
200 const char * const metacharacters
= "*?[]\\";
202 /* Return nonzero if S contains any shell glob characters.
205 contains_metacharacter(const char *s
)
207 if (NULL
== strpbrk(s
, metacharacters
))
215 * Read bytes from FP into the buffer at offset OFFSET in (*BUF),
216 * until we reach DELIMITER or end-of-file. We reallocate the buffer
217 * as necessary, altering (*BUF) and (*SIZ) as appropriate. No assumption
218 * is made regarding the content of the data (i.e. the implementation is
219 * 8-bit clean, the only delimiter is DELIMITER).
221 * Written Fri May 23 18:41:16 2003 by James Youngman, because getstr()
222 * has been removed from gnulib.
224 * We call the function locate_read_str() to avoid a name clash with the curses
228 locate_read_str(char **buf
, size_t *siz
, FILE *fp
, int delimiter
, int offs
)
234 nread
= getdelim(&p
, &sz
, delimiter
, fp
);
239 needed
= offs
+ nread
+ 1;
242 char *pnew
= realloc(*buf
, needed
);
245 return -1; /* FAIL */
253 memcpy((*buf
)+offs
, p
, nread
);
261 lc_strcpy(char *dest
, const char *src
)
265 *dest
++ = TOLOWER(*src
);
274 uintmax_t items_accepted
;
276 static struct locate_limits limits
;
281 uintmax_t compressed_bytes
;
282 uintmax_t total_filename_count
;
283 uintmax_t total_filename_length
;
284 uintmax_t whitespace_count
;
285 uintmax_t newline_count
;
286 uintmax_t highbit_filename_count
;
288 static struct locate_stats statistics
;
298 static struct stringbuf casebuf
;
304 struct stringbuf
*pbuf
;
307 struct regular_expression
309 struct re_pattern_buffer regex
; /* for --regex */
315 int c
; /* An input byte. */
316 int count
; /* The length of the prefix shared with the previous database entry. */
318 char *original_filename
; /* The current input database entry. */
319 size_t pathsize
; /* Amount allocated for it. */
320 char *munged_filename
; /* path or base_name(path) */
321 FILE *fp
; /* The pathname database. */
322 char *dbfile
; /* Its name, or "<stdin>" */
323 /* for the old database format,
324 the first and second characters of the most common bigrams. */
330 typedef int (*visitfunc
)(struct process_data
*procdata
,
337 struct visitor
*next
;
341 static struct visitor
*inspectors
= NULL
;
342 static struct visitor
*lastinspector
= NULL
;
343 static struct visitor
*past_pat_inspector
= NULL
;
345 /* 0 or 1 pattern(s) */
347 process_simple(struct process_data
*procdata
)
349 int result
= VISIT_CONTINUE
;
350 const struct visitor
*p
= inspectors
;
352 while ( ((VISIT_CONTINUE
| VISIT_ACCEPTED
) & result
) && (NULL
!= p
) )
354 result
= (p
->inspector
)(procdata
, p
->context
);
361 /* Accept if any pattern matches. */
363 process_or (struct process_data
*procdata
)
365 int result
= VISIT_CONTINUE
;
366 const struct visitor
*p
= inspectors
;
368 while ( ((VISIT_CONTINUE
| VISIT_REJECTED
) & result
) && (past_pat_inspector
!= p
) )
370 result
= (p
->inspector
)(procdata
, p
->context
);
374 if (result
== VISIT_CONTINUE
)
375 result
= VISIT_REJECTED
;
376 if (result
& (VISIT_ABORT
| VISIT_REJECTED
))
379 p
= past_pat_inspector
;
380 result
= VISIT_CONTINUE
;
382 while ( (VISIT_CONTINUE
== result
) && (NULL
!= p
) )
384 result
= (p
->inspector
)(procdata
, p
->context
);
388 if (VISIT_CONTINUE
== result
)
389 return VISIT_ACCEPTED
;
394 /* Accept if all pattern match. */
396 process_and (struct process_data
*procdata
)
398 int result
= VISIT_CONTINUE
;
399 const struct visitor
*p
= inspectors
;
401 while ( ((VISIT_CONTINUE
| VISIT_ACCEPTED
) & result
) && (past_pat_inspector
!= p
) )
403 result
= (p
->inspector
)(procdata
, p
->context
);
407 if (result
== VISIT_CONTINUE
)
408 result
= VISIT_REJECTED
;
409 if (result
& (VISIT_ABORT
| VISIT_REJECTED
))
412 p
= past_pat_inspector
;
413 result
= VISIT_CONTINUE
;
415 while ( (VISIT_CONTINUE
== result
) && (NULL
!= p
) )
417 result
= (p
->inspector
)(procdata
, p
->context
);
421 if (VISIT_CONTINUE
== result
)
422 return VISIT_ACCEPTED
;
427 typedef int (*processfunc
)(struct process_data
*procdata
);
429 static processfunc mainprocessor
= NULL
;
432 add_visitor(visitfunc fn
, void *context
)
434 struct visitor
*p
= xmalloc(sizeof(struct visitor
));
436 p
->context
= context
;
439 if (NULL
== lastinspector
)
441 lastinspector
= inspectors
= p
;
445 lastinspector
->next
= p
;
453 visit_justprint_quoted(struct process_data
*procdata
, void *context
)
456 print_quoted (stdout
, quote_opts
, stdout_is_a_tty
,
458 procdata
->original_filename
);
460 return VISIT_CONTINUE
;
464 visit_justprint_unquoted(struct process_data
*procdata
, void *context
)
467 fputs(procdata
->original_filename
, stdout
);
469 return VISIT_CONTINUE
;
473 visit_old_format(struct process_data
*procdata
, void *context
)
478 /* Get the offset in the path where this path info starts. */
479 if (procdata
->c
== LOCATEDB_OLD_ESCAPE
)
480 procdata
->count
+= getw (procdata
->fp
) - LOCATEDB_OLD_OFFSET
;
482 procdata
->count
+= procdata
->c
- LOCATEDB_OLD_OFFSET
;
484 /* Overlay the old path with the remainder of the new. */
485 for (s
= procdata
->original_filename
+ procdata
->count
;
486 (procdata
->c
= getc (procdata
->fp
)) > LOCATEDB_OLD_ESCAPE
;)
487 if (procdata
->c
< 0200)
488 *s
++ = procdata
->c
; /* An ordinary character. */
491 /* Bigram markers have the high bit set. */
493 *s
++ = procdata
->bigram1
[procdata
->c
];
494 *s
++ = procdata
->bigram2
[procdata
->c
];
498 procdata
->munged_filename
= procdata
->original_filename
;
500 return VISIT_CONTINUE
;
505 visit_locate02_format(struct process_data
*procdata
, void *context
)
511 if (procdata
->c
== LOCATEDB_ESCAPE
)
512 procdata
->count
+= (short)get_short (procdata
->fp
);
513 else if (procdata
->c
> 127)
514 procdata
->count
+= procdata
->c
- 256;
516 procdata
->count
+= procdata
->c
;
518 if (procdata
->count
> procdata
->len
|| procdata
->count
< 0)
520 /* This should not happen generally , but since we're
521 * reading in data which is outside our control, we
524 error(1, 0, _("locate database `%s' is corrupt or invalid"), procdata
->dbfile
);
527 /* Overlay the old path with the remainder of the new. */
528 nread
= locate_read_str (&procdata
->original_filename
, &procdata
->pathsize
,
529 procdata
->fp
, 0, procdata
->count
);
532 procdata
->c
= getc (procdata
->fp
);
533 procdata
->len
= procdata
->count
+ nread
;
534 s
= procdata
->original_filename
+ procdata
->len
- 1; /* Move to the last char in path. */
535 assert (s
[0] != '\0');
536 assert (s
[1] == '\0'); /* Our terminator. */
537 assert (s
[2] == '\0'); /* Added by locate_read_str. */
539 procdata
->munged_filename
= procdata
->original_filename
;
541 return VISIT_CONTINUE
;
545 visit_basename(struct process_data
*procdata
, void *context
)
548 procdata
->munged_filename
= base_name(procdata
->original_filename
);
550 return VISIT_CONTINUE
;
555 visit_casefold(struct process_data
*procdata
, void *context
)
557 struct stringbuf
*b
= context
;
559 if (*b
->preqlen
+1 > b
->buffersize
)
561 b
->buffer
= xrealloc(b
->buffer
, *b
->preqlen
+1); /* XXX: consider using extendbuf(). */
562 b
->buffersize
= *b
->preqlen
+1;
564 lc_strcpy(b
->buffer
, procdata
->munged_filename
);
566 return VISIT_CONTINUE
;
569 /* visit_existing_follow implements -L -e */
571 visit_existing_follow(struct process_data
*procdata
, void *context
)
576 /* munged_filename has been converted in some way (to lower case,
577 * or is just the base name of the file), and original_filename has not.
578 * Hence only original_filename is still actually the name of the file
579 * whose existence we would need to check.
581 if (stat(procdata
->original_filename
, &st
) != 0)
583 return VISIT_REJECTED
;
587 return VISIT_CONTINUE
;
591 /* visit_non_existing_follow implements -L -E */
593 visit_non_existing_follow(struct process_data
*procdata
, void *context
)
598 /* munged_filename has been converted in some way (to lower case,
599 * or is just the base name of the file), and original_filename has not.
600 * Hence only original_filename is still actually the name of the file
601 * whose existence we would need to check.
603 if (stat(procdata
->original_filename
, &st
) == 0)
605 return VISIT_REJECTED
;
609 return VISIT_CONTINUE
;
613 /* visit_existing_nofollow implements -P -e */
615 visit_existing_nofollow(struct process_data
*procdata
, void *context
)
620 /* munged_filename has been converted in some way (to lower case,
621 * or is just the base name of the file), and original_filename has not.
622 * Hence only original_filename is still actually the name of the file
623 * whose existence we would need to check.
625 if (lstat(procdata
->original_filename
, &st
) != 0)
627 return VISIT_REJECTED
;
631 return VISIT_CONTINUE
;
635 /* visit_non_existing_nofollow implements -P -E */
637 visit_non_existing_nofollow(struct process_data
*procdata
, void *context
)
642 /* munged_filename has been converted in some way (to lower case,
643 * or is just the base name of the file), and original_filename has not.
644 * Hence only original_filename is still actually the name of the file
645 * whose existence we would need to check.
647 if (lstat(procdata
->original_filename
, &st
) == 0)
649 return VISIT_REJECTED
;
653 return VISIT_CONTINUE
;
658 visit_substring_match_nocasefold(struct process_data
*procdata
, void *context
)
660 const char *pattern
= context
;
662 if (NULL
!= strstr(procdata
->munged_filename
, pattern
))
663 return VISIT_ACCEPTED
;
665 return VISIT_REJECTED
;
669 visit_substring_match_casefold(struct process_data
*procdata
, void *context
)
671 const struct casefolder
* p
= context
;
672 const struct stringbuf
* b
= p
->pbuf
;
675 if (NULL
!= strstr(b
->buffer
, p
->pattern
))
676 return VISIT_ACCEPTED
;
678 return VISIT_REJECTED
;
683 visit_globmatch_nofold(struct process_data
*procdata
, void *context
)
685 const char *glob
= context
;
686 if (fnmatch(glob
, procdata
->munged_filename
, 0) != 0)
687 return VISIT_REJECTED
;
689 return VISIT_ACCEPTED
;
694 visit_globmatch_casefold(struct process_data
*procdata
, void *context
)
696 const char *glob
= context
;
697 if (fnmatch(glob
, procdata
->munged_filename
, FNM_CASEFOLD
) != 0)
698 return VISIT_REJECTED
;
700 return VISIT_ACCEPTED
;
705 visit_regex(struct process_data
*procdata
, void *context
)
707 struct regular_expression
*p
= context
;
708 const size_t len
= strlen(procdata
->munged_filename
);
710 int rv
= re_search (&p
->regex
, procdata
->munged_filename
,
712 (struct re_registers
*) NULL
);
715 return VISIT_REJECTED
; /* no match (-1), or internal error (-2) */
719 return VISIT_ACCEPTED
; /* match */
725 visit_stats(struct process_data
*procdata
, void *context
)
727 struct locate_stats
*p
= context
;
728 size_t len
= strlen(procdata
->original_filename
);
730 int highbit
, whitespace
, newline
;
732 ++(p
->total_filename_count
);
733 p
->total_filename_length
+= len
;
735 highbit
= whitespace
= newline
= 0;
736 for (s
=procdata
->original_filename
; *s
; ++s
)
738 if ( (int)(*s
) & 128 )
742 newline
= whitespace
= 1;
744 else if (isspace((unsigned char)*s
))
751 ++(p
->highbit_filename_count
);
753 ++(p
->whitespace_count
);
755 ++(p
->newline_count
);
757 return VISIT_CONTINUE
;
762 visit_limit(struct process_data
*procdata
, void *context
)
764 struct locate_limits
*p
= context
;
768 if (++p
->items_accepted
>= p
->limit
)
771 return VISIT_CONTINUE
;
775 visit_count(struct process_data
*procdata
, void *context
)
777 struct locate_limits
*p
= context
;
782 return VISIT_CONTINUE
;
785 /* Emit the statistics.
788 print_stats(int argc
, size_t database_file_size
)
790 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
792 printf(_("Locate database size: %s bytes\n"),
793 human_readable ((uintmax_t) database_file_size
,
794 hbuf
, human_ceiling
, 1, 1));
796 printf(_("Filenames: %s "),
797 human_readable (statistics
.total_filename_count
,
798 hbuf
, human_ceiling
, 1, 1));
799 printf(_("with a cumulative length of %s bytes"),
800 human_readable (statistics
.total_filename_length
,
801 hbuf
, human_ceiling
, 1, 1));
803 printf(_("\n\tof which %s contain whitespace, "),
804 human_readable (statistics
.whitespace_count
,
805 hbuf
, human_ceiling
, 1, 1));
806 printf(_("\n\t%s contain newline characters, "),
807 human_readable (statistics
.newline_count
,
808 hbuf
, human_ceiling
, 1, 1));
809 printf(_("\n\tand %s contain characters with the high bit set.\n"),
810 human_readable (statistics
.highbit_filename_count
,
811 hbuf
, human_ceiling
, 1, 1));
814 printf(_("Compression ratio %4.2f%%\n"),
815 100.0 * ((double)statistics
.total_filename_length
816 - (double) database_file_size
)
817 / (double) statistics
.total_filename_length
);
822 /* Print or count the entries in DBFILE that match shell globbing patterns in
823 ARGV. Return the number of entries matched. */
833 struct locate_limits
*plimit
,
839 char *pathpart
; /* A pattern to consider. */
840 int argn
; /* Index to current pattern in argv. */
841 int need_fold
; /* Set when folding and any pattern is non-glob. */
842 int nread
; /* number of bytes read from an entry. */
843 struct process_data procdata
; /* Storage for data shared with visitors. */
845 int old_format
= 0; /* true if reading a bigram-encoded database. */
846 static bool did_stdin
= false; /* Set to prevent rereading stdin. */
847 struct visitor
* pvis
; /* temp for determining past_pat_inspector. */
849 /* To check the age of the database. */
855 regex_options
|= RE_ICASE
;
857 procdata
.len
= procdata
.count
= 0;
858 if (!strcmp (dbfile
, "-"))
862 error (0, 0, _("warning: the locate database can only be read from stdin once."));
867 procdata
.dbfile
= "<stdin>";
873 if (stat (dbfile
, &st
) || (procdata
.fp
= fopen (dbfile
, "r")) == NULL
)
875 error (0, errno
, "%s", dbfile
);
879 if (now
- st
.st_mtime
> WARN_SECONDS
)
882 warning: database `fred' is more than 8 days old */
883 error (0, 0, _("warning: database `%s' is more than %d %s old"),
884 dbfile
, WARN_NUMBER_UNITS
, _(warn_name_units
));
886 procdata
.dbfile
= dbfile
;
889 procdata
.pathsize
= 1026; /* Increased as necessary by locate_read_str. */
890 procdata
.original_filename
= xmalloc (procdata
.pathsize
);
892 nread
= fread (procdata
.original_filename
, 1, sizeof (LOCATEDB_MAGIC
),
894 if (nread
!= sizeof (LOCATEDB_MAGIC
)
895 || memcmp (procdata
.original_filename
, LOCATEDB_MAGIC
,
896 sizeof (LOCATEDB_MAGIC
)))
899 /* Read the list of the most common bigrams in the database. */
900 nread
= fread (procdata
.original_filename
+ sizeof (LOCATEDB_MAGIC
), 1,
901 256 - sizeof (LOCATEDB_MAGIC
), procdata
.fp
);
902 for (i
= 0; i
< 128; i
++)
904 procdata
.bigram1
[i
] = procdata
.original_filename
[i
<< 1];
905 procdata
.bigram2
[i
] = procdata
.original_filename
[(i
<< 1) + 1];
910 /* Set up the inspection regime */
912 lastinspector
= NULL
;
913 past_pat_inspector
= NULL
;
916 add_visitor(visit_old_format
, NULL
);
918 add_visitor(visit_locate02_format
, NULL
);
921 add_visitor(visit_basename
, NULL
);
923 /* See if we need fold. */
924 if (ignore_case
&& !regex
)
925 for ( argn
= 0; argn
< argc
; argn
++ )
927 pathpart
= argv
[argn
];
928 if (!contains_metacharacter(pathpart
))
937 add_visitor(visit_casefold
, &casebuf
);
938 casebuf
.preqlen
= &procdata
.pathsize
;
939 casebuf
.soffs
= &procdata
.count
;
942 /* Add an inspector for each pattern we're looking for. */
943 for ( argn
= 0; argn
< argc
; argn
++ )
945 pathpart
= argv
[argn
];
948 struct regular_expression
*p
= xmalloc(sizeof(*p
));
949 const char *error_message
= NULL
;
951 memset (&p
->regex
, 0, sizeof (p
->regex
));
953 re_set_syntax(regex_options
);
954 p
->regex
.allocated
= 100;
955 p
->regex
.buffer
= (unsigned char *) xmalloc (p
->regex
.allocated
);
956 p
->regex
.fastmap
= NULL
;
957 p
->regex
.syntax
= regex_options
;
958 p
->regex
.translate
= NULL
;
960 error_message
= re_compile_pattern (pathpart
, strlen (pathpart
),
964 error (1, 0, "%s", error_message
);
968 add_visitor(visit_regex
, p
);
971 else if (contains_metacharacter(pathpart
))
974 add_visitor(visit_globmatch_casefold
, pathpart
);
976 add_visitor(visit_globmatch_nofold
, pathpart
);
980 /* No glob characters used. Hence we match on
981 * _any part_ of the filename, not just the
982 * basename. This seems odd to me, but it is the
983 * traditional behaviour.
984 * James Youngman <jay@gnu.org>
988 struct casefolder
* cf
= xmalloc(sizeof(*cf
));
989 cf
->pattern
= pathpart
;
991 add_visitor(visit_substring_match_casefold
, cf
);
992 /* If we ignore case, convert it to lower now so we don't have to
995 lc_strcpy(pathpart
, pathpart
);
999 add_visitor(visit_substring_match_nocasefold
, pathpart
);
1004 pvis
= lastinspector
;
1006 /* We add visit_existing_*() as late as possible to reduce the
1007 * number of stat() calls.
1009 switch (check_existence
)
1011 case ACCEPT_EXISTING
:
1012 if (follow_symlinks
) /* -L, default */
1013 add_visitor(visit_existing_follow
, NULL
);
1015 add_visitor(visit_existing_nofollow
, NULL
);
1018 case ACCEPT_NON_EXISTING
:
1019 if (follow_symlinks
) /* -L, default */
1020 add_visitor(visit_non_existing_follow
, NULL
);
1022 add_visitor(visit_non_existing_nofollow
, NULL
);
1025 case ACCEPT_EITHER
: /* Default, neither -E nor -e */
1026 /* do nothing; no extra processing. */
1031 add_visitor(visit_stats
, &statistics
);
1035 if (print_quoted_filename
)
1036 add_visitor(visit_justprint_quoted
, NULL
);
1038 add_visitor(visit_justprint_unquoted
, NULL
);
1043 add_visitor(visit_limit
, plimit
);
1045 add_visitor(visit_count
, plimit
);
1050 past_pat_inspector
= pvis
->next
;
1052 mainprocessor
= process_and
;
1054 mainprocessor
= process_or
;
1057 mainprocessor
= process_simple
;
1061 printf(_("Database %s is in the %s format.\n"),
1063 old_format
? _("old") : "LOCATE02");
1067 procdata
.c
= getc (procdata
.fp
);
1068 /* If we are searching for filename patterns, the inspector list
1069 * will contain an entry for each pattern for which we are searching.
1071 while ( (procdata
.c
!= EOF
) &&
1072 (VISIT_ABORT
!= (mainprocessor
)(&procdata
)) )
1074 /* Do nothing; all the work is done in the visitor functions. */
1079 print_stats(argc
, st
.st_size
);
1082 if (ferror (procdata
.fp
))
1084 error (0, errno
, "%s", procdata
.dbfile
);
1087 if (procdata
.fp
!= stdin
&& fclose (procdata
.fp
) == EOF
)
1089 error (0, errno
, "%s", dbfile
);
1093 return plimit
->items_accepted
;
1099 extern char *version_string
;
1101 /* The name this program was run with. */
1105 usage (FILE *stream
)
1107 fprintf (stream
, _("\
1108 Usage: %s [-d path | --database=path] [-e | -E | --[non-]existing]\n\
1109 [-i | --ignore-case] [-w | --wholename] [-b | --basename] \n\
1110 [--limit=N | -l N] [-S | --statistics] [-0 | --null] [-c | --count]\n\
1111 [-P | -H | --nofollow] [-L | --follow] [-m | --mmap ] [ -s | --stdio ]\n\
1112 [-A | --all] [-p | --print] [-r | --regex ] [--regextype=TYPE]\n\
1113 [-version] [--help]\n\
1116 fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream
);
1120 REGEXTYPE_OPTION
= CHAR_MAX
+ 1
1124 static struct option
const longopts
[] =
1126 {"database", required_argument
, NULL
, 'd'},
1127 {"existing", no_argument
, NULL
, 'e'},
1128 {"non-existing", no_argument
, NULL
, 'E'},
1129 {"ignore-case", no_argument
, NULL
, 'i'},
1130 {"all", no_argument
, NULL
, 'A'},
1131 {"help", no_argument
, NULL
, 'h'},
1132 {"version", no_argument
, NULL
, 'v'},
1133 {"null", no_argument
, NULL
, '0'},
1134 {"count", no_argument
, NULL
, 'c'},
1135 {"wholename", no_argument
, NULL
, 'w'},
1136 {"wholepath", no_argument
, NULL
, 'w'}, /* Synonym. */
1137 {"basename", no_argument
, NULL
, 'b'},
1138 {"print", no_argument
, NULL
, 'p'},
1139 {"stdio", no_argument
, NULL
, 's'},
1140 {"mmap", no_argument
, NULL
, 'm'},
1141 {"limit", required_argument
, NULL
, 'l'},
1142 {"regex", no_argument
, NULL
, 'r'},
1143 {"regextype", required_argument
, NULL
, REGEXTYPE_OPTION
},
1144 {"statistics", no_argument
, NULL
, 'S'},
1145 {"follow", no_argument
, NULL
, 'L'},
1146 {"nofollow", no_argument
, NULL
, 'P'},
1147 {NULL
, no_argument
, NULL
, 0}
1151 main (int argc
, char **argv
)
1154 unsigned long int found
= 0uL;
1156 int ignore_case
= 0;
1159 int basename_only
= 0;
1162 int regex_options
= RE_SYNTAX_EMACS
;
1167 program_name
= argv
[0];
1169 #ifdef HAVE_SETLOCALE
1170 setlocale (LC_ALL
, "");
1172 bindtextdomain (PACKAGE
, LOCALEDIR
);
1173 textdomain (PACKAGE
);
1174 atexit (close_stdout
);
1177 limits
.items_accepted
= 0;
1179 quote_opts
= clone_quoting_options (NULL
);
1180 print_quoted_filename
= true;
1182 dbpath
= getenv ("LOCATE_PATH");
1186 check_existence
= ACCEPT_EITHER
;
1188 while ((optc
= getopt_long (argc
, argv
, "Abcd:eEil:prsm0SwHPL", longopts
, (int *) 0)) != -1)
1193 print_quoted_filename
= false; /* print filename 'raw'. */
1213 check_existence
= ACCEPT_EXISTING
;
1217 check_existence
= ACCEPT_NON_EXISTING
;
1233 printf (_("GNU locate version %s\n"), version_string
);
1244 case REGEXTYPE_OPTION
:
1245 regex_options
= get_regex_type(optarg
);
1253 follow_symlinks
= 1;
1256 /* In find, -P and -H differ in the way they handle paths
1257 * given on the command line. This is not relevant for
1258 * locate, but the -H option is supported because it is
1259 * probably more intuitive to do so.
1263 follow_symlinks
= 0;
1269 strtol_error err
= xstrtoumax(optarg
, &end
, 10, &limits
.limit
, NULL
);
1270 if (LONGINT_OK
!= err
)
1272 STRTOL_FATAL_ERROR(optarg
, _("argument to --limit"), err
);
1278 case 's': /* use stdio */
1279 case 'm': /* use mmap */
1280 /* These options are implemented simply for
1281 * compatibility with FreeBSD
1290 if (!just_count
&& !stats
)
1300 if (!just_count
&& optind
== argc
)
1308 if (1 == isatty(STDOUT_FILENO
))
1309 stdout_is_a_tty
= true;
1311 stdout_is_a_tty
= false;
1313 next_element (dbpath
, 0); /* Initialize. */
1315 /* Bail out early if limit already reached. */
1316 while ((e
= next_element ((char *) NULL
, 0)) != NULL
&&
1317 (!use_limit
|| limits
.limit
> limits
.items_accepted
))
1319 statistics
.compressed_bytes
=
1320 statistics
.total_filename_count
=
1321 statistics
.total_filename_length
=
1322 statistics
.whitespace_count
=
1323 statistics
.newline_count
=
1324 statistics
.highbit_filename_count
= 0u;
1326 if (0 == strlen(e
) || 0 == strcmp(e
, "."))
1328 /* Use the default database name instead (note: we
1329 * don't use 'dbpath' since that might itself contain a
1330 * colon-separated list.
1335 found
= locate (argc
- optind
, &argv
[optind
], e
, ignore_case
, print
, basename_only
, use_limit
, &limits
, stats
, op_and
, regex
, regex_options
);
1340 printf("%ld\n", found
);
1343 if (found
|| (use_limit
&& (limits
.limit
==0)) || stats
)