1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1988 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32
33 /*
34 * cscope - interactive C symbol cross-reference
35 *
36 * directory searching functions
37 */
38
39 #include <sys/types.h> /* needed by stat.h */
40 #include <sys/stat.h> /* stat */
41 #include "global.h"
42 #include "dirent.h"
43 #include "vp.h" /* vpdirs and vpndirs */
44
45 #define DIRSEPS " ,:" /* directory list separators */
46 #define DIRINC 10 /* directory list size increment */
47 #define HASHMOD 2003 /* must be a prime number */
48 #define SRCINC HASHMOD /* source file list size increment */
49 /* largest known database had 22049 files */
50
51 char **incdirs; /* #include directories */
52 char **srcdirs; /* source directories */
53 char **srcfiles; /* source files */
54 int nincdirs; /* number of #include directories */
55 int mincdirs = DIRINC; /* maximum number of #include directories */
56 int nsrcdirs; /* number of source directories */
57 int msrcdirs = DIRINC; /* maximum number of source directories */
58 int nsrcfiles; /* number of source files */
59 int msrcfiles = SRCINC; /* maximum number of source files */
60
61 static struct listitem { /* source file table entry */
62 char *file;
63 struct listitem *next;
64 } *srcfiletable[HASHMOD];
65
66
67 static void getsrcfiles(char *vpdir, char *dir);
68 static BOOL issrcfile(char *file);
69
70 /* add a source directory to the list for each view path source directory */
71
72 void
sourcedir(char * dirlist)73 sourcedir(char *dirlist)
74 {
75 struct stat statstruct;
76 char *dir;
77
78 /* don't change environment variable text */
79 dirlist = stralloc(dirlist);
80
81 /* parse the directory list */
82 dir = strtok(dirlist, DIRSEPS);
83 while (dir != NULL) {
84 /*
85 * make sure it is a directory (must exist in current
86 * view path node)
87 */
88 if (stat(compath(dir), &statstruct) == 0 &&
89 S_ISDIR(statstruct.st_mode)) {
90 if (srcdirs == NULL) {
91 srcdirs = mymalloc(msrcdirs * sizeof (char *));
92 } else if (nsrcdirs == msrcdirs) {
93 msrcdirs += DIRINC;
94 srcdirs = myrealloc(srcdirs,
95 msrcdirs * sizeof (char *));
96 }
97 srcdirs[nsrcdirs++] = stralloc(dir);
98 }
99 dir = strtok((char *)NULL, DIRSEPS);
100 }
101 }
102
103 /* add a #include directory to the list for each view path source directory */
104
105 void
includedir(char * dirlist)106 includedir(char *dirlist)
107 {
108 struct stat statstruct;
109 char *dir;
110
111 /* don't change environment variable text */
112 dirlist = stralloc(dirlist);
113
114 /* parse the directory list */
115 dir = strtok(dirlist, DIRSEPS);
116 while (dir != NULL) {
117
118 /*
119 * make sure it is a directory (must exist in current
120 * view path node)
121 */
122 if (stat(compath(dir), &statstruct) == 0 &&
123 S_ISDIR(statstruct.st_mode)) {
124 if (incdirs == NULL) {
125 incdirs = mymalloc(mincdirs * sizeof (char *));
126 } else if (nincdirs == mincdirs) {
127 mincdirs += DIRINC;
128 incdirs = myrealloc(incdirs,
129 mincdirs * sizeof (char *));
130 }
131 incdirs[nincdirs++] = stralloc(dir);
132 }
133 dir = strtok((char *)NULL, DIRSEPS);
134 }
135 }
136
137 /* make the source file list */
138
139 void
makefilelist(void)140 makefilelist(void)
141 {
142 static BOOL firstbuild = YES; /* first time through */
143 FILE *names; /* name file pointer */
144 char dir[PATHLEN + 1];
145 char path[PATHLEN + 1];
146 struct stat statstruct;
147 char *file;
148 char *s;
149 int i, j;
150
151 /* if there are source file arguments */
152 if (fileargc > 0) {
153 /* put them in a list that can be expanded */
154 for (i = 0; i < fileargc; ++i) {
155 file = fileargv[i];
156 if (infilelist(file) == NO) {
157 if (vpaccess(file, READ) == 0) {
158 addsrcfile(file);
159 } else {
160 (void) fprintf(stderr,
161 "cscope: cannot find file %s\n",
162 file);
163 errorsfound = YES;
164 }
165 }
166 }
167 return;
168 }
169 /* see if a file name file exists */
170 if (namefile == NULL && vpaccess(NAMEFILE, READ) == 0) {
171 namefile = NAMEFILE;
172 }
173 /* if there is a file of source file names */
174 if (namefile != NULL) {
175 if ((names = vpfopen(namefile, "r")) == NULL) {
176 cannotopen(namefile);
177 myexit(1);
178 }
179 /* get the names in the file */
180 while (fscanf(names, "%s", path) == 1) {
181 if (*path == '-') { /* if an option */
182 i = path[1];
183 switch (i) {
184 case 'q': /* quick search */
185 invertedindex = YES;
186 break;
187 case 'T':
188 /* truncate symbols to 8 characters */
189 truncatesyms = YES;
190 break;
191 case 'I': /* #include file directory */
192 case 'p': /* file path components to */
193 /* display */
194 s = path + 2; /* for "-Ipath" */
195 if (*s == '\0') { /* if "-I path" */
196 (void) fscanf(names,
197 "%s", path);
198 s = path;
199 }
200 switch (i) {
201 case 'I': /* #include file directory */
202 if (firstbuild == YES) {
203 /* expand $ and ~ */
204 shellpath(dir,
205 sizeof (dir), s);
206 includedir(dir);
207 }
208 break;
209 case 'p':
210 /* file path components */
211 /* to display */
212 if (*s < '0' || *s > '9') {
213 (void) fprintf(stderr,
214 "cscope: -p option "
215 "in file %s: "
216 "missing or "
217 "invalid numeric "
218 "value\n",
219 namefile);
220 }
221 dispcomponents = atoi(s);
222 break;
223 }
224 break;
225 default:
226 (void) fprintf(stderr,
227 "cscope: only -I, -p, and -T "
228 "options can be in file %s\n",
229 namefile);
230 }
231 } else if (vpaccess(path, READ) == 0) {
232 addsrcfile(path);
233 } else {
234 (void) fprintf(stderr,
235 "cscope: cannot find file %s\n",
236 path);
237 errorsfound = YES;
238 }
239 }
240 (void) fclose(names);
241 firstbuild = NO;
242 return;
243 }
244 /* make a list of all the source files in the directories */
245 for (i = 0; i < nsrcdirs; ++i) {
246 s = srcdirs[i];
247 getsrcfiles(s, s);
248 if (*s != '/') { /* if it isn't a full path name */
249
250 /* compute its path from any higher view path nodes */
251 for (j = 1; j < vpndirs; ++j) {
252 (void) sprintf(dir, "%s/%s", vpdirs[j], s);
253
254 /* make sure it is a directory */
255 if (stat(compath(dir), &statstruct) == 0 &&
256 S_ISDIR(statstruct.st_mode)) {
257 getsrcfiles(dir, s);
258 }
259 }
260 }
261 }
262 }
263
264 /* get the source file names in this directory */
265
266 static void
getsrcfiles(char * vpdir,char * dir)267 getsrcfiles(char *vpdir, char *dir)
268 {
269 DIR *dirfile; /* directory file descriptor */
270 struct dirent *entry; /* directory entry pointer */
271 char path[PATHLEN + 1];
272
273 /* attempt to open the directory */
274 if ((dirfile = opendir(vpdir)) != NULL) {
275
276 /* read each entry in the directory */
277 while ((entry = readdir(dirfile)) != NULL) {
278
279 /* if it is a source file not already found */
280 (void) sprintf(path, "%s/%s", dir, entry->d_name);
281 if (entry->d_ino != 0 &&
282 issrcfile(path) && infilelist(path) == NO) {
283 addsrcfile(path); /* add it to the list */
284 }
285 }
286 closedir(dirfile);
287 }
288 }
289
290 /* see if this is a source file */
291
292 static BOOL
issrcfile(char * file)293 issrcfile(char *file)
294 {
295 struct stat statstruct;
296 char *s;
297
298 /* if there is a file suffix */
299 if ((s = strrchr(file, '.')) != NULL && *++s != '\0') {
300
301 /* if an SCCS or versioned file */
302 if (file[1] == '.' && file + 2 != s) { /* 1 character prefix */
303 switch (*file) {
304 case 's':
305 case 'S':
306 return (NO);
307 }
308 }
309 if (s[1] == '\0') { /* 1 character suffix */
310 switch (*s) {
311 case 'c':
312 case 'h':
313 case 'l':
314 case 'y':
315 case 'C':
316 case 'G':
317 case 'H':
318 case 'L':
319 return (YES);
320 }
321 } else if (s[2] == '\0') { /* 2 character suffix */
322 if (*s == 'b' && s[1] == 'p' || /* breakpoint listing */
323 *s == 'q' &&
324 (s[1] == 'c' || s[1] == 'h') || /* Ingres */
325 *s == 'p' && s[1] == 'r' || /* SDL */
326 *s == 's' && s[1] == 'd') { /* SDL */
327
328 /*
329 * some directories have 2 character
330 * suffixes so make sure it is a file
331 */
332 if (vpstat(file, &statstruct) == 0 &&
333 S_ISREG(statstruct.st_mode)) {
334 return (YES);
335 }
336 }
337 }
338 }
339 return (NO);
340 }
341
342 /* add an include file to the source file list */
343
344 void
incfile(char * file,int type)345 incfile(char *file, int type)
346 {
347 char path[PATHLEN + 1];
348 int i;
349
350 /* see if the file is already in the source file list */
351 if (infilelist(file) == YES) {
352 return;
353 }
354 /* look in current directory if it was #include "file" */
355 if (type == '"' && vpaccess(file, READ) == 0) {
356 addsrcfile(file);
357 } else {
358 /* search for the file in the #include directory list */
359 for (i = 0; i < nincdirs; ++i) {
360
361 /* don't include the file from two directories */
362 (void) sprintf(path, "%s/%s", incdirs[i], file);
363 if (infilelist(path) == YES) {
364 break;
365 }
366 /* make sure it exists and is readable */
367 if (vpaccess(compath(path), READ) == 0) {
368 addsrcfile(path);
369 break;
370 }
371 }
372 }
373 }
374
375 /* see if the file is already in the list */
376
377 BOOL
infilelist(char * file)378 infilelist(char *file)
379 {
380 struct listitem *p;
381
382 for (p = srcfiletable[hash(compath(file)) % HASHMOD];
383 p != NULL; p = p->next) {
384 if (strequal(file, p->file)) {
385 return (YES);
386 }
387 }
388 return (NO);
389 }
390
391 /* add a source file to the list */
392
393 void
addsrcfile(char * path)394 addsrcfile(char *path)
395 {
396 struct listitem *p;
397 int i;
398
399 /* make sure there is room for the file */
400 if (nsrcfiles == msrcfiles) {
401 msrcfiles += SRCINC;
402 srcfiles = myrealloc(srcfiles, msrcfiles * sizeof (char *));
403 }
404 /* add the file to the list */
405 p = (struct listitem *)mymalloc(sizeof (struct listitem));
406 p->file = stralloc(compath(path));
407 i = hash(p->file) % HASHMOD;
408 p->next = srcfiletable[i];
409 srcfiletable[i] = p;
410 srcfiles[nsrcfiles++] = p->file;
411 }
412
413 /* free the memory allocated for the source file list */
414
415 void
freefilelist(void)416 freefilelist(void)
417 {
418 struct listitem *p, *nextp;
419 int i;
420
421 while (nsrcfiles > 0) {
422 free(srcfiles[--nsrcfiles]);
423 }
424 for (i = 0; i < HASHMOD; ++i) {
425 for (p = srcfiletable[i]; p != NULL; p = nextp) {
426 nextp = p->next;
427 free(p);
428 }
429 srcfiletable[i] = NULL;
430 }
431 }
432