home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
proglc
/
makemak.lzh
/
MAKEMAK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-02-21
|
14KB
|
546 lines
/*
makemak.c -- This program will generate a make file suitable for use
with Microsoft C or MASM. It makes an array of the names
of all the files in the current directory. It than searches
through the array for files that have an extension of C or
ASM. If so, it prints a make style "filename.obj: filename.c"
dependancy line. It then searches through the file to see if
any local include files are specified. If so, they are also
specified in the dependancy list. Finally, the link line is
printed.
Several make macro definitions are also printed. The source
of these definitions can come from several places. First, a
set of default definitions are built into the program. Second,
three environment variables, "CL, LINK, and MASM" are checked
and any values there become macro definitions. Lastly, a
configuration file is checked and any definitions there will
be included. This last set will override any definitions
set internally or from the environment.
Now for the caveats. 1) THIS THING IS BY NO MEANS PERFECT.
2) I have found that it will perform acceptably with little
to no editing of the generated make file. You may or may not
find this to be the case. It will be a function of your own
programming style and needs. 3) It requires that each program
that you generate a make file for has it's own directory.
If you do not use a seperate directory for each program, you
run the risk of having a large number of source and object
files in your dependancy lists that are not related to the
program you are trying to make. 4) You get what you pay for.
makemak allows the following flags;
-d show a dependency tree similar to "make' expects
-s show times. Display last modified times of files.
-v verbose. Running commentary during file parsing.
-h,H show a brief list of options
Much of this program is based on an article by Dave Taylor in the February,
1988 issue of Computer Language. It has been extensively modified for DOS.
The getopt function is from Augie Hansen's book "Proficient C".
Compiled under Microsoft C 5.0
*/
/* Last revised : Sun February 21, 1988 at 10:25:36 pm*/
/* Loran W. Richardson
7083 Fairways Drive
Longmont, CO 80501
(303) 939-9743
CIS 70441,3037
*/
#include <string.h> /* string stuff */
#include <stdio.h> /* standard stuff */
#include <stdlib.h> /* standard lib stuff*/
#include <direct.h> /* directory stuff */
#include <dos.h> /* DOS stuff */
#include <errno.h> /* system error */
#include <search.h>
#include <sys\types.h> /* more types!!! */
#include <sys\stat.h> /* stat stuff... */
#include <sys\utime.h>
#include "makemak.h"
struct find_t dp; /* file entry in directory */
struct dir_rec {
char name[FNAMELEN]; /* name of the file */
long time; /* last modified time */
int checked; /* has it been checked? */
} directory[MAXFILES];
int count = 0, /* how many files in directory? */
verbose = 0, /* -v (verbose) flag set... */
dependencies = 0, /* -d (dependencies) flag set.. */
show_times = 0; /* -s (show times) flag set */
makefile = 1; /* if no other options, make makefile */
srcs = 0; /* > 0 if source files are present */
objs = 0; /* > 0 if obj files are present */
hdrs = 0; /* > 0 if header files are present */
extern int errno; /* system error number */
extern char defaults[][SLEN];
extern char mak_defs[][FNAMELEN];
static char pgm[_MAX_FNAME] = {"makemak"};
char *cc_line = {"\n\t$(CC) $(C_OPTS) $(CDEFS) %s\n\n" };
char *mc_line = {"\n\t$(MC) $(M_OPTS) $(MDEFS) %s;\n\n" };
char *link_line = {"\t$(LINK) $(L_OPTS) $(OBJS), $(TARGET), $(LMAP), $(LIBS);\n" };
char compile_command[SLEN] = { "" };
void initially_read_in_directory();
void initialize_makefile();
void finish_makefile();
void get_file_modification_dates();
void figure_out_includes(int, int);
int check_for_include(char *);
int read_directory(char *);
int suffix(char *, char *);
int compare(); /* must be declared w/o args for qsort */
extern int getopt(int, char **, char *);
extern void mak_help(char *);
main(int argc, char *argv[])
{
extern char *getpname(char *, char *);
extern int mak_cfg(char *);
extern int optind, opterr;
extern char *optarg;
register int i;
int c;
int arg_err = 0;
if (_osmajor < 2)
fprintf(stderr, "%s: makemak requires DOS 2.00 or later.\n", pgm);
if (_osmajor >= 3)
getpname(*argv, pgm);
opterr = 0; /* supress getopt error message! */
while ((c = getopt(argc, argv, "dhHsv")) != EOF)
switch (c)
{
case 'd' :
dependencies++;
makefile = FALSE;
break;
case 'v' :
verbose++;
makefile = FALSE;
break;
case 's' :
show_times++;
makefile = FALSE;
break;
case 'h' :
case 'H' :
case '?' :
arg_err = TRUE;
break;
}
if (dependencies && verbose)
{
fprintf(stderr, "%s: Invalid option combination.\n", pgm);
exit(4);
}
argc -= optind;
argv += optind;
if ((makefile && (argc == 0)) || arg_err)
{
mak_help(pgm);
exit(3);
}
strcpy(defaults[TARGET], *argv);
if (mak_cfg(pgm) != 0)
{
fprintf(stderr, "%s: bad dependancy configuration file.\n", pgm);
exit(6);
}
initially_read_in_directory(); /* start up stuff */
if (makefile)
initialize_makefile();
/*
if the user wants to see the dates spin through and
spit 'em all out!
*/
if (show_times)
{
get_file_modification_dates(); /* read file dates */
for (i=0; i < count; i++)
if (suffix(".c", directory[i].name) ||
suffix(".h", directory[i].name) ||
suffix(".asm", directory[i].name)) /* a legit file? */
printf("%-15s %s", directory[i].name,
ctime(&directory[i].time));
}
/* now let's go through and check all the source files */
for (i=0; i < count; i++)
if (suffix(".c", directory[i].name) || suffix(".asm", directory[i].name))
figure_out_includes(i, 1); /* a source file? */
if (makefile)
finish_makefile();
exit(0);
}
void initially_read_in_directory()
{
/*
initialize the system variables and read in and sort the current directory...
*/
if (_dos_findfirst(".\\*.*", _A_NORMAL, &dp) == 0) /* current directory */
strcpy(directory[count++].name, strlwr(dp.name));
while (read_directory(directory[count++].name) && count < MAXFILES)
;
if (count >= MAXFILES)
{
fprintf(stderr,
"%s: Warning: more files than this program can deal with!\n",
pgm);
fprintf(stderr,
"%s continuing, but it might be wrong!\n", pgm);
}
qsort((void *)directory, (size_t) --count, sizeof (directory[0]), compare);
}
void initialize_makefile()
{
/*
outputs all the leading Makefile information as appropriate
*/
/* first off, let's dump the makefile_header stuff... */
register int i, len;
FLAGS k;
char buffer[SLEN];
printf("# Custom make file generated by %s for %s\n\n", pgm, defaults[TARGET]);
for (k = TARGET; k <= LIBS; k++)
printf("%s = %s\n", mak_defs[k], defaults[k]);
/* next, we'll need to output "HDRS", "SRCS" and "OBJS" ... */
printf("HDRS = ");
for (len=8, i=0; i < count; i++)
if (suffix(".h", directory[i].name))
{
++hdrs;
if (strlen(directory[i].name) + len > 75)
{
printf(" \\\n\t");
len = 8;
}
printf("%s ", directory[i].name);
len += strlen(directory[i].name)+1;
}
putchar('\n');
printf("SRCS = ");
for (len = 8, i=0; i < count; i++)
if (suffix(".c", directory[i].name) || suffix(".asm", directory[i].name))
{
++srcs;
if (strlen(directory[i].name) + len > 75)
{
printf(" \\\n\t");
len = 8;
}
printf("%s ", directory[i].name);
len += strlen(directory[i].name)+1;
}
putchar('\n');
printf("OBJS = ");
for (len = 8, i=0; i < count; i++)
if (suffix(".c", directory[i].name) || suffix(".asm", directory[i].name))
{
++objs;
if (strlen(directory[i].name) + len > 75)
{
printf(" \\\n\t");
len = 8;
}
strcpy(buffer, directory[i].name);
strcpy(strchr(buffer, '.'), ".obj"); /* make it a '.obj' file! */
printf("%s ", buffer);
len += strlen(buffer)+1;
}
printf(" \n\n");
}
void finish_makefile()
{
/*
adds some standard stuff to the end of the makefile
*/
printf(compile_command);
/* and the default binary target... */
printf("$(TARGET):\t");
printf("%s", (objs ? "$(OBJS) " : ""));
printf("%s", (srcs ? "$(SRCS) " : ""));
printf("%s", (hdrs ? "$(HDRS)\n" : "\n"));
printf("%s", link_line);
}
void get_file_modification_dates()
{
/*
do a 'stat' on each file in this directory, saving the last
modified date of each in the directory structure...
*/
struct stat buffer;
register int i;
for (i = 0; i < count ; i++)
if ((stat(directory[i].name, &buffer)) != 0)
{
fprintf(stderr,"%s: could not stat %s [%d] **\n",
pgm, directory[i].name, errno);
exit(errno);
}
else
{
directory[i].time = buffer.st_mtime;
}
}
void figure_out_includes(int index, int cnt)
{
/*
read the specified file, get all the files that this fellow
includes, then change the 'time' of the file entry in the
'directory' structure based on the times of the files it includes.
'cnt' is the nesting depth that we're currently at (for verbose
output and other I/O miscellany).
*/
FILE *thefile;
char buffer[SLEN];
int findex, i;
if (verbose)
if (cnt == 1)
printf("Checking file \"%s\"\n", directory[index].name);
else
{
for (i=0;i<cnt;i++)
printf(" ");
printf("includes file \"%s\"\n", directory[index].name);
}
if (cnt == 1 && makefile)
{
if (strlen(compile_command) > 0)
printf(compile_command);
if (suffix(".c", directory[index].name))
sprintf(compile_command, cc_line, directory[index].name);
else if (suffix(".asm", directory[index].name))
sprintf(compile_command, mc_line, directory[index].name);
}
if (dependencies || (makefile && cnt > 1))
printf("%s%s ", directory[index].name, cnt == 1 ? ":" : "");
else if (makefile && cnt == 1)
{
strcpy(buffer, directory[index].name);
strcpy(strchr(buffer, '.'), ".obj");
printf("%s:\t%s ", buffer, directory[index].name);
}
if (!verbose && !dependencies && !makefile && directory[index].checked)
return;
if ((thefile = fopen(directory[index].name,"r")) == NULL)
{
fprintf(stderr,"%s: could not open file %s for reading [%d] !\n",
pgm, directory[index].name, errno);
exit(errno);
}
/*
okay, now let's loop through this thing and try to get all the #include lines...
*/
while (fgets(buffer, SLEN, thefile) != NULL)
{
if (buffer[0] == '#') /* hmmm...a compiler directive... */
if ((findex = check_for_include(buffer)) != -1)
{
figure_out_includes(findex, cnt+1); /* recurse... */
}
}
directory[index].checked++;
if (dependencies && cnt==1) printf("\n");
(void) fclose(thefile);
}
int check_for_include(char *line)
{
/*
Line is an m4 directive line - this routine figures out if it is
an 'include' line, and if so, what file is being included. If the
file included is contained within this directory, then this routine
will return the index, otherwise it will return -1 if an error.
*/
char *line_ptr, *word, *strtok();
int i;
line[0] = ' '; /* remove the '#' */
/*
this first section is so we can have "# include" as well
as "#include" ... we simply get the first word token via
calls to 'strtok()'
*/
line_ptr = (char *) line; /* gets the address */
if ((word = strtok(line_ptr," \t")) != NULL)
{
if (strcmp(word, "include") != 0)
return(-1);
}
else
return(-1);
/*
to get to here, it must be an include line and the internal strtok
pointer must be pointing at the filename surrounded by quotes or
'<>' characters... (note that the " in the strtok call will also
suffice to remove the quotes from the filename too)
*/
if ((word = strtok(NULL, "\t \"")) != NULL)
{
if (word[0] == '<')
return(-1);
}
else
return(-1);
/*
to get to here, it must have included the file that is specified
as 'word' currently, and that file must be a specified file in
the local directory.
*/
for (i=0; i < strlen(word); i++)
if (word[i] == '\\')
return(-1);
/*
now, finally, we know that 'word' must be a file in the
current directory, so we merely need to find it's index
into the directory structure of this program and return it!
*/
for (i=0; i < count; i++)
if (strcmpi(word, directory[i].name) == 0)
return(i);
/* it wasn't in there??? */
fprintf(stderr,"%s: %s not in directory.\n",
pgm, word);
return(-1);
}
int read_directory(char *buffer)
{
/*
return the next name in the directory... returns zero when
we're out of entries.
*/
if (_dos_findnext(&dp) == 0)
{
strcpy(buffer, strlwr(dp.name));
return(1);
}
return(0);
}
int suffix(char *sf, char *string)
{
/* returns true iff the suffix of 'string' is 'sf' */
register int i, j;
i = strlen(string);
j = strlen(sf);
while (string[i] == sf[j] && j > 0)
{
i--;
j--;
}
return(sf[0] == string[i] && j == 0);
}
int compare(struct dir_rec *a, struct dir_rec *b)
{
/* strcmp on name field (for sort routine) */
return( strcmp(a->name, b->name));
}