/**
 * Bin2Rexx: "DosOpen() / DosRead() / DosWrite() / DosClose()" example.
 */

#include <OS2.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define WR /*WR*/
#define RC /*RC*/

#define Run int main
#define let void

#ifndef STDIN
#define STDIN  0
#define STDOUT 1
#define STDERR 2
#endif

let Say (PBYTE String) { ULONG Written = 0; DosWrite (STDOUT, String, strlen (String), &Written); }

let Say (PBYTE A, PBYTE B) { Say (A); Say (B); }
let Say (PBYTE A, PBYTE B, PBYTE C) { Say (A); Say (B); Say (C); }
let Say (PBYTE A, PBYTE B, PBYTE C, PBYTE D) { Say (A); Say (B); Say (C); Say (D); }
let Say (PBYTE A, PBYTE B, PBYTE C, PBYTE D, PBYTE E) { Say (A); Say (B); Say (C); Say (D); Say (E); }

/* * */

#define STR_REXX_BYTES_TO_JOIN 16
#define STR_REXX_LINE_LENGTH   256

/* * */

let JoinHexValues (PCHAR WR Line, PBYTE Memory, INT Length, INT Cntr, INT Bytes_to_join)
{
  for (INT Offset = 0; Offset < Bytes_to_join; Offset ++) 
  {
    INT Position = Cntr + Offset;

    if (Position < Length)
    {
      CHAR Hex_value[4] = {0};

      {
        BYTE Bin_value = (BYTE) Memory[Position]; ultoa (Bin_value, Hex_value, 16);

        INT Hex_value_length = strlen (Hex_value);

        if (Hex_value_length == 1) 
        {
          Hex_value[2] = 0; Hex_value[1] = Hex_value[0]; Hex_value[0] = '0';
        }

        if (islower (Hex_value[0])) Hex_value[0] = toupper (Hex_value[0]);
        if (islower (Hex_value[1])) Hex_value[1] = toupper (Hex_value[1]);
      }

      strcat (Line, "'");
      strcat (Line, Hex_value);
      strcat (Line, "'x");
    }
  }
}

let PrintProlog ()
{
  Say ("/* * */", "\r\n");
  Say ("\r\n");
  Say ("V = ''", "\r\n");
}

let PrintScript (PBYTE Memory, ULONG Length, PCHAR File_name)
{
  for (INT Cntr = 0; Cntr < Length; Cntr ++) 
  {
    CHAR Line[STR_REXX_LINE_LENGTH] = ""; strcpy (Line, "V = V || ");

    JoinHexValues (Line, Memory, Length, Cntr, STR_REXX_BYTES_TO_JOIN);

    Say (Line, "\r\n");

    Cntr += (STR_REXX_BYTES_TO_JOIN - 1);
  }
}

let PrintEpilog (PCHAR File_name)
{
  Say ("\r\n");
  Say ("File = '", File_name, "'", "\r\n");
  Say ("Call SysFileDelete File", "\r\n");
  Say ("Call CharOut File, V", "\r\n");
  Say ("\r\n");
  Say ("Exit");
}

let PrintRexxScript (PBYTE Memory, ULONG Length, PCHAR File_name)
{
  PrintProlog ();
  PrintScript (Memory, Length, File_name);
  PrintEpilog (File_name);
}

/* * */

Run (INT Arg_c, PCHAR Arg_v[])  
{
  if (Arg_c != 2 || !strstr (Arg_v[1], ".")) 
  {
    Say ("Usage: Bin2Rexx Binary-file.ext > Rexx-script.cmd");
  }
  else
  {
    HFILE File   = NULLHANDLE;
    ULONG Action = OPEN_ACTION_OPEN_IF_EXISTS;
    ULONG Mode   = OPEN_SHARE_DENYWRITE |
                   OPEN_ACCESS_READONLY;
    ULONG Report = 0;

    DosOpen (Arg_v[1], &File, &Report, 0, 0, Action, Mode, NULL);

    if (File)
    {
      ULONG Length = 0; DosSetFilePtr (File, 0, FILE_END, &Length);

      PBYTE Memory = NULL; DosAllocMem ((PPVOID) &Memory, Length, PAG_READ | PAG_WRITE | PAG_COMMIT);

      DosRead (File, Memory, Length, &Report);

      PrintRexxScript (Memory, Length, Arg_v[1]);

      DosFreeMem (Memory);

      DosClose (File);
    }
    else
    {
      DosExit (EXIT_PROCESS, -1);
    }
  }

  return 0;
}
