Anonymonk:
I have some perl code to do this conversion, which I can't seem to find it at the moment. But if you don't mind using C, I *did* trip across one of my older C programs that did this sort of conversion. It's not pretty, but maybe it might be useful. Towards the end, you just convert your PIC statement into a few function calls to do the conversion work. All the stuff before main are the helper routines to make the conversion section simple.
Much of it is boilerplate (in readmore tags so uninterested people can skip it).
/* ebcdic2ascii.cpp * * convert an EBCDIC file to ASCII. * * * gcc -funsigned-char ebcdic2ascii.cpp * * Unsigned char else the array lookup will fail.... */ #include <stdio.h> char xlat_ebcdic_to_ascii[256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D +E F * --- --- --- --- --- --- --- --- --- --- --- --- --- --- - +-- --- */ /* 0 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , + 1 , 1 , /* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , + 1 , 1 , /* 2 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , + 1 , 1 , /* 3 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , + 1 , 1 , /* 4 */ ' ', 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,'?','.','<','(', +'+','|', /* 5 */ '&', 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,'!','$','*',')', +';','?', /* 6 */ '-','/', 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,'|',',','%','_', +'>','?', /* 7 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,'`',':','#','@','\'' +,'=','~', /* 8 */ 1 ,'a','b','c','d','e','f','g','h','i', 1 , 1 , 1 , 1 , + 1 , 1 , /* 9 */ 1 ,'j','k','l','m','n','o','p','q','r', 1 , 1 , 1 , 1 , + 1 , 1 , /* A */ 1 ,'~','s','t','u','v','w','x','y','z', 1 , 1 , 1 , 1 , + 1 , 1 , /* B */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , + 1 , 1 , /* C */ '{','A','B','C','D','E','F','G','H','I', 1 , 1 , 1 , 1 , + 1 , 1 , /* D */ '}','J','K','L','M','N','O','P','Q','R', 1 , 1 , 1 , 1 , + 1 , 1 , /* E */ '\\',0 ,'S','T','U','V','W','X','Y','Z', 1 , 1 , 1 , 1 , + 1 , 1 , /* F */ '0','1','2','3','4','5','6','7','8','9', 1 , 1 , 1 , 1 , + 1 , 1 }; char tohex(char v) { // NOTE: if signed character, be sure it's not negative! So ignor +e the // warning, as it alerts you to a compile error (i.e. missing -fun +signed-char) if ( (v<0) || (v>15) ) { return '#'; } return "0123456789ABCDEF"[v]; } // convert <src> to ascii, stick in <*dst> and return next position char *ebcdic_to_ascii(char *dst, char src) { char x = xlat_ebcdic_to_ascii[src]; *dst++ = x; return dst; } // convert <len> chars at <*src> to ascii, storing them at <*dst> and // returning the next position char *xlat(char *dst, char *src, int len) { while (len--) { dst = ebcdic_to_ascii(dst, *src++); } return dst; } char packed_to_ascii[] = "0123456789 -+-++"; // SIGNED unpack: show trailing sign char *Sunpack(char *dst, char *src, int len, int skip=0) { // Skip digits as requested... while (skip > 1) { // Skip entire bytes ++src; skip -= 2; --len; } if (skip) { // Skip next digit (i.e. MSB) *dst++ = packed_to_ascii[ (*src++) & 0x0f ]; --len; } // Emit remaining digits while (len--) { *dst++ = packed_to_ascii[ (*src>>4) & 0x0f ]; *dst++ = packed_to_ascii[ (*src++) & 0x0f ]; } return dst; } // UNSIGNED unpack: skip sign char *Uunpack(char *dst, char *src, int len, int skip=0) { // Skip digits as requested... while (skip > 1) { // Skip entire bytes ++src; skip -= 2; --len; } if (skip) { // Skip next digit (i.e. MSB) *dst++ = packed_to_ascii[ (*src++) & 0x0f ]; --len; } // Emit remaining digits, except for last byte while (len-- > 1) { *dst++ = packed_to_ascii[ (*src>>4) & 0x0f ]; *dst++ = packed_to_ascii[ (*src++) & 0x0f ]; } // For last byte, show MSB only (last digit before sign) *dst++ = packed_to_ascii[ (*src>>4) & 0x0f ]; return dst; } #define IRECSIZE 500 // input record size #define ORECSIZE 2048 // Room for translated/unpacked record int main(int argc, char **argv) { if (argc != 3) { puts("Missing INFile or OUTFile!"); return 1; } // Open the input and output files FILE *fin = fopen(argv[1], "rb"); FILE *fout = fopen(argv[2], "w"); if (!fin || !fout) { puts("Can't open a file!"); return 2; } char inbuf[IRECSIZE+20]; char outbuf[ORECSIZE]; long recs = 0; while (!feof(fin)) { // Read the record size_t bytes_read = fread(inbuf, 1, IRECSIZE, fin); ++recs; if (IRECSIZE != bytes_read) { if (!bytes_read) printf("%lu: EOF detected?\n", recs); else printf("%lu: Sort record (saw %u, expected %u) found.\ +n", recs, bytes_read, IRECSIZE); continue; } // Translate input fields into output buffer. char *dst = outbuf;
The only bit you need to work with is this section, where you use the functions to split the mainframe file up and convert it into an ASCII flat file:
// ************************************************** // * YOU NEED TO CUSTOMIZE THE CODE BETWEEN HERE... * // ************************************************** // Now we use Uunpack, Sunpack, and xlat to translate the fiel +ds. // // Let's pretend our input record is: // // MERCHANT-NUMBER PIC 9(9) COMP-3. // STORE-NUMBER PIC 9(9) COMP-3. // CREATED-DATE PIC 9(8) COMP-3. (FMT=YYYYMMDD) // MERCHANT-NAME PIC X(32). // OWNER-NAME PIC X(32). // CURRENT-BALANCE PIC S9(8)v99. // // The first two fields are packed unsigned numeric, using an +odd number // of digits, so we use Uunpack: dst = Uunpack(dst, inbuf+0, 5); dst = Uunpack(dst, inbuf+5, 5); // The date is also a packed unsigned numeric, but has only 8 +digits, so // we tell Uunpack to skip the first digit (otherwise our date + would look // like '0YYYYMMDD'. dst = Uunpack(dst, inbuf+10, 5, 1); // The next two fields are simple text fields. This is the ea +sy // translation bit. You could call xlat twice, but since they +'re // adjacent, I'll translate both text fields at the same time: xlat(dst, inbuf+15, 64); // Signed numbers are similar to the unsigned, but they have t +railing // signs. A fancy program would move the sign to the front. +This is // decidedly *not* a fancy program. dst = Sunpack(dst, inbuf+74, 6); // Adding field delimiters, end of record markers, etc., is pr +etty // trivial. Here we'll add a CR+LF at the end of each line: *dst++ = '\r'; *dst++ = '\n'; *dst++ = 0; // ***************************** // * END OF CUSTOMIZED SECTION * // ***************************** // Write our translated record fputs(outbuf, fout); } printf("%lu reads\n", recs); fclose(fin); fclose(fout); }
Update: Put the boilerplate code in readmore tags to shorten the node a bit.
...roboticus
When your only tool is a hammer, all problems look like your thumb.
In reply to Re: Converting Mainframe EBCDIC data
by roboticus
in thread Converting Mainframe EBCDIC data
by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |