trivial pathname changes
[unix-history] / usr / src / usr.bin / find / function.c
CommitLineData
45fc66f9
KB
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Cimarron D. Taylor of the University of California, Berkeley.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#ifndef lint
1292488d 12static char sccsid[] = "@(#)function.c 5.5 (Berkeley) %G%";
45fc66f9
KB
13#endif /* not lint */
14
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/wait.h>
18#include <sys/mount.h>
19#include <grp.h>
20#include <pwd.h>
21#include <fts.h>
22#include <unistd.h>
23#include <tzfile.h>
24#include <stdio.h>
38dde0cd 25#include <string.h>
45fc66f9
KB
26#include "find.h"
27
28#define FIND_EQUAL 0
29#define FIND_LESSTHAN 1
30#define FIND_GREATER 2
31
45fc66f9
KB
32#define COMPARE(a, b) { \
33 switch(plan->flags) { \
34 case FIND_EQUAL: \
35 return(a == b); \
36 case FIND_LESSTHAN: \
37 return(a < b); \
38 case FIND_GREATER: \
39 return(a > b); \
40 } \
f2037504 41 return(0); \
45fc66f9
KB
42}
43
44#define NEW(t, f) { \
45 new = (PLAN *)emalloc(sizeof(PLAN)); \
46 new->type = t; \
47 new->eval = f; \
48 new->flags = 0; \
49 new->next = NULL; \
50}
51
52/*
53 * find_parsenum --
54 * Parse a string of the form [+-]# and return the value.
55 */
56long
57find_parsenum(plan, option, str, endch)
58 PLAN *plan;
59 char *option, *str, *endch;
60{
61 long value;
62 char *endchar; /* pointer to character ending conversion */
63
64 /* determine comparison from leading + or - */
65 switch(*str) {
66 case '+':
67 ++str;
68 plan->flags = FIND_GREATER;
69 break;
70 case '-':
71 ++str;
72 plan->flags = FIND_LESSTHAN;
73 break;
74 default:
75 plan->flags = FIND_EQUAL;
76 break;
77 }
78
79 /*
80 * convert the string with strtol(). Note, if strtol() returns zero
81 * and endchar points to the beginning of the string we know we have
82 * a syntax error.
83 */
84 value = strtol(str, &endchar, 10);
85 if (!value && endchar == str ||
86 endchar[0] && (!endch || endchar[0] != *endch))
87 bad_arg(option, "illegal numeric value");
88 if (endch)
89 *endch = endchar[0];
90 return(value);
91}
92
93/*
94 * -atime n functions --
95 *
96 * True if the difference between the file access time and the
97 * current time is n 24 hour periods.
98 *
99 */
100f_atime(plan, entry)
101 PLAN *plan;
102 FTSENT *entry;
103{
104 extern time_t now;
105
f2037504
KB
106 COMPARE((now - entry->fts_statb.st_atime +
107 SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
45fc66f9
KB
108}
109
110PLAN *
111c_atime(arg)
112 char *arg;
113{
114 PLAN *new;
115
116 ftsoptions &= ~FTS_NOSTAT;
117
118 NEW(T_ATIME, f_atime);
119 new->t_data = find_parsenum(new, "-atime", arg, (char *)NULL);
120 return(new);
121}
122/*
123 * -ctime n functions --
124 *
125 * True if the difference between the last change of file
126 * status information and the current time is n 24 hour periods.
127 */
128f_ctime(plan, entry)
129 PLAN *plan;
130 FTSENT *entry;
131{
132 extern time_t now;
133
f2037504
KB
134 COMPARE((now - entry->fts_statb.st_ctime +
135 SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
45fc66f9
KB
136}
137
138PLAN *
139c_ctime(arg)
140 char *arg;
141{
142 PLAN *new;
143
144 ftsoptions &= ~FTS_NOSTAT;
145
146 NEW(T_CTIME, f_ctime);
147 new->t_data = find_parsenum(new, "-ctime", arg, (char *)NULL);
148 return(new);
149}
150
151/*
152 * -depth functions --
153 *
154 * Always true, causes descent of the directory hierarchy to be done
155 * so that all entries in a directory are acted on before the directory
156 * itself.
157 */
158/* ARGSUSED */
159f_always_true(plan, entry)
160 PLAN *plan;
161 FTSENT *entry;
162{
f2037504 163 return(1);
45fc66f9
KB
164}
165
166PLAN *
167c_depth()
168{
169 extern int depth;
170 PLAN *new;
171
172 depth = 1;
173
174 NEW(T_DEPTH, f_always_true);
175 return(new);
176}
177
178/*
179 * [-exec | -ok] utility [arg ... ] ; functions --
180 *
181 * True if the executed utility returns a zero value as exit status.
182 * The end of the primary expression is delimited by a semicolon. If
183 * "{}" occurs anywhere, it gets replaced by the current pathname.
184 * The current directory for the execution of utility is the same as
185 * the current directory when the find utility was started.
186 *
187 * The primary -ok is different in that it requests affirmation of the
188 * user before executing the utility.
189 */
190f_exec(plan, entry)
191 register PLAN *plan;
192 FTSENT *entry;
193{
194 register int cnt;
195 char *find_subst();
196 union wait pstat;
197 pid_t pid, waitpid();
198
199 for (cnt = 0; plan->e_argv[cnt]; ++cnt)
200 if (plan->e_len[cnt])
201 find_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
f2037504 202 entry->fts_path, plan->e_len[cnt]);
45fc66f9
KB
203
204 if (plan->flags && !find_queryuser(plan->e_argv))
f2037504 205 return(0);
45fc66f9
KB
206
207 switch(pid = vfork()) {
208 case -1:
209 (void)fprintf(stderr, "find: fork: %s.\n", strerror(errno));
210 exit(1);
211 /* NOTREACHED */
212 case 0:
213 execvp(plan->e_argv[0], plan->e_argv);
214 (void)fprintf(stderr,
215 "find: %s: %s.\n", plan->e_argv[0], strerror(errno));
216 exit(1);
217 /* NOTREACHED */
218 }
219 pid = waitpid(pid, &pstat, 0);
f2037504 220 return(pid != -1 && !pstat.w_status);
45fc66f9
KB
221}
222
223/*
224 * c_exec --
225 * build three parallel arrays, one with pointers to the strings passed
226 * on the command line, one with (possibly duplicated) pointers to the
227 * argv array, and one with integer values that are lengths of the
228 * strings, but also flags meaning that the string has to be massaged.
229 */
230PLAN *
231c_exec(argvp, isok)
232 char ***argvp;
233 int isok;
234{
235 PLAN *new; /* node returned */
236 register int cnt;
237 register char **argv, **ap, *p;
238
239 ftsoptions |= FTS_NOCHDIR;
240 output_specified = 1;
241
242 NEW(T_EXEC, f_exec);
243 new->flags = isok;
244
245 for (ap = argv = *argvp;; ++ap) {
246 if (!*ap)
247 bad_arg(isok ? "-ok" : "-exec", "no terminating \";\"");
248 if (**ap == ';')
249 break;
250 }
251
252 cnt = ap - *argvp + 1;
253 new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
254 new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
255 new->e_len = (int *)emalloc((u_int)cnt * sizeof(u_char));
256
257 for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
258 new->e_orig[cnt] = *argv;
259 for (p = *argv; *p; ++p)
260 if (p[0] == '{' && p[1] == '}') {
261 new->e_argv[cnt] = emalloc((u_int)1024);
262 new->e_len[cnt] = 1024;
263 break;
264 }
265 if (!*p) {
266 new->e_argv[cnt] = *argv;
267 new->e_len[cnt] = 0;
268 }
269 }
270 new->e_argv[cnt] = new->e_orig[cnt] = NULL;
271
272 *argvp = argv + 1;
273 return(new);
274}
275
276/*
277 * -follow functions --
278 *
279 * Always true, causes symbolic links to be followed on a global
280 * basis.
281 */
282PLAN *
283c_follow()
284{
285 PLAN *new;
286
287 ftsoptions &= ~FTS_PHYSICAL;
288 ftsoptions |= FTS_LOGICAL;
289
290 NEW(T_FOLLOW, f_always_true);
291 return(new);
292}
293
294/*
295 * -fstype functions --
296 *
297 * True if the file is of a certain type.
298 */
299f_fstype(plan, entry)
300 PLAN *plan;
301 FTSENT *entry;
302{
1292488d
KB
303 static dev_t curdev; /* need a guaranteed illegal dev value */
304 static int first = 1;
45fc66f9 305 struct statfs sb;
f2037504 306 static short val;
45fc66f9
KB
307
308 /* only check when we cross mount point */
1292488d 309 if (first || curdev != entry->fts_statb.st_dev) {
f2037504 310 if (statfs(entry->fts_accpath, &sb)) {
45fc66f9 311 (void)fprintf(stderr, "find: %s: %s.\n",
f2037504 312 entry->fts_accpath, strerror(errno));
45fc66f9
KB
313 exit(1);
314 }
1292488d 315 first = 0;
f2037504 316 val = plan->flags == MOUNT_NONE ? sb.f_flags : sb.f_type;
45fc66f9 317 }
f2037504
KB
318 return(plan->flags == MOUNT_NONE ?
319 val & MNT_LOCAL : val == plan->flags);
45fc66f9
KB
320}
321
322PLAN *
323c_fstype(arg)
324 char *arg;
325{
326 register PLAN *new;
327
328 ftsoptions &= ~FTS_NOSTAT;
329
330 NEW(T_FSTYPE, f_fstype);
331 switch(*arg) {
f2037504
KB
332 case 'l':
333 if (!strcmp(arg, "local")) {
334 new->flags = MOUNT_NONE;
335 return(new);
336 }
337 break;
45fc66f9
KB
338 case 'm':
339 if (!strcmp(arg, "mfs")) {
340 new->flags = MOUNT_MFS;
341 return(new);
342 }
343 break;
344 case 'n':
345 if (!strcmp(arg, "nfs")) {
346 new->flags = MOUNT_NFS;
347 return(new);
348 }
349 break;
350 case 'p':
351 if (!strcmp(arg, "pc")) {
352 new->flags = MOUNT_PC;
353 return(new);
354 }
355 break;
356 case 'u':
357 if (!strcmp(arg, "ufs")) {
358 new->flags = MOUNT_UFS;
359 return(new);
360 }
361 break;
362 }
363 (void)fprintf(stderr, "find: unknown file type %s.\n", arg);
364 exit(1);
365 /* NOTREACHED */
366}
367
368/*
369 * -group gname functions --
370 *
371 * True if the file belongs to the group gname. If gname is numeric and
372 * an equivalent of the getgrnam() function does not return a valid group
373 * name, gname is taken as a group ID.
374 */
375f_group(plan, entry)
376 PLAN *plan;
377 FTSENT *entry;
378{
f2037504 379 return(entry->fts_statb.st_gid == plan->g_data);
45fc66f9
KB
380}
381
382PLAN *
383c_group(gname)
384 char *gname;
385{
386 PLAN *new;
387 struct group *g;
388 gid_t gid;
389
390 ftsoptions &= ~FTS_NOSTAT;
391
392 g = getgrnam(gname);
393 if (g == NULL) {
394 gid = atoi(gname);
395 if (gid == 0 && gname[0] != '0')
396 bad_arg("-group", "no such group");
397 } else
398 gid = g->gr_gid;
399
400 NEW(T_GROUP, f_group);
401 new->g_data = gid;
402 return(new);
403}
404
405/*
406 * -inum n functions --
407 *
408 * True if the file has inode # n.
409 */
410f_inum(plan, entry)
411 PLAN *plan;
412 FTSENT *entry;
413{
f2037504 414 COMPARE(entry->fts_statb.st_ino, plan->i_data);
45fc66f9
KB
415}
416
417PLAN *
418c_inum(arg)
419 char *arg;
420{
421 PLAN *new;
422
423 ftsoptions &= ~FTS_NOSTAT;
424
425 NEW(T_INUM, f_inum);
426 new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL);
427 return(new);
428}
429
430/*
431 * -links n functions --
432 *
433 * True if the file has n links.
434 */
435f_links(plan, entry)
436 PLAN *plan;
437 FTSENT *entry;
438{
f2037504 439 COMPARE(entry->fts_statb.st_nlink, plan->l_data);
45fc66f9
KB
440}
441
442PLAN *
443c_links(arg)
444 char *arg;
445{
446 PLAN *new;
447
448 ftsoptions &= ~FTS_NOSTAT;
449
450 NEW(T_LINKS, f_links);
451 new->l_data = find_parsenum(new, "-links", arg, (char *)NULL);
452 return(new);
453}
454
455/*
456 * -ls functions --
457 *
458 * Always true - prints the current entry to stdout in "ls" format.
459 */
460/* ARGSUSED */
461f_ls(plan, entry)
462 PLAN *plan;
463 FTSENT *entry;
464{
f2037504
KB
465 printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb);
466 return(1);
45fc66f9
KB
467}
468
469PLAN *
470c_ls()
471{
472 PLAN *new;
473
474 ftsoptions &= ~FTS_NOSTAT;
475 output_specified = 1;
476
477 NEW(T_LS, f_ls);
478 return(new);
479}
480
481/*
482 * -name functions --
483 *
484 * True if the basename of the filename being examined
485 * matches pattern using Pattern Matching Notation S3.14
486 */
487f_name(plan, entry)
488 PLAN *plan;
489 FTSENT *entry;
490{
f2037504 491 return(fnmatch(plan->c_data, entry->fts_name, FNM_QUOTE));
45fc66f9
KB
492}
493
494PLAN *
495c_name(pattern)
496 char *pattern;
497{
498 PLAN *new;
499
500 NEW(T_NAME, f_name);
501 new->c_data = pattern;
502 return(new);
503}
504
505/*
506 * -newer file functions --
507 *
508 * True if the current file has been modified more recently
509 * then the modification time of the file named by the pathname
510 * file.
511 */
512f_newer(plan, entry)
513 PLAN *plan;
514 FTSENT *entry;
515{
f2037504 516 return(entry->fts_statb.st_mtime > plan->t_data);
45fc66f9
KB
517}
518
519PLAN *
520c_newer(filename)
521 char *filename;
522{
523 PLAN *new;
524 struct stat sb;
525
526 ftsoptions &= ~FTS_NOSTAT;
527
528 if (stat(filename, &sb)) {
529 (void)fprintf(stderr, "find: %s: %s.\n",
530 filename, strerror(errno));
531 exit(1);
532 }
533 NEW(T_NEWER, f_newer);
534 new->t_data = sb.st_mtime;
535 return(new);
536}
537
538/*
539 * -nogroup functions --
540 *
541 * True if file belongs to a user ID for which the equivalent
542 * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
543 */
544/* ARGSUSED */
545f_nogroup(plan, entry)
546 PLAN *plan;
547 FTSENT *entry;
548{
f2037504 549 return(group_from_gid(entry->fts_statb.st_gid, 1));
45fc66f9
KB
550}
551
552PLAN *
553c_nogroup()
554{
555 PLAN *new;
556
557 ftsoptions &= ~FTS_NOSTAT;
558
559 NEW(T_NOGROUP, f_nogroup);
560 return(new);
561}
562
563/*
564 * -nouser functions --
565 *
566 * True if file belongs to a user ID for which the equivalent
567 * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
568 */
569/* ARGSUSED */
570f_nouser(plan, entry)
571 PLAN *plan;
572 FTSENT *entry;
573{
f2037504 574 return(user_from_uid(entry->fts_statb.st_uid, 1));
45fc66f9
KB
575}
576
577PLAN *
578c_nouser()
579{
580 PLAN *new;
581
582 ftsoptions &= ~FTS_NOSTAT;
583
584 NEW(T_NOUSER, f_nouser);
585 return(new);
586}
587
588/*
589 * -perm functions --
590 *
591 * The mode argument is used to represent file mode bits. If it starts
592 * with a leading digit, it's treated as an octal mode, otherwise as a
593 * symbolic mode.
594 */
595f_perm(plan, entry)
596 PLAN *plan;
597 FTSENT *entry;
598{
599 mode_t mode;
600
f2037504 601 mode = entry->fts_statb.st_mode &
45fc66f9
KB
602 (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
603 if (plan->flags)
604 return((plan->m_data | mode) == mode);
605 else
606 return(mode == plan->m_data);
607 /* NOTREACHED */
608}
609
610PLAN *
611c_perm(perm)
612 char *perm;
613{
614 PLAN *new;
615
616 ftsoptions &= ~FTS_NOSTAT;
617
618 NEW(T_PERM, f_perm);
619
620 if (*perm == '-') {
621 new->flags = 1;
622 ++perm;
623 }
624
625 if (setmode(perm))
626 bad_arg("-perm", "illegal mode string");
627
628 new->m_data = getmode(0);
629 return(new);
630}
631
632/*
633 * -print functions --
634 *
635 * Always true, causes the current pathame to be written to
636 * standard output.
637 */
638/* ARGSUSED */
639f_print(plan, entry)
640 PLAN *plan;
641 FTSENT *entry;
642{
f2037504
KB
643 (void)printf("%s\n", entry->fts_path);
644 return(1);
45fc66f9
KB
645}
646
647PLAN *
648c_print()
649{
650 PLAN *new;
651
652 output_specified = 1;
653
654 NEW(T_PRINT, f_print);
655 return(new);
656}
657
658/*
659 * -prune functions --
660 *
661 * Prune a portion of the hierarchy.
662 */
663/* ARGSUSED */
664f_prune(plan, entry)
665 PLAN *plan;
666 FTSENT *entry;
667{
668 extern FTS *tree;
669
670 if (ftsset(tree, entry, FTS_SKIP)) {
671 (void)fprintf(stderr,
f2037504 672 "find: %s: %s.\n", entry->fts_path, strerror(errno));
45fc66f9
KB
673 exit(1);
674 }
f2037504 675 return(1);
45fc66f9
KB
676}
677
678PLAN *
679c_prune()
680{
681 PLAN *new;
682
683 NEW(T_PRUNE, f_prune);
684 return(new);
685}
686
687/*
688 * -size n[c] functions --
689 *
690 * True if the file size in bytes, divided by an implementation defined
691 * value and rounded up to the next integer, is n. If n is followed by
692 * a c, the size is in bytes.
693 */
694#define FIND_SIZE 512
695static int divsize = 1;
696
697f_size(plan, entry)
698 PLAN *plan;
699 FTSENT *entry;
700{
701 off_t size;
702
f2037504
KB
703 size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) /
704 FIND_SIZE : entry->fts_statb.st_size;
45fc66f9
KB
705 COMPARE(size, plan->o_data);
706}
707
708PLAN *
709c_size(arg)
710 char *arg;
711{
712 PLAN *new;
713 char endch;
714
715 ftsoptions &= ~FTS_NOSTAT;
716
717 NEW(T_SIZE, f_size);
718 new->o_data = find_parsenum(new, "-size", arg, &endch);
719 if (endch == 'c')
720 divsize = 0;
721 return(new);
722}
723
724/*
725 * -type c functions --
726 *
727 * True if the type of the file is c, where c is b, c, d, p, or f for
728 * block special file, character special file, directory, FIFO, or
729 * regular file, respectively.
730 */
731f_type(plan, entry)
732 PLAN *plan;
733 FTSENT *entry;
734{
f2037504 735 return(entry->fts_statb.st_mode & plan->m_data);
45fc66f9
KB
736}
737
738PLAN *
739c_type(typestring)
740 char *typestring;
741{
742 PLAN *new;
743 mode_t mask;
744
745 ftsoptions &= ~FTS_NOSTAT;
746
747 switch (typestring[0]) {
748 case 'b':
749 mask = S_IFBLK;
750 break;
751 case 'c':
752 mask = S_IFCHR;
753 break;
754 case 'd':
755 mask = S_IFDIR;
756 break;
757 case 'f':
758 mask = S_IFREG;
759 break;
760 case 'l':
761 mask = S_IFLNK;
762 break;
763 case 'p':
764 mask = S_IFIFO;
765 break;
766 case 's':
767 mask = S_IFSOCK;
768 break;
769 default:
770 bad_arg("-type", "unknown type");
771 }
772
773 NEW(T_TYPE, f_type);
774 new->m_data = mask;
775 return(new);
776}
777
778/*
779 * -user uname functions --
780 *
781 * True if the file belongs to the user uname. If uname is numeric and
782 * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
783 * return a valid user name, uname is taken as a user ID.
784 */
785f_user(plan, entry)
786 PLAN *plan;
787 FTSENT *entry;
788{
f2037504 789 return(entry->fts_statb.st_uid == plan->u_data);
45fc66f9
KB
790}
791
792PLAN *
793c_user(username)
794 char *username;
795{
796 PLAN *new;
797 struct passwd *p;
798 uid_t uid;
799
800 ftsoptions &= ~FTS_NOSTAT;
801
802 p = getpwnam(username);
803 if (p == NULL) {
804 uid = atoi(username);
805 if (uid == 0 && username[0] != '0')
806 bad_arg("-user", "no such user");
807 } else
808 uid = p->pw_uid;
809
810 NEW(T_USER, f_user);
811 new->u_data = uid;
812 return(new);
813}
814
815/*
816 * -xdev functions --
817 *
818 * Always true, causes find not to decend past directories that have a
819 * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
45fc66f9
KB
820 */
821PLAN *
822c_xdev()
823{
45fc66f9
KB
824 PLAN *new;
825
45fc66f9 826 ftsoptions &= ~FTS_NOSTAT;
1292488d 827 ftsoptions |= FTS_XDEV;
45fc66f9
KB
828
829 NEW(T_XDEV, f_always_true);
830 return(new);
831}
832
833/*
834 * ( expression ) functions --
835 *
836 * True if expression is true.
837 */
838f_expr(plan, entry)
839 PLAN *plan;
840 FTSENT *entry;
841{
842 register PLAN *p;
843 register int state;
844
845 for (p = plan->p_data[0];
846 p && (state = (p->eval)(p, entry)); p = p->next);
847 return(state);
848}
849
850/*
851 * T_OPENPAREN and T_CLOSEPAREN nodes are temporary place markers. They are
852 * eliminated during phase 2 of find_formplan() --- the '(' node is converted
853 * to a T_EXPR node containing the expression and the ')' node is discarded.
854 */
855PLAN *
856c_openparen()
857{
858 PLAN *new;
859
860 NEW(T_OPENPAREN, (int (*)())-1);
861 return(new);
862}
863
864PLAN *
865c_closeparen()
866{
867 PLAN *new;
868
869 NEW(T_CLOSEPAREN, (int (*)())-1);
870 return(new);
871}
872
873/*
874 * -mtime n functions --
875 *
876 * True if the difference between the file modification time and the
877 * current time is n 24 hour periods.
878 */
879f_mtime(plan, entry)
880 PLAN *plan;
881 FTSENT *entry;
882{
883 extern time_t now;
884
f2037504
KB
885 COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) /
886 SECSPERDAY, plan->t_data);
45fc66f9
KB
887}
888
889PLAN *
890c_mtime(arg)
891 char *arg;
892{
893 PLAN *new;
894
895 ftsoptions &= ~FTS_NOSTAT;
896
897 NEW(T_MTIME, f_mtime);
898 new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
899 return(new);
900}
901
902/*
903 * ! expression functions --
904 *
905 * Negation of a primary; the unary NOT operator.
906 */
907f_not(plan, entry)
908 PLAN *plan;
909 FTSENT *entry;
910{
911 register PLAN *p;
912 register int state;
913
914 for (p = plan->p_data[0];
915 p && (state = (p->eval)(p, entry)); p = p->next);
916 return(!state);
917}
918
919PLAN *
920c_not()
921{
922 PLAN *new;
923
924 NEW(T_NOT, f_not);
925 return(new);
926}
927
928/*
929 * expression -o expression functions --
930 *
931 * Alternation of primaries; the OR operator. The second expression is
932 * not evaluated if the first expression is true.
933 */
934f_or(plan, entry)
935 PLAN *plan;
936 FTSENT *entry;
937{
938 register PLAN *p;
939 register int state;
940
941 for (p = plan->p_data[0];
942 p && (state = (p->eval)(p, entry)); p = p->next);
943
944 if (state)
f2037504 945 return(1);
45fc66f9
KB
946
947 for (p = plan->p_data[1];
948 p && (state = (p->eval)(p, entry)); p = p->next);
949 return(state);
950}
951
952PLAN *
953c_or()
954{
955 PLAN *new;
956
957 NEW(T_OR, f_or);
958 return(new);
959}