| /* | |
| * (C) Copyright 2002, Brian Knittel. | |
| * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN | |
| * RISK basis, there is no warranty of fitness for any purpose, and the rest of the | |
| * usual yada-yada. Please keep this notice and the copyright in any distributions | |
| * or modifications. | |
| * | |
| * This is not a supported product, but I welcome bug reports and fixes. | |
| * Mail to sim@ibm1130.org | |
| */ | |
| // --------------------------------------------------------------------------------- | |
| // BINDUMP - dumps card deck files in assembler object format | |
| // | |
| // Usage: | |
| /// bindump deckfile lists object header info & sector break cards | |
| // bindump -v deckfile lists object data records as well | |
| // bindump -p deckfile for system program, lists phase IDs in the deck | |
| // bindump -s deckfile >outfile for system program, sorts the phases & writes to stdout | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #ifdef _WIN32 | |
| # include <windows.h> | |
| # include <io.h> | |
| # include <fcntl.h> | |
| #endif | |
| #include "util_io.h" | |
| #ifndef TRUE | |
| #define BOOL int | |
| #define TRUE 1 | |
| #define FALSE 0 | |
| #endif | |
| typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC; | |
| BOOL verbose = FALSE; | |
| BOOL phid = FALSE; | |
| BOOL sort = FALSE; | |
| unsigned short card[80], buf[54], cardtype; | |
| // bindump - dump a binary (card format) deck to verify sbrks, etc | |
| void bail (char *msg); | |
| void dump (char *fname); | |
| void dump_data (char *fname); | |
| void dump_phids (char *fname); | |
| char *getname (unsigned short *ptr); | |
| char *getseq (void); | |
| int hollerith_to_ascii (unsigned short h); | |
| void process (char *fname); | |
| void show_raw (char *name); | |
| void show_data (void); | |
| void show_core (void); | |
| void show_endc (void); | |
| void show_81 (void); | |
| void show_main (void); | |
| void show_sub (void); | |
| void show_ils (void); | |
| void show_iss (void); | |
| void show_end (void); | |
| void sort_phases (char *fname); | |
| void trim (char *s); | |
| void unpack (unsigned short *card, unsigned short *buf); | |
| void verify_checksum(unsigned short *buf); | |
| int main (int argc, char **argv) | |
| { | |
| char *arg; | |
| static char usestr[] = "Usage: bindump [-psv] filename..."; | |
| int i; | |
| for (i = 1; i < argc; i++) { | |
| arg = argv[i]; | |
| if (*arg == '-') { | |
| arg++; | |
| while (*arg) { | |
| switch (*arg++) { | |
| case 'v': | |
| verbose = TRUE; | |
| break; | |
| case 'p': | |
| phid = TRUE; // print only phase ID's | |
| break; | |
| case 's': | |
| sort = TRUE; // sort deck by phases, writing to stdout | |
| break; | |
| default: | |
| bail(usestr); | |
| } | |
| } | |
| } | |
| } | |
| for (i = 1; i < argc; i++) { | |
| arg = argv[i]; | |
| if (*arg != '-') | |
| process(arg); | |
| } | |
| return 0; | |
| } | |
| void process (char *nm) | |
| { | |
| #ifdef _WIN32 | |
| WIN32_FIND_DATA fd; | |
| HANDLE hFind; | |
| char *c, buf[256]; | |
| if (strchr(nm, '*') == NULL && strchr(nm, '?') == NULL) | |
| dump(nm); | |
| else if ((hFind = FindFirstFile(nm, &fd)) == INVALID_HANDLE_VALUE) | |
| fprintf(stderr, "No files matching '%s'\n", nm); | |
| else { | |
| if ((c = strrchr(nm, '\\')) == NULL) | |
| c = strrchr(nm, ':'); | |
| do { | |
| if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
| continue; | |
| if (c == NULL) | |
| dump(fd.cFileName); | |
| else { | |
| strcpy(buf, nm); | |
| strcpy(buf + (c-nm+1), fd.cFileName); | |
| dump(buf); | |
| } | |
| } while (FindNextFile(hFind, &fd)); | |
| FindClose(hFind); | |
| } | |
| #else | |
| dump(nm); // on unices, sh globs for us | |
| #endif | |
| } | |
| void dump (char *fname) | |
| { | |
| if (sort) | |
| sort_phases(fname); | |
| else if (phid) | |
| dump_phids(fname); | |
| else | |
| dump_data(fname); | |
| } | |
| struct tag_card { | |
| int phid, seq; | |
| unsigned short card[80]; | |
| }; | |
| int cardcomp (const void *a, const void *b) | |
| { | |
| short diff; | |
| diff = ((struct tag_card *) a)->phid - ((struct tag_card *) b)->phid; | |
| return diff ? diff : (((struct tag_card *) a)->seq - ((struct tag_card *) b)->seq); | |
| } | |
| void sort_phases (char *fname) | |
| { | |
| int i, ncards, cardtype, len, seq = 0, phid; | |
| struct tag_card *deck; | |
| FILE *fd; | |
| BOOL saw_sbrk = TRUE; | |
| if ((fd = fopen(fname, "rb")) == NULL) { | |
| perror(fname); | |
| return; | |
| } | |
| fseek(fd, 0, SEEK_END); | |
| len = ftell(fd); // get length of file | |
| fseek(fd, 0, SEEK_SET); | |
| if (len <= 0 || (len % 160) != 0) { | |
| fprintf(stderr, "%s is not a binard deck image\n"); | |
| fclose(fd); | |
| return; | |
| } | |
| ncards = len / 160; | |
| if ((deck = (struct tag_card *) malloc(ncards*sizeof(struct tag_card))) == NULL) { | |
| fprintf(stderr, "%s: can't sort, insufficient memory\n"); | |
| fclose(fd); | |
| return; | |
| } | |
| phid = 0; | |
| for (i = 0; i < ncards; i++) { | |
| if (fxread(deck[i].card, sizeof(card[0]), 80, fd) != 80) { | |
| free(deck); | |
| fprintf(stderr, "%s: error reading deck\n"); | |
| fclose(fd); | |
| return; | |
| } | |
| unpack(deck[i].card, buf); | |
| deck[i].seq = seq++; | |
| deck[i].phid = phid; | |
| verify_checksum(buf); | |
| cardtype = (buf[2] >> 8) & 0xFF; | |
| if (cardtype == 1 || cardtype == 2) { // start of deck is same as sector break | |
| saw_sbrk = TRUE; | |
| } | |
| else if (cardtype == 0) { | |
| fprintf(stderr, "%s is a core image deck\n"); | |
| free(deck); | |
| fclose(fd); | |
| return; | |
| } | |
| else if (cardtype == 0x0A && saw_sbrk) { | |
| phid = (int) (signed short) buf[10]; | |
| if (phid < 0) | |
| phid = -phid; | |
| deck[i].phid = phid; // this belongs to the new phase | |
| deck[i-1].phid = phid; // as does previous card | |
| saw_sbrk = FALSE; | |
| } | |
| } | |
| fclose(fd); | |
| qsort(deck, ncards, sizeof(struct tag_card), cardcomp); // sort the deck | |
| #ifdef _WIN32 | |
| _setmode(_fileno(stdout), _O_BINARY); // set standard output to binary mode | |
| #endif | |
| for (i = 0; i < ncards; i++) // write to stdout | |
| fxwrite(deck[i].card, sizeof(card[0]), 80, stdout); | |
| free(deck); | |
| } | |
| void dump_phids (char *fname) | |
| { | |
| FILE *fp; | |
| BOOL first = TRUE; | |
| BOOL saw_sbrk = TRUE, neg; | |
| short id; | |
| if ((fp = fopen(fname, "rb")) == NULL) { | |
| perror(fname); | |
| return; | |
| } | |
| printf("\n%s:\n", fname); | |
| while (fxread(card, sizeof(card[0]), 80, fp) > 0) { | |
| unpack(card, buf); | |
| verify_checksum(buf); | |
| cardtype = (buf[2] >> 8) & 0xFF; | |
| if (cardtype == 1 && ! first) { // sector break | |
| saw_sbrk = TRUE; | |
| continue; | |
| } | |
| else { | |
| switch (cardtype) { | |
| case 0x00: | |
| printf(" This is a core image deck\n"); | |
| goto done; | |
| break; | |
| case 0x01: | |
| case 0x02: | |
| case 0x03: | |
| case 0x04: | |
| case 0x05: | |
| case 0x06: | |
| case 0x07: | |
| case 0x0F: | |
| break; | |
| case 0x0A: | |
| if (saw_sbrk) { | |
| id = buf[10]; | |
| if (id < 0) | |
| id = -id, neg = TRUE; | |
| else | |
| neg = FALSE; | |
| printf(" : %3d / %02x%s\n", id, id, neg ? " (neg)" : ""); | |
| saw_sbrk = FALSE; | |
| } | |
| break; | |
| default: | |
| show_raw("??? "); | |
| } | |
| } | |
| done: | |
| first = FALSE; | |
| } | |
| fclose(fp); | |
| } | |
| void dump_data (char *fname) | |
| { | |
| FILE *fp; | |
| BOOL first = TRUE; | |
| char str[80]; | |
| int i; | |
| if ((fp = fopen(fname, "rb")) == NULL) { | |
| perror(fname); | |
| return; | |
| } | |
| printf("\n%s:\n", fname); | |
| while (fxread(card, sizeof(card[0]), 80, fp) > 0) { | |
| unpack(card, buf); | |
| verify_checksum(buf); | |
| cardtype = (buf[2] >> 8) & 0xFF; | |
| if (cardtype == 1 && ! first) { // sector break | |
| for (i = 4; i < 72; i++) | |
| str[i] = hollerith_to_ascii(card[i]); | |
| str[i] = '\0'; | |
| trim(str+4); | |
| printf("*SBRK %s\n", str+4); | |
| continue; | |
| } | |
| else { | |
| switch (cardtype) { | |
| case 0x00: | |
| if (first) | |
| show_raw("CORE"); | |
| if (verbose) | |
| show_core(); | |
| break; | |
| case 0x01: | |
| show_raw("ABS "); | |
| show_main(); | |
| break; | |
| case 0x02: | |
| show_raw("REL "); | |
| show_main(); | |
| break; | |
| case 0x03: | |
| show_raw("LIB "); | |
| show_sub(); | |
| break; | |
| case 0x04: | |
| show_raw("SUB "); | |
| show_sub(); | |
| break; | |
| case 0x05: | |
| show_raw("ISSL"); | |
| show_iss(); | |
| break; | |
| case 0x06: | |
| show_raw("ISSC"); | |
| show_iss(); | |
| break; | |
| case 0x07: | |
| show_raw("ILS "); | |
| show_ils(); | |
| break; | |
| case 0x0F: | |
| show_raw("END "); | |
| show_end(); | |
| break; | |
| case 0x80: | |
| show_raw("ENDC"); | |
| show_endc(); | |
| break; | |
| case 0x81: | |
| show_raw("81 "); | |
| show_81(); | |
| break; | |
| case 0x0A: | |
| if (verbose) | |
| show_data(); | |
| break; | |
| default: | |
| show_raw("??? "); | |
| } | |
| } | |
| first = FALSE; | |
| } | |
| fclose(fp); | |
| } | |
| void show_data (void) | |
| { | |
| int i, n, jrel, rflag, nout, ch, reloc; | |
| BOOL first = TRUE; | |
| n = buf[2] & 0x00FF; | |
| printf("%04x: ", buf[0]); | |
| jrel = 3; | |
| nout = 0; | |
| rflag = buf[jrel++]; | |
| for (i = 0; i < n; i++) { | |
| if (nout >= 8) { | |
| rflag = buf[jrel++]; | |
| if (first) { | |
| printf(" %s", getseq()); | |
| first = FALSE; | |
| } | |
| printf("\n "); | |
| nout = 0; | |
| } | |
| reloc = (rflag >> 14) & 0x03; | |
| ch = (reloc == R_ABSOLUTE) ? ' ' : | |
| (reloc == R_RELATIVE) ? 'R' : | |
| (reloc == R_LIBF) ? 'L' : '@'; | |
| printf("%04x%c ", buf[9+i], ch); | |
| rflag <<= 2; | |
| nout++; | |
| } | |
| putchar('\n'); | |
| } | |
| void show_core (void) | |
| { | |
| int i, n, nout; | |
| BOOL first = TRUE; | |
| n = buf[2] & 0x00FF; | |
| printf("%04x: ", buf[0]); | |
| nout = 0; | |
| for (i = 0; i < n; i++) { | |
| if (nout >= 8) { | |
| if (first) { | |
| printf(" %s", getseq()); | |
| first = FALSE; | |
| } | |
| printf("\n "); | |
| nout = 0; | |
| } | |
| printf("%04x ", buf[9+i]); | |
| nout++; | |
| } | |
| putchar('\n'); | |
| } | |
| void info (int i, char *nm, char type) | |
| { | |
| if (nm) | |
| printf("%s ", nm); | |
| switch (type) { | |
| case 'd': | |
| printf("%d ", buf[i]); | |
| break; | |
| case 'x': | |
| printf("%04x ", buf[i]); | |
| break; | |
| case 'b': | |
| printf("%02x ", buf[i] & 0xFF); | |
| break; | |
| case 'n': | |
| printf("%s ", getname(buf+i)); | |
| break; | |
| default: | |
| bail("BAD TYPE"); | |
| } | |
| } | |
| void show_main (void) | |
| { | |
| printf(" "); | |
| info(2, "prec", 'b'); | |
| info(4, "common", 'd'); | |
| info(6, "work", 'd'); | |
| info(8, "files", 'd'); | |
| info(9, "name", 'n'); | |
| info(11, "pta", 'x'); | |
| putchar('\n'); | |
| } | |
| void show_sub (void) | |
| { | |
| int i, n; | |
| printf(" "); | |
| info( 2, "prec", 'b'); | |
| n = buf[5] / 3; | |
| for (i = 0; i < n; i++) { | |
| info( 9+3*i, "ent", 'n'); | |
| info(11+3*i, NULL, 'x'); | |
| } | |
| putchar('\n'); | |
| } | |
| void show_iss (void) | |
| { | |
| printf(" "); | |
| info(12, "level", 'd'); | |
| putchar('\n'); | |
| } | |
| void show_ils (void) | |
| { | |
| printf(" "); | |
| info( 2, "prec", 'b'); | |
| info( 5, "nint6", 'd'); | |
| info( 9, "ent", 'n'); | |
| info(11, NULL, 'x'); | |
| info(14, "nint", 'd'); | |
| info(15, "il1", 'd'); | |
| info(16, "il2", 'd'); | |
| putchar('\n'); | |
| } | |
| void show_end (void) | |
| { | |
| printf(" "); | |
| info(0, "size", 'd'); | |
| info(3, "pta", 'x'); | |
| putchar('\n'); | |
| } | |
| void show_endc(void) | |
| { | |
| printf(" "); | |
| info(52, "IX3", 'x'); | |
| info(53, "pta", 'x'); | |
| putchar('\n'); | |
| } | |
| void show_81(void) | |
| { | |
| } | |
| void show_raw (char *name) | |
| { | |
| int i; | |
| printf("*%s", name); | |
| for (i = 0; i < 12; i++) | |
| printf(" %04x", buf[i]); | |
| printf(" %s\n", getseq()); | |
| } | |
| char * getseq (void) | |
| { | |
| static char seq[10]; | |
| int i; | |
| for (i = 0; i < 8; i++) | |
| seq[i] = hollerith_to_ascii(card[72+i]); | |
| seq[i] = '\0'; | |
| return seq; | |
| } | |
| void bail (char *msg) | |
| { | |
| fprintf(stderr, "%s\n", msg); | |
| exit(1); | |
| } | |
| void unpack (unsigned short *icard, unsigned short *obuf) | |
| { | |
| int i, j; | |
| unsigned short wd1, wd2, wd3, wd4; | |
| for (i = j = 0; i < 54; i += 3, j += 4) { | |
| wd1 = icard[j]; | |
| wd2 = icard[j+1]; | |
| wd3 = icard[j+2]; | |
| wd4 = icard[j+3]; | |
| obuf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); | |
| obuf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); | |
| obuf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); | |
| } | |
| } | |
| void verify_checksum (unsigned short *obuf) | |
| { | |
| // unsigned short sum; | |
| if (obuf[1] == 0) // no checksum | |
| return; | |
| // if (sum != card[1]) | |
| // printf("Checksum %04x doesn't match card %04x\n", sum, card[1]); | |
| } | |
| typedef struct { | |
| unsigned short hollerith; | |
| char ascii; | |
| } CPCODE; | |
| static CPCODE cardcode_029[] = | |
| { | |
| 0x0000, ' ', | |
| 0x8000, '&', // + in 026 Fortran | |
| 0x4000, '-', | |
| 0x2000, '0', | |
| 0x1000, '1', | |
| 0x0800, '2', | |
| 0x0400, '3', | |
| 0x0200, '4', | |
| 0x0100, '5', | |
| 0x0080, '6', | |
| 0x0040, '7', | |
| 0x0020, '8', | |
| 0x0010, '9', | |
| 0x9000, 'A', | |
| 0x8800, 'B', | |
| 0x8400, 'C', | |
| 0x8200, 'D', | |
| 0x8100, 'E', | |
| 0x8080, 'F', | |
| 0x8040, 'G', | |
| 0x8020, 'H', | |
| 0x8010, 'I', | |
| 0x5000, 'J', | |
| 0x4800, 'K', | |
| 0x4400, 'L', | |
| 0x4200, 'M', | |
| 0x4100, 'N', | |
| 0x4080, 'O', | |
| 0x4040, 'P', | |
| 0x4020, 'Q', | |
| 0x4010, 'R', | |
| 0x3000, '/', | |
| 0x2800, 'S', | |
| 0x2400, 'T', | |
| 0x2200, 'U', | |
| 0x2100, 'V', | |
| 0x2080, 'W', | |
| 0x2040, 'X', | |
| 0x2020, 'Y', | |
| 0x2010, 'Z', | |
| 0x0820, ':', | |
| 0x0420, '#', // = in 026 Fortran | |
| 0x0220, '@', // ' in 026 Fortran | |
| 0x0120, '\'', | |
| 0x00A0, '=', | |
| 0x0060, '"', | |
| 0x8820, 'c', // cent | |
| 0x8420, '.', | |
| 0x8220, '<', // ) in 026 Fortran | |
| 0x8120, '(', | |
| 0x80A0, '+', | |
| 0x8060, '|', | |
| 0x4820, '!', | |
| 0x4420, '$', | |
| 0x4220, '*', | |
| 0x4120, ')', | |
| 0x40A0, ';', | |
| 0x4060, 'n', // not | |
| 0x2820, 'x', // what? | |
| 0x2420, ',', | |
| 0x2220, '%', // ( in 026 Fortran | |
| 0x2120, '_', | |
| 0x20A0, '>', | |
| 0x2060, '>', | |
| }; | |
| int hollerith_to_ascii (unsigned short h) | |
| { | |
| int i; | |
| h &= 0xFFF0; | |
| for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) | |
| if (cardcode_029[i].hollerith == h) | |
| return cardcode_029[i].ascii; | |
| return '?'; | |
| } | |
| // --------------------------------------------------------------------------------- | |
| // trim - remove trailing whitespace from string s | |
| // --------------------------------------------------------------------------------- | |
| void trim (char *s) | |
| { | |
| char *nb; | |
| for (nb = s-1; *s; s++) | |
| if (*s > ' ') | |
| nb = s; | |
| nb[1] = '\0'; | |
| } | |
| int ascii_to_ebcdic_table[128] = | |
| { | |
| 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, | |
| 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, | |
| 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, | |
| 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, | |
| 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, | |
| 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, | |
| 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, | |
| 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, | |
| }; | |
| char *getname (unsigned short *ptr) | |
| { | |
| static char str[6]; | |
| int i, j, ch; | |
| long v; | |
| v = (ptr[0] << 16L) | ptr[1]; | |
| for (i = 0; i < 5; i++) { | |
| ch = ((v >> 24) & 0x3F) | 0xC0; // recover those lost two bits | |
| v <<= 6; | |
| str[i] = ' '; | |
| for (j = 0; j < (sizeof(ascii_to_ebcdic_table)/sizeof(ascii_to_ebcdic_table[0])); j++) { | |
| if (ascii_to_ebcdic_table[j] == ch) { | |
| str[i] = j; | |
| break; | |
| } | |
| } | |
| } | |
| str[5] = '\0'; | |
| return str; | |
| } | |