look.c revision 1.1 1 1.1 perry /* $NetBSD: look.c,v 1.1 2005/06/29 21:06:12 perry Exp $ */
2 1.1 perry
3 1.1 perry /* derived from: OpenBSD: look.c,v 1.3 2003/06/03 02:56:16 millert Exp */
4 1.1 perry
5 1.1 perry /*-
6 1.1 perry * Copyright (c) 1991, 1993
7 1.1 perry * The Regents of the University of California. All rights reserved.
8 1.1 perry *
9 1.1 perry * This code is derived from software contributed to Berkeley by
10 1.1 perry * David Hitz of Auspex Systems, Inc.
11 1.1 perry *
12 1.1 perry * Redistribution and use in source and binary forms, with or without
13 1.1 perry * modification, are permitted provided that the following conditions
14 1.1 perry * are met:
15 1.1 perry * 1. Redistributions of source code must retain the above copyright
16 1.1 perry * notice, this list of conditions and the following disclaimer.
17 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright
18 1.1 perry * notice, this list of conditions and the following disclaimer in the
19 1.1 perry * documentation and/or other materials provided with the distribution.
20 1.1 perry * 3. Neither the name of the University nor the names of its contributors
21 1.1 perry * may be used to endorse or promote products derived from this software
22 1.1 perry * without specific prior written permission.
23 1.1 perry *
24 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 perry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 perry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 perry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 perry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 perry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 perry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 perry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 perry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 perry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 perry * SUCH DAMAGE.
35 1.1 perry */
36 1.1 perry
37 1.1 perry #ifndef lint
38 1.1 perry #if 0
39 1.1 perry static const char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
40 1.1 perry #endif
41 1.1 perry static const char rcsid[] = "$NetBSD: look.c,v 1.1 2005/06/29 21:06:12 perry Exp $";
42 1.1 perry #endif /* not lint */
43 1.1 perry
44 1.1 perry #include <sys/types.h>
45 1.1 perry #include <ctype.h>
46 1.1 perry #include <stdio.h>
47 1.1 perry #include <stdlib.h>
48 1.1 perry #include <string.h>
49 1.1 perry #include <err.h>
50 1.1 perry
51 1.1 perry u_char *binary_search(u_char *, u_char *, u_char *);
52 1.1 perry u_char *linear_search(u_char *, u_char *, u_char *);
53 1.1 perry int compare(u_char *, u_char *, u_char *);
54 1.1 perry int look(u_char *, u_char *, u_char *);
55 1.1 perry
56 1.1 perry int
57 1.1 perry look(u_char *string, u_char *front, u_char *back)
58 1.1 perry {
59 1.1 perry u_char *s;
60 1.1 perry
61 1.1 perry /* Convert string to lower case before searching. */
62 1.1 perry for (s = string; *s; s++) {
63 1.1 perry if (isupper(*s))
64 1.1 perry *s = _tolower(*s);
65 1.1 perry }
66 1.1 perry
67 1.1 perry front = binary_search(string, front, back);
68 1.1 perry front = linear_search(string, front, back);
69 1.1 perry
70 1.1 perry return (front != NULL);
71 1.1 perry }
72 1.1 perry
73 1.1 perry /*
74 1.1 perry * Binary search for "string" in memory between "front" and "back".
75 1.1 perry *
76 1.1 perry * This routine is expected to return a pointer to the start of a line at
77 1.1 perry * *or before* the first word matching "string". Relaxing the constraint
78 1.1 perry * this way simplifies the algorithm.
79 1.1 perry *
80 1.1 perry * Invariants:
81 1.1 perry * front points to the beginning of a line at or before the first
82 1.1 perry * matching string.
83 1.1 perry *
84 1.1 perry * back points to the beginning of a line at or after the first
85 1.1 perry * matching line.
86 1.1 perry *
87 1.1 perry * Base of the Invariants.
88 1.1 perry * front = NULL;
89 1.1 perry * back = EOF;
90 1.1 perry *
91 1.1 perry * Advancing the Invariants:
92 1.1 perry *
93 1.1 perry * p = first newline after halfway point from front to back.
94 1.1 perry *
95 1.1 perry * If the string at "p" is not greater than the string to match,
96 1.1 perry * p is the new front. Otherwise it is the new back.
97 1.1 perry *
98 1.1 perry * Termination:
99 1.1 perry *
100 1.1 perry * The definition of the routine allows it return at any point,
101 1.1 perry * since front is always at or before the line to print.
102 1.1 perry *
103 1.1 perry * In fact, it returns when the chosen "p" equals "back". This
104 1.1 perry * implies that there exists a string is least half as long as
105 1.1 perry * (back - front), which in turn implies that a linear search will
106 1.1 perry * be no more expensive than the cost of simply printing a string or two.
107 1.1 perry *
108 1.1 perry * Trying to continue with binary search at this point would be
109 1.1 perry * more trouble than it's worth.
110 1.1 perry */
111 1.1 perry #define SKIP_PAST_NEWLINE(p, back) \
112 1.1 perry while (p < back && *p++ != '\n');
113 1.1 perry
114 1.1 perry u_char *
115 1.1 perry binary_search(u_char *string, u_char *front, u_char *back)
116 1.1 perry {
117 1.1 perry u_char *p;
118 1.1 perry
119 1.1 perry p = front + (back - front) / 2;
120 1.1 perry SKIP_PAST_NEWLINE(p, back);
121 1.1 perry
122 1.1 perry /*
123 1.1 perry * If the file changes underneath us, make sure we don't
124 1.1 perry * infinitely loop.
125 1.1 perry */
126 1.1 perry while (p < back && back > front) {
127 1.1 perry if (compare(string, p, back) > 0)
128 1.1 perry front = p;
129 1.1 perry else
130 1.1 perry back = p;
131 1.1 perry p = front + (back - front) / 2;
132 1.1 perry SKIP_PAST_NEWLINE(p, back);
133 1.1 perry }
134 1.1 perry return (front);
135 1.1 perry }
136 1.1 perry
137 1.1 perry /*
138 1.1 perry * Find the first line that matches string, linearly searching from front
139 1.1 perry * to back.
140 1.1 perry *
141 1.1 perry * Return NULL for no such line.
142 1.1 perry *
143 1.1 perry * This routine assumes:
144 1.1 perry *
145 1.1 perry * o front points at the first character in a line.
146 1.1 perry * o front is before or at the first line to be printed.
147 1.1 perry */
148 1.1 perry u_char *
149 1.1 perry linear_search(u_char *string, u_char *front, u_char *back)
150 1.1 perry {
151 1.1 perry int result;
152 1.1 perry
153 1.1 perry while (front < back) {
154 1.1 perry result = compare(string, front, back);
155 1.1 perry if (result == 0)
156 1.1 perry return (front); /* found it */
157 1.1 perry if (result < 0)
158 1.1 perry return (NULL); /* not there */
159 1.1 perry
160 1.1 perry SKIP_PAST_NEWLINE(front, back);
161 1.1 perry }
162 1.1 perry return (NULL);
163 1.1 perry }
164 1.1 perry
165 1.1 perry int
166 1.1 perry compare(u_char *s1, u_char *s2, u_char *back)
167 1.1 perry {
168 1.1 perry int ch;
169 1.1 perry
170 1.1 perry /* Note that s1 is already upper case. */
171 1.1 perry for (;; ++s1, ++s2) {
172 1.1 perry if (*s2 == '\n' || s2 == back)
173 1.1 perry ch = '\0';
174 1.1 perry else if (isupper(*s2))
175 1.1 perry ch = _tolower(*s2);
176 1.1 perry else
177 1.1 perry ch = *s2;
178 1.1 perry if (*s1 != ch)
179 1.1 perry return (*s1 - ch);
180 1.1 perry if (ch == '\0')
181 1.1 perry return (0);
182 1.1 perry }
183 1.1 perry }
184