1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

SCP: Add CheckSourceCode facility to validate simh project standards

This commit is contained in:
Mark Pizzolato 2023-03-04 13:47:23 -10:00
parent c333a5f886
commit c7d01273df
5 changed files with 676 additions and 28 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.git-commit-id
.git-commit-id.h
#ignore thumbnails created by windows
Thumbs.db
#ignore Desktop Services Store created by OSX

View File

@ -2888,6 +2888,10 @@ else # end of primary make recipies
CC := @$(CC)
endif
# Extract source directories from the dependencies
D1 = $(sort $(foreach dir,$(DEPS),$(dir $(dir))))
# Extract potential source code directories from the -I specifiers in the options
space = $(empty) $(empty)
@ -2905,7 +2909,7 @@ else # end of primary make recipies
D6=$(foreach include,$(D5),$(patsubst ^-I%,%,$(include)))
# chop off any extra options beyond the include directory
D7=$(foreach include,$(D6),$(word 1,$(subst ^,$(space),$(include))))
DIRS = $(D7)
DIRS = $(strip $(D1) $(D7))
ifneq ($(WIN32),)
pathfix = $(subst /,\,$(1))
@ -3066,6 +3070,9 @@ $(TARGET): $(DEPS)
# invoke the just built simulator to engage its test activities
$@ $(call find_test,$(word 1,$(DIRS)),$(TEST_NAME)) ${TEST_ARG}
endif
ifneq (,$(SOURCE_CHECK))
$@ $(SOURCE_CHECK_SWITCHES) CheckSourceCode $(DEPS)
endif
endif # CPP_BUILD
endif # makefile recursion build support

5
scp.c
View File

@ -2968,6 +2968,11 @@ AIO_INIT; /* init Asynch I/O */
sim_finit (); /* init fio package */
sim_disk_init (); /* init disk package */
sim_tape_init (); /* init tape package */
if ((argc > 2) &&
(sim_strcasecmp (argv[1], "CheckSourceCode") == 0)) {
return sim_check_source (argc - 1, argv + 1);
}
for (i = 0; cmd_table[i].name; i++) {
size_t alias_len = strlen (cmd_table[i].name);
char *cmd_name = (char *)calloc (1 + alias_len, sizeof (*cmd_name));

668
sim_fio.c
View File

@ -564,12 +564,22 @@ static struct get_filelist_test {
int expected_count;
} get_test[] = {
{"test-1",
{"file.txt",
NULL},
"file.txt", 1},
{"test-2",
{"aab/bbc/ccd/eef/file.txt",
"aab/bbc/ccd/eef/file2.txt",
"aac/bbd/cce/eef/file2.txt",
NULL},
"file.txt", 1},
{"test-3",
{"aab/bbc/ccd/eef/file.txt",
"aab/bbc/ccd/eef/file2.txt",
"aac/bbd/cce/eef/file2.txt",
NULL},
"*.txt", 3},
{"test-2",
{"test-4",
{"xab/bbc/ccd/eef/file.txt",
"xab/bbc/ccd/eef/file2.bbb",
"xac/bbd/cce/eef/file2.txt",
@ -590,8 +600,8 @@ char test_desc[512];
uint8 result[512];
sim_register_internal_device (&sim_fio_test_dev);
sim_fio_test_dev.dctrl = (sim_switches & SWMASK ('D')) ? FIO_DBG_PACK : 0;
sim_fio_test_dev.dctrl = (sim_switches & SWMASK ('S')) ? FIO_DBG_SCAN : 0;
sim_fio_test_dev.dctrl |= (sim_switches & SWMASK ('D')) ? FIO_DBG_PACK : 0;
sim_fio_test_dev.dctrl |= (sim_switches & SWMASK ('S')) ? FIO_DBG_SCAN : 0;
sim_set_deb_switches (SWMASK ('F'));
sim_messagef (SCPE_OK, "sim_buf_pack_unpack - tests\n");
for (pt = p_test; pt->src; ++pt) {
@ -722,8 +732,10 @@ for (gt = get_test; gt->name; ++gt) {
fclose (fopen (xpath, "w"));
free (filename);
}
snprintf (xpath, sizeof (xpath), "testfiles/%s", gt->search);
sim_chdir ("testfiles");
snprintf (xpath, sizeof (xpath), "%s", gt->search);
filelist = sim_get_filelist (xpath);
sim_chdir ("..");
r = sim_messagef ((gt->expected_count != sim_count_filelist (filelist)) ? SCPE_IERR : SCPE_OK,
"sim_get_filelist (\"%s\") yielded %d entries:\n", xpath, sim_count_filelist (filelist));
sim_print_filelist (filelist);
@ -788,6 +800,82 @@ if (NULL == _sim_expand_homedir (path, pathbuf, sizeof (pathbuf)))
return rmdir (pathbuf);
}
typedef struct FILELIST_DIRECTORY_CACHE {
struct FILELIST_DIRECTORY_CACHE *next;
char *directory;
char **dirlist;
} FILELIST_DIRECTORY_CACHE;
static FILELIST_DIRECTORY_CACHE *_filelist_directory_cache = NULL;
static char **_check_filelist_directory_cache (const char *directory)
{
FILELIST_DIRECTORY_CACHE *entry = _filelist_directory_cache;
while (entry != NULL) {
if (strcmp (directory, entry->directory) == 0) {
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "_check_filelist_directory_cache(directory=\"%s\") found with %d entries\n", directory, sim_count_filelist (entry->dirlist));
return entry->dirlist;
}
entry = entry->next;
}
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "_check_filelist_directory_cache(directory=\"%s\") not found\n", directory);
return NULL;
}
static void _save_filelist_directory_cache (const char *directory, char **dirlist)
{
FILELIST_DIRECTORY_CACHE *entry;
if (_check_filelist_directory_cache (directory) != NULL) {
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "_save_filelist_directory_cache(directory=\"%s\") previously saved with %d directories\n", directory, sim_count_filelist (dirlist));
return;
}
entry = (FILELIST_DIRECTORY_CACHE *)calloc (1, sizeof (*entry));
entry->directory = strdup (directory);
entry->dirlist = dirlist;
entry->next = _filelist_directory_cache;
_filelist_directory_cache = entry;
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "_save_filelist_directory_cache(directory=\"%s\") saved with %d directories\n", directory, sim_count_filelist (dirlist));
}
static void _flush_filelist_directory_cache (void)
{
FILELIST_DIRECTORY_CACHE *entry = _filelist_directory_cache;
while (entry != NULL) {
_filelist_directory_cache = entry->next;
free (entry->directory);
sim_free_filelist (&entry->dirlist);
free (entry);
entry = _filelist_directory_cache;
}
}
static char **filelist_skip_directories = NULL;
void sim_set_get_filelist_skip_directories (const char * const *dirlist)
{
int dircount = 0;
if (dirlist != NULL) {
while (dirlist[dircount++] != NULL);
--dircount;
}
sim_free_filelist (&filelist_skip_directories);
filelist_skip_directories = (char **)calloc (dircount + 1, sizeof (*filelist_skip_directories));
dircount = 0;
while (*dirlist != NULL)
filelist_skip_directories[dircount++] = strdup (*dirlist++);
}
void sim_clear_get_filelist_skip_directories (void)
{
sim_free_filelist (&filelist_skip_directories);
}
static void _sim_dirlist_entry (const char *directory,
const char *filename,
t_offset FileSize,
@ -796,19 +884,41 @@ static void _sim_dirlist_entry (const char *directory,
{
char **dirlist = *(char ***)context;
char FullPath[PATH_MAX + 1];
int listcount = 0;
int listcount;
if ((strcmp (filename, "..") == 0) || /* Ignore previous dir */
(strcmp (filename, ".") == 0) || /* Ignore current dir */
((filestat->st_mode & S_IFDIR) == 0) || /* Ignore anything not a directory */
(stop_cpu))
return;
if (filelist_skip_directories != NULL) {
char **cdir = filelist_skip_directories;
while (*cdir != NULL) {
if (strcmp (*cdir, filename) == 0)
break;
++cdir;
}
if (*cdir != NULL) {
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "Skipping directory: %s\n", filename);
return;
}
}
if (strcmp (filename, ".") == 0)
filename = "";
snprintf (FullPath, sizeof (FullPath), "%s%s%s", directory, filename, (*filename != '\0') ? "/" : "");
/* Ignore this entry if it is already in the directory list */
listcount = 0;
if (dirlist != NULL) {
while (dirlist[listcount++] != NULL);
--listcount;
while (dirlist[listcount] != NULL) {
if (strcmp (FullPath, dirlist[listcount]) == 0) {
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "Ignoring already present directory: %s\n", FullPath);
return;
}
++listcount;
}
}
dirlist = (char **)realloc (dirlist, (listcount + 2) * sizeof (*dirlist));
dirlist[listcount] = strdup (FullPath);
@ -843,20 +953,20 @@ filelist[listcount + 1] = NULL;
char **sim_get_filelist (const char *filename)
{
t_stat r;
t_stat r = SCPE_OK;
char *dir = sim_filepath_parts (filename, "p");
size_t dirsize = strlen (dir);
char *file = sim_filepath_parts (filename, "nx");
char **dirlist, **dirs;
char **dirlist = NULL, **dirs;
char **filelist = NULL;
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, "sim_get_filelist(filename=\"%s\")\n", filename);
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, " Looking for Directories in\"%s\"\n", dir);
dir = (char *)realloc (dir, dirsize + 2);
strlcat (dir, "*", dirsize + 2);
dirlist = NULL;
dirlist = _check_filelist_directory_cache (dir);
if (dirlist == NULL)
r = sim_dir_scan (dir, _sim_dirlist_entry, &dirlist);
free (dir);
sim_debug (FIO_DBG_SCAN, &sim_fio_test_dev, " %d directories found, r=%d\n", sim_count_filelist (dirlist), r);
if (r == SCPE_OK) {
filelist = NULL;
@ -879,13 +989,14 @@ if (r == SCPE_OK) {
}
}
}
else
sim_dir_scan (filename, _sim_filelist_entry, &filelist);
free (file);
sim_free_filelist (&dirlist);
_save_filelist_directory_cache (dir, dirlist);
free (dir);
return filelist;
}
free (file);
free (dir);
r = sim_dir_scan (filename, _sim_filelist_entry, &filelist);
if (r == SCPE_OK)
return filelist;
@ -1468,7 +1579,13 @@ char *sim_getcwd (char *buf, size_t buf_size)
#if defined (VMS)
return getcwd (buf, buf_size, 0);
#else
return getcwd (buf, buf_size);
char *result = getcwd (buf, buf_size);
#if defined (_WIN32)
if ((result != NULL) && sim_islower (buf[0]) && (buf[1] == ':'))
buf[0] = sim_toupper (buf[0]);
#endif
return result;
#endif
}
@ -1539,8 +1656,8 @@ else { /* Need to prepend current directory */
}
while ((c = strchr (fullpath, '\\'))) /* standardize on / directory separator */
*c = '/';
if ((fullpath[1] == ':') && islower (fullpath[0]))
fullpath[0] = toupper (fullpath[0]);
if ((fullpath[1] == ':') && sim_islower (fullpath[0]))
fullpath[0] = sim_toupper (fullpath[0]);
while ((c = strstr (fullpath + 1, "//"))) /* strip out redundant / characters (leaving the option for a leading //) */
memmove (c, c + 1, 1 + strlen (c + 1));
while ((c = strstr (fullpath, "/./"))) /* strip out irrelevant /./ sequences */
@ -1690,7 +1807,7 @@ while ((wd[offset] != '\0') && (filepath[offset] != '\0')) {
continue;
}
#if defined(_WIN32) /* Windows has case independent file names */
#define _CMP(x) (islower (x) ? toupper (x) : x)
#define _CMP(x) (sim_islower (x) ? sim_toupper (x) : x)
#else
#define _CMP(x) (x)
#endif
@ -1772,6 +1889,8 @@ if ((hFind = FindFirstFileA (cptr, &File)) != INVALID_HANDLE_VALUE) {
while ((c = strchr (DirName, '\\')))
*c = '/'; /* Convert backslash to slash */
}
if (sim_islower (DirName[0]) && (DirName[1] == ':'))
DirName[0] = sim_toupper (DirName[0]);
sprintf (&DirName[strlen (DirName)], "%c", *pathsep);
do {
FileSize = (((t_int64)(File.nFileSizeHigh)) << 32) | File.nFileSizeLow;
@ -2124,3 +2243,516 @@ if (n != 0) {
return (s - src - 1); /* count does not include NUL */
}
/* SCP Simulator Source Code validator support */
static const char *_check_source_skip_dirs[] = {
".git",
".github",
".travis",
"BIN",
"doc",
NULL
};
static const char *_check_source_scp_sub_dirs[] = {
"slirp",
"slirp_glue",
"slirp_glue/qemu",
"slirp_glue/qemu/sysemu",
"display",
NULL
};
static const char *_check_source_allowed_sysincludes[] = {
"ctype.h",
"errno.h",
"limits.h",
"math.h",
"setjmp.h",
"stdarg.h",
"stddef.h",
"stdio.h",
"stdlib.h",
"string.h",
"sys/stat.h",
"time.h",
"SDL.h",
"SDL_ttf.h",
NULL
};
typedef struct FILE_STATS {
char RelativePath[PATH_MAX + 1];
t_offset FileSize;
int Lines;
t_bool IsInScpDir;
t_bool HasBinary;
t_bool IsSource;
t_bool HasTabs;
t_bool HasSimSockInclude;
int BenignIncludeCount;
char **BenignIncludes;
int LocalIncludeCount;
char **LocalIncludes;
int SysIncludeCount;
char **SysIncludes;
int OtherSysIncludeCount;
char **OtherSysIncludes;
int MissingIncludeCount;
char **MissingIncludes;
int LineEndingsLF;
int LineEndingsCRLF;
t_bool ProblemFile;
} FILE_STATS;
static char *sim_check_scp_dir = NULL;
static void _check_source_check_file (const char *directory,
const char *filename,
t_offset FileSize,
FILE_STATS *Stats)
{
char filepath[PATH_MAX + 1];
FILE *f;
char *data;
char *extension;
char *dir;
t_offset byte;
size_t lfcount = 0,
crlfcount = 0,
tabcount = 0,
wscount = 0,
bincount = 0;
const char *errmsg;
data = (char *)malloc ((size_t)(FileSize + 1));
data[FileSize] = '\0';
snprintf (filepath, sizeof (filepath), "%s%s", directory, filename);
strlcpy (Stats->RelativePath, sim_relative_path (filepath), sizeof (Stats->RelativePath));
extension = sim_filepath_parts (filepath, "x");
Stats->IsSource = ((0 == strcmp (".c", extension)) || (0 == strcmp (".h", extension)));
dir = sim_filepath_parts (directory, "p");
Stats->IsInScpDir = (sim_check_scp_dir != NULL) && (strcmp (dir, sim_check_scp_dir) == 0);
free (dir);
if ((!Stats->IsInScpDir) && (sim_check_scp_dir != NULL)) {
const char **scp_sub_dir = _check_source_scp_sub_dirs;
while (*scp_sub_dir != NULL) {
char tmp_dir[PATH_MAX + 1];
strlcpy (tmp_dir, sim_check_scp_dir, sizeof (tmp_dir));
strlcat (tmp_dir, *scp_sub_dir, sizeof (tmp_dir));
strlcat (tmp_dir, &directory[strlen (directory) - 1], sizeof (tmp_dir));
if (strcmp (directory, tmp_dir) == 0)
break;
++scp_sub_dir;
}
Stats->IsInScpDir = (*scp_sub_dir != NULL);
}
f = fopen (filepath, "rb");
if ((f == NULL) ||
((size_t)FileSize != fread (data, 1, (size_t)FileSize, f))) {
fprintf (stderr, "Error Opening or Reading: %s - %s\n", filepath, strerror (errno));
fclose (f);
free (data);
Stats->ProblemFile = TRUE;
return;
}
Stats->FileSize = FileSize;
for (byte=0; (byte < FileSize) && (bincount < 100); ++byte) {
switch (data[byte]) {
case '\n':
++lfcount;
break;
case '\r':
if (data[byte+1] == '\n')
++crlfcount;
break;
case '\t':
++tabcount;
break;
default:
if (sim_isspace (data[byte]))
++wscount;
else {
if (!sim_isprint (data[byte]))
++bincount;
}
break;
}
}
fclose (f);
if (tabcount > 0)
Stats->HasTabs = TRUE;
if (Stats->HasTabs && Stats->IsSource)
Stats->ProblemFile = TRUE;
if (FileSize > 0) {
if (crlfcount == lfcount)
Stats->Lines = crlfcount;
else {
Stats->Lines = lfcount;
Stats->ProblemFile = TRUE;
}
}
if (bincount > 0)
Stats->HasBinary = TRUE;
Stats->LineEndingsCRLF = crlfcount;
Stats->LineEndingsLF = lfcount;
if (Stats->IsSource) {
static pcre *sys_include_re = NULL;
static pcre *local_include_re = NULL;
static pcre *sim_sock_re = NULL;
int rc;
int matches = 0;
int ovec[6];
int startoffset = 0;
int erroffset;
if (sim_sock_re == NULL)
sim_sock_re = pcre_compile ("\\#\\s*include\\s+\\\"sim_sock\\.h\"", 0, &errmsg, &erroffset, NULL);
matches = 0;
while (1) {
rc = pcre_exec (sim_sock_re, NULL, data, (int)FileSize, startoffset, PCRE_NOTBOL, ovec, 6);
if (rc == PCRE_ERROR_NOMATCH)
break;
++matches;
startoffset = ovec[1];
}
if ((matches > 0) && (!Stats->IsInScpDir))
Stats->HasSimSockInclude = TRUE;
if (local_include_re == NULL)
local_include_re = pcre_compile ("\\#\\s*include\\s+\\\"(.+)\\\"", 0, &errmsg, &erroffset, NULL);
matches = startoffset = 0;
while (1) {
char *local_include;
rc = pcre_exec (local_include_re, NULL, data, (int)FileSize, startoffset, PCRE_NOTBOL, ovec, 6);
if (rc == PCRE_ERROR_NOMATCH)
break;
++matches;
startoffset = ovec[1];
local_include = (char *)calloc (1 + ovec[3] - ovec[2], sizeof (*local_include));
memcpy (local_include, &data[ovec[2]], ovec[3] - ovec[2]);
++Stats->LocalIncludeCount;
Stats->LocalIncludes = (char **)realloc (Stats->LocalIncludes, Stats->LocalIncludeCount * sizeof (*Stats->LocalIncludes));
Stats->LocalIncludes[Stats->LocalIncludeCount - 1] = local_include;
}
if (sys_include_re == NULL)
sys_include_re = pcre_compile ("\\#\\s*include\\s+\\<(.+)\\>", 0, &errmsg, &erroffset, NULL);
matches = startoffset = 0;
while (1) {
char *sys_include;
t_bool benign_include = FALSE;
const char **allowed_include = _check_source_allowed_sysincludes;
rc = pcre_exec (sys_include_re, NULL, data, (int)FileSize, startoffset, PCRE_NOTBOL, ovec, 6);
if (rc == PCRE_ERROR_NOMATCH)
break;
++matches;
startoffset = ovec[3];
sys_include = (char *)calloc (1 + ovec[3]-ovec[2], sizeof (*sys_include));
memcpy (sys_include, &data[ovec[2]], ovec[3] - ovec[2]);
if (Stats->IsInScpDir) {
++Stats->SysIncludeCount;
Stats->SysIncludes = (char **)realloc (Stats->SysIncludes, Stats->SysIncludeCount * sizeof (*Stats->SysIncludes));
Stats->SysIncludes[Stats->SysIncludeCount - 1] = sys_include;
}
else {
while (*allowed_include != NULL) {
if (0 == strcmp (sys_include, *allowed_include))
break;
++allowed_include;
}
if (*allowed_include != NULL) {
++Stats->BenignIncludeCount;
Stats->BenignIncludes = (char **)realloc (Stats->BenignIncludes, Stats->BenignIncludeCount * sizeof (*Stats->BenignIncludes));
Stats->BenignIncludes[Stats->BenignIncludeCount - 1] = sys_include;
}
else {
++Stats->OtherSysIncludeCount;
Stats->OtherSysIncludes = (char **)realloc (Stats->OtherSysIncludes, Stats->OtherSysIncludeCount * sizeof (*Stats->OtherSysIncludes));
Stats->OtherSysIncludes[Stats->OtherSysIncludeCount - 1] = sys_include;
}
}
}
if ((!Stats->IsInScpDir) && (Stats->OtherSysIncludeCount != 0))
Stats->ProblemFile = TRUE;
}
free (extension);
free (data);
}
typedef struct CHECK_STATS {
int BinaryFiles;
int SourceFiles;
int TextFiles;
int ProblemFiles;
int FileCount;
FILE_STATS **Files;
} CHECK_STATS;
static void _check_source_directory_check (const char *directory,
const char *filename,
t_offset FileSize,
const struct stat *filestat,
void *context)
{
CHECK_STATS *Stats = (CHECK_STATS *)context;
if (filestat->st_mode & S_IFDIR) {
char dirpath[PATH_MAX + 1];
char RelativePath[PATH_MAX + 1];
const char **skip_dir = _check_source_skip_dirs;
char pathsep = directory[strlen (directory) - 1];
/* Ignore directory self and parent */
if ((0 == strcmp (filename, ".")) ||
(0 == strcmp (filename, "..")))
return;
/* Ignore uninteresting directories */
while (*skip_dir != NULL) {
if (0 == strcmp (filename, *skip_dir))
return;
++skip_dir;
}
strlcpy (RelativePath, sim_relative_path (dirpath), sizeof (RelativePath));
sim_dir_scan (RelativePath, _check_source_directory_check, Stats);
}
else {
++Stats->FileCount;
Stats->Files = (FILE_STATS **)realloc (Stats->Files, Stats->FileCount * sizeof (FILE_STATS **));
Stats->Files[Stats->FileCount - 1] = (FILE_STATS *)calloc (1, sizeof (FILE_STATS));
_check_source_check_file (directory, filename, FileSize, Stats->Files[Stats->FileCount - 1]);
}
}
static void _check_source_scp_check (const char *directory,
const char *filename,
t_offset FileSize,
const struct stat *filestat,
void *context)
{
char **scp_dir = (char **)context;
if (strcmp ("scp.c", filename) == 0)
*scp_dir = sim_filepath_parts (directory, "p");
}
static void _check_source_print_string_list (const char *title, char **list, int count)
{
int i;
if (count > 0) {
sim_printf (" %s:\n", title);
for (i = 0; i < count; i++)
sim_printf (" %s\n", list[i]);
}
}
static void _check_source_free_string_list (char **list, int count)
{
int i;
for (i = 0; i < count; i++)
free (list[i]);
free (list);
}
static void _sim_check_source_file_report (FILE_STATS *File, int maxnamelen)
{
if ((sim_switches & SWMASK ('D')) || (File->ProblemFile)) {
sim_printf ("%*.*s ", -maxnamelen, -maxnamelen, File->RelativePath);
sim_printf ("%8u bytes", (unsigned int)File->FileSize);
if (File->Lines)
sim_printf (" %5d lines", File->Lines);
if (File->IsSource) {
if (File->HasTabs)
sim_printf (", has-tabs");
if (File->HasBinary)
sim_printf (", has-binary(non-ascii)");
if ((File->LineEndingsCRLF != 0) && (File->LineEndingsCRLF != File->LineEndingsLF))
sim_printf (", mixed CRLF and LF line-endings");
else {
if (File->LineEndingsLF == File->LineEndingsCRLF)
sim_printf (", CRLF line-endings");
else
sim_printf (", LF line-endings");
}
}
sim_printf ("\n");
if (File->HasSimSockInclude)
sim_printf ("Has unneeded include of sim_sock.h\n");
_check_source_print_string_list ("Benign (unneeded) System Include Files", File->BenignIncludes, File->BenignIncludeCount);
_check_source_print_string_list ("Local Include Files", File->LocalIncludes, File->LocalIncludeCount);
_check_source_print_string_list ("System Include Files", File->SysIncludes, File->SysIncludeCount);
_check_source_print_string_list ("Other System Include Files", File->OtherSysIncludes, File->OtherSysIncludeCount);
_check_source_print_string_list ("Missing Include Files", File->MissingIncludes, File->MissingIncludeCount);
}
_check_source_free_string_list (File->BenignIncludes, File->BenignIncludeCount);
_check_source_free_string_list (File->LocalIncludes, File->LocalIncludeCount);
_check_source_free_string_list (File->SysIncludes, File->SysIncludeCount);
_check_source_free_string_list (File->OtherSysIncludes, File->OtherSysIncludeCount);
_check_source_free_string_list (File->MissingIncludes, File->MissingIncludeCount);
free (File);
}
static void _check_source_add_needed_include (FILE_STATS *File, const char *include_file, CHECK_STATS *Stats)
{
char filepath[PATH_MAX + 1];
int file;
char **files;
if (sim_check_scp_dir == NULL)
return;
for (file = 0; file < Stats->FileCount; file++) {
char *filename = sim_filepath_parts (Stats->Files[file]->RelativePath, "nx");
if (strcmp (include_file, filename) == 0) {
free (filename);
break;
}
free (filename);
}
if (file == Stats->FileCount) {
char *filename;
char *filedir;
snprintf (filepath, sizeof (filepath), "%s%s", sim_check_scp_dir, include_file);
filename = sim_filepath_parts (filepath, "nx");
filedir = sim_filepath_parts (filepath, "p");
if (strchr (include_file, filedir[strlen (filedir) - 1]) != NULL)
snprintf (filepath, sizeof (filepath), "%s%s", sim_check_scp_dir, filename);
free (filename);
free (filedir);
files = sim_get_filelist (filepath);
if (files != NULL) {
char RelativePath[PATH_MAX + 1];
strlcpy (RelativePath, sim_relative_path (files[0]), sizeof (RelativePath));
for (file = 0; file < Stats->FileCount; file++) {
if (strcmp (RelativePath, Stats->Files[file]->RelativePath) == 0)
break;
}
if (file == Stats->FileCount) {
struct stat statb;
char *directory = sim_filepath_parts (files[0], "p");
char *filename = sim_filepath_parts (files[0], "nx");
sim_stat (files[0], &statb);
++Stats->FileCount;
Stats->Files = (FILE_STATS **)realloc (Stats->Files, Stats->FileCount * sizeof (FILE_STATS **));
Stats->Files[Stats->FileCount - 1] = (FILE_STATS *)calloc (1, sizeof (FILE_STATS));
_check_source_check_file (directory, filename, statb.st_size, Stats->Files[Stats->FileCount - 1]);
free (directory);
free (filename);
}
}
else {
if (!File->IsInScpDir)
File->ProblemFile = TRUE;
++File->MissingIncludeCount;
File->MissingIncludes = (char **)realloc (File->MissingIncludes, File->MissingIncludeCount * sizeof (*File->MissingIncludes));
File->MissingIncludes[File->MissingIncludeCount - 1] = strdup (include_file);
}
sim_free_filelist (&files);
}
}
static int _check_source_compare (const void *pa, const void *pb)
{
char **a = (char **)pa;
char **b = (char **)pb;
return strcasecmp(*a, *b);
}
static t_stat _sim_check_source_report (CHECK_STATS *Stats)
{
t_stat stat = SCPE_OK;
int file, namelen;
qsort (Stats->Files, Stats->FileCount, sizeof (Stats->Files[0]), _check_source_compare);
for (file = namelen = 0; file < Stats->FileCount; file++) {
if (namelen < (int)strlen (Stats->Files[file]->RelativePath))
namelen = (int)strlen (Stats->Files[file]->RelativePath);
}
/* Populate Counts */
for (file = 0; file < Stats->FileCount; file++) {
if (Stats->Files[file]->HasBinary)
++Stats->BinaryFiles;
else
++Stats->TextFiles;
if (Stats->Files[file]->IsSource)
++Stats->SourceFiles;
if (Stats->Files[file]->ProblemFile)
++Stats->ProblemFiles;
}
/* Report Results */
if ((sim_check_scp_dir != NULL) &&
((sim_switches & SWMASK ('D')) || (Stats->ProblemFiles > 0))) {
sim_printf ("scp.c directory: %s\n", sim_relative_path (sim_check_scp_dir));
free (sim_check_scp_dir);
sim_check_scp_dir = NULL;
}
for (file = 0; file < Stats->FileCount; file++)
_sim_check_source_file_report (Stats->Files[file], namelen);
if (Stats->ProblemFiles > 0)
stat = SCPE_FMT;
free (Stats->Files);
free (Stats);
if (sim_switches & SWMASK ('E')) /* -E switch means don't return any error */
stat = SCPE_OK;
return stat;
}
int
sim_check_source (int argc, char **argv)
{
CHECK_STATS *Stats = (CHECK_STATS *)calloc (1, sizeof (*Stats));
int i, file;
static const char *source_skip_dirs[] = { ".git", "BIN", NULL};
if (sim_switches & SWMASK ('D')) {
sim_printf ("Check Source args:");
for (i = 0; i < argc; i++)
sim_printf (" %s", argv[i]);
sim_printf ("\n");
}
free (sim_check_scp_dir);
sim_check_scp_dir = NULL;
sim_set_get_filelist_skip_directories (source_skip_dirs);
/* Find the directory where scp.c is located */
for (i = 1; i < argc; i++) {
if (sim_check_scp_dir != NULL)
break;
sim_dir_scan (argv[i], _check_source_scp_check, &sim_check_scp_dir);
}
/* Process the list of files */
while (--argc > 0) {
++argv;
sim_dir_scan (*argv, _check_source_directory_check, Stats);
}
/* Add includes to the file list if they're not there */
for (file = 0; file < Stats->FileCount; file++) {
int include;
for (include = 0; include < Stats->Files[file]->LocalIncludeCount; include++) {
_check_source_add_needed_include (Stats->Files[file], Stats->Files[file]->LocalIncludes[include], Stats);
}
}
sim_clear_get_filelist_skip_directories ();
_flush_filelist_directory_cache ();
return _sim_check_source_report (Stats);
}

View File

@ -88,6 +88,8 @@ typedef void (*DIR_ENTRY_CALLBACK)(const char *directory,
void *context);
t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context);
char **sim_get_filelist (const char *filename);
void sim_set_get_filelist_skip_directories (const char * const *dirlist);
void sim_clear_get_filelist_skip_directories (void);
void sim_free_filelist (char ***pfilelist);
void sim_print_filelist (char **filelist);
int sim_count_filelist (char **filelist);
@ -109,6 +111,7 @@ t_stat sim_shmem_open (const char *name, size_t size, SHMEM **shmem, void **addr
void sim_shmem_close (SHMEM *shmem);
int32 sim_shmem_atomic_add (int32 *ptr, int32 val);
t_bool sim_shmem_atomic_cas (int32 *ptr, int32 oldv, int32 newv);
extern int sim_check_source (int argc, char **argv);
extern t_bool sim_taddr_64; /* t_addr is > 32b and Large File Support available */
extern t_bool sim_toffset_64; /* Large File (>2GB) file I/O support */