2023-07-27 14:04:50 -04:00
|
|
|
/*===========================================================================
|
2023-08-04 14:34:51 -04:00
|
|
|
Copyright (c) 1998-2000, The Santa Cruz Operation
|
2023-07-27 14:04:50 -04:00
|
|
|
All rights reserved.
|
2023-08-04 14:34:51 -04:00
|
|
|
|
2023-07-27 14:04:50 -04:00
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
*Redistributions of source code must retain the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer.
|
|
|
|
|
|
|
|
*Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer in the documentation
|
|
|
|
and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
*Neither name of The Santa Cruz Operation nor the names of its contributors
|
|
|
|
may be used to endorse or promote products derived from this software
|
2023-08-04 14:34:51 -04:00
|
|
|
without specific prior written permission.
|
2023-07-27 14:04:50 -04:00
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
2023-08-04 15:09:58 -04:00
|
|
|
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT falseT LIMITED TO,
|
2023-07-27 14:04:50 -04:00
|
|
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
2023-08-04 15:19:25 -04:00
|
|
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
2023-07-27 14:04:50 -04:00
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
2023-08-04 15:09:58 -04:00
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT falseT LIMITED TO, PROCUREMENT OF
|
2023-07-27 14:04:50 -04:00
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION)
|
|
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
2023-08-04 14:34:51 -04:00
|
|
|
DAMAGE.
|
2023-07-27 14:04:50 -04:00
|
|
|
=========================================================================*/
|
|
|
|
|
|
|
|
|
2023-08-04 13:49:03 -04:00
|
|
|
/* cscope - interactive C symbol cross-reference
|
2023-07-27 14:04:50 -04:00
|
|
|
*
|
2023-08-04 13:49:03 -04:00
|
|
|
* directory searching functions
|
2023-07-27 14:04:50 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "global.h"
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
#include "vp.h" /* vpdirs and vpndirs */
|
2023-07-27 14:04:50 -04:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
2023-08-13 05:21:52 -04:00
|
|
|
#include <sys/types.h> /* needed by stat.h and dirent.h */
|
2023-07-27 14:04:50 -04:00
|
|
|
#include <dirent.h>
|
2023-08-13 05:21:52 -04:00
|
|
|
#include <sys/stat.h> /* stat */
|
2023-07-27 14:04:50 -04:00
|
|
|
#include <assert.h>
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
#define DIRSEPS " ,:" /* directory list separators */
|
|
|
|
#define DIRINC 10 /* directory list size increment */
|
|
|
|
#define HASHMOD 2003 /* must be a prime number */
|
|
|
|
#define SRCINC HASHMOD /* source file list size increment */
|
|
|
|
/* largest known database had 22049 files */
|
|
|
|
|
|
|
|
char currentdir[PATHLEN + 1]; /* current directory */
|
|
|
|
char **incdirs; /* #include directories */
|
|
|
|
char **srcdirs; /* source directories */
|
|
|
|
char **srcfiles; /* source files */
|
|
|
|
unsigned long nincdirs; /* number of #include directories */
|
|
|
|
unsigned long nsrcdirs; /* number of source directories */
|
|
|
|
unsigned long nsrcfiles; /* number of source files */
|
|
|
|
unsigned long msrcfiles = SRCINC; /* maximum number of source files */
|
|
|
|
|
|
|
|
static char **incnames; /* #include directory names without view pathing */
|
|
|
|
static unsigned long mincdirs = DIRINC; /* maximum number of #include directories */
|
|
|
|
static unsigned long msrcdirs; /* maximum number of source directories */
|
|
|
|
static unsigned long nvpsrcdirs; /* number of view path source directories */
|
|
|
|
|
|
|
|
static struct listitem { /* source file names without view pathing */
|
|
|
|
char *text;
|
|
|
|
struct listitem *next;
|
2023-07-27 14:04:50 -04:00
|
|
|
} *srcnames[HASHMOD];
|
|
|
|
|
|
|
|
/* Internal prototypes: */
|
2023-08-13 05:21:52 -04:00
|
|
|
static bool accessible_file(char *file);
|
|
|
|
static bool issrcfile(char *file);
|
|
|
|
static void addsrcdir(char *dir);
|
|
|
|
static void addincdir(char *name, char *path);
|
|
|
|
static void scan_dir(const char *dirfile, bool recurse);
|
|
|
|
static void makevpsrcdirs(void);
|
2023-07-27 14:04:50 -04:00
|
|
|
|
|
|
|
/* make the view source directory list */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
static void makevpsrcdirs(void) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* return if this function has already been called */
|
|
|
|
if(nsrcdirs > 0) { return; }
|
|
|
|
/* get the current directory name */
|
|
|
|
if(getcwd(currentdir, PATHLEN) == NULL) {
|
|
|
|
fprintf(stderr, PROGRAM_NAME ": warning: cannot get current directory name\n");
|
|
|
|
strcpy(currentdir, "<unknown>");
|
|
|
|
}
|
|
|
|
/* see if there is a view path and this directory is in it */
|
|
|
|
vpinit(currentdir);
|
|
|
|
if(vpndirs > 1) {
|
|
|
|
nsrcdirs = vpndirs;
|
|
|
|
} else {
|
|
|
|
nsrcdirs = 1;
|
|
|
|
}
|
|
|
|
/* create the source directory list */
|
|
|
|
msrcdirs = nsrcdirs + DIRINC;
|
|
|
|
srcdirs = malloc(msrcdirs * sizeof(*srcdirs));
|
|
|
|
*srcdirs = "."; /* first source dir is always current dir */
|
|
|
|
for(i = 1; i < vpndirs; ++i) {
|
|
|
|
srcdirs[i] = vpdirs[i];
|
|
|
|
}
|
|
|
|
/* save the number of original source directories in the view path */
|
|
|
|
nvpsrcdirs = nsrcdirs;
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add a source directory to the list for each view path source directory */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
void sourcedir(char *dirlist) {
|
|
|
|
char path[PATHLEN + 1];
|
|
|
|
char *dir;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
makevpsrcdirs(); /* make the view source directory list */
|
|
|
|
dirlist = strdup(dirlist); /* don't change environment variable text */
|
|
|
|
|
|
|
|
/* parse the directory list */
|
|
|
|
dir = strtok(dirlist, DIRSEPS);
|
|
|
|
while(dir != NULL) {
|
|
|
|
int dir_len = strlen(dir);
|
|
|
|
|
|
|
|
addsrcdir(dir);
|
|
|
|
|
|
|
|
/* if it isn't a full path name and there is a
|
|
|
|
multi-directory view path */
|
|
|
|
if(*dirlist != '/' && vpndirs > 1) {
|
|
|
|
|
|
|
|
/* compute its path from higher view path source dirs */
|
|
|
|
for(i = 1; i < nvpsrcdirs; ++i) {
|
|
|
|
snprintf(path,
|
|
|
|
sizeof(path),
|
|
|
|
"%.*s/%s",
|
|
|
|
PATHLEN - 2 - dir_len,
|
|
|
|
srcdirs[i],
|
|
|
|
dir);
|
|
|
|
addsrcdir(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dir = strtok(NULL, DIRSEPS);
|
|
|
|
}
|
|
|
|
free(dirlist); /* HBB 20000421: avoid memory leaks */
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add a source directory to the list */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
static void addsrcdir(char *dir) {
|
|
|
|
struct stat statstruct;
|
|
|
|
|
|
|
|
/* make sure it is a directory */
|
|
|
|
if(lstat(compath(dir), &statstruct) == 0 && S_ISDIR(statstruct.st_mode)) {
|
|
|
|
|
|
|
|
/* note: there already is a source directory list */
|
|
|
|
if(nsrcdirs == msrcdirs) {
|
|
|
|
msrcdirs += DIRINC;
|
|
|
|
srcdirs = realloc(srcdirs, msrcdirs * sizeof(*srcdirs));
|
|
|
|
}
|
|
|
|
srcdirs[nsrcdirs++] = strdup(dir);
|
|
|
|
}
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* HBB 20000421: new function, for avoiding leaks */
|
|
|
|
/* free list of src directories */
|
2023-08-13 05:21:52 -04:00
|
|
|
void freesrclist() {
|
|
|
|
if(!srcdirs) return;
|
|
|
|
while(nsrcdirs > 1)
|
|
|
|
free(srcdirs[--nsrcdirs]);
|
|
|
|
free(srcdirs);
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add a #include directory to the list for each view path source directory */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
void includedir(char *dirlist) {
|
|
|
|
char path[PATHLEN + 1];
|
|
|
|
char *dir;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
makevpsrcdirs(); /* make the view source directory list */
|
|
|
|
dirlist = strdup(dirlist); /* don't change environment variable text */
|
|
|
|
|
|
|
|
/* parse the directory list */
|
|
|
|
dir = strtok(dirlist, DIRSEPS);
|
|
|
|
while(dir != NULL) {
|
|
|
|
size_t dir_len = strlen(dir);
|
|
|
|
|
|
|
|
addincdir(dir, dir);
|
|
|
|
|
|
|
|
/* if it isn't a full path name and there is a
|
|
|
|
multi-directory view path */
|
|
|
|
if(*dirlist != '/' && vpndirs > 1) {
|
|
|
|
|
|
|
|
/* compute its path from higher view path source dirs */
|
|
|
|
for(i = 1; i < nvpsrcdirs; ++i) {
|
|
|
|
snprintf(path,
|
|
|
|
sizeof(path),
|
|
|
|
"%.*s/%s",
|
|
|
|
(int)(PATHLEN - 2 - dir_len),
|
|
|
|
srcdirs[i],
|
|
|
|
dir);
|
|
|
|
addincdir(dir, path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dir = strtok(NULL, DIRSEPS);
|
|
|
|
}
|
|
|
|
free(dirlist); /* HBB 20000421: avoid leaks */
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add a #include directory to the list */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
static void addincdir(char *name, char *path) {
|
|
|
|
struct stat statstruct;
|
|
|
|
|
|
|
|
/* make sure it is a directory */
|
|
|
|
if(lstat(compath(path), &statstruct) == 0 && S_ISDIR(statstruct.st_mode)) {
|
|
|
|
if(incdirs == NULL) {
|
|
|
|
incdirs = malloc(mincdirs * sizeof(*incdirs));
|
|
|
|
incnames = malloc(mincdirs * sizeof(*incnames));
|
|
|
|
} else if(nincdirs == mincdirs) {
|
|
|
|
mincdirs += DIRINC;
|
|
|
|
incdirs = realloc(incdirs, mincdirs * sizeof(*incdirs));
|
|
|
|
incnames = realloc(incnames, mincdirs * sizeof(*incnames));
|
|
|
|
}
|
|
|
|
incdirs[nincdirs] = strdup(path);
|
|
|
|
incnames[nincdirs++] = strdup(name);
|
|
|
|
}
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* HBB 2000421: new function, for avoiding memory leaks */
|
|
|
|
/* free the list of include files, if wanted */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
void freeinclist() {
|
|
|
|
if(!incdirs) return;
|
|
|
|
while(nincdirs > 0) {
|
|
|
|
free(incdirs[--nincdirs]);
|
|
|
|
free(incnames[nincdirs]);
|
|
|
|
}
|
|
|
|
free(incdirs);
|
|
|
|
free(incnames);
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* make the source file list */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
void makefilelist(void) {
|
|
|
|
static bool firstbuild = true; /* first time through */
|
|
|
|
FILE *names; /* name file pointer */
|
|
|
|
char dir[PATHLEN + 1];
|
|
|
|
char path[PATHLEN + 1];
|
|
|
|
char line[PATHLEN * 10];
|
|
|
|
char *file;
|
|
|
|
char *s;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
makevpsrcdirs(); /* make the view source directory list */
|
|
|
|
|
|
|
|
/* if -i was falseT given and there are source file arguments */
|
|
|
|
if(namefile == NULL && fileargc > 0) {
|
|
|
|
|
|
|
|
/* put them in a list that can be expanded */
|
|
|
|
for(i = 0; i < fileargc; ++i) {
|
|
|
|
file = fileargv[i];
|
|
|
|
if(infilelist(file) == false) {
|
|
|
|
if((s = inviewpath(file)) != NULL) {
|
|
|
|
addsrcfile(s);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, PROGRAM_NAME ": cannot find file %s\n", file);
|
|
|
|
errorsfound = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* see if a file name file exists */
|
|
|
|
if(namefile == NULL && vpaccess(NAMEFILE, READ) == 0) { namefile = NAMEFILE; }
|
|
|
|
|
|
|
|
if(namefile == NULL) {
|
|
|
|
/* No namefile --> make a list of all the source files
|
|
|
|
* in the directories */
|
|
|
|
for(i = 0; i < nsrcdirs; ++i) {
|
|
|
|
scan_dir(srcdirs[i], recurse_dir);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Came here --> there is a file of source file names */
|
|
|
|
|
|
|
|
if(strcmp(namefile, "-") == 0)
|
|
|
|
names = stdin;
|
|
|
|
else if((names = vpfopen(namefile, "r")) == NULL) {
|
|
|
|
cannotopen(namefile);
|
|
|
|
myexit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the names in the file */
|
|
|
|
while(fgets(line, 10 * PATHLEN, names) != NULL) {
|
|
|
|
char *point_in_line = line + (strlen(line) - 1);
|
|
|
|
size_t length_of_name = 0;
|
|
|
|
int unfinished_option = 0;
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
/* Kill away \n left at end of fgets()'d string: */
|
|
|
|
if(*point_in_line == '\n') *point_in_line = '\0';
|
|
|
|
|
|
|
|
/* Parse whitespace-terminated strings in line: */
|
|
|
|
point_in_line = line;
|
|
|
|
while(sscanf(point_in_line, "%" PATHLEN_STR "s", path) == 1) {
|
|
|
|
/* Have to store this length --- inviewpath() will
|
|
|
|
* modify path, later! */
|
|
|
|
length_of_name = strlen(path);
|
|
|
|
|
|
|
|
if(*path == '-') { /* if an option */
|
|
|
|
if(unfinished_option) {
|
|
|
|
/* Can't have another option directly after an
|
|
|
|
* -I or -p option with no name after it! */
|
|
|
|
fprintf(stderr,
|
|
|
|
PROGRAM_NAME
|
|
|
|
": Syntax error in namelist file %s: unfinished -I or -p option\n",
|
|
|
|
namefile);
|
|
|
|
unfinished_option = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = path[1];
|
|
|
|
switch(i) {
|
|
|
|
case 'c': /* ASCII characters only in crossref */
|
|
|
|
compress = false;
|
|
|
|
break;
|
|
|
|
case 'k': /* ignore DFLT_INCDIR */
|
|
|
|
kernelmode = true;
|
|
|
|
break;
|
|
|
|
case 'q': /* quick search */
|
|
|
|
invertedindex = true;
|
|
|
|
break;
|
|
|
|
case 'T': /* truncate symbols to 8 characters */
|
|
|
|
trun_syms = true;
|
|
|
|
break;
|
|
|
|
case 'I': /* #include file directory */
|
|
|
|
case 'p': /* file path components to display */
|
|
|
|
/* coverity[overwrite_var] */
|
|
|
|
s = path + 2; /* for "-Ipath" */
|
|
|
|
if(*s == '\0') { /* if "-I path" */
|
|
|
|
unfinished_option = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this code block used several times in here
|
|
|
|
* --> make it a macro to avoid unnecessary
|
|
|
|
* duplication */
|
|
|
|
#define HANDLE_OPTION_ARGUMENT(i, s) \
|
|
|
|
switch(i) { \
|
|
|
|
case 'I': /* #include file directory */ \
|
|
|
|
if(firstbuild == true) { \
|
|
|
|
/* expand $ and ~ */ \
|
|
|
|
shellpath(dir, sizeof(dir), (s)); \
|
|
|
|
includedir(dir); \
|
|
|
|
} \
|
|
|
|
unfinished_option = 0; \
|
|
|
|
done = true; \
|
|
|
|
break; \
|
|
|
|
case 'p': /* file path components to display */ \
|
|
|
|
if(*(s) < '0' || *(s) > '9') { \
|
|
|
|
fprintf(stderr, \
|
|
|
|
"csope: -p option in file %s: missing or invalid numeric value\n", \
|
|
|
|
namefile); \
|
|
|
|
} \
|
|
|
|
dispcomponents = atoi(s); \
|
|
|
|
unfinished_option = 0; \
|
|
|
|
done = true; \
|
|
|
|
break; \
|
|
|
|
default: \
|
|
|
|
done = false; \
|
|
|
|
} /* switch(i) */
|
|
|
|
|
|
|
|
/* ... and now call it for the first time */
|
|
|
|
HANDLE_OPTION_ARGUMENT(i, s)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr,
|
|
|
|
PROGRAM_NAME
|
|
|
|
": only -I, -c, -k, -p, and -T options can be in file %s\n",
|
|
|
|
namefile);
|
|
|
|
} /* switch(i) */
|
|
|
|
} /* if('-') */
|
|
|
|
else if(*path == '"') {
|
|
|
|
/* handle quoted filenames... */
|
|
|
|
size_t in = 1, out = 0;
|
|
|
|
char *newpath = malloc(PATHLEN + 1);
|
|
|
|
|
|
|
|
while(in < PATHLEN && point_in_line[in] != '\0') {
|
|
|
|
if(point_in_line[in] == '"') {
|
|
|
|
newpath[out] = '\0';
|
|
|
|
/* Tell outer loop to skip over this entire
|
|
|
|
* quoted string */
|
|
|
|
length_of_name = in + 1;
|
|
|
|
break; /* found end of quoted string */
|
|
|
|
} else if(point_in_line[in] == '\\' && in < PATHLEN - 1 &&
|
|
|
|
(point_in_line[in + 1] == '"' ||
|
|
|
|
point_in_line[in + 1] == '\\')) {
|
|
|
|
/* un-escape \" or \\ sequence */
|
|
|
|
newpath[out++] = point_in_line[in + 1];
|
|
|
|
in += 2;
|
|
|
|
} else {
|
|
|
|
newpath[out++] = point_in_line[in++];
|
|
|
|
}
|
|
|
|
} /* while(in) */
|
|
|
|
if(in >= PATHLEN) { /* safeguard against almost-overflow */
|
|
|
|
newpath[out] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If an -I or -p arguments was missing before,
|
|
|
|
* treat this name as the argument: */
|
|
|
|
HANDLE_OPTION_ARGUMENT(unfinished_option, newpath);
|
|
|
|
if(!done) {
|
|
|
|
/* coverity[overwrite_var] */
|
|
|
|
if((s = inviewpath(newpath)) != NULL) {
|
|
|
|
addsrcfile(s);
|
|
|
|
} else {
|
2023-09-25 17:15:52 -04:00
|
|
|
fprintf(stderr, PROGRAM_NAME ": cannot find file %s\n", newpath);
|
2023-08-13 05:21:52 -04:00
|
|
|
errorsfound = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(newpath);
|
|
|
|
} /* if(quoted name) */
|
|
|
|
else {
|
|
|
|
/* ... so this is an ordinary file name, unquoted */
|
|
|
|
|
|
|
|
/* If an -I or -p arguments was missing before,
|
|
|
|
* treat this name as the argument: */
|
|
|
|
HANDLE_OPTION_ARGUMENT(unfinished_option, path);
|
|
|
|
if(!done) {
|
|
|
|
if((s = inviewpath(path)) != NULL) {
|
|
|
|
addsrcfile(s);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, PROGRAM_NAME ": cannot find file %s\n", path);
|
|
|
|
errorsfound = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* else(ordinary name) */
|
|
|
|
|
|
|
|
point_in_line += length_of_name;
|
|
|
|
while(isspace((unsigned char)*point_in_line))
|
|
|
|
point_in_line++;
|
|
|
|
} /* while(sscanf(line)) */
|
|
|
|
} /* while(fgets(line)) */
|
|
|
|
|
|
|
|
if(names == stdin)
|
|
|
|
clearerr(stdin);
|
|
|
|
else
|
|
|
|
fclose(names);
|
|
|
|
firstbuild = false;
|
|
|
|
return;
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* scan a directory (recursively?) for source files */
|
2023-08-13 05:21:52 -04:00
|
|
|
static void scan_dir(const char *adir, bool recurse_dir) {
|
|
|
|
DIR *dirfile;
|
|
|
|
int adir_len = strlen(adir);
|
|
|
|
|
|
|
|
/* FIXME: no guards against adir_len > PATHLEN, yet */
|
|
|
|
|
|
|
|
if((dirfile = opendir(adir)) != NULL) {
|
|
|
|
struct dirent *entry;
|
|
|
|
char path[PATHLEN + 1];
|
|
|
|
|
|
|
|
while((entry = readdir(dirfile)) != NULL) {
|
|
|
|
if((strcmp(".", entry->d_name) != 0) && (strcmp("..", entry->d_name) != 0)) {
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
snprintf(path,
|
|
|
|
sizeof(path),
|
|
|
|
"%s/%.*s",
|
|
|
|
adir,
|
|
|
|
PATHLEN - 2 - adir_len,
|
|
|
|
entry->d_name);
|
|
|
|
|
|
|
|
if(lstat(path, &buf) == 0) {
|
|
|
|
if(recurse_dir && S_ISDIR(buf.st_mode)) {
|
|
|
|
scan_dir(path, recurse_dir);
|
|
|
|
} else if(issrcfile(path) && infilelist(path) == false &&
|
|
|
|
access(path, R_OK) == 0) {
|
|
|
|
addsrcfile(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(dirfile);
|
|
|
|
}
|
|
|
|
return;
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* see if this is a source file */
|
2023-08-13 05:21:52 -04:00
|
|
|
static bool issrcfile(char *path) {
|
|
|
|
struct stat statstruct;
|
2023-09-25 17:15:52 -04:00
|
|
|
const char *file = basename(path);
|
2023-08-13 05:21:52 -04:00
|
|
|
char *s = strrchr(file, '.');
|
|
|
|
bool looks_like_source = false;
|
|
|
|
|
|
|
|
/* ensure there is some file suffix */
|
2023-09-02 18:18:22 -04:00
|
|
|
if(s == NULL || *(++s) == '\0') { return false; }
|
2023-08-13 05:21:52 -04:00
|
|
|
|
|
|
|
/* if an SCCS or versioned file */
|
|
|
|
if(file[1] == '.' && file + 2 != s) { /* 1 character prefix */
|
|
|
|
switch(*file) {
|
|
|
|
case 's':
|
|
|
|
case 'S':
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(s[1] == '\0') { /* 1 character suffix */
|
|
|
|
switch(*s) {
|
|
|
|
case 'c':
|
|
|
|
case 'h':
|
|
|
|
case 'l':
|
|
|
|
case 'y':
|
|
|
|
case 'C':
|
|
|
|
case 'G':
|
|
|
|
case 'H':
|
|
|
|
case 'L':
|
|
|
|
looks_like_source = true;
|
|
|
|
}
|
|
|
|
} else if((s[2] == '\0') /* 2 char suffix */
|
|
|
|
&& ((s[0] == 'b' && s[1] == 'p') /* breakpoint listing */
|
|
|
|
|| (s[0] == 'q' && (s[1] == 'c' || s[1] == 'h')) /* Ingres */
|
|
|
|
|| (s[0] == 's' && s[1] == 'd') /* SDL */
|
|
|
|
|| (s[0] == 'c' && s[1] == 'c') /* C++ source */
|
|
|
|
|| (s[0] == 'h' && s[1] == 'h'))) { /* C++ header */
|
|
|
|
looks_like_source = true;
|
|
|
|
|
|
|
|
} else if((s[3] == '\0') /* 3 char suffix */
|
|
|
|
/* C++ template source */
|
|
|
|
&& ((s[0] == 't' && s[1] == 'c' && s[2] == 'c')
|
|
|
|
/* C++ source: */
|
|
|
|
|| (s[0] == 'c' && s[1] == 'p' && s[2] == 'p') ||
|
|
|
|
(s[0] == 'c' && s[1] == 'x' && s[2] == 'x') ||
|
|
|
|
(s[0] == 'h' && s[1] == 'p' && s[2] == 'p') ||
|
|
|
|
(s[0] == 'h' && s[1] == 'x' && s[2] == 'x'))) {
|
|
|
|
looks_like_source = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(looks_like_source != true) return false;
|
|
|
|
|
|
|
|
/* make sure it is a file */
|
|
|
|
if(lstat(path, &statstruct) == 0 && S_ISREG(statstruct.st_mode)) { return (true); }
|
|
|
|
return false;
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add an include file to the source file list */
|
2023-08-13 05:21:52 -04:00
|
|
|
void incfile(char *file, char *type) {
|
|
|
|
char name[PATHLEN + 1];
|
|
|
|
char path[PATHLEN + 1];
|
|
|
|
char *s;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
assert(file != NULL); /* should never happen, but let's make sure anyway */
|
|
|
|
/* see if the file is already in the source file list */
|
|
|
|
if(infilelist(file) == true) { return; }
|
|
|
|
/* look in current directory if it was #include "file" */
|
|
|
|
if(type[0] == '"' && (s = inviewpath(file)) != NULL) {
|
|
|
|
addsrcfile(s);
|
|
|
|
} else {
|
|
|
|
size_t file_len = strlen(file);
|
|
|
|
|
|
|
|
/* search for the file in the #include directory list */
|
|
|
|
for(i = 0; i < nincdirs; ++i) {
|
|
|
|
/* don't include the file from two directories */
|
|
|
|
snprintf(name,
|
|
|
|
sizeof(name),
|
|
|
|
"%.*s/%s",
|
|
|
|
(int)(PATHLEN - 2 - file_len),
|
|
|
|
incnames[i],
|
|
|
|
file);
|
|
|
|
if(infilelist(name) == true) { break; }
|
|
|
|
/* make sure it exists and is readable */
|
|
|
|
snprintf(path,
|
|
|
|
sizeof(path),
|
|
|
|
"%.*s/%s",
|
|
|
|
(int)(PATHLEN - 2 - file_len),
|
|
|
|
incdirs[i],
|
|
|
|
file);
|
|
|
|
if(access(compath(path), READ) == 0) {
|
|
|
|
addsrcfile(path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* see if the file is already in the list */
|
2023-08-13 05:21:52 -04:00
|
|
|
bool infilelist(char *path) {
|
|
|
|
struct listitem *p;
|
2023-07-27 14:04:50 -04:00
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
for(p = srcnames[hash(compath(path)) % HASHMOD]; p != NULL; p = p->next) {
|
|
|
|
if(strequal(path, p->text)) { return (true); }
|
|
|
|
}
|
|
|
|
return (false);
|
|
|
|
}
|
2023-07-27 14:04:50 -04:00
|
|
|
|
|
|
|
/* check if a file is readable enough to be allowed in the
|
|
|
|
* database */
|
2023-08-13 05:21:52 -04:00
|
|
|
static bool accessible_file(char *file) {
|
|
|
|
if(access(compath(file), READ) == 0) {
|
|
|
|
struct stat stats;
|
|
|
|
|
|
|
|
if(lstat(file, &stats) == 0 && S_ISREG(stats.st_mode)) { return true; }
|
|
|
|
}
|
|
|
|
return false;
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* search for the file in the view path */
|
2023-08-13 05:21:52 -04:00
|
|
|
char *inviewpath(char *file) {
|
|
|
|
static char path[PATHLEN + 1];
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
/* look for the file */
|
|
|
|
if(accessible_file(file)) { return (file); }
|
|
|
|
|
|
|
|
/* if it isn't a full path name and there is a multi-directory
|
|
|
|
* view path */
|
|
|
|
if(*file != '/' && vpndirs > 1) {
|
|
|
|
int file_len = strlen(file);
|
|
|
|
|
|
|
|
/* compute its path from higher view path source dirs */
|
|
|
|
for(i = 1; i < nvpsrcdirs; ++i) {
|
|
|
|
snprintf(path,
|
|
|
|
sizeof(path),
|
|
|
|
"%.*s/%s",
|
|
|
|
PATHLEN - 2 - file_len,
|
|
|
|
srcdirs[i],
|
|
|
|
file);
|
|
|
|
if(accessible_file(path)) { return (path); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (NULL);
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add a source file to the list */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
void addsrcfile(char *path) {
|
|
|
|
struct listitem *p;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* make sure there is room for the file */
|
|
|
|
if(nsrcfiles == msrcfiles) {
|
|
|
|
msrcfiles += SRCINC;
|
|
|
|
srcfiles = realloc(srcfiles, msrcfiles * sizeof(*srcfiles));
|
|
|
|
}
|
|
|
|
/* add the file to the list */
|
|
|
|
srcfiles[nsrcfiles++] = strdup(compath(path));
|
|
|
|
p = malloc(sizeof(*p));
|
|
|
|
p->text = strdup(compath(path));
|
|
|
|
i = hash(p->text) % HASHMOD;
|
|
|
|
p->next = srcnames[i];
|
|
|
|
srcnames[i] = p;
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free the memory allocated for the source file list */
|
|
|
|
|
2023-08-13 05:21:52 -04:00
|
|
|
void freefilelist(void) {
|
|
|
|
struct listitem *p, *nextp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* if '-d' option is used a string space block is allocated */
|
|
|
|
if(isuptodate == false) {
|
|
|
|
while(nsrcfiles > 0) {
|
|
|
|
free(srcfiles[--nsrcfiles]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* for '-d' option free the string space block */
|
|
|
|
/* protect against empty list */
|
|
|
|
if(nsrcfiles > 0) free(srcfiles[0]);
|
|
|
|
nsrcfiles = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(srcfiles); /* HBB 20000421: avoid leak */
|
|
|
|
msrcfiles = 0;
|
|
|
|
srcfiles = 0;
|
|
|
|
|
|
|
|
for(i = 0; i < HASHMOD; ++i) {
|
|
|
|
for(p = srcnames[i]; p != NULL; p = nextp) {
|
|
|
|
/* HBB 20000421: avoid memory leak */
|
|
|
|
free(p->text);
|
|
|
|
nextp = p->next;
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
srcnames[i] = NULL;
|
|
|
|
}
|
2023-07-27 14:04:50 -04:00
|
|
|
}
|