home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d8xx
/
d810
/
makedmake.lha
/
MakeDMake
/
MakeDMake.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-24
|
16KB
|
561 lines
/*
* MakeDMake v0.19 -- automatically construct a makefile for DMake
*
* Basically it's Tim McGrath's 'MakeMake' from Fish 74,
* -----------------------------------------------------
*
* but it has been slightly hacked, so that it got much more
* enterprising and workaholic, so to say.
*
*
* HOW TO:
*
* You give it the names of all the C-files that are to produce your
* executable (but NOT #include'd .c or .h files!), and it will
* automatically scan them to find all dependencies, and produce a
* ready to use (in many cases) DMakeFile calling DCC with options
* you will need for normal compilation and linking. Other things
* can be added if needed by editing that file. In most cases it
* should be enough to give MakeDMake '#? or '*' on command-line.
* You will be than asked about the name of the executable, if you
* just press RETURN -- you will get the default name, being EITHER
* the NAME of the input file without the extension (if it was the
* ONLY name MakeDMake got), or 'main' (without quotes).
*
* For exemple, if you call it with the command-line like this:
*
* MakeDMake file1.c file2.c file3.c ... filen.c
*
* and choose 'ex_file' as the name for the executable,
*
* you will get something like that in your DMakeFile:
*
* OPT1 =
* OPT2 =
*
* ex_file : file1.o file2.o file3.o ... filen.o
* dcc $(OPT1) -o ex_file file1.o file2.o file3.o ... filen.o
*
* filex.o : filex.c ... header file list ...
* dcc $(OPT1) filex.c
*
* where the header file list is the transitive closure of all
* files #included in filex.c (i.e. if filex.c #includes "header.h",
* and "header.h" #includes "subheader.h", both "header.h" and
* "subheader.h" appear in the list of header files). MakeDMake only
* examines header files delimited by double quotes ("). System header
* files enclosed in angle brackets (< and >) are not examined.
* (That last bit of beautiful native-speaker English was almost
* literally taken from Tim's original comment. Now, back to my own
* personal variant...)
*
* As you probably know, if you have all properly set, 'dmake'
* typed in the CLI with no parameters, will look for the
* file called 'DMakeFile' in current directory and use its information
* to update/recompile etc. your files. And it can be made even easier
* with aliases. With two csh aliases like that:
*
* alias mdm "MakeDMake *.c" ## for all C files in current dir
* alias go "DMake" ## not so much really, but...
*
* ## alternatively -- if you may have 'unique' makefile names
* ## in the form <something>.make, you may use:
*
* "alias go DMake -f *make"
*
* I can compile most of the C programs with no effort whatsoever,
* as most of the DCC I need use are already set in the ENV:DCCOPTS.
* You can, however, recompile with your own standard set of options.
* Many other things here can be easilly changed, adjusted and
* then recompiled; also for other compilers than DICE. Try to do
* that by changing the #defines first!
*
* The original 'MakeMake' was in Public Domain, and this stuff here
* also is.
*
* Piotr Obminski, January 1993
*/
#include <stdio.h>
#ifndef void
#define void int
#endif
#define LINEMAX 80 /* length of line in created DMakeFile */
#define CC_NAME "dcc" /* or e.g. "lc" for Lattice */
/* default name for executable (only if if given two or more C files!).
* NO '.' (like in 'a.out') PLEASE! This is still no UNIX!
*/
#define MAIN_NAME "main"
/* this program doesn't NECESSARILY need to call itself MakeDMake...!
*/
#define OUTFILE_NAME "DMakeFile"
/* default OPT1 & OPT2 strings
*/
#define O2X_OPT NULL /* 'object to executable' options */
#define C2O_OPT NULL /* 'C to object' options */
/* zero if we want call outfile 'DMakeFile' instead of the individualized
* (unique) name in the form '<executable>.make'
*/
#define UNIQUE_OUTNAME 0
/* ANSI sequences, #define them as '""' (no single quotes!)
* if you hate 'em!
*/
#define ANSI_BOLD "1m"
#define ANSI_WHITE "2m" /* more or less... */
#define ANSI_NORMAL "0m"
char main_name[ 40 ] = MAIN_NAME;
FILE *OutFile;
void
main( argc, argv )
char **argv;
int argc;
{
int dependent_count;
char **dependents;
char outfile_name[ 40 ] = OUTFILE_NAME;
char temp[ 40 ] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
int good_file_count = 0;
int i;
/* no input or '?', 'h', 'H' or something beginning with '-', so
* he needs help!
*/
if ( argc == 1 || ( *argv[ 1 ] == '?' ) || ( *argv[ 1 ] == '-' ) ||
( ( *argv[ 1 ] == 'h' ) && ( *( argv[ 1 ] + 1 ) == '\0' ) ) ||
( ( *argv[ 1 ] == 'H' ) && ( *( argv[ 1 ] + 1 ) == '\0' ) ) ) {
puts( "------------------------------------------------------------\n"
ANSI_BOLD "MakeDMake v0.19" ANSI_NORMAL ANSI_WHITE
" PD Utility for creating" ANSI_NORMAL ANSI_BOLD
" DMakeFile" ANSI_NORMAL "'s\n"
"------------------------------------------------------------\n"
ANSI_WHITE "USAGE: " ANSI_NORMAL "Give me names of your "
ANSI_BOLD "source files " ANSI_NORMAL
"and then we'll\n"
" get interactive. If I'm successful, the resulting\n"
" " ANSI_BOLD "DMakeFile" ANSI_NORMAL
" will be in the current directory.\n"
" Now that you know -- "
ANSI_BOLD "START AGAIN" ANSI_WHITE " !\n" ANSI_NORMAL
"------------------------------------------------------------" );
exit ( 1 );
}
/* if we got only one command-line argument, and it ends in '.c'
* we start by cutting off this '.c', then we look...
*/
if ( argc == 2 ) {
register char *p;
strcpy( temp, argv[ 1 ] );
if ( ( p = (char *)strstr( temp, ".c" ) ) && ( *( p + 2 ) == '\0' ) ) {
*p = '\0';
strcpy( main_name, temp );
}
else {
puts( ANSI_BOLD "This stuff you gave me ain't no C code!. "
ANSI_NORMAL ANSI_WHITE "Aborting!" ANSI_NORMAL );
exit( 1 );
}
}
printf( "Name for the executable? (or "
ANSI_BOLD "RETURN" ANSI_NORMAL " for "
"'" ANSI_WHITE "%s" ANSI_NORMAL "'): ", main_name );
gets( temp );
if ( isalpha( *temp ) ) {
strcpy( main_name, temp );
#if UNIQUE_OUTNAME
/* change name of the generated MakeFile to
* <executable>.make
*/
strcpy( outfile_name, temp );
strcat( outfile_name, ".make" );
#endif
}
printf( "------------------------------------------------------" );
{
register short i = strlen( temp );
if ( i )
putchar( '-' );
while ( i-- )
putchar( '-' );
}
putchar( '\n' );
if ( ( OutFile = fopen( outfile_name, "w" ) ) == 0L ) {
printf( ANSI_BOLD "CAN'T CREATE " ANSI_NORMAL ANSI_WHITE
"%s" ANSI_NORMAL ANSI_BOLD " !\n\07" ANSI_NORMAL,
outfile_name );
exit( 1 );
}
fputs( "# DMakeFile generated by MakeDMake v0.19\n\n", OutFile );
fprintf( OutFile, "OPT1 = %s\nOPT2 = %s\n\n", O2X_OPT, C2O_OPT );
depend_file( argc, argv, main_name, " ", ".o" );
for ( i = 1; i < argc; i++ ) {
/* we don't want MakeDMake to make a fool of himself by
* trying to compile various ReadMe's and Trashcan.icon!
* So we are skipping such stuff! However it's not always totally
* successful, so far...
*/
register char *p;
if ( ( p = (char *)strstr( argv[ i ], ".c" ) ) &&
( *( p + 2 ) == '\0' ) ) {
get_dependents( argv[ i ], &dependents, &dependent_count );
depend_file( dependent_count, dependents, argv[ i ], ".o", "" );
free_space( dependents, dependent_count );
good_file_count++;
}
else {
printf( "%s", argv[ i ] );
if ( strlen( argv[ i ] ) < 16 )
putchar( '\t' );
if ( strlen( argv[ i ] ) < 8 )
putchar( '\t' );
puts( "\t" ANSI_NORMAL ANSI_WHITE "<" ANSI_NORMAL ANSI_BOLD
"ignored" ANSI_NORMAL ANSI_WHITE ">" ANSI_NORMAL );
}
}
fclose( OutFile );
if ( good_file_count == 0 ) {
puts( ANSI_WHITE "Not even one good C file!" ANSI_NORMAL ANSI_BOLD
" Who" ANSI_NORMAL "(m) " ANSI_BOLD
"do you think you're kidding?" ANSI_NORMAL );
exit( 1 );
}
exit( 0 );
}
int
free_space( dp, dc )
/*
* Purpose: free up list of file names
* Inputs: dp - points to list of pointers to strings
* dc - number of pointers in the list
*/
char **dp;
int dc;
{
while ( dc > 0 ) {
free( *dp++ ); dc--;
}
/* free( dp ); <------ here is the offender in the original
* which makes the program to hang.
*/
}
char *
file_exten( pgm_name, xtension, bufout )
/*
* Purpose: append new extension onto file name
* Inputs: pgm_name - pointer to name of file
* xtension - pointer to new file name extension (2 chars only)
* Outputs: bufout - points to area for new file name
* Returns: bufout
*/
char *pgm_name, *xtension, *bufout;
{
int i = 0;
while ( *pgm_name ) {
bufout[ i++ ] = *pgm_name;
if ( *pgm_name++ == '.' && xtension[ 0 ] != '\0' ) {
bufout[ i++ ] = xtension[ 1 ];
break;
}
}
bufout[ i ] = '\0'; return( bufout );
}
void
depend_file( ct, flist, pgm_name, pgmx, filex )
/*
* Purpose: print file name and list of dependents
* Inputs: ct - number of dependents in the list
* flist - pointer to a list of pointers to dependent names
* pgm_name - name of file whose dependents are being printed
* pgmx - extension for pgm_name file (or "" if none)
* filex - extension for dependent file names (or "" if none)
*/
char **flist, *pgm_name, *pgmx, *filex;
int ct;
{
int i;
char buf[ LINEMAX ], add_name[ LINEMAX ], pname[ LINEMAX ];
char bare_name[ LINEMAX ];
{
register short i = 0;
do {
bare_name[ i ] = pgm_name[ i ];
} while ( pgm_name[ i ] && ( pgm_name[ i++ ] != '.' ) );
bare_name[ --i ] = '\0';
}
start_line( file_exten( pgm_name, pgmx, pname ), buf );
if ( strcmp( pgm_name, main_name ) )
strcat( strcat( buf, " " ), pgm_name );
for ( i = 1; i < ct; i++ ) {
file_exten( flist[ i ], filex, add_name );
if ( columns( buf ) + strlen( add_name ) + 1 >= LINEMAX - 1 ) {
fputs( buf, OutFile ); fputs( "\\\n", OutFile );
continue_line( file_exten( NULL, NULL, pname ), buf );
}
strcat( strcat( buf, " " ), add_name );
}
fputs( buf, OutFile ); fputc( '\n', OutFile );
if ( strcmp( pgm_name, main_name ) ) {
fprintf( OutFile,"\t%s $(OPT2) -c %s.o %s.c\n\n",
CC_NAME, bare_name, bare_name );
}
else {
fprintf( OutFile, "\t%s $(OPT1) -o %s ", CC_NAME, main_name );
output_objects( flist, ct );
fputs( "\n\n", OutFile );
}
}
void
output_objects( files, count )
char **files;
int count;
{
unsigned short i, col, len;
char arr[ 40 ], *brk1, *brk2;
register char *p;
col = 32; /* more or less initial column */
for ( i = 1; i < count; i++ ) {
/* see if file has legal name ending in '.c'
*/
if ( ( p = (char *)strstr( files[ i ], ".c" ) ) &&
( *( p + 2 ) == '\0' ) ) {
strcpy( arr, files[ i ] );
len = strlen( arr );
col += len;
if ( col >= LINEMAX - 2 ) {
brk1 = "\\\n\t\t\t";
brk2 = "";
col = 32 + len + 1;
}
else {
brk1 = " ";
brk2 = "";
}
p = (char *)strchr( arr, '.' );
*++p = 'o';
fprintf( OutFile, "%s%s%s", brk1, arr, brk2 );
}
}
}
void
start_line( with_name, buf )
/*
* Purpose: give each line a standard indentation
* Inputs: with_name - name of root file on each line
* buf - place to put indented line
*/
char *with_name, *buf;
{
strcpy( buf, with_name ); strcat( buf, "\t" );
if ( columns( buf ) < 16 )
strcat( buf, "\t" );
if ( columns( buf ) < 24 )
strcat( buf, "\t" );
strcat( buf, ":" );
}
void
continue_line( with_name, buf )
/*
* Purpose: let the line continue after '\' and '\n'
* Inputs: with_name - name of root file on each line
* buf - place to put indented line
*/
char *with_name, *buf;
{
strcpy( buf, with_name );
strcat( buf, "\t " );
if ( columns( buf ) < 16 )
strcat( buf, "\t " );
if ( columns( buf ) < 24 )
strcat( buf, "\t " );
}
int
columns( s )
/*
* Purpose: count the number of columns a line spans
* Inputs: s - the characters in a line
* Returns: the number of columns ( including tab expansion )
*/
char *s;
{
int col = 0;
while ( *s ) {
if ( *s++ == '\t' )
while ( ++col & 7 )
;
else ++col;
}
return( col );
}
void
get_dependents( fn, depv, depc )
/*
* Purpose: return a list of files depending on a C source file
* Inputs: fn - name of the c source file
* Outputs: depv - list of dependents (an array of pointers to filenames)
* depc - number of dependents
*/
char *fn, ***depv;
int *depc;
{
char **lst;
int i;
lst = (char **)malloc( 1024 * sizeof( char * ) );
move_name( &lst[ 0 ], fn );
fputs( fn, stdout ); fputc( '\n', stdout ); i = 0;
scan_file( lst, &i, fn ); *depv = lst; *depc = i + 1;
}
void
move_name( p, s )
/*
* Purpose: Allocate space for a new filename and copy it
* Inputs: p - location for new pointer to filename
* s - pointer to file name
*/
char **p, *s;
{
*p = (char *)malloc( strlen( s ) + 1 );
strcpy( *p, s );
}
void
scan_file( file_name_list, last_list_used, fn )
/*
* Purpose: search a C source file file #includes, and search the #includes
* for nested #includes
* Inputs: fn - name of file to scan
* Outputs: file_name_list - list of included files
* last_list_used - last used filename position in file_name_list
*/
char **file_name_list, *fn;
int *last_list_used;
{
FILE *fp;
char buf[ 1024 ], ifn[ LINEMAX ];
int j,k;
fp = fopen( fn, "r" );
if ( ! fp ) {
fprintf( stdout, ANSI_BOLD "\tcouldn't open file "
ANSI_NORMAL ANSI_WHITE "%s\n" ANSI_NORMAL, fn );
return;
}
while ( fgets( buf, 1024, fp ) ) {
if ( strncmp( buf, "#include", 8 ) == 0 ) {
j = 8;
while ( buf[ j ] == ' ' || buf[ j ] == '\t' )
j++;
if ( buf[ j++ ] != '"' )
continue;
k = 0;
while ( buf[ j ] ) {
if ( buf[ j ] == '"' || buf[ j ] == '\n' )
break;
else
ifn[ k++ ] = buf[ j++ ];
}
ifn[ k ] = '\0';
if ( add_name( file_name_list, last_list_used, ifn ) )
scan_file( file_name_list, last_list_used, ifn );
}
}
fclose( fp );
}
int
add_name( file_name_list, last_list_used, fn )
/*
* Purpose: Add a file name to the list if it's not there already
* Inputs: file_name_list - pointer to array of pointers to file names
* last_list_used - last element in array with a filename
* fn - name of file
* Returns: 1 if file name added, 0 otherwise
*/
char **file_name_list, *fn;
int *last_list_used;
{
int i;
for ( i = 0; i <= *last_list_used; i++ )
if ( ! strcmp( file_name_list[ i ], fn ) )
return( 0 );
*last_list_used += 1;
move_name( &file_name_list[ *last_list_used ], fn );
return( 1 );
}