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