home *** CD-ROM | disk | FTP | other *** search
- /*
- 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));
- }
-