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