Rev 1026 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include <stdarg.h>#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <process.h>#include "CRTDBG.H"#include "version.h"#ifndef TRUE#define TRUE (-1)#endif#ifndef FALSE#define FALSE (0)#endif#define MAX_LINE_LEN 1024typedef enum {BIG_ENDIAN, LITTLE_ENDIAN} endian_t;/** GLOBAL DATA*/FILE *op_stream;FILE *ip_stream;FILE *cmd_stream;int i_op_file_opened = FALSE;int i_ip_file_opened = FALSE;char cmd_line[MAX_LINE_LEN];int i_had_input_stream_errors = FALSE;fpos_t ip_stream_pos;int ip_stream_pos_valid = FALSE;int ip_stream_pos_cmdLineNumber;long cmdLineNum = 0;int endianism = BIG_ENDIAN;long op_stream_tell[10];long base_reference = 0;int debug_level = 0;int mustAbort = 0;int exitCode = 0;typedef struct{int cmdLineNumber;fpos_t filepos;} stack_t;#define MAX_STACK 50stack_t stack[MAX_STACK];int stackptr = -1;int skippingPastSub = 0;#define DEBUG_CONTROL_CMD_MASK 0x0001#define DEBUG_OUTPUT_CMD_MASK 0x0002#define DEBUG_INPUT_CMD_MASK 0x0004/**************************************************************************//* COMMAND REPEAT support*/typedef struct {int cmdLineNumber;fpos_t cmd_stream_pos;int cmd_stream_repeat;} cmd_rep_type;#define MAX_NEST_LEVEL 10cmd_rep_type cmd_repeat_stack[MAX_NEST_LEVEL];int cmd_repeat_nest_level = -1;/**************************************************************************//* PROTOTYPES */void ins_quad(unsigned __int64 value);void ins_long(unsigned long value);void ins_word(unsigned long value);void ins_byte(unsigned long value);/**************************************************************************/char * skip_to_spaces(char * strptr){while ( (isspace(*strptr) == 0) && (*strptr != 0) )strptr++;return strptr;}char * skip_past_spaces(char * strptr){while ( (isspace(*strptr) != 0) && (*strptr != 0) )strptr++;return strptr;}char * next_value(char * arg_ptr, unsigned long * value, int * got_a_value){char * endp;unsigned long arg_val = 0;*got_a_value = FALSE;// skip to the first numericwhile ( ((*arg_ptr < '0') || (*arg_ptr > '9'))&&(*arg_ptr != 0) ) {arg_ptr++;}arg_val = strtoul( arg_ptr, &endp, 0 );*value = arg_val;if (endp > arg_ptr)*got_a_value = TRUE;arg_ptr = endp;return arg_ptr;}char * next_value64(char * arg_ptr, unsigned __int64 * value, int * got_a_value){char * endp;unsigned __int64 calc = 0;unsigned long arg_val = 0;*got_a_value = FALSE;// skip to the first numericwhile ( ((*arg_ptr < '0') || (*arg_ptr > '9')) && (*arg_ptr != 0) ) {arg_ptr++;}// Process Dataendp = arg_ptr;while ( ((*endp >= '0') && (*endp <= '9')) && (*endp != 0) ) {calc = calc * 10;calc += *endp - '0';endp++;}*value = calc;if (endp > arg_ptr)*got_a_value = TRUE;arg_ptr = endp;return arg_ptr;}char * remove_trailing_spaces(char * pStr){int str_len = strlen(pStr);if (str_len > 0){while ( (--str_len >= 0) && (pStr[str_len] == ' ') ){pStr[str_len] = 0;}}return pStr;}void strip_trailing_comment(char * pStr){char * comment_ptr;comment_ptr = strchr(pStr, '#');if (comment_ptr != NULL)*comment_ptr = 0;}void strip_trailing_comment_and_spaces(char * pStr){char * comment_ptr;comment_ptr = strchr(pStr, '#');if (comment_ptr != NULL)*comment_ptr = 0;(void)remove_trailing_spaces(pStr);}char * remove_newline_char(char * pStr){// look for a \n at the end of the string, and if found, remove itint str_len = strlen(pStr);if (str_len > 0){if (pStr[str_len - 1] == '\n'){pStr[str_len - 1] = 0;}}return pStr;}char * fgets_and_strip_newline(char * s, int n, FILE * stream){char * retVal;if ((retVal = fgets( s, n, stream )) != NULL){remove_newline_char(s);}return retVal;}/**************************************************************************//** Errors - Where output file will be compromised* Warnings - less serious ??*/void ERROR(char * str){printf("ERROR Line %05ld : %s\n", cmdLineNum, str);mustAbort = 1;}void WARNING(char * str){printf("WARNING Line %05ld : %s\n", cmdLineNum, str);}void DEBUG( int level, char * fmt, ... ){if (level & debug_level){char buff[256];long offset;va_list arg;va_start(arg, fmt);vsprintf( buff, fmt, arg );if (i_op_file_opened){offset = ftell(op_stream);printf( "DEBUG CmdFileLine:%05ld, OutputFilePos:%06ld : %s\n", cmdLineNum, offset, buff );}else{printf( "DEBUG CmdFileLine:%05ld, OutputFilePos:------ : %s\n", cmdLineNum, buff );}va_end(arg);}}/**************************************************************************/long adjusted_op_stream_tell( long var ){if (op_stream_tell[var] >= base_reference){return op_stream_tell[var] - base_reference;}else{ERROR("Negative offset");}return op_stream_tell[var];}/**************************************************************************/void fn_DEBUG(char * arg_ptr){unsigned long value;int got_a_value = TRUE;(void)next_value(arg_ptr, &value, &got_a_value);if (got_a_value){debug_level = value;}}/**************************************************************************/void fn_DUP(char * arg_ptr){unsigned long count, value, i;int got_a_value;DEBUG( DEBUG_OUTPUT_CMD_MASK, "DUP %s", arg_ptr );arg_ptr = next_value(arg_ptr, &count, &got_a_value);if (got_a_value){arg_ptr = next_value(arg_ptr, &value, &got_a_value);if (got_a_value){if (value <= 255){for (i=0; i<count; i++)fputc(value, op_stream);}else{ERROR("Bad value in DUP command");}return;}}ERROR("Bad/missing count/value in DUP command");}void fn_DB(char * arg_ptr){unsigned long value;int got_a_value = TRUE;DEBUG( DEBUG_OUTPUT_CMD_MASK, "DB %s", arg_ptr );while ( (*arg_ptr != 0) && (got_a_value) ){arg_ptr = next_value(arg_ptr, &value, &got_a_value);if (got_a_value) {if (value <= 255){fputc(value, op_stream);}else{ERROR("Bad value in DB command (values must be 0..255)");}}}}void fn_DW(char * arg_ptr){unsigned long value;int got_a_value = TRUE;DEBUG( DEBUG_OUTPUT_CMD_MASK, "DW %s", arg_ptr );while ( (*arg_ptr != 0) && (got_a_value) ){arg_ptr = next_value(arg_ptr, &value, &got_a_value);if (got_a_value){if (value <= 65535){ins_word(value);}else{ERROR("Bad value in DW command (values must be 0..65535)");}}}}void fn_DL(char * arg_ptr){unsigned long value;int got_a_value = TRUE;DEBUG( DEBUG_OUTPUT_CMD_MASK, "DL %s", arg_ptr );while ( (*arg_ptr != 0) && (got_a_value) ){arg_ptr = next_value(arg_ptr, &value, &got_a_value);if (got_a_value){ins_long(value);}}}void fn_DQ(char * arg_ptr){unsigned __int64 value;int got_a_value = TRUE;DEBUG( DEBUG_OUTPUT_CMD_MASK, "DQ %s", arg_ptr );while ( (*arg_ptr != 0) && (got_a_value) ){arg_ptr = next_value64(arg_ptr, &value, &got_a_value);if (got_a_value){ins_quad(value);}}}void fn_TEXT(char * arg_ptr){if (*arg_ptr != 0){DEBUG( DEBUG_OUTPUT_CMD_MASK, "TEXT %s", arg_ptr );while (*arg_ptr != 0)fputc(*arg_ptr++, op_stream);}else{ERROR("Missing text from TEXT command");}}void fn_NTEXT(char * arg_ptr){char * initial_arg_ptr = arg_ptr;unsigned long value;int got_a_value;arg_ptr = next_value(arg_ptr, &value, &got_a_value);if (got_a_value){arg_ptr++; /* skip past ',' character */if (*arg_ptr != 0){DEBUG( DEBUG_OUTPUT_CMD_MASK, "NTEXT %s", initial_arg_ptr );/* feed text to output */while ( (*arg_ptr != 0) && (value > 0) ){fputc(*arg_ptr++, op_stream);value--;}/* Pad output with 0's if necessary */while ( value > 0){fputc(0, op_stream);value--;}}else{ERROR("Missing text from NTEXT command");}}else{ERROR("Bad/missing count/value in NTEXT command");}}void fn_ZTEXT(char * arg_ptr){char * initial_arg_ptr = arg_ptr;unsigned long value;int got_a_value;arg_ptr = next_value(arg_ptr, &value, &got_a_value);if (got_a_value){if ( value <= 1 ){ERROR("ZTEXT length too short");}arg_ptr++; /* skip past ',' character */if (*arg_ptr != 0){DEBUG( DEBUG_OUTPUT_CMD_MASK, "ZTEXT %s", initial_arg_ptr );/* feed text to output */while ( (*arg_ptr != 0) && (value > 1) ){fputc(*arg_ptr++, op_stream);value--;}/* Pad output with 0's if necessary */while ( value > 0){fputc(0, op_stream);value--;}}else{ERROR("Missing text from ZTEXT command");}}else{ERROR("Bad/missing count/value in ZTEXT command");}}/**************************************************************************/void fn_FEED(char * arg_ptr){unsigned long count, i;int c, got_a_value;(void)next_value(arg_ptr, &count, &got_a_value);if (got_a_value){DEBUG( DEBUG_OUTPUT_CMD_MASK | DEBUG_INPUT_CMD_MASK, "FEED %s", arg_ptr );for (i=0; i<count; i++){c = fgetc(ip_stream);if (c != EOF)fputc(c, op_stream);else{i_had_input_stream_errors = TRUE;break;}}}else{ERROR("Bad/missing count value in FEED command");}}void fn_SKIP(char * arg_ptr){unsigned long count, i;int c, got_a_value;(void)next_value(arg_ptr, &count, &got_a_value);if (got_a_value){DEBUG( DEBUG_INPUT_CMD_MASK, "SKIP %s", arg_ptr );for (i=0; i<count; i++){c = fgetc(ip_stream);if (c == EOF){i_had_input_stream_errors = TRUE;break;}}}else{ERROR("Bad/missing count value in SKIP command");}}void fn_MARK(char * arg_ptr){if (fgetpos(ip_stream, &ip_stream_pos) == 0){DEBUG( DEBUG_CONTROL_CMD_MASK, "MARK %s", arg_ptr );ip_stream_pos_cmdLineNumber = cmdLineNum;ip_stream_pos_valid = TRUE;}else{ip_stream_pos_valid = FALSE;ERROR("MARK command failed on input file");}}void fn_REWIND(char * arg_ptr){if (ip_stream_pos_valid){if (fsetpos(ip_stream, &ip_stream_pos)){ERROR("REWIND command failed on input file");}else{cmdLineNum = ip_stream_pos_cmdLineNumber;DEBUG( DEBUG_CONTROL_CMD_MASK, "REWIND %s (pos:%ld)", arg_ptr, ip_stream_pos );}}else{ERROR("REWIND could not be matched to a previous MARK command");}}/**************************************************************************/void fn_SEEKSTART(char * arg_ptr){unsigned long offset;int got_a_value;(void)next_value(arg_ptr, &offset, &got_a_value);if (got_a_value){if (fseek(op_stream, (long)offset, SEEK_SET)){ERROR("SEEKSTART command failed on output file");}else{DEBUG( DEBUG_CONTROL_CMD_MASK, "SEEKSTART %s (offset:%ld)", arg_ptr, offset );}}else{ERROR("Bad/missing offset value in SEEKSTART command");}}void fn_SEEKEND(char * arg_ptr){unsigned long offset;int got_a_value;(void)next_value(arg_ptr, &offset, &got_a_value);if (got_a_value){DEBUG( DEBUG_CONTROL_CMD_MASK, "SEEKEND %s (offset:%ld)", arg_ptr, offset );if (fseek(op_stream, (long)offset, SEEK_END)){ERROR("SEEKEND command failed on output file");}}else{ERROR("Bad/missing offset value in SEEKEND command");}}void fn_SEEKCUR(char * arg_ptr){unsigned long offset;int got_a_value;(void)next_value(arg_ptr, &offset, &got_a_value);if (got_a_value){DEBUG( DEBUG_CONTROL_CMD_MASK, "SEEKCUR %s (offset:%ld)", arg_ptr, offset );if (fseek(op_stream, (long)offset, SEEK_CUR)){ERROR("SEEKCUR command failed on output file");}}else{ERROR("Bad/missing offset value in SEEKCUR command");}}void fn_TELL(char * arg_ptr){long offset;unsigned long var;int got_a_value;(void)next_value(arg_ptr, &var, &got_a_value);if (got_a_value){if (var >= 1 && var <= 10){offset = ftell(op_stream);if (offset == -1L){ERROR("TELL command failed on output file");}else{op_stream_tell[var] = offset;DEBUG( DEBUG_CONTROL_CMD_MASK, "TELL %s (result:%ld)", arg_ptr, offset );}}else{ERROR("Out of range variable number in TELL command (must be 1..10)");}}else{ERROR("Bad/missing variable number in TELL command");}}void fn_SEEKTELL(char * arg_ptr){unsigned long var;int got_a_value;(void)next_value(arg_ptr, &var, &got_a_value);if (got_a_value){if (var >= 1 && var <= 10){DEBUG( DEBUG_CONTROL_CMD_MASK, "SEEKTELL %s (offset:%ld)", arg_ptr, op_stream_tell[var] );if (fseek(op_stream, op_stream_tell[var], SEEK_SET)){ERROR("SEEKTELL command failed on output file");}}else{ERROR("Out of range variable number in SEEKTELL command (must be 1..10)");}}else{ERROR("Bad/missing variable number in SEEKTELL command");}}void fn_ALIGNMENT(char * arg_ptr, unsigned long requested_alignment){long offset;offset = ftell(op_stream);if (offset == -1L){ERROR("ALIGNMENT command failed on output file (ftell)");}else{unsigned long required_alignment;int got_a_value;(void)next_value(arg_ptr, &required_alignment, &got_a_value);if (got_a_value || requested_alignment){// allow caller to override the alignment valueif (requested_alignment)required_alignment = requested_alignment;if (required_alignment == 2 || required_alignment == 4 || required_alignment == 8){if (offset & (required_alignment - 1)){int padding_required = required_alignment - (offset & (required_alignment - 1));// find out the current output file sizeif (0==fseek(op_stream, 0, SEEK_END)){long filesize = ftell(op_stream);if (filesize!=-1L){// get back to where we wereif (0==fseek(op_stream, offset, SEEK_SET)){if (offset == filesize){// current position is at the end of the file// We need to append a null byte for the alignment commandDEBUG( DEBUG_OUTPUT_CMD_MASK, "ALIGNMENT (appended %d null byte(s))", padding_required );while (padding_required--){if (EOF==fputc(0, op_stream)){ERROR("ALIGNMENT command failed on output file (fputc)");break;}}}else if (offset < filesize){// current position is not at the end of the file// We simply need to advance the position by one byteDEBUG( DEBUG_OUTPUT_CMD_MASK, "ALIGNMENT (advanced filepos %d bytes only)", padding_required );while (padding_required--){if (0!=fseek(op_stream, 1, SEEK_CUR)){ERROR("ALIGNMENT command failed on output file (fseek)");break;}}}else{ERROR("ALIGNMENT command failed on output file (offset)");}}else{ERROR("ALIGNMENT command failed on output file (fseek)");}}else{ERROR("ALIGNMENT command failed on output file (ftell)");}}else{ERROR("ALIGNMENT command failed on output file (fseek)");}}else{DEBUG( DEBUG_OUTPUT_CMD_MASK, "ALIGNMENT (no padding required)" );}}else{ERROR("Invalid alignment number in ALIGNMENT command (must be 2, 4, or 8)");}}else{ERROR("Bad/missing variable number in ALIGNMENT command");}}}void fn_DWTELL(char * arg_ptr){unsigned long var;int got_a_value;(void)next_value(arg_ptr, &var, &got_a_value);if (got_a_value){if (var >= 1 && var <= 10){DEBUG( DEBUG_OUTPUT_CMD_MASK, "DWTELL %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var) );ins_word( adjusted_op_stream_tell(var) );}else{ERROR("Out of range variable number in DWTELL command (must be 1..10)");}}else{ERROR("Bad/missing variable number in DWTELL command");}}void fn_DLTELL(char * arg_ptr){unsigned long var;int got_a_value;(void)next_value(arg_ptr, &var, &got_a_value);if (got_a_value){if (var >= 1 && var <= 10){DEBUG( DEBUG_OUTPUT_CMD_MASK, "DLTELL %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var) );ins_long( adjusted_op_stream_tell(var) );}else{ERROR("Out of range variable number in DLTELL command (must be 1..10)");}}else{ERROR("Bad/missing variable number in DLTELL command");}}void fn_DWTELLSUB(char * arg_ptr){unsigned long var1;unsigned long var2;int got_a_value;arg_ptr = next_value(arg_ptr, &var1, &got_a_value);if (got_a_value){if (var1 >= 1 && var1 <= 10){arg_ptr = next_value(arg_ptr, &var2, &got_a_value);if (got_a_value){if (var2 >= 1 && var2 <= 10){DEBUG( DEBUG_OUTPUT_CMD_MASK, "DWTELLSUB %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) );ins_word( adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) );}else{ERROR("Out of range variable number in DWTELLSUB command (must be 1..10)");}}else{ERROR("Bad/missing variable number in DWTELLSUB command");}}else{ERROR("Out of range variable number in DWTELLSUB command (must be 1..10)");}}else{ERROR("Bad/missing variable number in DWTELLSUB command");}}void fn_DLTELLSUB(char * arg_ptr){unsigned long var1;unsigned long var2;int got_a_value;arg_ptr = next_value(arg_ptr, &var1, &got_a_value);if (got_a_value){if (var1 >= 1 && var1 <= 10){arg_ptr = next_value(arg_ptr, &var2, &got_a_value);if (got_a_value){if (var2 >= 1 && var2 <= 10){DEBUG( DEBUG_OUTPUT_CMD_MASK, "DLTELLSUB %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) );ins_long( adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) );}else{ERROR("Out of range variable number in DLTELLSUB command (must be 1..10)");}}else{ERROR("Bad/missing variable number in DLTELLSUB command");}}else{ERROR("Out of range variable number in DLTELLSUB command (must be 1..10)");}}else{ERROR("Bad/missing variable number in DLTELLSUB command");}}void fn_SETBASE(char * arg_ptr){long offset;offset = ftell(op_stream);if (offset == -1L){ERROR("SETBASE command failed on output file");}else{DEBUG( DEBUG_CONTROL_CMD_MASK, "SETBASE %s (base_reference:%ld)", arg_ptr, base_reference );base_reference = offset;}}/**************************************************************************/void fn_REPEAT(char * arg_ptr){unsigned long count;int got_a_value;fpos_t stream_pos;(void)next_value(arg_ptr, &count, &got_a_value);if (got_a_value){if (fgetpos(cmd_stream, &stream_pos) == 0){if (cmd_repeat_nest_level < (MAX_NEST_LEVEL - 1)){cmd_repeat_nest_level++;cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_pos = stream_pos;cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat = count;cmd_repeat_stack[cmd_repeat_nest_level].cmdLineNumber = cmdLineNum;DEBUG( DEBUG_CONTROL_CMD_MASK, "REPEAT %s (nesting:%d, pos:%ld)", arg_ptr, cmd_repeat_nest_level, stream_pos );}else{ERROR("REPEAT command nested too deeply");}}else{ERROR("REPEAT command failed to get current cmd file position");}}else{ERROR("Bad/missing count value in REPEAT command");}}void fn_END(char * arg_ptr){if (cmd_repeat_nest_level >= 0){if (cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat > 0){cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat--;DEBUG( DEBUG_CONTROL_CMD_MASK, "END-REPEAT (nesting:%d)", cmd_repeat_nest_level );if (cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat > 0){if (fsetpos(cmd_stream, &(cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_pos))){ERROR("END could not restore cmd file position");}else{cmdLineNum = cmd_repeat_stack[cmd_repeat_nest_level].cmdLineNumber;}}else{cmd_repeat_nest_level--;}}else{DEBUG( DEBUG_CONTROL_CMD_MASK, "END-REPEAT (nesting:%d)", cmd_repeat_nest_level );cmd_repeat_nest_level--;}}else{ERROR("END could not be matched to a previous REPEAT command");}}/**************************************************************************/void fn_FEEDFILE(char * arg_ptr){FILE * fip_stream;arg_ptr = skip_past_spaces(arg_ptr);if( (fip_stream = fopen( arg_ptr, "rb" )) != NULL ){int c;DEBUG( DEBUG_OUTPUT_CMD_MASK, "FEEDFILE %s", arg_ptr );c = fgetc(fip_stream);while (c != EOF){fputc(c, op_stream);c = fgetc(fip_stream);}fclose(fip_stream);}else{ERROR("Could not open file");}}/**************************************************************************/void fn_NAMEVAR(char * arg_ptr){char * initial_arg_ptr = arg_ptr;unsigned long variantType;unsigned long dataSize;int got_a_value;arg_ptr = next_value(arg_ptr, &variantType, &got_a_value);if (got_a_value){while ( (*arg_ptr != ',') )arg_ptr++;if (*arg_ptr == ',')arg_ptr++;arg_ptr = skip_past_spaces(arg_ptr);// put the representation typevariantType = (0x1000 + variantType) & 0xFFFF;dataSize = strlen(arg_ptr);dataSize++; // Account for null trerminatorif (dataSize & 1) // Do alignmentdataSize++;DEBUG( DEBUG_OUTPUT_CMD_MASK, "NAMEVAR %s (variantType:%d, dataSize:%d)", initial_arg_ptr, variantType, dataSize );ins_word(variantType);ins_word(dataSize);// put the textwhile (*arg_ptr != 0)fputc(*arg_ptr++, op_stream);fputc(0, op_stream); // put null terminatorfn_ALIGNMENT(arg_ptr, 2); // do alignment}else{ERROR("Bad/missing variantType value in NAMEVAR command");}}/**************************************************************************/void fn_GOSUB(char * arg_ptr){char * initial_arg_ptr = arg_ptr;// Read subroutine namestatic char subname[256];static char *subnameptr = &subname[0];static int subnamelen = 0;static fpos_t subposition;int found = 0;*subnameptr = 0;if (*arg_ptr != 0){if (stackptr < (MAX_STACK-1)){fpos_t fposition;if (fgetpos(cmd_stream, &fposition) == 0){if (strlen(arg_ptr) > 250){ERROR("GOSUB subroutine name too long");}else{// Get subname, subnameptr, subnamelensubnameptr = &subname[0];while (*arg_ptr != 0)*subnameptr++ = *arg_ptr++;*subnameptr = 0;subnamelen = strlen(subname);if (subnamelen == 0){ERROR("GOSUB subroutine name missing");}else{// scan cmd file from the beginning, for the subroutine of the required nameif (0==fseek(cmd_stream, 0, SEEK_SET)){char * cmd_args;long tempCmdLineNum = 1;fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream );do {cmd_args = skip_to_spaces(cmd_line);cmd_args = skip_past_spaces(cmd_args);if (strnicmp(cmd_line, "SUB", 3) == 0) {if (strnicmp(subname, cmd_args, subnamelen) == 0) {// capture cmd file position where the subroutine beginsif (fgetpos(cmd_stream, &subposition) == 0) {stackptr++;stack[stackptr].filepos = fposition;stack[stackptr].cmdLineNumber = cmdLineNum;DEBUG( DEBUG_CONTROL_CMD_MASK, "GOSUB %s", subname );cmdLineNum = tempCmdLineNum;found = 1;break;}else {ERROR("GOSUB failed to get cmd stream subroutine filepos");}}}tempCmdLineNum++;} while (fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ) != NULL);if (!found){ERROR("GOSUB could not find subroutine");}}else{ERROR("GOSUB failed to seek to beginning of cmd file");}}}}else{ERROR("GOSUB failed to get cmd stream calling filepos");}}else{ERROR("GOSUB out of stack space");}}}/**************************************************************************/void fn_MSG(char * arg_ptr){if (*arg_ptr != 0){printf( arg_ptr );}}/**************************************************************************/void fn_OUTPUT_FILE(char * arg_ptr){char filename[1024];char * pFilename = filename;if (*arg_ptr != 0){while (*arg_ptr != 0){*pFilename++ = *arg_ptr++;}*pFilename = 0;if (i_op_file_opened){i_op_file_opened = FALSE;fclose(op_stream);}if( (op_stream = fopen( filename, "wb" )) == NULL ){char buff[2048];sprintf(buff, "Could not open output file %s", filename );ERROR( buff );}else{i_op_file_opened = TRUE;DEBUG( DEBUG_OUTPUT_CMD_MASK, "OUTPUT_FILE %s", filename );}}else{ERROR("Missing filename from OUTPUT_FILE command");}}/**************************************************************************/int InputFileOpen(void){if (!i_ip_file_opened){ERROR("No binary input file has been specified");return FALSE;}else{return TRUE;}}int OutputFileOpen(void){if (!i_op_file_opened){ERROR("No binary output file has been specified");return FALSE;}else{return TRUE;}}/**************************************************************************/void do_binflow_processing(void){char * cmd_args;if (fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ) == NULL){printf("ERROR : Command File is empty\n");return;}else{do{cmdLineNum++;if (cmd_line[0] != 0){cmd_args = skip_to_spaces(cmd_line);cmd_args = skip_past_spaces(cmd_args);if (skippingPastSub){if (strnicmp(cmd_line, "SUB", 3) == 0) {ERROR("SUBROUTINE definition nesting is prohibited");}else if (strnicmp(cmd_line, "ENDSUB", 6) == 0) {skippingPastSub = 0;}}else if (strnicmp(cmd_line, "LITTLE_ENDIAN", 13) == 0) {endianism = LITTLE_ENDIAN;}else if (strnicmp(cmd_line, "BIG_ENDIAN", 10) == 0) {endianism = BIG_ENDIAN;}else if (strnicmp(cmd_line, "OUTPUT_FILE", 11) == 0) {strip_trailing_comment_and_spaces( cmd_line );fn_OUTPUT_FILE(cmd_args);}else if (strnicmp(cmd_line, "BREAKPOINT", 10) == 0) {_CrtDbgBreak();}else if (strnicmp(cmd_line, "SEEKSTART", 9) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_SEEKSTART(cmd_args);}else if (strnicmp(cmd_line, "DWTELLSUB", 9) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DWTELLSUB(cmd_args);}else if (strnicmp(cmd_line, "DLTELLSUB", 9) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DLTELLSUB(cmd_args);}else if (strnicmp(cmd_line, "ALIGNMENT", 9) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_ALIGNMENT(cmd_args, 0);}else if (strnicmp(cmd_line, "SEEKTELL", 8) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_SEEKTELL(cmd_args);}else if (strnicmp(cmd_line, "FEEDFILE", 8) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_FEEDFILE(cmd_args);}else if (strnicmp(cmd_line, "SEEKEND", 7) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_SEEKEND(cmd_args);}else if (strnicmp(cmd_line, "SEEKCUR", 7) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_SEEKCUR(cmd_args);}else if (strnicmp(cmd_line, "NAMEVAR", 7) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_NAMEVAR(cmd_args);}else if (strnicmp(cmd_line, "SETBASE", 7) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_SETBASE(cmd_args);}else if (strnicmp(cmd_line, "ENDSUB", 6) == 0) {if (stackptr > -1) {if (fsetpos(cmd_stream, &stack[stackptr].filepos)) {ERROR("ENDSUB failed to return to calling point");}else {DEBUG( DEBUG_CONTROL_CMD_MASK, "ENDSUB" );cmdLineNum = stack[stackptr].cmdLineNumber;stackptr--;}}else {ERROR("ENDSUB unexpected at this time");}}else if (strnicmp(cmd_line, "REWIND", 6) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (InputFileOpen())fn_REWIND(cmd_args);}else if (strnicmp(cmd_line, "REPEAT", 6) == 0) {strip_trailing_comment_and_spaces( cmd_line );fn_REPEAT(cmd_args);}else if (strnicmp(cmd_line, "DWTELL", 6) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DWTELL(cmd_args);}else if (strnicmp(cmd_line, "DLTELL", 6) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DLTELL(cmd_args);}else if (strnicmp(cmd_line, "DEBUG", 5) == 0) {strip_trailing_comment_and_spaces( cmd_line );fn_DEBUG(cmd_args);}else if (strnicmp(cmd_line, "NTEXT", 5) == 0) {strip_trailing_comment( cmd_line );if (OutputFileOpen())fn_NTEXT(cmd_args);}else if (strnicmp(cmd_line, "ZTEXT", 5) == 0) {strip_trailing_comment( cmd_line );if (OutputFileOpen())fn_ZTEXT(cmd_args);}else if (strnicmp(cmd_line, "ALIGN", 5) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_ALIGNMENT(cmd_args, 2);}else if (strnicmp(cmd_line, "GOSUB", 5) == 0) {strip_trailing_comment_and_spaces( cmd_line );fn_GOSUB(cmd_args);}else if (strnicmp(cmd_line, "FEED", 4) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen() && InputFileOpen())fn_FEED(cmd_args);}else if (strnicmp(cmd_line, "SKIP", 4) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (InputFileOpen())fn_SKIP(cmd_args);}else if (strnicmp(cmd_line, "TEXT", 4) == 0) {strip_trailing_comment( cmd_line );if (OutputFileOpen())fn_TEXT(cmd_args);}else if (strnicmp(cmd_line, "MARK", 4) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (InputFileOpen())fn_MARK(cmd_args);}else if (strnicmp(cmd_line, "TELL", 4) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_TELL(cmd_args);}else if (strnicmp(cmd_line, "DUP", 3) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DUP(cmd_args);}else if (strnicmp(cmd_line, "END", 3) == 0) {strip_trailing_comment_and_spaces( cmd_line );fn_END(cmd_args);}else if (strnicmp(cmd_line, "MSG", 3) == 0) {strip_trailing_comment_and_spaces( cmd_line );fn_MSG(cmd_args);}else if (strnicmp(cmd_line, "SUB", 3) == 0) {if (stackptr > -1) {ERROR("SUBROUTINE definition nesting is prohibited");}else {skippingPastSub = 1;}}else if (strnicmp(cmd_line, "DB", 2) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DB(cmd_args);}else if (strnicmp(cmd_line, "DW", 2) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DW(cmd_args);}else if (strnicmp(cmd_line, "DL", 2) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DL(cmd_args);}else if (strnicmp(cmd_line, "DQ", 2) == 0) {strip_trailing_comment_and_spaces( cmd_line );if (OutputFileOpen())fn_DQ(cmd_args);}else {if ( ( cmd_line[0] != ' ' )&& ( cmd_line[0] != 0 )&& ( cmd_line[0] != '\n' )&& ( cmd_line[0] != '#' ) ){printf("ERROR on line %u of command file\n\n", cmdLineNum);printf(" %s\n", cmd_line);printf(" ^\n");printf(" |\n");printf(" | Unknown Command\n");mustAbort = 1;break;}}}if (mustAbort)break;} while (fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ) != NULL);}}/**************************************************************************/void newline(void){printf("\n");}void header(void){newline();printf("%s, by Gordon Huddy, %s\n", BUILDNAME, BUILDDATE);newline();}void commands(void){header();printf("Processor commands:-\n");newline();printf(" COMMAND FILE COMMANDS --------------------------------------------------------------------------\n\n");printf(" # 'Start of comment' marker in command file\n");printf(" REPEAT n Specify a command block to be repeated n times\n");printf(" END Marks the end of a repeated command block\n");printf(" DEBUG mask Turns on debug\n");printf(" Masks: 1 = Command File Control commands\n");printf(" 2 = Output Binary File commands\n");printf(" 4 = Input Binary File commands\n");printf(" MSG text Sends the message text to stdout\n");newline();printf(" NB. REPEAT-END commands can be nested (Max Level %d)\n", MAX_NEST_LEVEL);newline();printf(" OUTPUT BINARY FILE COMMANDS---------------------------------------------------------------------\n\n");printf(" DUP n,v Add the 8-bit value v to the output file, n times\n");printf(" DB v,v,..,v Add the specified list of 8-bit values to the output file\n");printf(" DW v,v,..,v Add the specified list of 16-bit values to the output file\n");printf(" DL v,v,..,v Add the specified list of 32-bit values to the output file\n");printf(" DQ v,v,..,v Add the specified list of 64-bit values to the output file\n");printf(" TEXT text Add the specified text to the output file\n");printf(" NTEXT v,text Add exactly v characters of the specified text to the output file\n");printf(" - pad output file with 0's if insufficient text provided\n");printf(" ZTEXT v,text Add exactly v-1 characters and a NULL terminator of the specified text to the output file\n");printf(" BIG_ENDIAN Turn Big-endian on (default behaviour)\n");printf(" LITTLE_ENDIAN Turn Big-endian off\n");printf(" OUTPUT_FILE name Opens a new Output File, closing the previous one\n");printf(" SEEKSTART offset Seeks to the specified offset from the start of the output file\n");printf(" SEEKEND offset Seeks to the specified offset from the end of the output file\n");printf(" SEEKCUR offset Seeks to the specified offset from the current position in the output file\n");printf(" TELL var Saves current position in the output file to internal variable 1..10\n");printf(" SEEKTELL var Using internal variable 1..10, seeks to the saved position in the output file\n");printf(" DWTELL var Using internal variable 1..10, adds the saved position as a 16-bit value to the output file\n");printf(" DLTELL var Using internal variable 1..10, adds the saved position as a 32-bit value to the output file\n");printf(" DWTELLSUB var1, var2 Using internal variables 1..10, adds the difference between saved positions (var1 - var2)\n");printf(" as a 16-bit value to the output file\n");printf(" DLTELLSUB var1, var2 Using internal variables 1..10, adds the difference between saved positions (var1 - var2)\n");printf(" as a 32-bit value to the output file\n");printf(" SETBASE Sets the base reference from which offsets in internal variables 1..10 are measured,\n");printf(" to the current output file position (default = beginning of output file)\n");printf(" SETBASE only affects the values DLTELL and DWTELL write.\n");printf(" ALIGN If current file position is odd, advances it by 1 byte (equivalent to 'ALIGNMENT 2' command)\n");printf(" ALIGNMENT v Performs specified alignment - v must be 2, 4, or 8\n");printf(" NAMEVAR vt,text Add the specified name variant type to the output file\n");printf(" SUB name Begin Defining a subroutine\n");printf(" ENDSUB End the definition of a subroutine\n");printf(" GOSUB name Call a subroutine\n");printf(" FEEDFILE filename Feed the entire contents of the file with the given name to the output file\n");newline();printf(" INPUT BINARY FILE COMMANDS---------------------------------------------------------------------\n\n");printf(" FEED n Feed n bytes from the input file to the output file\n");printf(" SKIP n Skip n bytes of the input file\n");printf(" MARK 'Marks' current position in input file\n");printf(" REWIND Return to 'Marked' position in input file\n");newline();}void usage(void){header();printf("BINFLOW /c=cmdfile [/o=outfile] [/i=infile] [/d=mask] \n");newline();printf(" /c=cmdfile : Compulsory - contains your processor command script.\n");printf(" /o=outfile : Optional - Specifies an output file. This switch can be\n");printf(" omitted if the cmdfile itself specifies one or more output files.\n");printf(" /i=infile : Optional - Specifies a binary input file containing some data that must find\n");printf(" its way through to the outfile under control of the script commands given in\n");printf(" the cmdfile.\n");printf(" /d=mask : Optional - Identical to the operation of the DEBUG command inside a cmdfile\n");newline();printf(" This program enables you to produce a binary file from a command file\n");printf(" description using simple commands. Some commands allow data from a source\n");printf(" binary file to be passed to the output file also. The command file\n");printf(" is processed sequentially.\n");newline();printf(" Type BINFLOW ? for a summary of commands available\n");newline();}int main( int argc, /* Number of strings in array argv */char *argv[], /* Array of command-line argument strings */char **envp ) /* Array of environment variable strings */{char * pCmdFilename = NULL;char * pOutputFilename = NULL;char * pInputFilename = NULL;int showUsage = FALSE;int showCommands = FALSE;int argi = 1;if (argi == argc){showUsage = TRUE;goto binflow_exit;}while (argi < argc){char * pArg = argv[argi];if (pArg[0] == '/' || pArg[0] == '\\'){if ( strlen(pArg) > 3 ){switch(pArg[1]){case 'c' :pCmdFilename = &pArg[3];break;case 'i' :pInputFilename = &pArg[3];break;case 'o':pOutputFilename = &pArg[3];break;case 'd':fn_DEBUG(pArg);break;default:printf("ERROR : Unrecognized command line switch (%s)\n", pArg );showUsage = TRUE;goto binflow_exit;break;}}else{printf("ERROR : Command line switch appears incomplete or malformed (%s)\n", pArg );showUsage = TRUE;goto binflow_exit;}}else if (pArg[0] == '?' ){showCommands = TRUE;goto binflow_exit;}else{printf("ERROR : Unrecognized command line switch (%s)\n", pArg );showUsage = TRUE;goto binflow_exit;}argi++;}if (pCmdFilename){if( (cmd_stream = fopen( pCmdFilename, "r" )) == NULL ){printf("ERROR : Could not open command file\n");goto binflow_exit;}}else{printf("ERROR : A command file must be specified\n");showUsage = TRUE;goto binflow_exit;}if (pOutputFilename){if( (op_stream = fopen( pOutputFilename, "wb" )) == NULL ){fclose(cmd_stream);printf("ERROR : Could not open output file\n");mustAbort = 1;goto binflow_exit;}else{i_op_file_opened = TRUE;}}if (pInputFilename){if( (ip_stream = fopen( pInputFilename, "rb" )) == NULL ){fclose(cmd_stream);if (pOutputFilename)fclose(op_stream);printf("ERROR : Could not open binary input file\n");goto binflow_exit;}else{i_ip_file_opened = TRUE;}}do_binflow_processing();fclose(op_stream);fclose(cmd_stream);if (i_ip_file_opened)fclose(ip_stream);if (i_had_input_stream_errors){printf("ERROR : Errors occurred when reading your input data file\n");mustAbort = 1;}if (mustAbort){exitCode = 1;if ( pOutputFilename )unlink (pOutputFilename);}return exitCode;binflow_exit:exitCode = 2;if (showUsage){usage();}else if (showCommands){commands();}return exitCode;}/************************************************************************************************************//** ENDIAN CONVERSION FUNCTIONS *****************************************************************************//************************************************************************************************************/void ins_byte(unsigned long value){fputc(value & 255, op_stream);}void ins_word(unsigned long value){if (endianism == BIG_ENDIAN){fputc((value >> 8) & 255, op_stream);fputc(value & 255, op_stream);}else{fputc(value & 255, op_stream);fputc((value >> 8) & 255, op_stream);}}void ins_long(unsigned long value){if (endianism == BIG_ENDIAN){fputc((value >> 24) & 255, op_stream);fputc((value >> 16) & 255, op_stream);fputc((value >> 8 ) & 255, op_stream);fputc(value & 255, op_stream);}else{fputc(value & 255, op_stream);fputc((value >> 8 ) & 255, op_stream);fputc((value >> 16) & 255, op_stream);fputc((value >> 24) & 255, op_stream);}}void ins_quad(unsigned __int64 value){if (endianism == BIG_ENDIAN){fputc((int)(value >> 7*8) & 255, op_stream);fputc((int)(value >> 6*8) & 255, op_stream);fputc((int)(value >> 5*8) & 255, op_stream);fputc((int)(value >> 4*8) & 255, op_stream);fputc((int)(value >> 3*8) & 255, op_stream);fputc((int)(value >> 2*8) & 255, op_stream);fputc((int)(value >> 1*8) & 255, op_stream);fputc((int)(value) & 255, op_stream);}else{fputc((int)value & 255, op_stream);fputc((int)(value >> 1*8 )& 255, op_stream);fputc((int)(value >> 2*8) & 255, op_stream);fputc((int)(value >> 3*8) & 255, op_stream);fputc((int)(value >> 4*8) & 255, op_stream);fputc((int)(value >> 5*8) & 255, op_stream);fputc((int)(value >> 6*8) & 255, op_stream);fputc((int)(value >> 7*8) & 255, op_stream);}}/* END OF File */