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