#include <system_io_constants.h>
#define CV char_varying

extern void s$error (short *status, CV(32) *caller, CV(256) *msg);

extern void s$attach_port (CV(32) *port_name, CV(256)* path,
    short *hold, short *port_id, short *status);

extern void s$open (short *port_id, short *organization,
    short *max_rec_len, short *io_type, short *locking_type,
    short *access_mode, CV(32) *index_name, short *status);

extern void s$detach_port (short *port_id, short *status);

extern void s$close (short *port_id, short *status);

extern void s$seq_read (short *port_id, short *buff_size,
    short *rec_len, void *buffer, short *status);

extern void s$seq_write (short *port_id, short *rec_length,
    void *buffer, short *status);

extern void s$parse_command (CV(32) *caller, short *status, ... );

static CV(32) caller = "ckltxt";
static CV(40) in_def = "binary_file:pathname.pm,required";
static CV(40) out_def = "text_file:pathname,required";
static CV(3)  end_def = "end";
static CV(32) in_port_name = "in_port";
static CV(32) out_port_name = "out_port";
static CV(32) index_name = "";
static char   digits[16] = "0123456789ABCDEF";

void ckltxt (void)
{
  short status;
  short buff_len;
  short rec_len;
  char  buff[4096];
  char  txt_buff[80];
  int   buff_ndx;
  int   txt_ndx;
  CV(256) in_path;
  CV(256) out_path;
  short   in_port;
  short   out_port;
  short   flag;
  short   io_type;
  short   lock_type;
  short   access;
  short   org;
  unsigned byte;
  int      null_cnt;
  char    null_buff[4];

  s$parse_command (&caller, &status,
                   &in_def, &in_path,
                   &out_def, &out_path,
                   &end_def);

  if (status)
    return;

  flag = 0;
  s$attach_port (&in_port_name, &in_path, &flag, &in_port, &status);
  if (status)
  {
    s$error (&status, &caller, &in_path);
    return;
  }

  org = FIXED_FILE;
  buff_len = sizeof buff;
  io_type = INPUT_TYPE;
  lock_type = READ_LOCK;
  access = SEQUENTIAL_MODE;
  s$open (&in_port, &org, &buff_len, &io_type, &lock_type, &access,
          &index_name, &status);
  if (status)
  {
    s$error (&status, &caller, &in_path);
    return;
  }

  flag = 0;
  s$attach_port (&out_port_name, &out_path, &flag, &out_port, &status);
  if (status)
  {
    s$error (&status, &caller, &out_path);
    return;
  }

  org = STREAM_FILE;
  buff_len = sizeof buff;
  io_type = OUTPUT_TYPE;
  lock_type = WRITE_LOCK;
  access = SEQUENTIAL_MODE;
  s$open (&out_port, &org, &buff_len, &io_type, &lock_type, &access,
          &index_name, &status);
  if (status)
  {
    s$error (&status, &caller, &out_path);
    return;
  }

  while (1)
  {
    s$seq_read (&in_port, &buff_len, &rec_len, &buff, &status);
    if (status)
      break;

    null_cnt = 0;

    /* process one record in the source file */
    for (buff_ndx = 0; buff_ndx < sizeof buff; buff_ndx = buff_ndx + 32)
    {
      flag = 0; /* have not seen non-null byte yet */
      for (txt_ndx = 0; txt_ndx < 64; txt_ndx = txt_ndx + 2)
      {
        byte = buff[buff_ndx + (txt_ndx / 2)];
        if (byte != 0)
          flag = 1; /* found a non-null byte in record */
        txt_buff[txt_ndx] = digits[byte / 16];
        txt_buff[txt_ndx+1] = digits[byte % 16];
      }

      if (flag == 0)
      {
        null_cnt = null_cnt + 1;
      }

      if ((null_cnt > 0) && ((buff_ndx + 32 == sizeof buff) || (flag == 1)))
      {
        null_buff[0] = 'Z';
        byte = null_cnt;
        null_buff[1] = digits[byte / 16];
        null_buff[2] = digits[byte % 16];
        rec_len = 3;
        s$seq_write (&out_port, &rec_len, &null_buff, &status);
        if (status)
        {
          s$error (&status, &caller, &out_path);

          s$close (&in_port, &status);
          s$detach_port (&in_port, &status);

          s$close (&out_port, &status);
          s$detach_port (&out_port, &status);

          return;
        }
        null_cnt = 0;
      }

      if (flag == 1)
      {
        rec_len = 64;
        s$seq_write (&out_port, &rec_len, &txt_buff, &status);
        if (status)
        {
          s$error (&status, &caller, &out_path);

          s$close (&in_port, &status);
          s$detach_port (&in_port, &status);

          s$close (&out_port, &status);
          s$detach_port (&out_port, &status);

          return;
        } /* if status != 0 */
      } /* if flag is 1 */
    } /* for buff_ndx ... */
  } /* while (1) */

  s$close (&in_port, &status);
  s$detach_port (&in_port, &status);

  s$close (&out_port, &status);
  s$detach_port (&out_port, &status);

}
