home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
makdep4d.zip
/
MAKDPWIN.ZIP
/
MAKEDEP.C
next >
Wrap
C/C++ Source or Header
|
1995-05-25
|
16KB
|
746 lines
// ---------------------------------------------------------------------------
//
// Program: MakeDeps
// File: MakeDep.c
// By: David M. Miller
// Business Visions, Inc.
// Date: 11-May-95
//
// Description:
// Generate a dependency list for C, (Windows) RC, and ASM files for MAKE
//
// Notes:
//
// ---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <io.h>
#include <dos.h>
#include <string.h>
#include <malloc.h>
#include <limits.h>
#define ELEMENTS(array) (sizeof array/sizeof array[0])
typedef enum { FT_UNK = 1, FT_C, FT_ASM, FT_RC } FTYPE;
typedef enum { ERR_LOGO, ERR_MEMORY, ERR_RESP, ERR_USAGE, ERR_LOC, ERR_NOT,
ERR_OPT } ERRCODE;
typedef struct tagFCACHE
{
char *foundat;
FTYPE ft;
}
FCACHE;
static char logo[] =
"MakeDep2 dependency generator (c) 1995, Business Visions, Inc.\n\n";
static char usage[] =
"\nusage: makedeps [-options] {target | @respfile} [target ..]\n" \
"where:\n" \
" -l suppress logo\n" \
" -ipath[;path] include file search directories\n" \
" -spath[;path] source file search directories\n" \
" target specifies source file name (wildcards permitted)\n" \
" (examples: *.cpp file.c file.asm file.rc)\n" \
" respfile contains targets and/or options.\n" \
" -? this message\n" \
"\n" \
"INCLUDE environment variable will be used to locate quoted include\n" \
"files not in the current directory. -I flag adds directories to search\n";
static char wseol[] = " \t\n\r"; // white space with EOLs
static char ws[] = " \t"; // white space
int nologo = 0;
// file types that produce .OBJs
char *ctargets[] = {"c", "cpp", "cxx" };
char *asmtargets[] = {"a", "asm" };
// file types that produce .RESs
char *rctargets[] = {"rc", "dlg", "ver"};
// file types that won't have includes within them
char *rcdepsonly[] = {".ico", ".bmp", ".dib"};
char **sps = NULL; // source paths
int nsps = 0; // count
char **incs = NULL; // include paths
int nincs = 0; // count
char **targs = NULL; // targets
int ntargs = 0; // count
char **depends = NULL; // dependencies
int ndepends = 0; // count
FCACHE *findcache = NULL;
int nfound = 0;
char _drv[_MAX_DRIVE];
char _dir[_MAX_DIR];
char _fnm[_MAX_FNAME];
char _ext[_MAX_EXT];
char pathname[_MAX_PATH];
void scan_targets(void);
void scan_file(char *target, FTYPE ft);
void print_list(char *target);
char *is_c_include(char *buf);
char *is_rc_include(char *buf);
char *is_asm_include(char *buf);
FTYPE find_file(char *target, char **paths, int npaths, char *pathname);
FTYPE get_filetype(char *ext);
int get_args(int argc, char **argv);
int expargv(int *pargc, char ***pargv);
int add_list_to_array(char *p, char ***parray, int *psize);
int add_to_array(char *p, char ***parray, int *psize);
int in_array(char *p, char **array, int size);
void free_array(char **array, int size);
FCACHE *in_cache(char *target);
FCACHE *en_cache(char *pathname);
char *strip_path(char *fn);
void error(ERRCODE errcode, char *p);
int main(int argc, char *argv[])
{
int i;
char *p;
switch (expargv(&argc, &argv))
{
case -1:
error(ERR_MEMORY, "loading response file");
return 1;
case -2:
error(ERR_RESP, "loading response file");
return 1;
}
if (argc < 2)
{
error(ERR_USAGE, NULL);
return 1;
}
if (get_args(argc, argv)) // examine options
return 1;
error(ERR_LOGO, NULL); // print logo
// add directories in the INCLUDE environment variable to the list of
// directories in which to search for include files
if ((p = getenv("INCLUDE")) && add_list_to_array(strdup(p), &incs, &nincs))
{
error(ERR_MEMORY, "expanding dependencies");
return 1;
}
// off we go ...
scan_targets();
free_array(sps, nsps);
free_array(incs, nincs);
free_array(targs, ntargs);
if (nfound)
{
for (i = 0; i < nfound; ++i)
free(findcache[i].foundat);
free(findcache);
}
return 0;
}
void scan_targets()
{
int i;
FTYPE ft;
char pathname[_MAX_PATH];
for (i = 0; i < ntargs; ++i)
{
if ((ft = find_file(targs[i], sps, nsps, pathname)) > FT_UNK)
{
scan_file(pathname, ft);
print_list(pathname);
}
else
error(ERR_NOT, pathname);
free_array(depends, ndepends);
depends = NULL;
ndepends = 0;
}
}
void scan_file(char *target, FTYPE ft)
{
FILE *fp;
int i, start;
char *p;
char buf[512];
char outfile[_MAX_PATH];
if ((fp = fopen(target, "rt")) == NULL)
{
error(ERR_LOC, target);
exit(1);
}
if (add_to_array(target, &depends, &ndepends))
{
error(ERR_MEMORY, "expanding dependencies");
exit(1);
}
start = ndepends;
while (fgets(buf, sizeof buf, fp))
{
p = NULL;
switch (ft)
{
case FT_C:
p = is_c_include(buf);
break;
case FT_RC:
p = is_rc_include(buf);
break;
case FT_ASM:
p = is_asm_include(buf);
break;
}
// search for included file
if (p && find_file(p, incs, nincs, outfile))
{
if (add_to_array(strdup(outfile), &depends, &ndepends))
{
error(ERR_MEMORY, "expanding dependencies");
exit(1);
}
}
}
fclose(fp);
// any new dependencies?
if (ndepends - start)
{
// scan them too
for (i = start; i < ndepends; ++i)
{
if (ft == FT_RC)
{
// make sure dependent file is not an icon or a bitmap
_splitpath(depends[start], NULL, NULL, NULL, _ext);
if (in_array(_ext, rcdepsonly, ELEMENTS(rcdepsonly)))
continue;
}
scan_file(depends[i], ft);
}
}
}
void print_list(char *target)
{
int i, len;
char *ext;
char buf[512];
if (ndepends)
{
// print out the list of dependencies
_splitpath(target, NULL, NULL, _fnm, _ext);
// get the file extension, without the period
ext = _ext+(_ext[0] == '.');
if (in_array(ext, ctargets, ELEMENTS(ctargets)) ||
in_array(ext, asmtargets, ELEMENTS(asmtargets)))
_makepath(buf, NULL, NULL, _fnm, "obj");
else if (in_array(ext, rctargets,
ELEMENTS(rctargets)))
_makepath(buf, NULL, NULL, _fnm, "res");
else
strcpy(buf, target); // don't know what else to do with it
// print all of the dependencies
strcat(buf, ":");
for (len = strlen(buf), i = 0; i < ndepends; ++i)
{
if (len + 1 + strlen(depends[i]) > 78)
{
strcat(buf, "\\\n");
len = 0;
}
strcat(buf, " ");
strcat(buf, depends[i]);
len += 1 + strlen(depends[i]);
}
puts(buf);
}
}
char *is_c_include(char *buf)
{
int len;
char *p = buf + strspn(buf, ws); // skip to first non-whitespace
if (*p == '\0')
return NULL;
if (*p != '#')
return NULL;
// some compilers allow whitespace here
p += 1 + strspn(p+1, ws);
if (strncmp(p, "include", 7)) // must be lowercase
return NULL;
// found #include, now get filename and length
p += 7 + strspn(p+7, ws);
len = strcspn(p, wseol);
if (*p != '"' || *(p+len-1) != '"')
return NULL;
*(p+len-1) = '\0';
return ++p;
}
char *is_rc_include(char *buf)
{
char *p = is_c_include(buf); // if it's not a c style #include
if (!p) // check whether it's rc-style
{
// examine first word for "RCINCLUDE"
int is_rcinclude = (stricmp(strtok(buf, ws), "rcinclude") == 0);
// is there a second word? then, if first word not "RCINCLUDE"
if ((p = strtok(NULL, ws)) && !is_rcinclude)
{
// if second word is not "ICON" or "BITMAP"
if (stricmp(p, "icon") && stricmp(p, "bitmap"))
return NULL; // fail
// for "ICON" or "BITMAP": the last word on the line is the
// filename
do // loop
{
buf = p; // save current word
p = strtok(NULL, ws); // get next word
}
while (p); // until no more words
p = buf; // saved pointer is last word
}
}
return p;
}
char *is_asm_include(char *buf)
{
char *p = buf + strspn(buf, ws); // skip to first non-whitespace
if (*p == '\0')
return NULL;
if (strnicmp(p, "include", 7))
return NULL;
// found include, now get filename and length
p += 7 + strspn(p+7, ws);
*(p+strcspn(p, ws)) = '\0';
return p;
}
FTYPE find_file(char *target, char **paths, int npaths, char *pathname)
{
int i = 0;
char origpath[_MAX_PATH];
char *p;
struct find_t find;
FCACHE *ff;
if ((ff = in_cache(target)) != NULL)
{
strcpy(pathname, ff->foundat);
_splitpath(pathname, _drv, _dir, _fnm, _ext);
return ff->ft;
}
_splitpath(target, _drv, _dir, _fnm, _ext);
_makepath(origpath, _drv, _dir, NULL, NULL);
p = origpath;
// first time through, p points at original pathname that came with
// target. subsequently, all paths in sps are attempted. if found,
// the pathname by which it was found is left in pathname.
do
{
_makepath(pathname, NULL, p, _fnm, _ext);
if (!_dos_findfirst(pathname, _A_ARCH|_A_RDONLY|_A_HIDDEN, &find))
{
if ((ff = en_cache(pathname)) == NULL)
exit(1);
return ff->ft;
}
p = paths[i];
}
while (i++ < npaths);
return 0;
}
FTYPE get_filetype(char *ext)
{
int i;
if (*ext == '.')
++ext;
for (i = 0; i < ELEMENTS(ctargets); ++i)
if (stricmp(ext, ctargets[i]) == 0)
return FT_C;
for (i = 0; i < ELEMENTS(rctargets); ++i)
if (stricmp(ext, rctargets[i]) == 0)
return FT_RC;
for (i = 0; i < ELEMENTS(asmtargets); ++i)
if (stricmp(ext, asmtargets[i]) == 0)
return FT_ASM;
return FT_UNK;
}
int get_args(int argc, char **argv)
{
int i;
char *p;
for (i = 1; i < argc; ++i)
{
if (*argv[i] == '-' || *argv[i] == '/')
{
++argv[i];
switch (tolower(*argv[i]))
{
case '?':
puts(usage);
exit(0);
case 'l': // no logo
nologo = 1;
break;
case 'i': // INCLUDE path
// see if path starts immediately after argument
if (*(p = ++argv[i]) == '\0')
p = argv[++i]; // if not, look at next argument
if (p && add_list_to_array(strdup(p), &incs, &nincs))
{
error(ERR_MEMORY, "expanding include direectories");
return 1;
}
break;
case 's': // source path
// see if path starts immediately after argument
if (*(p = ++argv[i]) == '\0')
p = argv[++i]; // if not, look at next argument
if (p && add_list_to_array(strdup(p), &sps, &nsps))
{
error(ERR_MEMORY, "expanding source directories");
return 1;
}
break;
default:
error(ERR_OPT, argv[i]);
return 1;
}
}
else
add_to_array(strlwr(argv[i]), &targs, &ntargs);
}
return 0;
}
int expargv(int *pargc, char ***pargv)
{
int i;
int nargc;
int expanded = 0;
char **nargv;
// allocate a new argv array
if ((nargv = (char **)malloc((*pargc + 1) * sizeof(char *))) == NULL)
return -1;
// copy all pargv elements to nargv, expanding response files
for (i = nargc = 0; i < *pargc; ++i)
{
char **argv = *pargv;
// if argument doesn't start with '@', copy it
if (*argv[i] != '@')
nargv[nargc++] = argv[i];
// else expand response file
else
{
FILE *fp;
int nargs = 0;
long filesize;
size_t bytes;
char *buf;
char **tmp;
char *p;
if ((fp = fopen(argv[i]+1, "rt")) == NULL)
{
free(nargv);
return -2;
}
if ((filesize = filelength(fileno(fp))) >= UINT_MAX)
{
fclose(fp);
free(nargv);
return -2;
}
if ((buf = (char *)malloc((size_t)filesize + 1)) == NULL)
{
fclose(fp);
free(nargv);
return -2;
}
bytes = fread(buf, 1, (size_t)filesize, fp);
if (bytes != (size_t)filesize && ferror(fp))
{
free(buf);
fclose(fp);
free(nargv);
return -2;
}
fclose(fp);
buf[bytes] = '\0';
// count arguments in file
for (p = buf; *p; )
{
// skip whitespace
p += strspn(p, wseol);
if (*p)
++nargs;
// skip to next whitespace
p += strcspn(p, wseol);
}
// reallocate nargv[] array to hold new items
if ((tmp = (char **)realloc(nargv, ((*pargc + 1) + nargs) *
sizeof(char *))) == NULL)
{
free(buf);
free(nargv);
return -1;
}
nargv = tmp;
// collect new items from file arguments
for (p = strtok(buf, wseol); p; p = strtok(NULL, wseol))
nargv[nargc++] = p;
expanded = 1;
}
}
if (expanded)
{
nargv[nargc] = NULL;
*pargc = nargc;
*pargv = nargv;
}
else
free(nargv);
return 0;
}
int add_list_to_array(char *p, char ***parray, int *psize)
{
if (p == NULL)
return -1;
if ((p = strtok(p, ";")) != NULL)
do
{
if (add_to_array(p, parray, psize))
return -1;
}
while (p = strtok(NULL, ";"));
return 0;
}
int add_to_array(char *p, char ***parray, int *psize)
{
char **narray;
if (!p)
return -1;
// don't add it if it's already there
if (!in_array(p, *parray, *psize))
{
// increase the size of the array by 1
// NOTE: this expects realloc(NULL, ...) to behave like malloc(...) !!
narray = (char **)realloc(*parray, (1 + *psize) * sizeof(char *));
if (narray == NULL) // realloc failed, leave old array
return -1;
narray[(*psize)++] = p; // add string to array
*parray = narray;
}
return 0;
}
int in_array(char *p, char **array, int size)
{
int i;
for (i = 0; i < size; ++i)
if (stricmp(p, array[i]) == 0)
break;
return (i < size);
}
void free_array(char **array, int size)
{
int i;
if (array)
{
for (i = 0; i < size; ++i)
if (array[i])
free(array[i]);
free(array);
}
}
FCACHE *in_cache(char *target)
{
FCACHE *ff;
target = strip_path(target);
for (ff = findcache; ff && ff - findcache < nfound; ++ff)
{
if (stricmp(target, strip_path(ff->foundat)) == 0)
return ff;
}
return NULL;
}
FCACHE *en_cache(char *pathname)
{
int i;
char *p;
FCACHE *ff = realloc(findcache, (1 + nfound) * sizeof *ff);
if (ff == NULL)
{
error(ERR_MEMORY, "expanding dependencies");
return NULL;
}
findcache = ff;
p = strip_path(pathname);
for (i = 0; i < nfound; ++i, ++ff)
if (stricmp(p, strip_path(ff->foundat)) < 0)
{
memmove(ff+1, ff, (nfound - i) * sizeof *ff);
break;
}
ff->foundat = strdup(pathname);
ff->ft = get_filetype(_ext);
++nfound;
return ff;
}
char *strip_path(char *fn)
{
int i;
char *p;
static char parts[] = "\\:/";
for (i = 0; i < sizeof parts - 1; ++i)
if (p = strrchr(fn, parts[i]))
return p+1;
return fn;
}
void error(ERRCODE errcode, char *p)
{
if (!nologo)
{
fputs(logo, stderr);
nologo = 1;
}
if (errcode == ERR_LOGO)
return;
switch (errcode)
{
case ERR_RESP:
perror(p);
return;
case ERR_MEMORY:
fputs("Out of memory", stderr);
fputs(p, stderr);
fputc('\n', stderr);
break;
case ERR_NOT:
fputs("Not a valid target file (.C??, .RC, .ASM): ", stderr);
fputs(p, stderr);
fputc('\n', stderr);
break;
case ERR_LOC:
fputs("Unable to locate target file: ", stderr);
fputs(p, stderr);
fputc('\n', stderr);
break;
case ERR_OPT:
fputs("Unknown option: -", stderr);
fputs(p, stderr);
fputc('\n', stderr);
// fall through
case ERR_USAGE:
fputs(usage, stderr);
}
}