xref: /original-bsd/usr.bin/look/look.c (revision 42b80877)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1987 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)look.c	4.7 (Berkeley) 05/11/89";
15 #endif not lint
16 
17 #include <sys/types.h>
18 #include <sys/file.h>
19 #include <sys/stat.h>
20 #include <stdio.h>
21 #include <ctype.h>
22 #include "pathnames.h"
23 
24 #define	EOS		'\0'
25 #define	MAXLINELEN	250
26 #define	YES		1
27 
28 static int	fold, dict, len;
29 
30 main(argc, argv)
31 	int	argc;
32 	char	**argv;
33 {
34 	extern char	*optarg;
35 	extern int	optind;
36 	static char	*filename = _PATH_WORDS;
37 	register off_t	bot, mid, top;
38 	register int	c;
39 	struct stat	sb;
40 	char	entry[MAXLINELEN], copy[MAXLINELEN];
41 
42 	while ((c = getopt(argc, argv, "df")) != EOF)
43 		switch((char)c) {
44 		case 'd':
45 			dict = YES;
46 			break;
47 		case 'f':
48 			fold = YES;
49 			break;
50 		case '?':
51 		default:
52 			usage();
53 		}
54 	argv += optind;
55 	argc -= optind;
56 
57 	switch(argc) {
58 	case 1:	/* if default file, set to dictionary order and folding */
59 		dict = fold = YES;
60 		break;
61 	case 2:
62 		filename = argv[1];
63 		break;
64 	default:
65 		usage();
66 	}
67 
68 	if (!freopen(filename, "r", stdin)) {
69 		fprintf(stderr,"look: can't read %s.\n", filename);
70 		exit(2);
71 	}
72 	if (fstat(fileno(stdin), &sb)) {
73 		perror("look: fstat");
74 		exit(2);
75 	}
76 
77 	len = strlen(*argv);
78 	canon(*argv, *argv);
79 	len = strlen(*argv);		/* may have changed */
80 	if (len > MAXLINELEN - 1) {
81 		fputs("look: search string is too long.\n", stderr);
82 		exit(2);
83 	}
84 
85 	for (bot = 0, top = sb.st_size;;) {
86 		mid = (top + bot) / 2;
87 		(void)fseek(stdin, mid, L_SET);
88 
89 		for (++mid; (c = getchar()) != EOF && c != '\n'; ++mid);
90 		if (!getline(entry))
91 			break;
92 		canon(entry, copy);
93 		if (strncmp(*argv, copy, len) <= 0) {
94 			if (top <= mid)
95 				break;
96 			top = mid;
97 		}
98 		else
99 			bot = mid;
100 	}
101 	(void)fseek(stdin, bot, L_SET);
102 	while (ftell(stdin) < top) {
103 		register int val;
104 
105 		if (!getline(entry))
106 			exit(0);
107 		canon(entry, copy);
108 		if (!(val = strncmp(*argv, copy, len))) {
109 			puts(entry);
110 			break;
111 		}
112 		if (val < 0)
113 			exit(0);
114 	}
115 	while (getline(entry)) {
116 		canon(entry, copy);
117 		if (strncmp(*argv, copy, len))
118 			break;
119 		puts(entry);
120 	}
121 	exit(0);
122 }
123 
124 /*
125  * getline --
126  *	get a line
127  */
128 static
129 getline(buf)
130 	register char	*buf;
131 {
132 	register int	c;
133 
134 	for (;;) {
135 		if ((c = getchar()) == EOF)
136 			return(0);
137 		if (c == '\n')
138 			break;
139 		*buf++ = c;
140 	}
141 	*buf = EOS;
142 	return(1);
143 }
144 
145 /*
146  * canon --
147  *	create canonical version of word
148  */
149 static
150 canon(src, copy)
151 	register char	*src, *copy;
152 {
153 	register int	cnt;
154 	register char	c;
155 
156 	for (cnt = len + 1; (c = *src++) && cnt; --cnt)
157 		if (!dict || isalnum(c))
158 			*copy++ = fold && isupper(c) ? tolower(c) : c;
159 	*copy = EOS;
160 }
161 
162 /*
163  * usage --
164  *	print a usage message and die
165  */
166 static
167 usage()
168 {
169 	fputs("usage: look [-df] string [file]\n", stderr);
170 	exit(1);
171 }
172