xref: /illumos-gate/usr/src/tools/cscope-fast/dir.c (revision a38ddfee9c8c6b6c5a2947ff52fd2338362a4444)
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
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
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
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
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
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
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
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
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
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