Subversion Repositories DevTools

Rev

Rev 1024 | Go to most recent revision | 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    1024

typedef 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 50
stack_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 10

cmd_rep_type cmd_repeat_stack[MAX_NEST_LEVEL];

int cmd_repeat_nest_level = -1;

/**************************************************************************/

/* PROTOTYPES */
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 numeric
   while ( ((*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 * 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 it
   int 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_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 value
         if (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 size
               if (0==fseek(op_stream, 0, SEEK_END))
               {
                  long filesize = ftell(op_stream);
                  if (filesize!=-1L)
                  {
                     // get back to where we were
                     if (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 command
                           DEBUG( 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 byte
                           DEBUG( 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 type
      variantType = (0x1000 + variantType) & 0xFFFF;

      dataSize = strlen(arg_ptr);
      dataSize++;                   // Account for null trerminator
      if (dataSize & 1)             // Do alignment
         dataSize++;

      DEBUG( DEBUG_OUTPUT_CMD_MASK, "NAMEVAR %s (variantType:%d, dataSize:%d)", initial_arg_ptr, variantType, dataSize );

      ins_word(variantType);

      ins_word(dataSize);

      // put the text
      while (*arg_ptr != 0)
         fputc(*arg_ptr++, op_stream);

      fputc(0, op_stream); // put null terminator

      fn_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 name
   static 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, subnamelen
               subnameptr = &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 name
                  if (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 begins
                              if (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 (  ( 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("  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);
   }
}



/* END OF File */