mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-12-22 14:30:29 +00:00
784e3de7cd
passwd, ps, purge, shutdown, stty, upper, and vi. These sources are for the versions of the utils shipped with GNO v2.0.4.
493 lines
16 KiB
C
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, ¶ms[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 */
|
|
}
|