sigset.c -> sigsetops.c, add sigsetops man page
[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
b51b784d 12static char sccsid[] = "@(#)function.c 5.8 (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) {
86408357 310 curdev = entry->fts_statb.st_dev;
f2037504 311 if (statfs(entry->fts_accpath, &sb)) {
45fc66f9 312 (void)fprintf(stderr, "find: %s: %s.\n",
f2037504 313 entry->fts_accpath, strerror(errno));
45fc66f9
KB
314 exit(1);
315 }
1292488d 316 first = 0;
f2037504 317 val = plan->flags == MOUNT_NONE ? sb.f_flags : sb.f_type;
45fc66f9 318 }
f2037504
KB
319 return(plan->flags == MOUNT_NONE ?
320 val & MNT_LOCAL : val == plan->flags);
45fc66f9
KB
321}
322
323PLAN *
324c_fstype(arg)
325 char *arg;
326{
327 register PLAN *new;
328
329 ftsoptions &= ~FTS_NOSTAT;
330
331 NEW(T_FSTYPE, f_fstype);
332 switch(*arg) {
f2037504
KB
333 case 'l':
334 if (!strcmp(arg, "local")) {
335 new->flags = MOUNT_NONE;
336 return(new);
337 }
338 break;
45fc66f9
KB
339 case 'm':
340 if (!strcmp(arg, "mfs")) {
341 new->flags = MOUNT_MFS;
342 return(new);
343 }
344 break;
345 case 'n':
346 if (!strcmp(arg, "nfs")) {
347 new->flags = MOUNT_NFS;
348 return(new);
349 }
350 break;
351 case 'p':
352 if (!strcmp(arg, "pc")) {
353 new->flags = MOUNT_PC;
354 return(new);
355 }
356 break;
357 case 'u':
358 if (!strcmp(arg, "ufs")) {
359 new->flags = MOUNT_UFS;
360 return(new);
361 }
362 break;
363 }
364 (void)fprintf(stderr, "find: unknown file type %s.\n", arg);
365 exit(1);
366 /* NOTREACHED */
367}
368
369/*
370 * -group gname functions --
371 *
372 * True if the file belongs to the group gname. If gname is numeric and
373 * an equivalent of the getgrnam() function does not return a valid group
374 * name, gname is taken as a group ID.
375 */
376f_group(plan, entry)
377 PLAN *plan;
378 FTSENT *entry;
379{
f2037504 380 return(entry->fts_statb.st_gid == plan->g_data);
45fc66f9
KB
381}
382
383PLAN *
384c_group(gname)
385 char *gname;
386{
387 PLAN *new;
388 struct group *g;
389 gid_t gid;
390
391 ftsoptions &= ~FTS_NOSTAT;
392
393 g = getgrnam(gname);
394 if (g == NULL) {
395 gid = atoi(gname);
396 if (gid == 0 && gname[0] != '0')
397 bad_arg("-group", "no such group");
398 } else
399 gid = g->gr_gid;
400
401 NEW(T_GROUP, f_group);
402 new->g_data = gid;
403 return(new);
404}
405
406/*
407 * -inum n functions --
408 *
409 * True if the file has inode # n.
410 */
411f_inum(plan, entry)
412 PLAN *plan;
413 FTSENT *entry;
414{
f2037504 415 COMPARE(entry->fts_statb.st_ino, plan->i_data);
45fc66f9
KB
416}
417
418PLAN *
419c_inum(arg)
420 char *arg;
421{
422 PLAN *new;
423
424 ftsoptions &= ~FTS_NOSTAT;
425
426 NEW(T_INUM, f_inum);
427 new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL);
428 return(new);
429}
430
431/*
432 * -links n functions --
433 *
434 * True if the file has n links.
435 */
436f_links(plan, entry)
437 PLAN *plan;
438 FTSENT *entry;
439{
f2037504 440 COMPARE(entry->fts_statb.st_nlink, plan->l_data);
45fc66f9
KB
441}
442
443PLAN *
444c_links(arg)
445 char *arg;
446{
447 PLAN *new;
448
449 ftsoptions &= ~FTS_NOSTAT;
450
451 NEW(T_LINKS, f_links);
452 new->l_data = find_parsenum(new, "-links", arg, (char *)NULL);
453 return(new);
454}
455
456/*
457 * -ls functions --
458 *
459 * Always true - prints the current entry to stdout in "ls" format.
460 */
461/* ARGSUSED */
462f_ls(plan, entry)
463 PLAN *plan;
464 FTSENT *entry;
465{
f2037504
KB
466 printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb);
467 return(1);
45fc66f9
KB
468}
469
470PLAN *
471c_ls()
472{
473 PLAN *new;
474
475 ftsoptions &= ~FTS_NOSTAT;
476 output_specified = 1;
477
478 NEW(T_LS, f_ls);
479 return(new);
480}
481
482/*
483 * -name functions --
484 *
485 * True if the basename of the filename being examined
486 * matches pattern using Pattern Matching Notation S3.14
487 */
488f_name(plan, entry)
489 PLAN *plan;
490 FTSENT *entry;
491{
f2037504 492 return(fnmatch(plan->c_data, entry->fts_name, FNM_QUOTE));
45fc66f9
KB
493}
494
495PLAN *
496c_name(pattern)
497 char *pattern;
498{
499 PLAN *new;
500
501 NEW(T_NAME, f_name);
502 new->c_data = pattern;
503 return(new);
504}
505
506/*
507 * -newer file functions --
508 *
509 * True if the current file has been modified more recently
510 * then the modification time of the file named by the pathname
511 * file.
512 */
513f_newer(plan, entry)
514 PLAN *plan;
515 FTSENT *entry;
516{
f2037504 517 return(entry->fts_statb.st_mtime > plan->t_data);
45fc66f9
KB
518}
519
520PLAN *
521c_newer(filename)
522 char *filename;
523{
524 PLAN *new;
525 struct stat sb;
526
527 ftsoptions &= ~FTS_NOSTAT;
528
529 if (stat(filename, &sb)) {
530 (void)fprintf(stderr, "find: %s: %s.\n",
531 filename, strerror(errno));
532 exit(1);
533 }
534 NEW(T_NEWER, f_newer);
535 new->t_data = sb.st_mtime;
536 return(new);
537}
538
539/*
540 * -nogroup functions --
541 *
542 * True if file belongs to a user ID for which the equivalent
543 * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
544 */
545/* ARGSUSED */
546f_nogroup(plan, entry)
547 PLAN *plan;
548 FTSENT *entry;
549{
f2037504 550 return(group_from_gid(entry->fts_statb.st_gid, 1));
45fc66f9
KB
551}
552
553PLAN *
554c_nogroup()
555{
556 PLAN *new;
557
558 ftsoptions &= ~FTS_NOSTAT;
559
560 NEW(T_NOGROUP, f_nogroup);
561 return(new);
562}
563
564/*
565 * -nouser functions --
566 *
567 * True if file belongs to a user ID for which the equivalent
568 * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
569 */
570/* ARGSUSED */
571f_nouser(plan, entry)
572 PLAN *plan;
573 FTSENT *entry;
574{
f2037504 575 return(user_from_uid(entry->fts_statb.st_uid, 1));
45fc66f9
KB
576}
577
578PLAN *
579c_nouser()
580{
581 PLAN *new;
582
583 ftsoptions &= ~FTS_NOSTAT;
584
585 NEW(T_NOUSER, f_nouser);
586 return(new);
587}
588
589/*
590 * -perm functions --
591 *
592 * The mode argument is used to represent file mode bits. If it starts
593 * with a leading digit, it's treated as an octal mode, otherwise as a
594 * symbolic mode.
595 */
596f_perm(plan, entry)
597 PLAN *plan;
598 FTSENT *entry;
599{
600 mode_t mode;
601
f2037504 602 mode = entry->fts_statb.st_mode &
45fc66f9
KB
603 (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
604 if (plan->flags)
605 return((plan->m_data | mode) == mode);
606 else
607 return(mode == plan->m_data);
608 /* NOTREACHED */
609}
610
611PLAN *
612c_perm(perm)
613 char *perm;
614{
615 PLAN *new;
b51b784d 616 mode_t *set, *setmode();
45fc66f9
KB
617
618 ftsoptions &= ~FTS_NOSTAT;
619
620 NEW(T_PERM, f_perm);
621
622 if (*perm == '-') {
623 new->flags = 1;
624 ++perm;
625 }
626
948b36af 627 if ((set = setmode(perm)) == NULL)
45fc66f9
KB
628 bad_arg("-perm", "illegal mode string");
629
948b36af 630 new->m_data = getmode(set, 0);
45fc66f9
KB
631 return(new);
632}
633
634/*
635 * -print functions --
636 *
637 * Always true, causes the current pathame to be written to
638 * standard output.
639 */
640/* ARGSUSED */
641f_print(plan, entry)
642 PLAN *plan;
643 FTSENT *entry;
644{
f2037504
KB
645 (void)printf("%s\n", entry->fts_path);
646 return(1);
45fc66f9
KB
647}
648
649PLAN *
650c_print()
651{
652 PLAN *new;
653
654 output_specified = 1;
655
656 NEW(T_PRINT, f_print);
657 return(new);
658}
659
660/*
661 * -prune functions --
662 *
663 * Prune a portion of the hierarchy.
664 */
665/* ARGSUSED */
666f_prune(plan, entry)
667 PLAN *plan;
668 FTSENT *entry;
669{
670 extern FTS *tree;
671
672 if (ftsset(tree, entry, FTS_SKIP)) {
673 (void)fprintf(stderr,
f2037504 674 "find: %s: %s.\n", entry->fts_path, strerror(errno));
45fc66f9
KB
675 exit(1);
676 }
f2037504 677 return(1);
45fc66f9
KB
678}
679
680PLAN *
681c_prune()
682{
683 PLAN *new;
684
685 NEW(T_PRUNE, f_prune);
686 return(new);
687}
688
689/*
690 * -size n[c] functions --
691 *
692 * True if the file size in bytes, divided by an implementation defined
693 * value and rounded up to the next integer, is n. If n is followed by
694 * a c, the size is in bytes.
695 */
696#define FIND_SIZE 512
697static int divsize = 1;
698
699f_size(plan, entry)
700 PLAN *plan;
701 FTSENT *entry;
702{
703 off_t size;
704
f2037504
KB
705 size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) /
706 FIND_SIZE : entry->fts_statb.st_size;
45fc66f9
KB
707 COMPARE(size, plan->o_data);
708}
709
710PLAN *
711c_size(arg)
712 char *arg;
713{
714 PLAN *new;
715 char endch;
716
717 ftsoptions &= ~FTS_NOSTAT;
718
719 NEW(T_SIZE, f_size);
720 new->o_data = find_parsenum(new, "-size", arg, &endch);
721 if (endch == 'c')
722 divsize = 0;
723 return(new);
724}
725
726/*
727 * -type c functions --
728 *
729 * True if the type of the file is c, where c is b, c, d, p, or f for
730 * block special file, character special file, directory, FIFO, or
731 * regular file, respectively.
732 */
733f_type(plan, entry)
734 PLAN *plan;
735 FTSENT *entry;
736{
948b36af 737 return((entry->fts_statb.st_mode & S_IFMT) == plan->m_data);
45fc66f9
KB
738}
739
740PLAN *
741c_type(typestring)
742 char *typestring;
743{
744 PLAN *new;
745 mode_t mask;
746
747 ftsoptions &= ~FTS_NOSTAT;
748
749 switch (typestring[0]) {
750 case 'b':
751 mask = S_IFBLK;
752 break;
753 case 'c':
754 mask = S_IFCHR;
755 break;
756 case 'd':
757 mask = S_IFDIR;
758 break;
759 case 'f':
760 mask = S_IFREG;
761 break;
762 case 'l':
763 mask = S_IFLNK;
764 break;
765 case 'p':
766 mask = S_IFIFO;
767 break;
768 case 's':
769 mask = S_IFSOCK;
770 break;
771 default:
772 bad_arg("-type", "unknown type");
773 }
774
775 NEW(T_TYPE, f_type);
776 new->m_data = mask;
777 return(new);
778}
779
780/*
781 * -user uname functions --
782 *
783 * True if the file belongs to the user uname. If uname is numeric and
784 * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
785 * return a valid user name, uname is taken as a user ID.
786 */
787f_user(plan, entry)
788 PLAN *plan;
789 FTSENT *entry;
790{
f2037504 791 return(entry->fts_statb.st_uid == plan->u_data);
45fc66f9
KB
792}
793
794PLAN *
795c_user(username)
796 char *username;
797{
798 PLAN *new;
799 struct passwd *p;
800 uid_t uid;
801
802 ftsoptions &= ~FTS_NOSTAT;
803
804 p = getpwnam(username);
805 if (p == NULL) {
806 uid = atoi(username);
807 if (uid == 0 && username[0] != '0')
808 bad_arg("-user", "no such user");
809 } else
810 uid = p->pw_uid;
811
812 NEW(T_USER, f_user);
813 new->u_data = uid;
814 return(new);
815}
816
817/*
818 * -xdev functions --
819 *
820 * Always true, causes find not to decend past directories that have a
821 * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
45fc66f9
KB
822 */
823PLAN *
824c_xdev()
825{
45fc66f9
KB
826 PLAN *new;
827
45fc66f9 828 ftsoptions &= ~FTS_NOSTAT;
1292488d 829 ftsoptions |= FTS_XDEV;
45fc66f9
KB
830
831 NEW(T_XDEV, f_always_true);
832 return(new);
833}
834
835/*
836 * ( expression ) functions --
837 *
838 * True if expression is true.
839 */
840f_expr(plan, entry)
841 PLAN *plan;
842 FTSENT *entry;
843{
844 register PLAN *p;
845 register int state;
846
847 for (p = plan->p_data[0];
848 p && (state = (p->eval)(p, entry)); p = p->next);
849 return(state);
850}
851
852/*
853 * T_OPENPAREN and T_CLOSEPAREN nodes are temporary place markers. They are
854 * eliminated during phase 2 of find_formplan() --- the '(' node is converted
855 * to a T_EXPR node containing the expression and the ')' node is discarded.
856 */
857PLAN *
858c_openparen()
859{
860 PLAN *new;
861
862 NEW(T_OPENPAREN, (int (*)())-1);
863 return(new);
864}
865
866PLAN *
867c_closeparen()
868{
869 PLAN *new;
870
871 NEW(T_CLOSEPAREN, (int (*)())-1);
872 return(new);
873}
874
875/*
876 * -mtime n functions --
877 *
878 * True if the difference between the file modification time and the
879 * current time is n 24 hour periods.
880 */
881f_mtime(plan, entry)
882 PLAN *plan;
883 FTSENT *entry;
884{
885 extern time_t now;
886
f2037504
KB
887 COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) /
888 SECSPERDAY, plan->t_data);
45fc66f9
KB
889}
890
891PLAN *
892c_mtime(arg)
893 char *arg;
894{
895 PLAN *new;
896
897 ftsoptions &= ~FTS_NOSTAT;
898
899 NEW(T_MTIME, f_mtime);
900 new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
901 return(new);
902}
903
904/*
905 * ! expression functions --
906 *
907 * Negation of a primary; the unary NOT operator.
908 */
909f_not(plan, entry)
910 PLAN *plan;
911 FTSENT *entry;
912{
913 register PLAN *p;
914 register int state;
915
916 for (p = plan->p_data[0];
917 p && (state = (p->eval)(p, entry)); p = p->next);
918 return(!state);
919}
920
921PLAN *
922c_not()
923{
924 PLAN *new;
925
926 NEW(T_NOT, f_not);
927 return(new);
928}
929
930/*
931 * expression -o expression functions --
932 *
933 * Alternation of primaries; the OR operator. The second expression is
934 * not evaluated if the first expression is true.
935 */
936f_or(plan, entry)
937 PLAN *plan;
938 FTSENT *entry;
939{
940 register PLAN *p;
941 register int state;
942
943 for (p = plan->p_data[0];
944 p && (state = (p->eval)(p, entry)); p = p->next);
945
946 if (state)
f2037504 947 return(1);
45fc66f9
KB
948
949 for (p = plan->p_data[1];
950 p && (state = (p->eval)(p, entry)); p = p->next);
951 return(state);
952}
953
954PLAN *
955c_or()
956{
957 PLAN *new;
958
959 NEW(T_OR, f_or);
960 return(new);
961}