#include <stdio.h>
#include <stdlib.h>
//
// UNIVAC xs3 code -- '_' added for 0x2e '@' added for 0x13
//            0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
char xs3[]={ ' ', '&', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '<', '>',  // 00
             '+', ')', '.', '@',  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '=', 0,   0,   // 01
              0,  '*', '$',  0,  'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',  0,  '_',  0,   // 02
              0,  '(', ',', '\'','/', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',  0,   0,   0 }; // 03

// Pierce .bdc tape images set 0x80 as a flag bit with a couple of special values
// It also retains the 7th bit for parity
// The first byte of a record has the 0x80 bit set
// File marks are signaled with a 0x99 byte preceeded by a 0x00
//
// TODO:
// there are a few places on the tapes where the card pairs get out of sync, and only
// resync at the header record
//

int main(){
unsigned char in, c, out;
int column = 0;   // record column 
int state = 1;   // where we are dumping the tape, 1 header, 2 first half, 3 second half
int recnum = 1;  // record number on the tape

 while(1){
  c = getchar();
  if(feof(stdin)){putchar('\n'); exit(0);}
  column++;

  if(c & 0x80){
   column = 1;
   if(c == 0x99){ state = 4; printf("\n{-- tape mark --} \n"); continue;}                    // .bcd tape mark
   if(c == 0xd7){ state = 1; putchar('\n'); continue; }
   if(c == 0xd8){
    if (state == 1) { state = 2; putchar('\n'); continue;}
    if (state == 2) { state = 3; continue;}
    if (state == 3) { state = 2; putchar('\n'); continue;}
   }
// there are 0xff records which throw off the two-card synchronization
   if(c == 0xff){  // a garbage record
    if (state == 2) { state = 3; printf("\n {0xff record at %d}\n", recnum); continue;};
    if (state == 3) { state = 2; printf("\n {0xff record at %d}\n", recnum); continue;};
   }
  }

  c &= 0x3f;

// there should only be two types of records, 0x17, a 165 byte label record, and 0x18, the actual data split across 2 records

  if(state == 1){  // the header
   if(column < 5){ // convert header record number to decimal
    if(column == 2) recnum = (c << 12);
    if(column == 3) recnum |= (c << 6);
    if(column == 4) recnum |= c;
   }
   if(column == 4){ printf("\n%06d ",recnum); continue;}

   if(column > 80) continue;
   if(column > 4) putchar(xs3[c&0x3f]);
  }

  if(state == 2) {
   if(column < 8) continue;
   if(column > 80) continue;
 //  if(xs3[c] == 0){printf(" {%02x} ",c); continue;} // unprintable character
   putchar(xs3[c&0x3f]);
  }

  if(state == 3) {
   if(column < 25) continue;
// if(xs3[c] == 0){printf(" {%02x} ",c); continue;} // unprintable character
   putchar(xs3[c&0x3f]);
  }
 }
}
