|
|
1.1 root 1: /* look.c - look for matching lines of text in a sorted file.
2: */
3: #include <stdio.h>
4: #include <ctype.h>
5:
6: #define TRUE 1
7: #define FALSE 0
8: #define EQ 1
9: #define LESS 0
10: #define GREATER 2
11: #define TAB ' '
12: #define BSIZ 512
13:
14: extern long ftell() ;
15:
16: /* Globals
17: */
18:
19: int d_mode, f_mode ;
20: long top, bottom ;
21: long fsiz ;
22: FILE *fildes ;
23: char stbuf[BSIZ], rbuf[BSIZ] ;
24: char *rbufp ;
25:
26: /* getx - Get the nex character from the character buffer.
27: * If the buffer is empty get the next block.
28: */
29:
30: /* getx()
31: * {
32: * if (rbufp < &rbuf[BSIZ])
33: * return(*rbufp++) ;
34: * else {
35: * gnb() ;
36: * return(getx()) ;
37: * }
38: * }
39: */
40:
41: #ifdef FIXED /* Bug in 8086 compiler */
42: #define getx() ((rbuf < &rbuf[BSIZ]) ? *rbufp++ : (gnb(), *rbufp++))
43: #else
44: getx()
45: {
46: if (rbufp >= &rbuf[BSIZ])
47: gnb();
48: return (*rbufp++);
49: }
50: #endif
51:
52: /* order - Order relation for characters. Returns GREATER, LESS or EQ.
53: */
54:
55: /* order(a, b)
56: * {
57: * if (a > b)
58: * return(GREATER) ;
59: * else if (a < b)
60: * return(LESS) ;
61: * return(EQ) ;
62: * }
63: */
64:
65: #define order(a, b) ((a > b) ? GREATER : ((a < b) ? LESS : EQ))
66:
67: /* isdict - Test for a dictionary character. From the class :
68: * [a-zA-Z0-9 ].
69: */
70:
71: /* isdict(ch)
72: * {
73: * if (isalnum(ch) || (ch == ' '))
74: * return(1) ;
75: * return(0) ;
76: * }
77: */
78:
79: #define isdict(ch) ((isalnum(ch) || (ch == ' ')) ? 1 : 0)
80:
81: /* main - Get args, set flags and get the ball rolling.
82: */
83:
84: main(argc, argv)
85: register char *argv[] ;
86: {
87: ++argv ;
88: switch (argc) {
89:
90: case 4 :
91: case 3 :
92: if (setop(argv[0])) {
93: ++argv ;
94: --argc ;
95: } else
96: if (argc == 4) {
97: form() ;
98: break ;
99: }
100: case 2 :
101: if (argc == 3)
102: gfile(argv[1]) ;
103: else
104: gfile(NULL) ;
105: if (gstring(argv[0])) {
106: look() ;
107: exit(0) ;
108: break ;
109: }
110: default :
111: form() ;
112: }
113: exit(1) ;
114: }
115:
116: /* setop - set option flags d_mode and f_mode. d_mode marks an occurance
117: * of -d[f] or -[f]d and f_mode marks an occurance of -f[d] or
118: * -[d]f.
119: */
120:
121: setop(fp)
122: register char *fp ;
123: {
124: register int i ;
125:
126: d_mode = FALSE ;
127: f_mode = FALSE ;
128:
129: if (*fp++ != '-')
130: return(0) ;
131: else {
132: for (i = 0; i < 2; i++) {
133: switch (*fp++) {
134:
135: case 'd' :
136: d_mode = TRUE ;
137: break ;
138: case 'f' :
139: f_mode = TRUE ;
140: break ;
141: case '\0' :
142: --fp ;
143: return(1) ;
144: default :
145: return(0) ;
146: }
147: }
148: if (*fp != '\0')
149: return(0) ;
150: return(1) ;
151: }
152: }
153:
154: /* gstring - gets the match string <string> and places it in the
155: * stbuf buffer after conforming it to the d_mode and
156: * f_mode options (That will make the compare routine
157: * faster). Returns the number of characters in stbuf.
158: */
159:
160: gstring(fp)
161: register char *fp ;
162: {
163: register int nc ;
164: register char *st ;
165:
166: nc = 0 ;
167: st = stbuf ;
168: while ((nc++ < BSIZ) && (*fp != '\0')) {
169: if (d_mode && !isdict(*fp)) {
170: fp++ ;
171: nc-- ;
172: continue ;
173: }
174: if (f_mode && islower(*fp)) {
175: *st++ = toupper(*fp++) ;
176: continue ;
177: }
178: *st++ = *fp++ ;
179: }
180: if (nc >= BSIZ)
181: return(0) ;
182: return(nc) ;
183: }
184:
185:
186: /* gfile - Gets the specified file and opens it for reading.
187: * If no file is specified /usr/dict/words is opened.
188: */
189:
190: gfile(fp)
191: register char *fp ;
192: {
193: register char *file ;
194:
195: if (fp == NULL) {
196: file = "/usr/dict/words" ;
197: d_mode = TRUE ;
198: f_mode = TRUE ;
199: } else
200: file = fp ;
201:
202: if ((fildes = fopen(file, "r")) == NULL) {
203: aww("look : Cannot open file") ;
204: exit(1) ;
205: }
206:
207: bottom = 0 ;
208: if (fseek(fildes, 0L, 2) == -1) {
209: aww("look : Cannot seek on file") ;
210: exit(1) ;
211: }
212:
213: top = ftell(fildes) ;
214: top -= 2 ;
215: fsiz = top ;
216:
217:
218: return(1) ;
219: }
220:
221: /* aww - Error condition. Prints out the passed string.
222: */
223:
224: aww(sp)
225: char *sp ;
226: {
227: fprintf(stderr, "%s\n", sp) ;
228: }
229:
230: /* form - Prints out a Usage message.
231: */
232:
233: form()
234: {
235: fprintf(stderr, "Usage : look [-df] string [file]\n") ;
236: }
237:
238: /* look - Binary search looking for a string match. If a match
239: * is found (the EQ case) all the strings that match
240: * are printed and then we quit else the window is
241: * decreased and the test goes on.
242: */
243:
244: look()
245: {
246: register int nmove ;
247: long mid1, mid2 ;
248: long gll() ;
249: long gteol() ;
250:
251: while (top != bottom) {
252: mid1 = (top - bottom)/2 + bottom ;
253: mid2 = gll(mid1) ;
254: nmove = comstr() ;
255: switch (nmove) {
256:
257: case EQ :
258: wstr(mid2) ;
259: return(1) ;
260: case GREATER :
261: bottom = gteol(mid1) ;
262: break ;
263: case LESS :
264: top = mid2 - 2 ;
265: break ;
266: }
267: if (top < bottom)
268: top = bottom ;
269: }
270: }
271:
272:
273: /* wstr - We found a string that matches but we are not sure that
274: * this is the only occurance of a matched string and hence
275: * we must back up until we find a non match and print
276: * forward till we find a non match in the other direction.
277: */
278:
279: wstr(seek)
280: long seek ;
281: {
282: long temp1, temp2 ;
283: long gll() ;
284:
285: if (seek != 0) {
286: temp2 = seek ;
287: temp1 = gll(seek - 2) ;
288: while (comstr() == EQ) {
289: temp2 = temp1 ;
290: if (temp1 == 0)
291: break ;
292: else
293: temp1 = gll(temp1 - 2) ;
294: }
295: } else
296: temp2 = 0 ;
297: fseek(fildes, temp2, 0) ;
298: while (ftell(fildes) <= seek) {
299: fgets(rbuf, BSIZ, fildes) ;
300: fputs(rbuf, stdout) ;
301: }
302: fgets(rbuf, BSIZ, fildes) ;
303: rbufp = rbuf ;
304: while (comstr() == EQ) {
305: fputs(rbuf, stdout) ;
306: fgets(rbuf, BSIZ, fildes) ;
307: rbufp = rbuf ;
308: }
309: return(1) ;
310: }
311:
312: /* comstr - Compare the base string to the input line.
313: * Returns a stat telling what the difference between the
314: * two strings is. EQ is equal, GREATER implies the base string
315: * is greater then the input string and LESS is vice versa.
316: */
317:
318: comstr()
319: {
320: register int state ;
321: register int ch ;
322: register char *sp ;
323:
324: sp = stbuf ;
325: while (*sp != '\0') {
326: ch = getx() ;
327: if (ch == '\n')
328: return(GREATER) ;
329: if (d_mode && !isdict(ch)) {
330: continue ;
331: }
332: if (f_mode && islower(ch))
333: ch = toupper(ch) ;
334: if ((state = order(*sp, ch)) != EQ) {
335: return(state) ;
336: }
337: ++sp ;
338: }
339: return(EQ) ;
340: }
341:
342: /* gll - Get last line. Using the seek variable, returns a pointer to
343: * the beginning of the last line of text. If neccesary
344: * gll will wind back seek a block at a time looking for
345: * the last line.
346: */
347:
348: long
349: gll(seek)
350: long seek ;
351: {
352: register char *cp ;
353: register int tmp ;
354:
355: if (seek == 0) {
356: rbufp = rbuf ;
357: return(0) ;
358: }
359:
360: if (seek < BSIZ) {
361: cp = &rbuf[(int) seek] ;
362: seek = 0 ;
363: fseek(fildes, 0L, 0) ;
364: } else {
365: cp = &rbuf[BSIZ - 1] ;
366: seek -= BSIZ ;
367: fseek(fildes, seek, 0) ;
368: }
369: fread(rbuf, sizeof(*cp), BSIZ, fildes) ;
370:
371: while (cp >= rbuf) {
372: if (*cp == '\n')
373: break ;
374: --cp ;
375: }
376:
377: if (*cp == '\n') {
378: rbufp = ++cp ;
379: tmp = cp - rbuf ;
380: seek += (long) tmp ;
381: if (seek > fsiz)
382: return(-1) ;
383: fseek(fildes, seek, 0) ;
384: fread(rbuf, sizeof(*rbufp), BSIZ, fildes) ;
385: rbufp = rbuf ;
386: return(seek) ;
387: } else
388: return(gll(seek)) ;
389: }
390:
391: /* gnb - Get the next block from the file and adjust the
392: * character buffer pointer.
393: */
394:
395: gnb()
396: {
397: fseek(fildes, 512L, 1) ;
398: fread(rbuf, sizeof(*rbufp), BSIZ, fildes) ;
399: rbufp = rbuf ;
400: return(1) ;
401: }
402:
403: /* gteol - Go to end of line. Returns the seek adress of the end of line.
404: */
405:
406: long
407: gteol(seek)
408: long seek ;
409: {
410: if (seek >= fsiz)
411: return(fsiz) ;
412: fseek(fildes, seek, 0) ;
413: while (fgetc(fildes) != '\n')
414: ;
415: return(ftell(fildes)) ;
416: }
417:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.