~ubuntu-branches/ubuntu/gutsy/findutils/gutsy-proposed

« back to all changes in this revision

Viewing changes to find/parser.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Metzler
  • Date: 2005-07-04 11:37:37 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20050704113737-ll89ui8be35r0pir
Tags: 4.2.22-2
* Remove locatedb on purge. (Closes: #315343)
* revert regex-syntax back to emacs-re. (Closes: #315136) Future versions
  will allow to select this by commandline parameter.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* parser.c -- convert the command line args into an expression tree.
2
 
   Copyright (C) 1990, 91, 92, 93, 94, 2000 Free Software Foundation, Inc.
 
2
   Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003, 
 
3
                 2004, 2005 Free Software Foundation, Inc.
3
4
 
4
5
   This program is free software; you can redistribute it and/or modify
5
6
   it under the terms of the GNU General Public License as published by
13
14
 
14
15
   You should have received a copy of the GNU General Public License
15
16
   along with this program; if not, write to the Free Software
16
 
   Foundation, Inc., 9 Temple Place - Suite 330, Boston, MA 02111-1307,
 
17
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17
18
   USA.
18
19
*/
19
20
 
 
21
 
20
22
#include "defs.h"
21
23
#include <ctype.h>
22
24
#include <pwd.h>
23
25
#include <grp.h>
 
26
#include <fnmatch.h>
24
27
#include "modechange.h"
25
28
#include "modetype.h"
26
29
#include "xstrtol.h"
 
30
#include "xalloc.h"
 
31
#include "quote.h"
 
32
#include "quotearg.h"
 
33
#include "buildcmd.h"
 
34
#include "nextelem.h"
 
35
 
 
36
#ifdef HAVE_FCNTL_H
 
37
#include <fcntl.h>
 
38
#else
 
39
#include <sys/file.h>
 
40
#endif
 
41
 
 
42
#ifdef HAVE_UNISTD_H
 
43
/* We need <unistd.h> for isatty(). */
 
44
#include <unistd.h>
 
45
#endif
 
46
 
27
47
 
28
48
#if ENABLE_NLS
29
49
# include <libintl.h>
34
54
#ifdef gettext_noop
35
55
# define N_(String) gettext_noop (String)
36
56
#else
37
 
# define N_(String) (String)
 
57
/* See locate.c for explanation as to why not use (String) */
 
58
# define N_(String) String
38
59
#endif
39
60
 
40
61
#if !defined (isascii) || defined (STDC_HEADERS)
44
65
#define isascii(c) 1
45
66
#endif
46
67
 
47
 
#define ISDIGIT(c) (isascii (c) && isdigit (c))
48
 
#define ISUPPER(c) (isascii (c) && isupper (c))
 
68
#define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
 
69
#define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
49
70
 
50
71
#ifndef HAVE_ENDGRENT
51
72
#define endgrent()
64
85
static boolean parse_comma PARAMS((char *argv[], int *arg_ptr));
65
86
static boolean parse_ctime PARAMS((char *argv[], int *arg_ptr));
66
87
static boolean parse_daystart PARAMS((char *argv[], int *arg_ptr));
 
88
static boolean parse_delete PARAMS((char *argv[], int *arg_ptr));
 
89
static boolean parse_d PARAMS((char *argv[], int *arg_ptr));
67
90
static boolean parse_depth PARAMS((char *argv[], int *arg_ptr));
68
91
static boolean parse_empty PARAMS((char *argv[], int *arg_ptr));
69
92
static boolean parse_exec PARAMS((char *argv[], int *arg_ptr));
 
93
static boolean parse_execdir PARAMS((char *argv[], int *arg_ptr));
70
94
static boolean parse_false PARAMS((char *argv[], int *arg_ptr));
71
95
static boolean parse_fls PARAMS((char *argv[], int *arg_ptr));
72
96
static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr));
82
106
static boolean parse_inum PARAMS((char *argv[], int *arg_ptr));
83
107
static boolean parse_ipath PARAMS((char *argv[], int *arg_ptr));
84
108
static boolean parse_iregex PARAMS((char *argv[], int *arg_ptr));
 
109
static boolean parse_iwholename PARAMS((char *argv[], int *arg_ptr));
85
110
static boolean parse_links PARAMS((char *argv[], int *arg_ptr));
86
111
static boolean parse_lname PARAMS((char *argv[], int *arg_ptr));
87
112
static boolean parse_ls PARAMS((char *argv[], int *arg_ptr));
95
120
static boolean parse_noleaf PARAMS((char *argv[], int *arg_ptr));
96
121
static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr));
97
122
static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr));
 
123
static boolean parse_nowarn PARAMS((char *argv[], int *arg_ptr));
98
124
static boolean parse_ok PARAMS((char *argv[], int *arg_ptr));
 
125
static boolean parse_okdir PARAMS((char *argv[], int *arg_ptr));
99
126
boolean parse_open PARAMS((char *argv[], int *arg_ptr));
100
127
static boolean parse_or PARAMS((char *argv[], int *arg_ptr));
101
128
static boolean parse_path PARAMS((char *argv[], int *arg_ptr));
106
133
static boolean parse_prune PARAMS((char *argv[], int *arg_ptr));
107
134
static boolean parse_regex PARAMS((char *argv[], int *arg_ptr));
108
135
static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
 
136
static boolean parse_samefile PARAMS((char *argv[], int *arg_ptr));
109
137
static boolean parse_size PARAMS((char *argv[], int *arg_ptr));
110
138
static boolean parse_true PARAMS((char *argv[], int *arg_ptr));
111
139
static boolean parse_type PARAMS((char *argv[], int *arg_ptr));
113
141
static boolean parse_used PARAMS((char *argv[], int *arg_ptr));
114
142
static boolean parse_user PARAMS((char *argv[], int *arg_ptr));
115
143
static boolean parse_version PARAMS((char *argv[], int *arg_ptr));
 
144
static boolean parse_wholename PARAMS((char *argv[], int *arg_ptr));
116
145
static boolean parse_xdev PARAMS((char *argv[], int *arg_ptr));
 
146
static boolean parse_ignore_race PARAMS((char *argv[], int *arg_ptr));
 
147
static boolean parse_noignore_race PARAMS((char *argv[], int *arg_ptr));
 
148
static boolean parse_warn PARAMS((char *argv[], int *arg_ptr));
117
149
static boolean parse_xtype PARAMS((char *argv[], int *arg_ptr));
 
150
static boolean parse_quit PARAMS((char *argv[], int *arg_ptr));
118
151
 
119
152
static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, boolean ignore_case));
120
 
static boolean insert_type PARAMS((char *argv[], int *arg_ptr, boolean (*which_pred )()));
121
 
static boolean insert_fprintf PARAMS((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
 
153
static boolean insert_type PARAMS((char *argv[], int *arg_ptr, PRED_FUNC which_pred));
 
154
static boolean insert_fprintf PARAMS((FILE *fp, PRED_FUNC func, char *argv[], int *arg_ptr));
122
155
static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind));
123
 
static boolean insert_exec_ok PARAMS((boolean (*func )(), char *argv[], int *arg_ptr));
 
156
static boolean insert_exec_ok PARAMS((const char *action, PRED_FUNC func, char *argv[], int *arg_ptr));
124
157
static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type));
125
 
static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PFB pred));
 
158
static boolean insert_time PARAMS((char *argv[], int *arg_ptr, PRED_FUNC pred));
126
159
static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type));
127
 
static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PFB pred));
 
160
static boolean insert_num PARAMS((char *argv[], int *arg_ptr, PRED_FUNC pred));
128
161
static FILE *open_output_file PARAMS((char *path));
 
162
static boolean stream_is_tty(FILE *fp);
129
163
 
130
164
#ifdef DEBUG
131
 
char *find_pred_name PARAMS((PFB pred_func));
 
165
char *find_pred_name PARAMS((PRED_FUNC pred_func));
132
166
#endif /* DEBUG */
133
167
 
 
168
 
 
169
 
 
170
enum arg_type
 
171
  {
 
172
    ARG_OPTION,                 /* regular options like -maxdepth */
 
173
    ARG_POSITIONAL_OPTION,      /* options whose position is important (-follow) */
 
174
    ARG_TEST,                   /* a like -name */
 
175
    ARG_PUNCTUATION,            /* like -o or ( */
 
176
    ARG_ACTION                  /* like -print */
 
177
  };
 
178
 
 
179
 
134
180
struct parser_table
135
181
{
 
182
  enum arg_type type;
136
183
  char *parser_name;
137
 
  PFB parser_func;
 
184
  PARSE_FUNC parser_func;
138
185
};
139
186
 
140
187
/* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
142
189
 
143
190
static struct parser_table const parse_table[] =
144
191
{
145
 
  {"!", parse_negate},
146
 
  {"not", parse_negate},        /* GNU */
147
 
  {"(", parse_open},
148
 
  {")", parse_close},
149
 
  {",", parse_comma},           /* GNU */
150
 
  {"a", parse_and},
151
 
  {"amin", parse_amin},         /* GNU */
152
 
  {"and", parse_and},           /* GNU */
153
 
  {"anewer", parse_anewer},     /* GNU */
154
 
  {"atime", parse_atime},
155
 
  {"cmin", parse_cmin},         /* GNU */
156
 
  {"cnewer", parse_cnewer},     /* GNU */
 
192
  {ARG_PUNCTUATION,        "!",                     parse_negate},
 
193
  {ARG_PUNCTUATION,        "not",                   parse_negate},      /* GNU */
 
194
  {ARG_PUNCTUATION,        "(",                     parse_open},
 
195
  {ARG_PUNCTUATION,        ")",                     parse_close},
 
196
  {ARG_PUNCTUATION,        ",",                     parse_comma},       /* GNU */
 
197
  {ARG_PUNCTUATION,        "a",                     parse_and},
 
198
  {ARG_TEST,               "amin",                  parse_amin},        /* GNU */
 
199
  {ARG_PUNCTUATION,        "and",                   parse_and},         /* GNU */
 
200
  {ARG_TEST,               "anewer",                parse_anewer},      /* GNU */
 
201
  {ARG_TEST,               "atime",                 parse_atime},
 
202
  {ARG_TEST,               "cmin",                  parse_cmin},        /* GNU */
 
203
  {ARG_TEST,               "cnewer",                parse_cnewer},      /* GNU */
157
204
#ifdef UNIMPLEMENTED_UNIX
158
205
  /* It's pretty ugly for find to know about archive formats.
159
206
     Plus what it could do with cpio archives is very limited.
160
207
     Better to leave it out.  */
161
 
  {"cpio", parse_cpio},         /* Unix */
162
 
#endif
163
 
  {"ctime", parse_ctime},
164
 
  {"daystart", parse_daystart}, /* GNU */
165
 
  {"depth", parse_depth},
166
 
  {"empty", parse_empty},       /* GNU */
167
 
  {"exec", parse_exec},
168
 
  {"false", parse_false},       /* GNU */
169
 
  {"fls", parse_fls},           /* GNU */
170
 
  {"follow", parse_follow},     /* GNU, Unix */
171
 
  {"fprint", parse_fprint},     /* GNU */
172
 
  {"fprint0", parse_fprint0},   /* GNU */
173
 
  {"fprintf", parse_fprintf},   /* GNU */
174
 
  {"fstype", parse_fstype},     /* GNU, Unix */
175
 
  {"gid", parse_gid},           /* GNU */
176
 
  {"group", parse_group},
177
 
  {"help", parse_help},         /* GNU */
178
 
  {"-help", parse_help},        /* GNU */
179
 
  {"ilname", parse_ilname},     /* GNU */
180
 
  {"iname", parse_iname},       /* GNU */
181
 
  {"inum", parse_inum},         /* GNU, Unix */
182
 
  {"ipath", parse_ipath},       /* GNU */
183
 
  {"iregex", parse_iregex},     /* GNU */
184
 
  {"links", parse_links},
185
 
  {"lname", parse_lname},       /* GNU */
186
 
  {"ls", parse_ls},             /* GNU, Unix */
187
 
  {"maxdepth", parse_maxdepth}, /* GNU */
188
 
  {"mindepth", parse_mindepth}, /* GNU */
189
 
  {"mmin", parse_mmin},         /* GNU */
190
 
  {"mount", parse_xdev},        /* Unix */
191
 
  {"mtime", parse_mtime},
192
 
  {"name", parse_name},
193
 
#ifdef UNIMPLEMENTED_UNIX
194
 
  {"ncpio", parse_ncpio},       /* Unix */
195
 
#endif
196
 
  {"newer", parse_newer},
197
 
  {"noleaf", parse_noleaf},     /* GNU */
198
 
  {"nogroup", parse_nogroup},
199
 
  {"nouser", parse_nouser},
200
 
  {"o", parse_or},
201
 
  {"or", parse_or},             /* GNU */
202
 
  {"ok", parse_ok},
203
 
  {"path", parse_path},         /* GNU, HP-UX */
204
 
  {"perm", parse_perm},
205
 
  {"print", parse_print},
206
 
  {"print0", parse_print0},     /* GNU */
207
 
  {"printf", parse_printf},     /* GNU */
208
 
  {"prune", parse_prune},
209
 
  {"regex", parse_regex},       /* GNU */
210
 
  {"size", parse_size},
211
 
  {"true", parse_true},         /* GNU */
212
 
  {"type", parse_type},
213
 
  {"uid", parse_uid},           /* GNU */
214
 
  {"used", parse_used},         /* GNU */
215
 
  {"user", parse_user},
216
 
  {"version", parse_version},   /* GNU */
217
 
  {"-version", parse_version},  /* GNU */
218
 
  {"xdev", parse_xdev},
219
 
  {"xtype", parse_xtype},       /* GNU */
220
 
  {0, 0}
 
208
  {ARG_UNIMPLEMENTED,      "cpio",                  parse_cpio},        /* Unix */
 
209
#endif                                              
 
210
  {ARG_TEST,               "ctime",                 parse_ctime},
 
211
  {ARG_POSITIONAL_OPTION,  "daystart",              parse_daystart},    /* GNU */
 
212
  {ARG_ACTION,             "delete",                parse_delete},      /* GNU, Mac OS, FreeBSD */
 
213
  {ARG_OPTION,             "d",                     parse_d},           /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated  in favour of -depth */
 
214
  {ARG_OPTION,             "depth",                 parse_depth},
 
215
  {ARG_TEST,               "empty",                 parse_empty},       /* GNU */
 
216
  {ARG_ACTION,             "exec",                  parse_exec},
 
217
  {ARG_ACTION,             "execdir",               parse_execdir},     /* *BSD, GNU */
 
218
  {ARG_TEST,               "false",                 parse_false},       /* GNU */
 
219
  {ARG_ACTION,             "fls",                   parse_fls},         /* GNU */
 
220
  {ARG_POSITIONAL_OPTION,  "follow",                parse_follow},      /* GNU, Unix */
 
221
  {ARG_ACTION,             "fprint",                parse_fprint},      /* GNU */
 
222
  {ARG_ACTION,             "fprint0",               parse_fprint0},     /* GNU */
 
223
  {ARG_ACTION,             "fprintf",               parse_fprintf},     /* GNU */
 
224
  {ARG_TEST,               "fstype",                parse_fstype},      /* GNU, Unix */
 
225
  {ARG_TEST,               "gid",                   parse_gid},         /* GNU */
 
226
  {ARG_TEST,               "group",                 parse_group},
 
227
  {ARG_TEST,               "help",                  parse_help},        /* GNU */
 
228
  {ARG_TEST,               "-help",                 parse_help},        /* GNU */
 
229
  {ARG_OPTION,             "ignore_readdir_race",   parse_ignore_race}, /* GNU */
 
230
  {ARG_TEST,               "ilname",                parse_ilname},      /* GNU */
 
231
  {ARG_TEST,               "iname",                 parse_iname},       /* GNU */
 
232
  {ARG_TEST,               "inum",                  parse_inum},        /* GNU, Unix */
 
233
  {ARG_TEST,               "ipath",                 parse_ipath},       /* GNU, deprecated in favour of iwholename */
 
234
  {ARG_TEST,               "iregex",                parse_iregex},      /* GNU */
 
235
  {ARG_TEST,               "iwholename",            parse_iwholename},  /* GNU */
 
236
  {ARG_TEST,               "links",                 parse_links},
 
237
  {ARG_TEST,               "lname",                 parse_lname},       /* GNU */
 
238
  {ARG_ACTION,             "ls",                    parse_ls},          /* GNU, Unix */
 
239
  {ARG_OPTION,             "maxdepth",              parse_maxdepth},    /* GNU */
 
240
  {ARG_OPTION,             "mindepth",              parse_mindepth},    /* GNU */
 
241
  {ARG_TEST,               "mmin",                  parse_mmin},        /* GNU */
 
242
  {ARG_OPTION,             "mount",                 parse_xdev},        /* Unix */
 
243
  {ARG_TEST,               "mtime",                 parse_mtime},
 
244
  {ARG_TEST,               "name",                  parse_name},
 
245
#ifdef UNIMPLEMENTED_UNIX                           
 
246
  {ARG_UNIMPLEMENTED,      "ncpio",                 parse_ncpio},       /* Unix */
 
247
#endif                                              
 
248
  {ARG_TEST,               "newer",                 parse_newer},
 
249
  {ARG_OPTION,             "noleaf",                parse_noleaf},      /* GNU */
 
250
  {ARG_TEST,               "nogroup",               parse_nogroup},
 
251
  {ARG_TEST,               "nouser",                parse_nouser},
 
252
  {ARG_OPTION,             "noignore_readdir_race", parse_noignore_race},/* GNU */
 
253
  {ARG_OPTION,             "nowarn",                parse_nowarn},       /* GNU */
 
254
  {ARG_PUNCTUATION,        "o",                     parse_or},
 
255
  {ARG_PUNCTUATION,        "or",                    parse_or},           /* GNU */
 
256
  {ARG_ACTION,             "ok",                    parse_ok},
 
257
  {ARG_ACTION,             "okdir",                 parse_okdir},        /* GNU (-execdir is BSD) */
 
258
  {ARG_TEST,               "path",                  parse_path},         /* GNU, HP-UX, GNU prefers wholename */
 
259
  {ARG_TEST,               "perm",                  parse_perm},
 
260
  {ARG_ACTION,             "print",                 parse_print},
 
261
  {ARG_ACTION,             "print0",                parse_print0},      /* GNU */
 
262
  {ARG_ACTION,             "printf",                parse_printf},      /* GNU */
 
263
  {ARG_TEST,               "prune",                 parse_prune},
 
264
  {ARG_ACTION,             "quit",                  parse_quit},        /* GNU */
 
265
  {ARG_TEST,               "regex",                 parse_regex},       /* GNU */
 
266
  {ARG_TEST,               "samefile",              parse_samefile},    /* GNU */
 
267
  {ARG_TEST,               "size",                  parse_size},
 
268
  {ARG_TEST,               "true",                  parse_true},        /* GNU */
 
269
  {ARG_TEST,               "type",                  parse_type},
 
270
  {ARG_TEST,               "uid",                   parse_uid},         /* GNU */
 
271
  {ARG_TEST,               "used",                  parse_used},        /* GNU */
 
272
  {ARG_TEST,               "user",                  parse_user},
 
273
  {ARG_TEST,               "version",               parse_version},     /* GNU */
 
274
  {ARG_TEST,               "-version",              parse_version},     /* GNU */
 
275
  {ARG_OPTION,             "warn",                  parse_warn},        /* GNU */
 
276
  {ARG_TEST,               "wholename",             parse_wholename},   /* GNU, replaces -path */
 
277
  {ARG_OPTION,             "xdev",                  parse_xdev},
 
278
  {ARG_TEST,               "xtype",                 parse_xtype},       /* GNU */
 
279
  {0, 0, 0}
221
280
};
222
281
 
 
282
 
 
283
static const char *first_nonoption_arg = NULL;
 
284
 
223
285
/* Return a pointer to the parser function to invoke for predicate
224
286
   SEARCH_NAME.
225
287
   Return NULL if SEARCH_NAME is not a valid predicate name. */
226
288
 
227
 
PFB
 
289
PARSE_FUNC
228
290
find_parser (char *search_name)
229
291
{
230
292
  int i;
231
 
 
 
293
  const char *original_arg = search_name;
 
294
  
232
295
  if (*search_name == '-')
233
296
    search_name++;
234
297
  for (i = 0; parse_table[i].parser_name != 0; i++)
235
 
    if (strcmp (parse_table[i].parser_name, search_name) == 0)
236
 
      return (parse_table[i].parser_func);
237
 
  return (NULL);
 
298
    {
 
299
      if (strcmp (parse_table[i].parser_name, search_name) == 0)
 
300
        {
 
301
          /* If this is an option, but we have already had a 
 
302
           * non-option argument, the user may be under the 
 
303
           * impression that the behaviour of the option 
 
304
           * argument is conditional on some preceding 
 
305
           * tests.  This might typically be the case with,
 
306
           * for example, -maxdepth.
 
307
           *
 
308
           * The options -daystart and -follow are exempt 
 
309
           * from this treatment, since their positioning
 
310
           * in the command line does have an effect on 
 
311
           * subsequent tests but not previous ones.  That
 
312
           * might be intentional on the part of the user.
 
313
           */
 
314
          if (parse_table[i].type != ARG_POSITIONAL_OPTION)
 
315
            {
 
316
              /* Something other than -follow/-daystart.
 
317
               * If this is an option, check if it followed
 
318
               * a non-option and if so, issue a warning.
 
319
               */
 
320
              if (parse_table[i].type == ARG_OPTION)
 
321
                {
 
322
                  if ((first_nonoption_arg != NULL)
 
323
                      && options.warnings )
 
324
                    {
 
325
                      /* option which folows a non-option */
 
326
                      error (0, 0,
 
327
                             _("warning: you have specified the %s "
 
328
                               "option after a non-option argument %s, "
 
329
                               "but options are not positional (%s affects "
 
330
                               "tests specified before it as well as those "
 
331
                               "specified after it).  Please specify options "
 
332
                               "before other arguments.\n"),
 
333
                             original_arg,
 
334
                             first_nonoption_arg,
 
335
                             original_arg);
 
336
                    }
 
337
                }
 
338
              else
 
339
                {
 
340
                  /* Not an option or a positional option,
 
341
                   * so remember we've seen it in order to 
 
342
                   * use it in a possible future warning message.
 
343
                   */
 
344
                  if (first_nonoption_arg == NULL)
 
345
                    {
 
346
                      first_nonoption_arg = original_arg;
 
347
                    }
 
348
                }
 
349
            }
 
350
          
 
351
          return (parse_table[i].parser_func);
 
352
        }
 
353
    }
 
354
  return NULL;
238
355
}
239
356
 
240
357
/* The parsers are responsible to continue scanning ARGV for
259
376
    return (false);
260
377
  if (!get_num_days (argv[*arg_ptr], &num, &c_type))
261
378
    return (false);
262
 
  t = cur_day_start + DAYSECS - num * 60;
 
379
  t = options.cur_day_start + DAYSECS - num * 60;
263
380
  our_pred = insert_primary (pred_amin);
264
381
  our_pred->args.info.kind = c_type;
265
382
  our_pred->args.info.negative = t < 0;
273
390
{
274
391
  struct predicate *our_pred;
275
392
 
 
393
  (void) argv;
 
394
  (void) arg_ptr;
 
395
  
276
396
  our_pred = get_new_pred ();
277
397
  our_pred->pred_func = pred_and;
278
398
#ifdef  DEBUG
280
400
#endif  /* DEBUG */
281
401
  our_pred->p_type = BI_OP;
282
402
  our_pred->p_prec = AND_PREC;
283
 
  our_pred->need_stat = false;
 
403
  our_pred->need_stat = our_pred->need_type = false;
284
404
  return (true);
285
405
}
286
406
 
292
412
 
293
413
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
294
414
    return (false);
295
 
  if ((*xstat) (argv[*arg_ptr], &stat_newer))
 
415
  if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
296
416
    error (1, errno, "%s", argv[*arg_ptr]);
297
417
  our_pred = insert_primary (pred_anewer);
298
418
  our_pred->args.time = stat_newer.st_mtime;
311
431
{
312
432
  struct predicate *our_pred;
313
433
 
 
434
  (void) argv;
 
435
  (void) arg_ptr;
 
436
  
314
437
  our_pred = get_new_pred ();
315
438
  our_pred->pred_func = pred_close;
316
439
#ifdef  DEBUG
318
441
#endif  /* DEBUG */
319
442
  our_pred->p_type = CLOSE_PAREN;
320
443
  our_pred->p_prec = NO_PREC;
321
 
  our_pred->need_stat = false;
 
444
  our_pred->need_stat = our_pred->need_type = false;
322
445
  return (true);
323
446
}
324
447
 
334
457
    return (false);
335
458
  if (!get_num_days (argv[*arg_ptr], &num, &c_type))
336
459
    return (false);
337
 
  t = cur_day_start + DAYSECS - num * 60;
 
460
  t = options.cur_day_start + DAYSECS - num * 60;
338
461
  our_pred = insert_primary (pred_cmin);
339
462
  our_pred->args.info.kind = c_type;
340
463
  our_pred->args.info.negative = t < 0;
351
474
 
352
475
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
353
476
    return (false);
354
 
  if ((*xstat) (argv[*arg_ptr], &stat_newer))
 
477
  if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
355
478
    error (1, errno, "%s", argv[*arg_ptr]);
356
479
  our_pred = insert_primary (pred_cnewer);
357
480
  our_pred->args.time = stat_newer.st_mtime;
364
487
{
365
488
  struct predicate *our_pred;
366
489
 
 
490
  (void) argv;
 
491
  (void) arg_ptr;
 
492
 
367
493
  our_pred = get_new_pred ();
368
494
  our_pred->pred_func = pred_comma;
369
495
#ifdef  DEBUG
371
497
#endif /* DEBUG */
372
498
  our_pred->p_type = BI_OP;
373
499
  our_pred->p_prec = COMMA_PREC;
374
 
  our_pred->need_stat = false;
 
500
  our_pred->need_stat = our_pred->need_type = false;
375
501
  return (true);
376
502
}
377
503
 
386
512
{
387
513
  struct tm *local;
388
514
 
389
 
  if (full_days == false)
 
515
  (void) argv;
 
516
  (void) arg_ptr;
 
517
 
 
518
  if (options.full_days == false)
390
519
    {
391
 
      cur_day_start += DAYSECS;
392
 
      local = localtime (&cur_day_start);
393
 
      cur_day_start -= (local
 
520
      options.cur_day_start += DAYSECS;
 
521
      local = localtime (&options.cur_day_start);
 
522
      options.cur_day_start -= (local
394
523
                        ? (local->tm_sec + local->tm_min * 60
395
524
                           + local->tm_hour * 3600)
396
 
                        : cur_day_start % DAYSECS);
397
 
      full_days = true;
 
525
                        : options.cur_day_start % DAYSECS);
 
526
      options.full_days = true;
398
527
    }
 
528
  return true;
 
529
}
 
530
 
 
531
static boolean
 
532
parse_delete (  char *argv[], int *arg_ptr)
 
533
{
 
534
  struct predicate *our_pred;
 
535
  (void) argv;
 
536
  (void) arg_ptr;
 
537
  
 
538
  our_pred = insert_primary (pred_delete);
 
539
  our_pred->side_effects = true;
 
540
  our_pred->no_default_print = true;
 
541
  /* -delete implies -depth */
 
542
  options.do_dir_first = false;
399
543
  return (true);
400
544
}
401
545
 
402
546
static boolean
403
547
parse_depth (char **argv, int *arg_ptr)
404
548
{
405
 
  do_dir_first = false;
 
549
  (void) argv;
 
550
  (void) arg_ptr;
 
551
 
 
552
  options.do_dir_first = false;
406
553
  return (true);
407
554
}
408
555
 
409
556
static boolean
 
557
parse_d (char **argv, int *arg_ptr)
 
558
{
 
559
  (void) argv;
 
560
  (void) arg_ptr;
 
561
  
 
562
  if (options.warnings)
 
563
    {
 
564
      error (0, 0,
 
565
             _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature."));
 
566
    }
 
567
  return parse_depth(argv, arg_ptr);
 
568
}
 
569
 
 
570
static boolean
410
571
parse_empty (char **argv, int *arg_ptr)
411
572
{
 
573
  (void) argv;
 
574
  (void) arg_ptr;
 
575
 
412
576
  insert_primary (pred_empty);
413
577
  return (true);
414
578
}
416
580
static boolean
417
581
parse_exec (char **argv, int *arg_ptr)
418
582
{
419
 
  return (insert_exec_ok (pred_exec, argv, arg_ptr));
 
583
  return (insert_exec_ok ("-exec", pred_exec, argv, arg_ptr));
 
584
}
 
585
 
 
586
static boolean
 
587
parse_execdir (char **argv, int *arg_ptr)
 
588
{
 
589
  return (insert_exec_ok ("-execdir", pred_execdir, argv, arg_ptr));
420
590
}
421
591
 
422
592
static boolean
423
593
parse_false (char **argv, int *arg_ptr)
424
594
{
425
595
  struct predicate *our_pred;
 
596
  
 
597
  (void) argv;
 
598
  (void) arg_ptr;
426
599
 
427
600
  our_pred = insert_primary (pred_false);
428
 
  our_pred->need_stat = false;
 
601
  our_pred->need_stat = our_pred->need_type = false;
429
602
  return (true);
430
603
}
431
604
 
465
638
static boolean
466
639
parse_follow (char **argv, int *arg_ptr)
467
640
{
468
 
  dereference = true;
469
 
  xstat = stat;
470
 
  no_leaf_check = true;
471
 
  return (true);
 
641
  (void) argv;
 
642
  (void) arg_ptr;
 
643
 
 
644
  set_follow_state(SYMLINK_ALWAYS_DEREF);
 
645
  return true;
472
646
}
473
647
 
474
648
static boolean
477
651
  struct predicate *our_pred;
478
652
 
479
653
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
480
 
    return (false);
 
654
    return false;
481
655
  our_pred = insert_primary (pred_fprint);
482
 
  our_pred->args.stream = open_output_file (argv[*arg_ptr]);
 
656
  our_pred->args.printf_vec.segment = NULL;
 
657
  our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]);
 
658
  our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream);
 
659
  our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
483
660
  our_pred->side_effects = true;
484
661
  our_pred->no_default_print = true;
485
 
  our_pred->need_stat = false;
 
662
  our_pred->need_stat = our_pred->need_type = false;
486
663
  (*arg_ptr)++;
487
 
  return (true);
 
664
  return true;
488
665
}
489
666
 
490
667
static boolean
498
675
  our_pred->args.stream = open_output_file (argv[*arg_ptr]);
499
676
  our_pred->side_effects = true;
500
677
  our_pred->no_default_print = true;
501
 
  our_pred->need_stat = false;
 
678
  our_pred->need_stat = our_pred->need_type = false;
502
679
  (*arg_ptr)++;
503
680
  return (true);
504
681
}
552
729
static boolean
553
730
parse_help (char **argv, int *arg_ptr)
554
731
{
 
732
  (void) argv;
 
733
  (void) arg_ptr;
 
734
  
555
735
  printf (_("\
556
736
Usage: %s [path...] [expression]\n"), program_name);
557
 
  puts (_("\
 
737
  puts (_("\n\
558
738
default path is the current directory; default expression is -print\n\
559
 
expression may consist of:\n\
 
739
expression may consist of: operators, options, tests, and actions:\n"));
 
740
  puts (_("\
560
741
operators (decreasing precedence; -and is implicit where no others are given):\n\
561
 
      ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n"));
562
 
  puts (_("\
563
 
      EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
564
 
options (always true): -daystart -depth -follow --help\n\
565
 
      -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
566
 
tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n"));
567
 
  puts (_("\
 
742
      ( EXPR )   ! EXPR   -not EXPR   EXPR1 -a EXPR2   EXPR1 -and EXPR2\n\
 
743
      EXPR1 -o EXPR2   EXPR1 -or EXPR2   EXPR1 , EXPR2\n"));
 
744
  puts (_("\
 
745
positional options (always true): -daystart -follow\n\
 
746
normal options (always true, specified before other expressions):\n\
 
747
      -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
 
748
      --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
 
749
  puts (_("\
 
750
tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
568
751
      -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
569
 
      -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
570
 
      -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n"));
 
752
      -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
 
753
      -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
571
754
  puts (_("\
572
755
      -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
573
 
      -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
574
 
      -xtype [bcdpfls]\n"));
 
756
      -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
 
757
      -used N -user NAME -xtype [bcdpfls]\n"));
575
758
  puts (_("\
576
759
actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
577
 
      -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n"));
578
 
  puts (_("\nReport bugs to <bug-findutils@gnu.org>."));
 
760
      -fls FILE -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls -delete\n\
 
761
      -quit\n"));
 
762
  puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
 
763
page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
 
764
email to <bug-findutils@gnu.org>."));
579
765
  exit (0);
580
766
}
581
767
 
592
778
  return (true);
593
779
}
594
780
 
 
781
 
 
782
/* sanity check the fnmatch() function to make sure
 
783
 * it really is the GNU version. 
 
784
 */
 
785
static boolean 
 
786
fnmatch_sanitycheck(void)
 
787
{
 
788
  /* fprintf(stderr, "Performing find sanity check..."); */
 
789
  if (0 != fnmatch("foo", "foo", 0)
 
790
      || 0 == fnmatch("Foo", "foo", 0)
 
791
      || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
 
792
    {
 
793
      error (1, 0, _("sanity check of the fnmatch() library function failed."));
 
794
      /* fprintf(stderr, "FAILED\n"); */
 
795
      return false;
 
796
    }
 
797
 
 
798
  /* fprintf(stderr, "OK\n"); */
 
799
  return true;
 
800
}
 
801
 
 
802
 
 
803
static boolean 
 
804
check_name_arg(const char *pred, const char *arg)
 
805
{
 
806
  if (strchr(arg, '/'))
 
807
    {
 
808
      error(0, 0,_("warning: Unix filenames usually don't contain slashes (though pathnames do).  That means that '%s %s' will probably evaluate to false all the time on this system.  You might find the '-wholename' test more useful, or perhaps '-samefile'.  Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ %s'."),
 
809
            pred, arg, arg);
 
810
    }
 
811
  return true;                  /* allow it anyway */
 
812
}
 
813
 
 
814
 
 
815
 
595
816
static boolean
596
817
parse_iname (char **argv, int *arg_ptr)
597
818
{
599
820
 
600
821
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
601
822
    return (false);
 
823
  if (!check_name_arg("-iname", argv[*arg_ptr]))
 
824
    return false;
 
825
 
 
826
  fnmatch_sanitycheck();
 
827
  
602
828
  our_pred = insert_primary (pred_iname);
603
 
  our_pred->need_stat = false;
 
829
  our_pred->need_stat = our_pred->need_type = false;
604
830
  our_pred->args.str = argv[*arg_ptr];
605
831
  (*arg_ptr)++;
606
832
  return (true);
612
838
  return (insert_num (argv, arg_ptr, pred_inum));
613
839
}
614
840
 
 
841
/* -ipath is deprecated (at RMS's request) in favour of 
 
842
 * -iwholename.   See the node "GNU Manuals" in standards.texi
 
843
 * for the rationale for this (basically, GNU prefers the use 
 
844
 * of the phrase "file name" to "path name"
 
845
 */
615
846
static boolean
616
847
parse_ipath (char **argv, int *arg_ptr)
617
848
{
 
849
  error (0, 0,
 
850
         _("warning: the predicate -ipath is deprecated; please use -iwholename instead."));
 
851
  
 
852
  return parse_iwholename(argv, arg_ptr);
 
853
}
 
854
 
 
855
static boolean
 
856
parse_iwholename (char **argv, int *arg_ptr)
 
857
{
618
858
  struct predicate *our_pred;
619
859
 
620
860
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
621
861
    return (false);
 
862
 
 
863
  fnmatch_sanitycheck();
 
864
  
622
865
  our_pred = insert_primary (pred_ipath);
623
 
  our_pred->need_stat = false;
 
866
  our_pred->need_stat = our_pred->need_type = false;
624
867
  our_pred->args.str = argv[*arg_ptr];
625
868
  (*arg_ptr)++;
626
869
  return (true);
643
886
{
644
887
  struct predicate *our_pred;
645
888
 
 
889
  (void) argv;
 
890
  (void) arg_ptr;
 
891
  
646
892
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
647
893
    return (false);
 
894
 
 
895
  fnmatch_sanitycheck();
 
896
  
648
897
  our_pred = insert_primary (pred_lname);
649
898
  our_pred->args.str = argv[*arg_ptr];
650
899
  (*arg_ptr)++;
656
905
{
657
906
  struct predicate *our_pred;
658
907
 
 
908
  (void) &argv;
 
909
  (void) &arg_ptr;
 
910
 
659
911
  our_pred = insert_primary (pred_ls);
660
912
  our_pred->side_effects = true;
661
913
  our_pred->no_default_print = true;
668
920
  int depth_len;
669
921
 
670
922
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
671
 
    return (false);
 
923
    return false;
672
924
  depth_len = strspn (argv[*arg_ptr], "0123456789");
673
925
  if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
674
 
    return (false);
675
 
  maxdepth = atoi (argv[*arg_ptr]);
676
 
  if (maxdepth < 0)
677
 
    return (false);
 
926
    return false;
 
927
  options.maxdepth = atoi (argv[*arg_ptr]);
 
928
  if (options.maxdepth < 0)
 
929
    return false;
678
930
  (*arg_ptr)++;
679
 
  return (true);
 
931
  return true;
680
932
}
681
933
 
682
934
static boolean
685
937
  int depth_len;
686
938
 
687
939
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
688
 
    return (false);
 
940
    return false;
689
941
  depth_len = strspn (argv[*arg_ptr], "0123456789");
690
942
  if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
691
 
    return (false);
692
 
  mindepth = atoi (argv[*arg_ptr]);
693
 
  if (mindepth < 0)
694
 
    return (false);
 
943
    return false;
 
944
  options.mindepth = atoi (argv[*arg_ptr]);
 
945
  if (options.mindepth < 0)
 
946
    return false;
695
947
  (*arg_ptr)++;
696
 
  return (true);
 
948
  return true;
697
949
}
698
950
 
699
951
static boolean
708
960
    return (false);
709
961
  if (!get_num_days (argv[*arg_ptr], &num, &c_type))
710
962
    return (false);
711
 
  t = cur_day_start + DAYSECS - num * 60;
 
963
  t = options.cur_day_start + DAYSECS - num * 60;
712
964
  our_pred = insert_primary (pred_mmin);
713
965
  our_pred->args.info.kind = c_type;
714
966
  our_pred->args.info.negative = t < 0;
728
980
{
729
981
  struct predicate *our_pred;
730
982
 
 
983
  (void) argv;
 
984
  (void) arg_ptr;
 
985
  
731
986
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
732
987
    return (false);
 
988
  if (!check_name_arg("-name", argv[*arg_ptr]))
 
989
    return false;
 
990
  fnmatch_sanitycheck();
 
991
  
733
992
  our_pred = insert_primary (pred_name);
734
 
  our_pred->need_stat = false;
 
993
  our_pred->need_stat = our_pred->need_type = false;
735
994
  our_pred->args.str = argv[*arg_ptr];
736
995
  (*arg_ptr)++;
737
996
  return (true);
742
1001
{
743
1002
  struct predicate *our_pred;
744
1003
 
 
1004
  (void) &argv;
 
1005
  (void) &arg_ptr;
 
1006
 
745
1007
  our_pred = get_new_pred_chk_op ();
746
1008
  our_pred->pred_func = pred_negate;
747
1009
#ifdef  DEBUG
749
1011
#endif  /* DEBUG */
750
1012
  our_pred->p_type = UNI_OP;
751
1013
  our_pred->p_prec = NEGATE_PREC;
752
 
  our_pred->need_stat = false;
 
1014
  our_pred->need_stat = our_pred->need_type = false;
753
1015
  return (true);
754
1016
}
755
1017
 
759
1021
  struct predicate *our_pred;
760
1022
  struct stat stat_newer;
761
1023
 
 
1024
  (void) argv;
 
1025
  (void) arg_ptr;
 
1026
  
762
1027
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
763
1028
    return (false);
764
 
  if ((*xstat) (argv[*arg_ptr], &stat_newer))
 
1029
  if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
765
1030
    error (1, errno, "%s", argv[*arg_ptr]);
766
1031
  our_pred = insert_primary (pred_newer);
767
1032
  our_pred->args.time = stat_newer.st_mtime;
772
1037
static boolean
773
1038
parse_noleaf (char **argv, int *arg_ptr)
774
1039
{
775
 
  no_leaf_check = true;
 
1040
  (void) &argv;
 
1041
  (void) &arg_ptr;
 
1042
  
 
1043
  options.no_leaf_check = true;
776
1044
  return true;
777
1045
}
778
1046
 
797
1065
{
798
1066
  struct predicate *our_pred;
799
1067
 
 
1068
  (void) &argv;
 
1069
  (void) &arg_ptr;
 
1070
  
800
1071
  our_pred = insert_primary (pred_nogroup);
801
1072
#ifdef CACHE_IDS
802
1073
  if (gid_unused == NULL)
829
1100
parse_nouser (char **argv, int *arg_ptr)
830
1101
{
831
1102
  struct predicate *our_pred;
 
1103
  (void) argv;
 
1104
  (void) arg_ptr;
 
1105
  
832
1106
 
833
1107
  our_pred = insert_primary (pred_nouser);
834
1108
#ifdef CACHE_IDS
859
1133
}
860
1134
 
861
1135
static boolean
 
1136
parse_nowarn (char **argv, int *arg_ptr)
 
1137
{
 
1138
  (void) argv;
 
1139
  (void) arg_ptr;
 
1140
  
 
1141
  options.warnings = false;
 
1142
  return true;;
 
1143
}
 
1144
 
 
1145
static boolean
862
1146
parse_ok (char **argv, int *arg_ptr)
863
1147
{
864
 
  return (insert_exec_ok (pred_ok, argv, arg_ptr));
 
1148
  return (insert_exec_ok ("-ok", pred_ok, argv, arg_ptr));
 
1149
}
 
1150
 
 
1151
static boolean
 
1152
parse_okdir (char **argv, int *arg_ptr)
 
1153
{
 
1154
  return (insert_exec_ok ("-okdir", pred_okdir, argv, arg_ptr));
865
1155
}
866
1156
 
867
1157
boolean
869
1159
{
870
1160
  struct predicate *our_pred;
871
1161
 
 
1162
  (void) argv;
 
1163
  (void) arg_ptr;
 
1164
  
872
1165
  our_pred = get_new_pred_chk_op ();
873
1166
  our_pred->pred_func = pred_open;
874
1167
#ifdef  DEBUG
876
1169
#endif  /* DEBUG */
877
1170
  our_pred->p_type = OPEN_PAREN;
878
1171
  our_pred->p_prec = NO_PREC;
879
 
  our_pred->need_stat = false;
 
1172
  our_pred->need_stat = our_pred->need_type = false;
880
1173
  return (true);
881
1174
}
882
1175
 
885
1178
{
886
1179
  struct predicate *our_pred;
887
1180
 
 
1181
  (void) argv;
 
1182
  (void) arg_ptr;
 
1183
  
888
1184
  our_pred = get_new_pred ();
889
1185
  our_pred->pred_func = pred_or;
890
1186
#ifdef  DEBUG
892
1188
#endif  /* DEBUG */
893
1189
  our_pred->p_type = BI_OP;
894
1190
  our_pred->p_prec = OR_PREC;
895
 
  our_pred->need_stat = false;
 
1191
  our_pred->need_stat = our_pred->need_type = false;
896
1192
  return (true);
897
1193
}
898
1194
 
 
1195
/* -path is deprecated (at RMS's request) in favour of 
 
1196
 * -iwholename.   See the node "GNU Manuals" in standards.texi
 
1197
 * for the rationale for this (basically, GNU prefers the use 
 
1198
 * of the phrase "file name" to "path name".
 
1199
 *
 
1200
 * We do not issue a warning that this usage is deprecated
 
1201
 * since HPUX find supports this predicate also.
 
1202
 */
899
1203
static boolean
900
1204
parse_path (char **argv, int *arg_ptr)
901
1205
{
 
1206
  return parse_wholename(argv, arg_ptr);
 
1207
}
 
1208
 
 
1209
static boolean
 
1210
parse_wholename (char **argv, int *arg_ptr)
 
1211
{
902
1212
  struct predicate *our_pred;
903
1213
 
904
1214
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
905
1215
    return (false);
906
1216
  our_pred = insert_primary (pred_path);
907
 
  our_pred->need_stat = false;
 
1217
  our_pred->need_stat = our_pred->need_type = false;
908
1218
  our_pred->args.str = argv[*arg_ptr];
909
1219
  (*arg_ptr)++;
910
1220
  return (true);
915
1225
{
916
1226
  mode_t perm_val;
917
1227
  int mode_start = 0;
918
 
  struct mode_change *change;
 
1228
  enum permissions_type kind = PERM_EXACT;
 
1229
  struct mode_change *change = NULL;
919
1230
  struct predicate *our_pred;
920
1231
 
921
1232
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
924
1235
  switch (argv[*arg_ptr][0])
925
1236
    {
926
1237
    case '-':
927
 
    case '+':
928
1238
      mode_start = 1;
 
1239
      kind = PERM_AT_LEAST;
929
1240
      break;
 
1241
      
 
1242
     case '+':
 
1243
       change = mode_compile (argv[*arg_ptr]);
 
1244
       if (NULL == change)
 
1245
         {
 
1246
           /* Most likely the caller is an old script that is still
 
1247
            * using the obsolete GNU syntax '-perm +MODE'.  This old
 
1248
            * syntax was withdrawn in favor of '-perm /MODE' because
 
1249
            * it is incompatible with POSIX in some cases, but we
 
1250
            * still support uses of it that are not incompatible with
 
1251
            * POSIX.
 
1252
            */
 
1253
           mode_start = 1;
 
1254
           kind = PERM_ANY;
 
1255
         }
 
1256
       else
 
1257
         {
 
1258
           /* This is a POSIX-compatible usage */
 
1259
           mode_start = 0;
 
1260
           kind = PERM_EXACT;
 
1261
         }
 
1262
       break;
 
1263
      
 
1264
    case '/':                   /* GNU extension */
 
1265
       mode_start = 1;
 
1266
       kind = PERM_ANY;
 
1267
       break;
 
1268
       
930
1269
    default:
931
 
      /* empty */
 
1270
      /* For example, '-perm 0644', which is valid and matches 
 
1271
       * only files whose mode is exactly 0644.
 
1272
       *
 
1273
       * We do nothing here, because mode_start and kind are already
 
1274
       * correctly set.
 
1275
       */
932
1276
      break;
933
1277
    }
934
1278
 
935
 
  change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
936
 
  if (change == MODE_INVALID)
937
 
    error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
938
 
  else if (change == MODE_MEMORY_EXHAUSTED)
939
 
    error (1, 0, _("virtual memory exhausted"));
940
 
  perm_val = mode_adjust (0, change);
941
 
  mode_free (change);
942
 
 
 
1279
  if (NULL == change)
 
1280
    {
 
1281
      change = mode_compile (argv[*arg_ptr] + mode_start);
 
1282
      if (NULL == change)
 
1283
        error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]);
 
1284
    }
 
1285
  perm_val = mode_adjust (0, change, 0);
 
1286
  free (change);
 
1287
  
943
1288
  our_pred = insert_primary (pred_perm);
944
1289
 
945
1290
  switch (argv[*arg_ptr][0])
964
1309
{
965
1310
  struct predicate *our_pred;
966
1311
 
 
1312
  (void) argv;
 
1313
  (void) arg_ptr;
 
1314
  
967
1315
  our_pred = insert_primary (pred_print);
968
1316
  /* -print has the side effect of printing.  This prevents us
969
1317
     from doing undesired multiple printing when the user has
970
1318
     already specified -print. */
971
1319
  our_pred->side_effects = true;
972
1320
  our_pred->no_default_print = true;
973
 
  our_pred->need_stat = false;
 
1321
  our_pred->need_stat = our_pred->need_type = false;
 
1322
  our_pred->args.printf_vec.segment = NULL;
 
1323
  our_pred->args.printf_vec.stream = stdout;
 
1324
  our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout);
 
1325
  our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
 
1326
  
974
1327
  return (true);
975
1328
}
976
1329
 
979
1332
{
980
1333
  struct predicate *our_pred;
981
1334
 
 
1335
  (void) argv;
 
1336
  (void) arg_ptr;
 
1337
  
982
1338
  our_pred = insert_primary (pred_print0);
983
1339
  /* -print0 has the side effect of printing.  This prevents us
984
1340
     from doing undesired multiple printing when the user has
985
1341
     already specified -print0. */
986
1342
  our_pred->side_effects = true;
987
1343
  our_pred->no_default_print = true;
988
 
  our_pred->need_stat = false;
 
1344
  our_pred->need_stat = our_pred->need_type = false;
989
1345
  return (true);
990
1346
}
991
1347
 
1002
1358
{
1003
1359
  struct predicate *our_pred;
1004
1360
 
 
1361
  (void) argv;
 
1362
  (void) arg_ptr;
 
1363
  
1005
1364
  our_pred = insert_primary (pred_prune);
1006
 
  our_pred->need_stat = false;
 
1365
  our_pred->need_stat = our_pred->need_type = false;
1007
1366
  /* -prune has a side effect that it does not descend into
1008
1367
     the current directory. */
1009
1368
  our_pred->side_effects = true;
1010
1369
  return (true);
1011
1370
}
1012
1371
 
 
1372
static boolean 
 
1373
parse_quit  (char **argv, int *arg_ptr)
 
1374
{
 
1375
  struct predicate *our_pred = insert_primary (pred_quit);
 
1376
  (void) argv;
 
1377
  (void) arg_ptr;
 
1378
  our_pred->need_stat = our_pred->need_type = false;
 
1379
  return true;
 
1380
}
 
1381
 
 
1382
 
1013
1383
static boolean
1014
1384
parse_regex (char **argv, int *arg_ptr)
1015
1385
{
1022
1392
  struct predicate *our_pred;
1023
1393
  struct re_pattern_buffer *re;
1024
1394
  const char *error_message;
 
1395
  int opt = RE_SYNTAX_POSIX_BASIC;
1025
1396
 
1026
1397
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
1027
1398
    return (false);
1028
1399
  our_pred = insert_primary (pred_regex);
1029
 
  our_pred->need_stat = false;
 
1400
  our_pred->need_stat = our_pred->need_type = false;
1030
1401
  re = (struct re_pattern_buffer *)
1031
1402
    xmalloc (sizeof (struct re_pattern_buffer));
1032
1403
  our_pred->args.regex = re;
1035
1406
  re->fastmap = NULL;
1036
1407
 
1037
1408
  if (ignore_case)
1038
 
    {
1039
 
      unsigned i;
1040
 
      
1041
 
      re->translate = xmalloc (256);
1042
 
      /* Map uppercase characters to corresponding lowercase ones.  */
1043
 
      for (i = 0; i < 256; i++)
1044
 
        re->translate[i] = ISUPPER (i) ? tolower (i) : i;
1045
 
    }
1046
 
  else
1047
 
    re->translate = NULL;
1048
 
 
 
1409
    opt |= RE_ICASE;
 
1410
 
 
1411
  re_set_syntax(opt);
 
1412
  re->syntax = opt;
 
1413
  re->translate = NULL;
 
1414
  
1049
1415
  error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
1050
1416
                                      re);
1051
1417
  if (error_message)
1085
1451
      argv[*arg_ptr][len - 1] = '\0';
1086
1452
      break;
1087
1453
 
 
1454
    case 'M':                   /* Megabytes */
 
1455
      blksize = 1024*1024;
 
1456
      argv[*arg_ptr][len - 1] = '\0';
 
1457
      break;
 
1458
 
 
1459
    case 'G':                   /* Gigabytes */
 
1460
      blksize = 1024*1024*1024;
 
1461
      argv[*arg_ptr][len - 1] = '\0';
 
1462
      break;
 
1463
 
1088
1464
    case 'w':
1089
1465
      blksize = 2;
1090
1466
      argv[*arg_ptr][len - 1] = '\0';
1115
1491
  return (true);
1116
1492
}
1117
1493
 
 
1494
 
 
1495
static boolean
 
1496
parse_samefile (char **argv, int *arg_ptr)
 
1497
{
 
1498
  struct predicate *our_pred;
 
1499
  struct stat st;
 
1500
  
 
1501
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
 
1502
    return (false);
 
1503
  if ((*options.xstat) (argv[*arg_ptr], &st))
 
1504
    error (1, errno, "%s", argv[*arg_ptr]);
 
1505
  
 
1506
  our_pred = insert_primary (pred_samefile);
 
1507
  our_pred->args.fileid.ino = st.st_ino;
 
1508
  our_pred->args.fileid.dev = st.st_dev;
 
1509
  our_pred->need_type = false;
 
1510
  our_pred->need_stat = true;
 
1511
  (*arg_ptr)++;
 
1512
  return (true);
 
1513
}
 
1514
 
 
1515
 
1118
1516
static boolean
1119
1517
parse_true (char **argv, int *arg_ptr)
1120
1518
{
1121
1519
  struct predicate *our_pred;
1122
1520
 
 
1521
  (void) argv;
 
1522
  (void) arg_ptr;
 
1523
  
1123
1524
  our_pred = insert_primary (pred_true);
1124
 
  our_pred->need_stat = false;
 
1525
  our_pred->need_stat = our_pred->need_type = false;
1125
1526
  return (true);
1126
1527
}
1127
1528
 
1189
1590
parse_version (char **argv, int *arg_ptr)
1190
1591
{
1191
1592
  extern char *version_string;
1192
 
 
 
1593
  int features = 0;
 
1594
  
 
1595
  (void) argv;
 
1596
  (void) arg_ptr;
 
1597
  
1193
1598
  fflush (stderr);
1194
1599
  printf (_("GNU find version %s\n"), version_string);
 
1600
  printf (_("Features enabled: "));
 
1601
  
 
1602
#if CACHE_IDS
 
1603
  printf("CACHE_IDS ");
 
1604
  ++features;
 
1605
#endif
 
1606
#if DEBUG
 
1607
  printf("DEBUG ");
 
1608
  ++features;
 
1609
#endif
 
1610
#if DEBUG_STAT
 
1611
  printf("DEBUG_STAT ");
 
1612
  ++features;
 
1613
#endif
 
1614
#if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE)
 
1615
  printf("D_TYPE ");
 
1616
  ++features;
 
1617
#endif
 
1618
#if defined(O_NOFOLLOW)
 
1619
  printf("O_NOFOLLOW(%s) ",
 
1620
         (options.open_nofollow_available ? "enabled" : "disabled"));
 
1621
  ++features;
 
1622
#endif
 
1623
  
 
1624
  if (0 == features)
 
1625
    {
 
1626
      /* For the moment, leave this as English in case someone wants
 
1627
         to parse these strings. */
 
1628
      printf("none");
 
1629
    }
 
1630
  printf("\n");
 
1631
  
1195
1632
  exit (0);
1196
1633
}
1197
1634
 
1198
1635
static boolean
1199
1636
parse_xdev (char **argv, int *arg_ptr)
1200
1637
{
1201
 
  stay_on_filesystem = true;
 
1638
  (void) argv;
 
1639
  (void) arg_ptr;
 
1640
  options.stay_on_filesystem = true;
 
1641
  return true;
 
1642
}
 
1643
 
 
1644
static boolean
 
1645
parse_ignore_race (char **argv, int *arg_ptr)
 
1646
{
 
1647
  (void) argv;
 
1648
  (void) arg_ptr;
 
1649
  options.ignore_readdir_race = true;
 
1650
  return true;
 
1651
}
 
1652
 
 
1653
static boolean
 
1654
parse_noignore_race (char **argv, int *arg_ptr)
 
1655
{
 
1656
  (void) argv;
 
1657
  (void) arg_ptr;
 
1658
  options.ignore_readdir_race = false;
 
1659
  return true;
 
1660
}
 
1661
 
 
1662
static boolean
 
1663
parse_warn (char **argv, int *arg_ptr)
 
1664
{
 
1665
  (void) argv;
 
1666
  (void) arg_ptr;
 
1667
  options.warnings = true;
1202
1668
  return true;
1203
1669
}
1204
1670
 
1205
1671
static boolean
1206
1672
parse_xtype (char **argv, int *arg_ptr)
1207
1673
{
 
1674
  (void) argv;
 
1675
  (void) arg_ptr;
1208
1676
  return insert_type (argv, arg_ptr, pred_xtype);
1209
1677
}
1210
1678
 
1211
1679
static boolean
1212
 
insert_type (char **argv, int *arg_ptr, boolean (*which_pred) (/* ??? */))
 
1680
insert_type (char **argv, int *arg_ptr, PRED_FUNC which_pred)
1213
1681
{
1214
1682
  mode_t type_cell;
1215
1683
  struct predicate *our_pred;
1255
1723
      return (false);
1256
1724
    }
1257
1725
  our_pred = insert_primary (which_pred);
 
1726
 
 
1727
  /* Figure out if we will need to stat the file, because if we don't
 
1728
   * need to follow symlinks, we can avoid a stat call by using 
 
1729
   * struct dirent.d_type.
 
1730
   */
 
1731
  if (which_pred == pred_xtype)
 
1732
    {
 
1733
      our_pred->need_stat = true;
 
1734
      our_pred->need_type = false;
 
1735
    }
 
1736
  else
 
1737
    {
 
1738
      our_pred->need_stat = false; /* struct dirent is enough */
 
1739
      our_pred->need_type = true;
 
1740
    }
1258
1741
  our_pred->args.type = type_cell;
1259
1742
  (*arg_ptr)++;                 /* Move on to next argument. */
1260
1743
  return (true);
1261
1744
}
1262
1745
 
 
1746
 
 
1747
/* Return true if the file accessed via FP is a terminal.
 
1748
 */
 
1749
static boolean 
 
1750
stream_is_tty(FILE *fp)
 
1751
{
 
1752
  int fd = fileno(fp);
 
1753
  if (-1 == fd)
 
1754
    {
 
1755
      return false; /* not a valid stream */
 
1756
    }
 
1757
  else
 
1758
    {
 
1759
      return isatty(fd) ? true : false;
 
1760
    }
 
1761
  
 
1762
}
 
1763
 
 
1764
 
 
1765
 
1263
1766
/* If true, we've determined that the current fprintf predicate
1264
1767
   uses stat information. */
1265
1768
static boolean fprintf_stat_needed;
1266
1769
 
1267
1770
static boolean
1268
 
insert_fprintf (FILE *fp, boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
 
1771
insert_fprintf (FILE *fp, PRED_FUNC func, char **argv, int *arg_ptr)
1269
1772
{
1270
1773
  char *format;                 /* Beginning of unprocessed format string. */
1271
1774
  register char *scan;          /* Current address in scanning `format'. */
1280
1783
  our_pred->side_effects = true;
1281
1784
  our_pred->no_default_print = true;
1282
1785
  our_pred->args.printf_vec.stream = fp;
 
1786
  our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp);
 
1787
  our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
1283
1788
  segmentp = &our_pred->args.printf_vec.segment;
1284
1789
  *segmentp = NULL;
1285
1790
 
1360
1865
          if (*scan2 == '.')
1361
1866
            for (scan2++; ISDIGIT (*scan2); scan2++)
1362
1867
              /* Do nothing. */ ;
1363
 
          if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
 
1868
          if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2))
1364
1869
            {
1365
1870
              segmentp = make_segment (segmentp, format, scan2 - format,
1366
1871
                                       (int) *scan2);
1390
1895
 
1391
1896
  if (scan > format)
1392
1897
    make_segment (segmentp, format, scan - format, KIND_PLAIN);
 
1898
  our_pred->need_type = false;
1393
1899
  our_pred->need_stat = fprintf_stat_needed;
1394
1900
  return (true);
1395
1901
}
1421
1927
 
1422
1928
    case 'a':                   /* atime in `ctime' format */
1423
1929
    case 'A':                   /* atime in user-specified strftime format */
1424
 
    case 'b':                   /* size in 512-byte blocks */
1425
1930
    case 'c':                   /* ctime in `ctime' format */
1426
1931
    case 'C':                   /* ctime in user-specified strftime format */
1427
1932
    case 'F':                   /* filesystem type */
1428
 
    case 'G':                   /* GID number */
1429
1933
    case 'g':                   /* group name */
1430
1934
    case 'i':                   /* inode number */
1431
 
    case 'k':                   /* size in 1K blocks */
1432
1935
    case 'l':                   /* object of symlink */
1433
 
    case 'n':                   /* number of links */
 
1936
    case 'M':                   /* mode in `ls -l' format (eg., "drwxr-xr-x") */
1434
1937
    case 's':                   /* size in bytes */
1435
1938
    case 't':                   /* mtime in `ctime' format */
1436
1939
    case 'T':                   /* mtime in user-specified strftime format */
1437
 
    case 'U':                   /* UID number */
1438
1940
    case 'u':                   /* user name */
 
1941
    case 'y':                   /* file type */
 
1942
    case 'Y':                   /* symlink pointed file type */
1439
1943
      fprintf_stat_needed = true;
1440
1944
      /* FALLTHROUGH */
1441
1945
    case 'f':                   /* basename of path */
1446
1950
      *fmt++ = 's';
1447
1951
      break;
1448
1952
 
 
1953
      /* Numeric items that one might expect to honour 
 
1954
       * #, 0, + flags but which do not.
 
1955
       */
 
1956
    case 'G':                   /* GID number */
 
1957
    case 'U':                   /* UID number */
 
1958
    case 'b':                   /* size in 512-byte blocks */
 
1959
    case 'D':                   /* Filesystem device on which the file exits */
 
1960
    case 'k':                   /* size in 1K blocks */
 
1961
    case 'n':                   /* number of links */
 
1962
      fprintf_stat_needed = true;
 
1963
      *fmt++ = 's';
 
1964
      break;
 
1965
      
 
1966
      /* Numeric items that DO honour #, 0, + flags.
 
1967
       */
1449
1968
    case 'd':                   /* depth in search tree (0 = ARGV element) */
1450
1969
      *fmt++ = 'd';
1451
1970
      break;
1459
1978
 
1460
1979
  return (&(*segment)->next);
1461
1980
}
1462
 
 
1463
 
/* handles both exec and ok predicate */
1464
 
static boolean
1465
 
insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
 
1981
 
 
1982
static void 
 
1983
check_path_safety(const char *action)
 
1984
{
 
1985
  const char *path = getenv("PATH");
 
1986
  char *s;
 
1987
  s = next_element(path, 1);
 
1988
  while ((s = next_element ((char *) NULL, 1)) != NULL)
 
1989
    {
 
1990
      if (0 == strcmp(s, "."))
 
1991
        {
 
1992
          error(1, 0, _("The current directory is included in the PATH environment variable, which is insecure in combination with the %s action of find.  Please remove the current directory from your $PATH (that is, remove \".\" or leading or trailing colons)"),
 
1993
                action);
 
1994
        }
 
1995
    }
 
1996
}
 
1997
 
 
1998
 
 
1999
/* handles both exec and ok predicate */
 
2000
#if defined(NEW_EXEC)
 
2001
/* handles both exec and ok predicate */
 
2002
static boolean
 
2003
new_insert_exec_ok (const char *action,
 
2004
                    PRED_FUNC func,
 
2005
                    char **argv,
 
2006
                    int *arg_ptr)
 
2007
{
 
2008
  int start, end;               /* Indexes in ARGV of start & end of cmd. */
 
2009
  int i;                        /* Index into cmd args */
 
2010
  int saw_braces;               /* True if previous arg was '{}'. */
 
2011
  boolean allow_plus;           /* True if + is a valid terminator */
 
2012
  int brace_count;              /* Number of instances of {}. */
 
2013
  
 
2014
  struct predicate *our_pred;
 
2015
  struct exec_val *execp;       /* Pointer for efficiency. */
 
2016
 
 
2017
  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
 
2018
    return (false);
 
2019
 
 
2020
  our_pred = insert_primary (func);
 
2021
  our_pred->side_effects = true;
 
2022
  our_pred->no_default_print = true;
 
2023
  execp = &our_pred->args.exec_vec;
 
2024
 
 
2025
  if ((func != pred_okdir) && (func != pred_ok))
 
2026
    allow_plus = true;
 
2027
  else
 
2028
    allow_plus = false;
 
2029
  
 
2030
  if ((func == pred_execdir) || (func == pred_okdir))
 
2031
    {
 
2032
      options.ignore_readdir_race = false;
 
2033
      check_path_safety(action);
 
2034
      execp->use_current_dir = true;
 
2035
    }
 
2036
  else
 
2037
    {
 
2038
      execp->use_current_dir = false;
 
2039
    }
 
2040
  
 
2041
  our_pred->args.exec_vec.multiple = 0;
 
2042
 
 
2043
  /* Count the number of args with path replacements, up until the ';'. 
 
2044
   * Also figure out if the command is terminated by ";" or by "+".
 
2045
   */
 
2046
  start = *arg_ptr;
 
2047
  for (end = start, saw_braces=0, brace_count=0;
 
2048
       (argv[end] != NULL)
 
2049
       && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
 
2050
       end++)
 
2051
    {
 
2052
      /* For -exec and -execdir, "{} +" can terminate the command. */
 
2053
      if ( allow_plus
 
2054
           && argv[end][0] == '+' && argv[end][1] == 0
 
2055
           && saw_braces)
 
2056
        {
 
2057
          our_pred->args.exec_vec.multiple = 1;
 
2058
          break;
 
2059
        }
 
2060
      
 
2061
      saw_braces = 0;
 
2062
      if (strstr (argv[end], "{}"))
 
2063
        {
 
2064
          saw_braces = 1;
 
2065
          ++brace_count;
 
2066
          
 
2067
          if (0 == end && (func == pred_execdir || func == pred_okdir))
 
2068
            {
 
2069
              /* The POSIX standard says that {} replacement should
 
2070
               * occur even in the utility name.  This is insecure
 
2071
               * since it means we will be executing a command whose
 
2072
               * name is chosen according to whatever find finds in
 
2073
               * the filesystem.  That can be influenced by an
 
2074
               * attacker.  Hence for -execdir and -okdir this is not
 
2075
               * allowed.  We can specify this as those options are 
 
2076
               * not defined by POSIX.
 
2077
               */
 
2078
              error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem."));
 
2079
            }
 
2080
        }
 
2081
    }
 
2082
  
 
2083
  /* Fail if no command given or no semicolon found. */
 
2084
  if ((end == start) || (argv[end] == NULL))
 
2085
    {
 
2086
      *arg_ptr = end;
 
2087
      free(our_pred);
 
2088
      return false;
 
2089
    }
 
2090
 
 
2091
  if (our_pred->args.exec_vec.multiple && brace_count > 1)
 
2092
    {
 
2093
        
 
2094
      const char *suffix;
 
2095
      if (func == pred_execdir)
 
2096
        suffix = "dir";
 
2097
      else
 
2098
        suffix = "";
 
2099
 
 
2100
      error(1, 0,
 
2101
            _("Only one instance of {} is supported with -exec%s ... +"),
 
2102
            suffix);
 
2103
    }
 
2104
 
 
2105
  /* execp->ctl   = xmalloc(sizeof struct buildcmd_control); */
 
2106
  bc_init_controlinfo(&execp->ctl);
 
2107
  execp->ctl.exec_callback = launch;
 
2108
 
 
2109
  if (our_pred->args.exec_vec.multiple)
 
2110
    {
 
2111
      /* "+" terminator, so we can just append our arguments after the
 
2112
       * command and initial arguments.
 
2113
       */
 
2114
      execp->replace_vec = NULL;
 
2115
      execp->ctl.replace_pat = NULL;
 
2116
      execp->ctl.rplen = 0;
 
2117
      execp->ctl.lines_per_exec = 0; /* no limit */
 
2118
      execp->ctl.args_per_exec = 0; /* no limit */
 
2119
      
 
2120
      /* remember how many arguments there are */
 
2121
      execp->ctl.initial_argc = (end-start) - 1;
 
2122
 
 
2123
      /* execp->state = xmalloc(sizeof struct buildcmd_state); */
 
2124
      bc_init_state(&execp->ctl, &execp->state, execp);
 
2125
  
 
2126
      /* Gather the initial arguments.  Skip the {}. */
 
2127
      for (i=start; i<end-1; ++i)
 
2128
        {
 
2129
          bc_push_arg(&execp->ctl, &execp->state,
 
2130
                      argv[i], strlen(argv[i])+1,
 
2131
                      NULL, 0,
 
2132
                      1);
 
2133
        }
 
2134
    }
 
2135
  else
 
2136
    {
 
2137
      /* Semicolon terminator - more than one {} is supported, so we
 
2138
       * have to do brace-replacement.
 
2139
       */
 
2140
      execp->num_args = end - start;
 
2141
      
 
2142
      execp->ctl.replace_pat = "{}";
 
2143
      execp->ctl.rplen = strlen(execp->ctl.replace_pat);
 
2144
      execp->ctl.lines_per_exec = 0; /* no limit */
 
2145
      execp->ctl.args_per_exec = 0; /* no limit */
 
2146
      execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
 
2147
 
 
2148
 
 
2149
      /* execp->state = xmalloc(sizeof(*(execp->state))); */
 
2150
      bc_init_state(&execp->ctl, &execp->state, execp);
 
2151
 
 
2152
      /* Remember the (pre-replacement) arguments for later. */
 
2153
      for (i=0; i<execp->num_args; ++i)
 
2154
        {
 
2155
          execp->replace_vec[i] = argv[i+start];
 
2156
        }
 
2157
    }
 
2158
  
 
2159
  if (argv[end] == NULL)
 
2160
    *arg_ptr = end;
 
2161
  else
 
2162
    *arg_ptr = end + 1;
 
2163
  
 
2164
  return true;
 
2165
}
 
2166
#else
 
2167
/* handles both exec and ok predicate */
 
2168
static boolean
 
2169
old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr)
1466
2170
{
1467
2171
  int start, end;               /* Indexes in ARGV of start & end of cmd. */
1468
2172
  int num_paths;                /* Number of args with path replacements. */
1493
2197
  our_pred->side_effects = true;
1494
2198
  our_pred->no_default_print = true;
1495
2199
  execp = &our_pred->args.exec_vec;
 
2200
  execp->usercontext = our_pred;
 
2201
  execp->use_current_dir = false;
1496
2202
  execp->paths =
1497
2203
    (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
1498
2204
  execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
1528
2234
    *arg_ptr = end + 1;
1529
2235
  return (true);
1530
2236
}
 
2237
#endif
 
2238
 
 
2239
 
 
2240
 
 
2241
static boolean
 
2242
insert_exec_ok (const char *action, PRED_FUNC func, char **argv, int *arg_ptr)
 
2243
{
 
2244
#if defined(NEW_EXEC)
 
2245
  return new_insert_exec_ok(action, func, argv, arg_ptr);
 
2246
#else
 
2247
  return old_insert_exec_ok(func, argv, arg_ptr);
 
2248
#endif
 
2249
}
 
2250
 
 
2251
 
1531
2252
 
1532
2253
/* Get a number of days and comparison type.
1533
2254
   STR is the ASCII representation.
1568
2289
   Used by -atime, -ctime, and -mtime parsers. */
1569
2290
 
1570
2291
static boolean
1571
 
insert_time (char **argv, int *arg_ptr, PFB pred)
 
2292
insert_time (char **argv, int *arg_ptr, PRED_FUNC pred)
1572
2293
{
1573
2294
  struct predicate *our_pred;
1574
2295
  uintmax_t num_days;
1579
2300
    return (false);
1580
2301
  if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
1581
2302
    return (false);
1582
 
  t = (cur_day_start - num_days * DAYSECS
1583
 
       + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
 
2303
 
 
2304
  /* Figure out the timestamp value we are looking for. */
 
2305
  t = ( options.cur_day_start - num_days * DAYSECS
 
2306
                   + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
 
2307
 
 
2308
  if (1)
 
2309
    {
 
2310
      /* We introduce a scope in which 'val' can be declared, for the 
 
2311
       * benefit of compilers that are really C89 compilers
 
2312
       * which support intmax_t because config.h #defines it
 
2313
       */
 
2314
      intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS
 
2315
                       + ((c_type == COMP_GT) ? DAYSECS - 1 : 0));
 
2316
      t = val;
 
2317
      
 
2318
      /* Check for possibility of an overflow */
 
2319
      if ( (intmax_t)t != val ) 
 
2320
        {
 
2321
          error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]);
 
2322
        }
 
2323
    }
 
2324
  
1584
2325
  our_pred = insert_primary (pred);
1585
2326
  our_pred->args.info.kind = c_type;
1586
2327
  our_pred->args.info.negative = t < 0;
1587
2328
  our_pred->args.info.l_val = t;
1588
2329
  (*arg_ptr)++;
1589
2330
#ifdef  DEBUG
1590
 
  printf (_("inserting %s\n"), our_pred->p_name);
1591
 
  printf (_("    type: %s    %s  "),
 
2331
  fprintf (stderr, "inserting %s\n", our_pred->p_name);
 
2332
  fprintf (stderr, "    type: %s    %s  ",
1592
2333
          (c_type == COMP_GT) ? "gt" :
1593
2334
          ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1594
2335
          (c_type == COMP_GT) ? " >" :
1595
2336
          ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
1596
2337
  t = our_pred->args.info.l_val;
1597
 
  printf ("%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
 
2338
  fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1598
2339
  if (c_type == COMP_EQ)
1599
2340
    {
1600
2341
      t = our_pred->args.info.l_val += DAYSECS;
1601
 
      printf ("                 <  %ju %s",
 
2342
      fprintf (stderr, "                 <  %ju %s",
1602
2343
              (uintmax_t) our_pred->args.info.l_val, ctime (&t));
1603
2344
      our_pred->args.info.l_val -= DAYSECS;
1604
2345
    }
1619
2360
static boolean
1620
2361
get_num (char *str, uintmax_t *num, enum comparison_type *comp_type)
1621
2362
{
1622
 
  int len_num;                  /* Length of field. */
1623
 
 
1624
2363
  if (str == NULL)
1625
2364
    return (false);
1626
2365
  switch (str[0])
1654
2393
   Used by -inum and -links parsers. */
1655
2394
 
1656
2395
static boolean
1657
 
insert_num (char **argv, int *arg_ptr, PFB pred)
 
2396
insert_num (char **argv, int *arg_ptr, PRED_FUNC pred)
1658
2397
{
1659
2398
  struct predicate *our_pred;
1660
2399
  uintmax_t num;
1669
2408
  our_pred->args.info.l_val = num;
1670
2409
  (*arg_ptr)++;
1671
2410
#ifdef  DEBUG
1672
 
  printf (_("inserting %s\n"), our_pred->p_name);
1673
 
  printf (_("    type: %s    %s  "),
 
2411
  fprintf (stderr, "inserting %s\n", our_pred->p_name);
 
2412
  fprintf (stderr, "    type: %s    %s  ",
1674
2413
          (c_type == COMP_GT) ? "gt" :
1675
2414
          ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
1676
2415
          (c_type == COMP_GT) ? " >" :
1677
2416
          ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
1678
 
  printf ("%ju\n", our_pred->args.info.l_val);
 
2417
  fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
1679
2418
#endif  /* DEBUG */
1680
2419
  return (true);
1681
2420
}