gno/bin/make/make.c
gdr-ftp 784e3de7cd Initial checkin of aroff, binprint, center, less, ls, make, makemake,
passwd, ps, purge, shutdown, stty, upper, and vi.  These sources are
for the versions of the utils shipped with GNO v2.0.4.
1998-03-09 08:30:21 +00:00

493 lines
16 KiB
C

#pragma stacksize 2048
#pragma debug 24
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <gsos.h>
#include <shell.h>
#include <orca.h>
#pragma lint -1
/* #define DEBUG_MODE */
#define version "Make - Version 1.1"
#define NAME_SIZE 80 /* max file name size */
#define MSG_SIZE 80 /* max size of any generated message */
#define PARAM_SIZE 256 /* max size of any input parameter */
#define d_flag 'D' /* display date/time info */
#define p_flag 'P' /* programmer (debug) mode */
#define s_flag 'S' /* silent mode */
#define target_delim ':' /* target file delimiters */
#define dep_delims " ," /* dependant file delimiters */
#define comment_char '#' /* start of comment */
/* System error return values */
#define BAD_OPTION 1
#define NO_INPUT_FILE 2
#define NO_MEM_AVAIL 3
#define SYNTAX_ERR 4
#define USER_ABORT 5
#define SHELL_ERR 6
#define EOF_ERR 7
#define ILLEGAL_FILE 8
#define MEM_UNAVAIL "Not enough memory available to execute."
typedef struct readVariableDCB {
Str255 *varName, *value;
} readVariableDCB;
typedef struct executeDCB {
int flag;
char *commandString;
} executeDCB;
/* Routine prototypes */
void ShowLastParam(void);
int GetInfo(FileInfoRecPtrGS file_info, int params, char *file_name);
int FileExists(char *);
void ErrorMessage(char *);
void ErrorAbort(char *, int);
int CheckDepFiles(char *dep_params, char *target_file);
int GetTargetFile(char *params, char *target);
int ExecuteMakeCommand(char *make_command, char *target_file);
enum MODES {PARAM, CONTINUATION, COMMAND, DONE};
unsigned char valid_types[] = { 0x04, 0xB0, 0 }; /* valid file types TXT, SRC */
FILE *make_file;
char msg[MSG_SIZE], make_param[PARAM_SIZE], prog_name[NAME_SIZE];
int silent, debugging, disp_date_time;
int main(int argc, char *argv[])
{
int i, type_ok;
enum MODES mode;
char *tmp_file, *make_file_name;
char first_char, *dep_params, *target_file;
FileInfoRecGS file_info;
StopPB stop_info;
/*
Initialize all global variables so that we can run as a re-startable
command in the shell environment.
*/
make_param[0] = '\0'; /* init to NULL string */
/*dep_params[0] = '\0';
target_file[0] = '\0'; */ /* NONONONONONONO */
msg[0] = '\0';
strcpy(prog_name, argv[0]); /* for error message processing */
silent = FALSE;
debugging = FALSE;
disp_date_time = FALSE;
/* Allocate some dynamic work variables */
if ( (make_file_name = malloc(NAME_SIZE)) == NULL )
ErrorAbort(MEM_UNAVAIL, NO_MEM_AVAIL);
if ( (dep_params = malloc(PARAM_SIZE)) == NULL )
ErrorAbort(MEM_UNAVAIL, NO_MEM_AVAIL);
if ( (target_file = malloc(NAME_SIZE)) == NULL )
ErrorAbort(MEM_UNAVAIL, NO_MEM_AVAIL);
*make_file_name = 0; /* this was a bug- jb */
/* Parse the command line information */
for (i = 1; i < argc; i++)
if ( argv[i][0] == '-' || argv[i][0] == '+' ) { /* command line option */
switch (toupper(argv[i][1])) {
case p_flag: debugging = TRUE; /* set appropriate flag */
break;
case s_flag: silent = TRUE;
break;
case d_flag: disp_date_time = TRUE;
break;
default: ErrorAbort("Invalid option specified.", BAD_OPTION);
}
}
else
strcpy(make_file_name, argv[i]); /* not an opt, must be a file */
if ( !silent )
puts(version); /* display version info */
if ( strlen(make_file_name) == 0 ) { /* did we get an input file name */
strcpy(make_file_name, "makefile");
/* fputs("MAKE file: ", stdout); /* nope, ask for one */
/* if ( gets(make_file_name) == NULL ) /* make sure we got one */
/* exit(NO_INPUT_FILE); /* if not, give up */
}
/*
Allocate some work variables:
tmp_file - will be used to check for a file with the default extention.
*/
if ( (tmp_file = malloc(NAME_SIZE)) == NULL )
exit(NO_MEM_AVAIL);
strcpy(tmp_file, make_file_name); /* get a copy of the specified name */
strcat(tmp_file, ".make"); /* default extention */
if ( FileExists(tmp_file) ) /* check for default name */
strcpy(make_file_name, tmp_file); /* got it */
else
if ( !FileExists(make_file_name) ) { /* nope check specified name */
sprintf(msg, "Make file %s does not exist.", make_file_name);
ErrorAbort(msg, NO_INPUT_FILE); /* still not there, give up */
}
free(tmp_file); /* done with this memory */
GetInfo(&file_info, 3, make_file_name); /* Check input file type */
type_ok = FALSE;
for ( i=0; i < sizeof(valid_types); i++ ) /* search valid types */
if ( file_info.fileType == valid_types[i] ) {
type_ok = TRUE;
break;
}
if ( !type_ok )
ErrorAbort("Input file must be either TXT or SRC.", ILLEGAL_FILE);
/* Open the input file */
if ( (make_file = fopen(make_file_name, "r")) == NULL ) {
perror(prog_name);
sprintf(msg, "Error opening input file %s.", make_file_name);
ErrorAbort(msg, NO_INPUT_FILE);
}
mode = PARAM; /* initial mode is parameter search */
/* Read the input file and process the make commands */
while ( fgets(make_param, sizeof(make_param), make_file) != NULL ) {
if ( (i = strpos(make_param, '\n')) >= 0 )
make_param[i] = '\0'; /* remove NL character */
if ( debugging )
printf("make_param:[%s] i: %d, mode: %d\n", make_param, i, mode);
first_char = make_param[0]; /* we will check this char often */
if ( (first_char == '\0') || (first_char == comment_char) ) {
mode = PARAM; /* blank line terminates COMMAND/CONTINUE mode */
continue; /* ignore blank lines & comment lines */
}
if ( mode == CONTINUATION ) { /* CheckDepFiles wants more params */
strcpy(dep_params, make_param); /* pre-load params */
mode = CheckDepFiles(dep_params, target_file);
}
else if ( first_char != ' ' ) {
mode = PARAM; /* back into param search mode */
strcpy(dep_params, make_param); /* set up for parsing */
if ( GetTargetFile(dep_params, target_file) ) /* we should find one */
mode = CheckDepFiles(dep_params, target_file);
else
ErrorAbort("Target file specification error, no ';' found.",SYNTAX_ERR);
}
else if ( mode == COMMAND )
mode = ExecuteMakeCommand(make_param, target_file);
STOP(&stop_info); /* Check for user termination */
if ( stop_info.stop == 1 )
ErrorAbort("User termination.", USER_ABORT);
} /* while reading parameters and not in DONE mode */
if ( mode == CONTINUATION )
ErrorAbort("Unexpected End-Of-File encountered after continuation.", EOF_ERR);
fclose(make_file);
exit(0);
}
void ErrorMessage(char *error_mesg)
{
printf("%s: %s\n", prog_name, error_mesg);
}
void ShowLastParam(void)
{
ErrorMessage("Error occured at:");
ErrorMessage(make_param);
}
void ErrorAbort(char *abort_mesg, int error_num)
{
ErrorPB error_params;
if ( (error_params.error = toolerror()) != 0 ) /* If a tool error */
ERROR(&error_params); /* Have the shell display the msg */
ErrorMessage(abort_mesg); /* Display my message */
if ( strlen(make_param) > 0 ) /* If param parsing */
ShowLastParam(); /* display the param */
exit(error_num);
}
GSString255Ptr strcpygs(GSString255Ptr gs_str, char *str)
{
gs_str->length = strlen(str);
strcpy((char *) gs_str->text, str);
return(gs_str);
}
int GetInfo(FileInfoRecPtrGS file_info, int params, char *file_name)
{
GSString255 file_info_name;
#ifdef DEBUG_MODE
puts("GetInfo");
#endif
file_info->pCount = params;
file_info->pathname = strcpygs(&file_info_name, file_name);
GetFileInfoGS(file_info);
return(toolerror());
}
int FileExists(char *file_name)
{
FileInfoRecGS file_info;
return(GetInfo(&file_info, 2, file_name) ? FALSE : TRUE);
}
void TrimLeft(char *str)
{
char *tmp;
tmp = str;
while ( *tmp == ' ' && *tmp != '\0' ) tmp++;
strcpy(str, tmp);
}
void TrimRight(char *str)
{
int tmp;
tmp = strlen(str);
while ( tmp >= 0 && str[tmp] == ' ') tmp--;
str[++tmp] = '\0';
}
int ExecuteMakeCommand(char *make_command, char *target_file)
{
char var_name[80], var_value[80];
Get_VarPB get_var;
executeDCB exec_params;
#ifdef DEBUG_MODE
puts("ExecuteMakeCommand()");
#endif
TrimLeft(make_command);
if ( !silent )
printf("\n%s\n\n", make_command);
make_command[strlen(make_command)+1] = '\0'; /* add an extra NULL */
exec_params.flag = 1; /* use existing variable table */
exec_params.commandString = make_command;
EXECUTE(&exec_params);
strcpy((char *) var_name, "\pStatus");
get_var.var_name = var_name;
get_var.value = var_value;
GET_VAR(&get_var);
if ( toolerror() != 0 )
ErrorAbort("Error occured during READ_VARIABLE.", SHELL_ERR);
var_value[var_value[0]+1] = '\0';
if ( debugging )
printf("var_name: %p = %p\n",var_name, var_value);
if ( strcmp((char *) var_value+1, "0") != 0 ) {
remove(target_file);
ErrorAbort("Error occurred during the last command.", SHELL_ERR);
} /* Status != "0" */
return COMMAND; /* remain in COMMAND mode */
}
int GetTargetFile(char *params, char *target)
{
int ch;
#ifdef DEBUG_MODE
puts("GetTargetFile()");
#endif
if ( (ch = strpos(params, target_delim)) == -1 )
return FALSE;
strncpy(target, params, ch);
target[ch] = '\0';
TrimLeft(target);
strcpy(params, &params[ch+1]);
if ( debugging )
printf("params: [%s] target: [%s]\n", params, target);
return TRUE;
}
void GetModDate(TimeRec *info, char *date)
{
sprintf(date, "%d/%02d/%02d", info->month+1, info->day+1, info->year);
}
void GetModTime(TimeRec *info, char *time)
{
sprintf(time, "%d:%02d:%02d", info->hour, info->minute, info->second);
}
int DepFileOlder(char *target_file, char *dep_file)
{
FileInfoRecGS target, dependant;
char mod_date[12];
#ifdef DEBUG_MODE
puts("DepFileOlder()");
printf("target_file:[%s] dep_file:[%s]\n", target_file, dep_file);
#endif
if ( GetInfo(&target, 7, target_file) != 0 ) {
ErrorMessage("target file does not exist.");
return TRUE; /* if any errors, assume target not found */
}
if ( debugging || disp_date_time ) { /* Diaplay mod date if in debug mode */
GetModDate(&target.modDateTime, mod_date);
printf("[Date]Target: %s = %s\n", target_file, mod_date);
}
if ( GetInfo(&dependant, 7, dep_file) != 0 ) {
ErrorMessage("dependant file does not exist.");
return FALSE; /* dependant file exist? No, user must be nuts */
}
if ( debugging || disp_date_time ) { /* Diaplay mod date if in debug mode */
GetModDate(&dependant.modDateTime, mod_date);
printf("[Date]Dependant: %s = %s\n", dep_file, mod_date);
}
/* Both the target file and the dependant file exists, check mod info */
if ( ( dependant.modDateTime.year == target.modDateTime.year ) &&
( dependant.modDateTime.month == target.modDateTime.month ) &&
( dependant.modDateTime.day == target.modDateTime.day ) ) { /* equal dates */
if ( debugging || disp_date_time ) { /* display debug info */
GetModTime(&target.modDateTime, mod_date);
printf("[Time]Target: %s = %s\n", target_file, mod_date);
GetModTime(&dependant.modDateTime, mod_date);
printf("[Time]Dependant: %s = %s\n", dep_file, mod_date);
}
/* check times */
if ( dependant.modDateTime.hour > target.modDateTime.hour )
return TRUE;
else if ( dependant.modDateTime.hour < target.modDateTime.hour )
return FALSE;
else if ( dependant.modDateTime.minute > target.modDateTime.minute)
return TRUE;
else if ( dependant.modDateTime.minute < target.modDateTime.minute)
return FALSE;
else if ( dependant.modDateTime.second > target.modDateTime.second)
return TRUE; /* dependant older */
else
return FALSE; /* target older */
} else /* unequal dates */
if ( dependant.modDateTime.year > target.modDateTime.year )
return TRUE;
else if ( dependant.modDateTime.year < target.modDateTime.year )
return FALSE;
else if ( dependant.modDateTime.month > target.modDateTime.month )
return TRUE;
else if ( dependant.modDateTime.month < target.modDateTime.month )
return FALSE;
else if ( dependant.modDateTime.day > target.modDateTime.day )
return TRUE; /* dependant is older */
else
return FALSE; /* target is older */
}
void FlushParams(void)
{
char *param_token;
int read_file = FALSE, flush_complete = FALSE;
#ifdef DEBUG_MODE
puts("FlushParams()");
#endif
do {
if ( read_file ) { /* handle continuation, read another line */
if ( fgets(make_param, sizeof(make_param), make_file) == NULL )
ErrorAbort("Unexpected End-Of-File encountered after continuation.", EOF_ERR);
param_token = strtok(make_param, dep_delims); /* init parser */
read_file = FALSE; /* reset read flag */
}
else
param_token = strtok(NULL, dep_delims); /* continue reading */
if ( debugging )
printf("param_token:[%s]\n", param_token);
if ( param_token == NULL || *param_token == comment_char ) /* done yet? */
flush_complete = TRUE; /* yes, signal end */
else if ( *param_token == '\\' ) /* continuation? */
read_file = TRUE; /* yes, read another line */
} while ( !flush_complete );
}
int CheckDepFiles(char *dep_params, char *target_file)
{
int first_file;
char *dep_file;
#ifdef DEBUG_MODE
puts("CheckDepFiles()");
printf("dep_params: [%s] target_file: [%s]\n",dep_params, target_file);
#endif
first_file = TRUE;
do { /* parse all dependant files from dep_params */
if ( first_file ) { /* first time through, init parser */
dep_file = strtok(dep_params, dep_delims); /* get 1st file name */
if ( dep_file == NULL ) /* there must be at least 1 file name */
ErrorAbort("No dependant files specified.", SYNTAX_ERR);
first_file = FALSE;
}
else /* all subsequent parsing is done from the previous params */
dep_file = strtok(NULL, dep_delims);
if ( dep_file == NULL ) /* any more parameters? */
return PARAM; /* nope, back to param search mode */
if ( debugging )
printf("dep_file:[%s]\n", dep_file);
if ( *dep_file == '\\' ) /* continuation? */
return CONTINUATION; /* yes, get the next line */
else if ( *dep_file == comment_char ) /* trailing comment? */
return PARAM; /* yes, skip all commands until next param */
else if ( *dep_file == '\0' ) /* Null string? */
continue; /* yes, look some more */
else if ( DepFileOlder(target_file, dep_file) ) {
FlushParams(); /* skip over any continuation stuff */
return COMMAND; /* dependant is older, rebuild target */
}
} while ( dep_file != NULL ); /* until no more dependant files */
return PARAM; /* return to param search mode */
}