From 52a31597ec164a80cde08b48df8114aff7273ac1 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 7 May 2019 05:26:20 -0700 Subject: [PATCH] TAPE: Add ANSIFILES tape format --- PDP11/pdp11_tq.c | 5 +- README.md | 1 + doc/simh_doc.doc | Bin 264704 -> 270336 bytes doc/simh_faq.doc | Bin 106496 -> 109056 bytes sim_tape.c | 650 ++++++++++++++++++++++++++++++++++++++++++----- sim_tape.h | 1 + 6 files changed, 590 insertions(+), 67 deletions(-) diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 61397f2f..d33a2dbc 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -1209,8 +1209,9 @@ if ((uptr = tq_getucb (lu))) { /* unit exist? */ if (sts == ST_SUC) { /* ok? */ uptr->cpkt = pkt; /* op in progress */ if ((tq_pkt[pkt].d[CMD_MOD] & MD_RWD) && /* rewind? */ - (!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM))) /* !immediate? */ - sim_activate_after (uptr, 2000000); /* use 2 sec rewind execute time */ + (!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM))) { /* !immediate? */ + sim_activate_after (uptr, tq_rwtime); /* use 2 sec rewind execute time */ + } else { /* otherwise */ uptr->iostarttime = sim_grtime(); sim_activate (uptr, 0); /* use normal execute time */ diff --git a/README.md b/README.md index 9f735f9a..af1a664f 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,7 @@ Host platforms which have libSDL available can leverage this functionality. #### Tape Extensions AWS format tape support TAR format tape support + ANSIFILES format tape support #### Embedded ROM support Simulators which have boot commands which load constant files as part of diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc index a89cc2ab22ee93737b176acdb87c9e79bf1d7b9a..7f636454a72f8fa58f7867b3a94ddcdd8ffabcd9 100644 GIT binary patch delta 22619 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 delta 18616 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 URJ+}7b67fCQ(dn%HNPeNKklQljQ{`u diff --git a/doc/simh_faq.doc b/doc/simh_faq.doc index cb505e5b8c4273ffb03e9e958556eb4fa637e59e..60478201226e195944da14f710c32d922f2429d1 100644 GIT binary patch delta 25334 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 diff --git a/sim_tape.c b/sim_tape.c index e720c7ac..2c1cdcfa 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -108,13 +108,14 @@ struct sim_tape_fmt { }; static struct sim_tape_fmt fmts[MTUF_N_FMT] = { - { "SIMH", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt)}, - { "E11", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) }, + { "SIMH", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) }, + { "E11", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) }, { "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) }, - { "P7B", 0, 0, 0 }, - { "AWS", 0, 0, 0 }, - { "TAR", 0, 0, 0 }, - { NULL, 0, 0 } + { "P7B", 0, 0, 0 }, + { "AWS", 0, 0, 0 }, + { "TAR", 0, 0, 0 }, + { "ANSIFILES", 0, 0, 0 }, + { NULL, 0, 0, 0 } }; static const uint32 bpi [] = { /* tape density table, indexed by MT_DENS constants */ @@ -375,6 +376,89 @@ return FALSE; (_callback) (uptr, r); #endif +typedef struct VOL1 { + char type[3]; /* VOL */ + char num; /* 1 */ + char ident[6]; /* characters blank padded > */ + char accessibity; /* blank */ + char reserved1[13]; /* */ + char implement[13]; /* */ + char owner[14]; /* */ + char reserved2[28]; /* */ + char standard; /* 1,3 or 4 */ + } VOL1; + +typedef struct HDR1 { /* Also EOF1, EOV1 */ + char type[3]; /* HDR|EOF|EOV */ + char num; /* 1 */ + char file_ident[17]; /* filename */ + char file_set[6]; /* label ident */ + char file_section[4]; /* 0001 */ + char file_sequence[4]; /* 0001 */ + char generation_number[4]; /* 0001 */ + char version_number[2]; /* 00 */ + char creation_date[6]; /* cyyddd */ + char expiration_date[6]; + char accessibility; /* space */ + char block_count[6]; /* 000000 */ + char system_code[13]; /* */ + char reserved[7]; /* blank */ + } HDR1; + +typedef struct HDR2 { /* Also EOF2, EOV2 */ + char type[3]; /* HDR */ + char num; /* 2 */ + char record_format; /* F(fixed)|D(variable)|S(spanned) */ + char block_length[5]; /* label ident */ + char record_length[5]; /* */ + char reserved_os[35]; /* */ + char buffer_offset[2]; /* */ + char reserved_std[28]; /* */ + } HDR2; + +typedef struct HDR3 { /* Also EOF3, EOV3 */ + char type[3]; /* HDR */ + char num; /* 2 */ + char record_format; /* F(fixed)|D(variable)|S(spanned) */ + char block_length[5]; /* label ident */ + char record_length[5]; /* */ + char reserved_os[35]; /* */ + char buffer_offset[2]; /* */ + char reserved_std[28]; /* */ + } HDR3; + +typedef struct HDR4 { /* Also EOF4, EOV4 */ + char type[3]; /* HDR */ + char num; /* 4 */ + char blank; /* blank */ + char extra_name[62]; /* */ + char extra_name_used[2]; /* 99 */ + char unused[11]; + } HDR4; + +typedef struct TAPE_RECORD { + uint32 size; + uint8 data[1]; + } TAPE_RECORD; + +typedef struct ANSI_TAPE { + uint32 file_count; + uint32 record_count; + uint32 array_size; + uint32 block_size; + TAPE_RECORD **records; + VOL1 vol1; + } ANSI_TAPE; + +static ANSI_TAPE *ansi_create_tape (const char *label, uint32 block_size); +static int ansi_free_tape (void *vtape); +static void sim_tape_add_ansi_entry (const char *directory, + const char *filename, + t_offset FileSize, + const struct stat *filestat, + void *context); +static t_bool ansi_tape_add_block (ANSI_TAPE *tape, uint8 *block, uint32 size); + /* Enable asynchronous operation */ @@ -448,7 +532,8 @@ sim_tape_clr_async (uptr); if (sim_asynch_enabled) sim_tape_set_async (uptr, ctx->asynch_io_latency); #endif -fflush (uptr->fileref); +if (MT_GET_FMT (uptr) != MTUF_F_ANSI) + fflush (uptr->fileref); } /* Attach tape unit */ @@ -502,9 +587,36 @@ if (MT_GET_FMT (uptr) == MTUF_F_TAR) { uptr->recsize = TAR_DFLT_RECSIZE; } if ((MT_GET_FMT (uptr) == MTUF_F_TPC) || - (MT_GET_FMT (uptr) == MTUF_F_TAR)) - sim_switches |= SWMASK ('R'); /* Force ReadOnly attach for TPC and TAR tapes */ -r = attach_unit (uptr, (CONST char *)cptr); /* attach unit */ + (MT_GET_FMT (uptr) == MTUF_F_TAR) || + (MT_GET_FMT (uptr) == MTUF_F_ANSI)) + sim_switches |= SWMASK ('R'); /* Force ReadOnly attach for TPC, TAR and ANSIFILES tapes */ +if (MT_GET_FMT (uptr) == MTUF_F_ANSI) { + const char *ocptr = cptr; + char label[CBUFSIZE] = "simh"; + + uptr->fileref = (FILE *)ansi_create_tape (label, 2048); + if (!uptr->fileref) + return SCPE_MEM; + while (*cptr != 0) { /* do all mods */ + cptr = get_glyph_nc (cptr, gbuf, ','); /* get filename */ + sim_dir_scan (gbuf, sim_tape_add_ansi_entry, uptr->fileref); + } + if (((ANSI_TAPE *)uptr->fileref)->file_count > 0) { + r = SCPE_OK; + ansi_tape_add_block ((ANSI_TAPE *)uptr->fileref, NULL, 0); + uptr->flags |= UNIT_ATT; + uptr->filename = (char *)malloc (strlen (ocptr) + 1); + strcpy (uptr->filename, ocptr); + uptr->tape_eom = ((ANSI_TAPE *)uptr->fileref)->record_count; + } + else { + r = SCPE_ARG; + ansi_free_tape (uptr->fileref); + uptr->fileref = NULL; + } + } +else + r = attach_unit (uptr, (CONST char *)cptr); /* attach unit */ if (r != SCPE_OK) /* error? */ return sim_messagef (r, "Can't open tape image: %s\n", cptr); @@ -591,7 +703,13 @@ if (ctx) sim_tape_clr_async (uptr); MT_CLR_INMRK (uptr); /* Not within an AWS or TAR tapemark */ -r = detach_unit (uptr); /* detach unit */ +if (MT_GET_FMT (uptr) == MTUF_F_ANSI) { + r = ansi_free_tape ((void *)uptr->fileref); + uptr->fileref = NULL; + uptr->flags &= ~UNIT_ATT; + } +else + r = detach_unit (uptr); /* detach unit */ if (r != SCPE_OK) return r; switch (f) { /* case on format */ @@ -639,7 +757,7 @@ fprintf (st, " -R Attach Read Only.\n"); fprintf (st, " -E Must Exist (if not specified an attempt to create the indicated\n"); fprintf (st, " virtual tape will be attempted).\n"); fprintf (st, " -F Open the indicated tape container in a specific format (default\n"); -fprintf (st, " is SIMH, alternatives are E11, TPC, P7B, AWS and TAR)\n"); +fprintf (st, " is SIMH, alternatives are E11, TPC, P7B, AWS, TAR and ANSIFILES)\n"); fprintf (st, " -B For TAR format tapes, the record size for data read from the\n"); fprintf (st, " specified file. This record size will be used for all but\n"); fprintf (st, " possibly the last record which will be what remains unread.\n"); @@ -650,7 +768,13 @@ fprintf (st, " -L Display detailed record size counts observed durin fprintf (st, " validation pass\n"); fprintf (st, " contained in the tape image scan performed when it is attached.\n"); fprintf (st, " -D Causes the internal tape structure information to be displayed\n"); -fprintf (st, " while the tape image is scanned.\n"); +fprintf (st, " while the tape image is scanned.\n\n"); +fprintf (st, "Notes: ANSIFILES format allows one or several files to be presented to as a\n"); +fprintf (st, " read only ANSI Level 3 labeled tape with file labels that make each\n"); +fprintf (st, " individual file accessible directly as files on the tape.\n\n"); +fprintf (st, "Examples:\n\n"); +fprintf (st, " sim> ATTACH -F %s ANSIFILES Hobbyist-USE-ONLY-VA.TXT\n\n", dptr->name); +fprintf (st, " sim> ATTACH -F %s ANSIFILES *.TXT,*.ini,*.exe\n", dptr->name); return SCPE_OK; } @@ -664,6 +788,20 @@ if (sim_deb && ((uptr->dctrl | ctx->dptr->dctrl) & reason)) sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), "", len, txt, reason); } +static int sim_tape_seek (UNIT *uptr, t_addr pos) +{ +if (MT_GET_FMT (uptr) != MTUF_F_ANSI) + return sim_fseek (uptr->fileref, pos, SEEK_SET); +return 0; +} + +static t_offset sim_tape_size (UNIT *uptr) +{ +if (MT_GET_FMT (uptr) != MTUF_F_ANSI) + return sim_fsize_ex (uptr->fileref); +return uptr->tape_eom; +} + /* Read record length forward (internal routine). Inputs: @@ -782,7 +920,7 @@ if ((uptr->tape_eom) && return MTSE_EOM; /* and quit with I/O error status */ } -if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the initial tape position; if it fails */ +if (sim_tape_seek (uptr, uptr->pos)) { /* set the initial tape position; if it fails */ MT_SET_PNU (uptr); /* then set position not updated */ return sim_tape_ioerr (uptr); /* and quit with I/O error status */ } @@ -878,8 +1016,8 @@ switch (f) { /* otherwise the read method else if (*bc == MTR_FHGAP) { /* otherwise if the value if a half gap */ uptr->pos = uptr->pos - sizeof (t_mtrlnt) / 2; /* then back up and resync */ - if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the tape position; if it fails */ - status = sim_tape_ioerr (uptr); /* then quit with I/O error status */ + if (sim_tape_seek (uptr, uptr->pos)) { /* set the tape position; if it fails */ + status = sim_tape_ioerr (uptr); /* then quit with I/O error status */ break; } @@ -904,7 +1042,7 @@ switch (f) { /* otherwise the read method if (status == MTSE_OK) { /* Validate the reverse record size for data records */ t_mtrlnt rev_lnt; - if (sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET)){ /* then seek to the end of record size; if it fails */ + if (sim_tape_seek (uptr, uptr->pos - sizeof (t_mtrlnt))) { /* then seek to the end of record size; if it fails */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */ break; } @@ -924,7 +1062,7 @@ switch (f) { /* otherwise the read method MT_SET_PNU (uptr); /* pos not upd */ break; } - if (sim_fseek (uptr->fileref, saved_pos, SEEK_SET)) /* then seek back to the beginning of the data; if it fails */ + if (sim_tape_seek (uptr, saved_pos)) /* then seek back to the beginning of the data; if it fails */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */ } break; /* otherwise the operation succeeded */ @@ -976,7 +1114,7 @@ switch (f) { /* otherwise the read method if (status == MTSE_OK) { *bc = sbc; /* save rec lnt */ - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ + (void)sim_tape_seek (uptr, uptr->pos); /* for read */ uptr->pos = uptr->pos + sbc; /* spc over record */ if (all_eof) { /* tape mark? */ status = MTSE_TMK; @@ -1018,7 +1156,7 @@ switch (f) { /* otherwise the read method uptr->pos += awshdr.nxtlen; /* spc over record */ memset (&awshdr, 0, sizeof (t_awslnt)); saved_pos = (t_addr)sim_ftell (uptr->fileref); - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ + (void)sim_tape_seek (uptr, uptr->pos); /* for read */ (void)sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); if (awshdr.rectyp == AWS_TMK) MT_SET_INMRK (uptr); /* within an AWS tapemark */ @@ -1028,7 +1166,7 @@ switch (f) { /* otherwise the read method MT_CLR_INMRK (uptr); /* not within an AWS tapemark */ } else - (void)sim_fseek (uptr->fileref, saved_pos, SEEK_SET); /* Move back to the data */ + (void)sim_tape_seek (uptr, saved_pos); /* Move back to the data */ } break; @@ -1038,7 +1176,7 @@ switch (f) { /* otherwise the read method *bc = (t_mtrlnt)uptr->recsize; /* TAR record size */ else *bc = (t_mtrlnt)(uptr->hwmark - uptr->pos); /* TAR remnant last record */ - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); + (void)sim_tape_seek (uptr, uptr->pos); uptr->pos += *bc; MT_CLR_INMRK (uptr); } @@ -1052,6 +1190,22 @@ switch (f) { /* otherwise the read method } break; + case MTUF_F_ANSI: + if (1) { + ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref; + + if (uptr->pos >= tape->record_count) + status = MTSE_EOM; + else { + if (tape->records[uptr->pos]->size == 0) + status = MTSE_TMK; + else + *bc = tape->records[uptr->pos]->size; + ++uptr->pos; + } + } + break; + default: status = MTSE_FMT; } @@ -1171,10 +1325,10 @@ else switch (f) { /* otherwise the read me bufcap = sizeof (buffer) /* to the full size of the buffer */ / sizeof (buffer [0]); - if (sim_fseek (uptr->fileref, /* seek back to the location */ - uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */ - SEEK_SET)) { /* of the buffer; if it fails */ - status = sim_tape_ioerr (uptr); /* and fail with I/O error status */ + if (sim_tape_seek (uptr, /* seek back to the location */ + uptr->pos - bufcap * sizeof (t_mtrlnt))) { /* corresponding to the start */ + /* of the buffer; if it fails */ + status = sim_tape_ioerr (uptr); /* and fail with I/O error status */ break; } @@ -1213,9 +1367,8 @@ else switch (f) { /* otherwise the read me uptr->pos = uptr->pos - sizeof (t_mtrlnt) /* position to the start */ - (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */ - if (sim_fseek (uptr->fileref, /* seek to the start of the data area; if it fails */ - uptr->pos + sizeof (t_mtrlnt), /* then return with I/O error status */ - SEEK_SET)) { + if (sim_tape_seek (uptr, /* seek to the start of the data area; if it fails */ + uptr->pos + sizeof (t_mtrlnt))) {/* then return with I/O error status */ status = sim_tape_ioerr (uptr); break; } @@ -1230,7 +1383,7 @@ else switch (f) { /* otherwise the read me case MTUF_F_TPC: ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */ - (void)sim_fseek (uptr->fileref, ppos, SEEK_SET);/* position */ + (void)sim_tape_seek (uptr, ppos); /* position */ (void)sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); *bc = (t_mtrlnt)tpcbc; /* save rec lnt */ @@ -1243,7 +1396,7 @@ else switch (f) { /* otherwise the read me if (*bc == MTR_TMK) /* tape mark? */ status = MTSE_TMK; else - (void)sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); + (void)sim_tape_seek (uptr, uptr->pos + sizeof (t_tpclnt)); } break; @@ -1265,7 +1418,7 @@ else switch (f) { /* otherwise the read me buf_offset = uptr->pos - (sbc - 1 + BUF_SZ); read_size = BUF_SZ; } - (void)sim_fseek (uptr->fileref, buf_offset, SEEK_SET); + (void)sim_tape_seek (uptr, buf_offset); bytes_in_buf = sim_fread (buf, sizeof (uint8), read_size, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ status = sim_tape_ioerr (uptr); @@ -1286,7 +1439,7 @@ else switch (f) { /* otherwise the read me if (status == MTSE_OK) { uptr->pos = uptr->pos - sbc; /* update position */ *bc = sbc; /* save rec lnt */ - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for next read */ + (void)sim_tape_seek (uptr, uptr->pos); /* for next read */ if (all_eof) /* tape mark? */ status = MTSE_TMK; } @@ -1300,7 +1453,7 @@ else switch (f) { /* otherwise the read me status = MTSE_BOT; /* then we're done */ break; } - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);/* position */ + (void)sim_tape_seek (uptr, uptr->pos); /* position */ memset (&awshdr, 0, sizeof (awshdr)); rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ @@ -1336,9 +1489,8 @@ else switch (f) { /* otherwise the read me uptr->pos -= sizeof (t_awshdr); /* position to the start of the record */ uptr->pos -= awshdr.prelen; /* Including the data length */ - if (sim_fseek (uptr->fileref, /* seek to the start of the data area; if it fails */ - uptr->pos + sizeof (t_awshdr), - SEEK_SET)) { + if (sim_tape_seek (uptr, /* seek to the start of the data area; if it fails */ + uptr->pos + sizeof (t_awshdr))) { status = sim_tape_ioerr (uptr); /* then return with I/O error status */ break; } @@ -1368,10 +1520,22 @@ else switch (f) { /* otherwise the read me *bc = (t_mtrlnt)uptr->recsize; if (*bc) { uptr->pos -= *bc; - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); + (void)sim_tape_seek (uptr, uptr->pos); } break; + case MTUF_F_ANSI: + if (1) { + ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref; + + --uptr->pos; + if (tape->records[uptr->pos]->size == 0) + status = MTSE_TMK; + else + *bc = tape->records[uptr->pos]->size; + } + break; + default: status = MTSE_FMT; } @@ -1439,11 +1603,19 @@ if (rbc > max) { /* rec out of range? */ uptr->pos = opos; return MTSE_INVRL; } -i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ -if (ferror (uptr->fileref)) { /* error? */ - MT_SET_PNU (uptr); - uptr->pos = opos; - return sim_tape_ioerr (uptr); +if (f != MTUF_F_ANSI) { + i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ + if (ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); + uptr->pos = opos; + return sim_tape_ioerr (uptr); + } + } +else { + ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref; + + memcpy (buf, tape->records[uptr->pos - 1]->data, rbc); + i = rbc; } for ( ; i < rbc; i++) /* fill with 0's */ buf[i] = 0; @@ -1504,9 +1676,17 @@ if (st != MTSE_OK) { *bc = rbc = MTR_L (tbc); /* strip error flag */ if (rbc > max) /* rec out of range? */ return MTSE_INVRL; -i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ -if (ferror (uptr->fileref)) /* error? */ - return sim_tape_ioerr (uptr); +if (f != MTUF_F_ANSI) { + i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ + if (ferror (uptr->fileref)) /* error? */ + return sim_tape_ioerr (uptr); + } +else { + ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref; + + memcpy (buf, tape->records[uptr->pos]->data, rbc); + i = rbc; + } for ( ; i < rbc; i++) /* fill with 0's */ buf[i] = 0; if (f == MTUF_F_P7B) /* p7b? strip SOR */ @@ -1561,7 +1741,7 @@ if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; if (sbc == 0) /* nothing to do? */ return MTSE_OK; -if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* set pos */ +if (sim_tape_seek (uptr, uptr->pos)) /* set pos */ return MTSE_IOERR; switch (f) { /* case on format */ @@ -1619,7 +1799,7 @@ size_t rdcnt; t_bool replacing_record; memset (&awshdr, 0, sizeof (t_awshdr)); -if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* set pos */ +if (sim_tape_seek (uptr, uptr->pos)) /* set pos */ return MTSE_IOERR; rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ @@ -1632,7 +1812,7 @@ if ((!sim_tape_bot (uptr)) && MT_SET_PNU (uptr); /* pos not upd */ return MTSE_INVRL; } -if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* set pos */ +if (sim_tape_seek (uptr, uptr->pos)) /* set pos */ return MTSE_IOERR; replacing_record = (awshdr.nxtlen == (t_awslnt)bc) && (awshdr.rectyp == (bc ? AWS_REC : AWS_TMK)); awshdr.nxtlen = (t_awslnt)bc; @@ -1667,7 +1847,7 @@ if (ctx == NULL) /* if not properly attac return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; -(void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +(void)sim_tape_seek (uptr, uptr->pos); /* set pos */ (void)sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); @@ -1889,7 +2069,7 @@ else if (gap_size == 0 || format != MTUF_F_STD) /* otherwise if zero len file_size = sim_fsize (uptr->fileref); /* get the file size */ -if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* position the tape; if it fails */ +if (sim_tape_seek (uptr, uptr->pos)) { /* position the tape; if it fails */ MT_SET_PNU (uptr); /* then set position not updated */ return sim_tape_ioerr (uptr); /* and quit with I/O error status */ } @@ -1943,8 +2123,8 @@ do { else if (meta == MTR_FHGAP) { /* half gap? */ uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */ - if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */ - return sim_tape_ioerr (uptr); /* then quit with I/O error status */ + if (sim_tape_seek (uptr, uptr->pos)) /* position the tape; if it fails */ + return sim_tape_ioerr (uptr); /* then quit with I/O error status */ gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */ gap_needed = gap_needed - meta_size / 2; /* reduce requirement */ @@ -1969,8 +2149,8 @@ do { if (rec_size < gap_needed + min_rec_size) { /* rec too small? */ uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */ - if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */ - return sim_tape_ioerr (uptr); /* then quit with I/O error status */ + if (sim_tape_seek (uptr, uptr->pos)) /* position the tape; if it fails */ + return sim_tape_ioerr (uptr); /* then quit with I/O error status */ gap_alloc = gap_alloc + rec_size; /* allocate record */ gap_needed = gap_needed - rec_size; /* reduce requirement */ @@ -2095,7 +2275,7 @@ if (gap_size == meta_size) { /* if the request is for else /* otherwise */ uptr->pos -= meta_size; /* back up the file pointer */ - if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */ + if (sim_tape_seek (uptr, uptr->pos)) /* position the tape; if it fails */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */ (void)sim_fread (&metadatum, meta_size, 1, uptr->fileref);/* read a metadatum */ @@ -2104,7 +2284,7 @@ if (gap_size == meta_size) { /* if the request is for return sim_tape_ioerr (uptr); /* then report the error and quit */ else if (metadatum == MTR_TMK) /* otherwise if a tape mark is present */ - if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* then reposition the tape; if it fails */ + if (sim_tape_seek (uptr, uptr->pos)) /* then reposition the tape; if it fails */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */ else { /* otherwise */ @@ -2665,8 +2845,9 @@ if (uptr->flags & UNIT_ATT) { sim_debug_unit (ctx->dbit, uptr, "sim_tape_rewind(unit=%d)\n", (int)(uptr-ctx->dptr->units)); } uptr->pos = 0; -if (uptr->flags & UNIT_ATT) - (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); +if (uptr->flags & UNIT_ATT) { + (void)sim_tape_seek (uptr, uptr->pos); + } MT_CLR_PNU (uptr); MT_CLR_INMRK (uptr); /* Not within an AWS or TAR tapemark */ return MTSE_OK; @@ -2851,7 +3032,7 @@ recbuf = (uint8 *)malloc (65536); tape_size = (t_addr)sim_fsize (uptr->fileref); sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: tape_size: %" T_ADDR_FMT "u\n", tape_size); for (objc = 0, sizec = 0, tpos = 0;; ) { - (void)sim_fseek (uptr->fileref, tpos, SEEK_SET); + (void)sim_tape_seek (uptr, tpos); i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref); if (i == 0) /* past or at eof? */ break; @@ -3015,7 +3196,7 @@ while (r == SCPE_OK) { break; } memset (buf_f, 0, bc_f); - memset (buf_r, 0, bc_f); + memset (buf_r, 0, bc_r); if (pos_f != pos_r) { sim_printf ("Unexpected tape file position between forward and reverse record read: (%" T_ADDR_FMT "u, %" T_ADDR_FMT "u\n", pos_f, pos_r); break; @@ -3049,10 +3230,10 @@ while (r == SCPE_OK) { uptr->tape_eom = uptr->pos; if ((!stop_cpu) && ((r != MTSE_EOM) || (sim_switches & SWMASK ('V')) || (sim_switches & SWMASK ('L')) || - ((uint32)(sim_fsize_ex (uptr->fileref) - (t_offset)uptr->pos) > fmts[MT_GET_FMT (uptr)].eom_remnant) || + ((uint32)(sim_tape_size (uptr) - (t_offset)uptr->pos) > fmts[MT_GET_FMT (uptr)].eom_remnant) || (unique_record_sizes > 2 * tapemark_total))) { - remaining_data = (uint32)(sim_fsize_ex (uptr->fileref) - (t_offset)uptr->tape_eom); - sim_printf ("Tape Image '%s' scanned as %s format.\n", uptr->filename, fmts[MT_GET_FMT (uptr)].name); + remaining_data = (uint32)(sim_tape_size (uptr) - (t_offset)uptr->tape_eom); + sim_printf ("Tape Image %s'%s' scanned as %s format.\n", ((MT_GET_FMT (uptr) == MTUF_F_ANSI) ? "made from " : ""), uptr->filename, fmts[MT_GET_FMT (uptr)].name); if (r != MTSE_EOM) sim_printf ("After processing "); else @@ -3081,7 +3262,7 @@ free (buf_f); free (buf_r); free (rec_sizes); uptr->pos = saved_pos; -(void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); +(void)sim_tape_seek (uptr, uptr->pos); return SCPE_OK; } @@ -3580,3 +3761,342 @@ SIM_TEST(sim_tape_test_remove_tape_files (dptr->units, "TapeTestFile1")); return SCPE_OK; } + +const char HDR3_RMS_STREAM[] = "HDR3020002040000" + "0000000100000000" + "0000000002000000" + "0000000000000000" + "0000 "; +const char HDR3_RMS_STMLF[] = "HDR3020002050000" + "0000000100000000" + "0000000002000000" + "0000000000000000" + "0000 "; +const char HDR3_RMS_VAR[] = "HDR3005C02020000" + "0000000100000000" + "0000000000000000" + "0000000000000000" + "0000 "; +const char HDR3_RMS_FIXED[] = "HDR3020000010000" + "0000000100000000" + "0000000002000000" + "0000000000000000" + "0000 "; + +static void ansi_date (time_t datetime, char date[6]) + { + struct tm *lt; + char buf[20]; + + lt = localtime (&datetime); + sprintf (buf, "%c%02d%03d", (lt->tm_year < 100) ? ' ' : '0' + (lt->tm_year/100 - 1), + lt->tm_year % 100, + lt->tm_yday + 1); + memcpy (date, buf, 6); + } + +static void to_ansi_a (char *out, const char *in, size_t size) + { + memset (out, ' ', size); + while (size--) { + if (isupper (*in) || isdigit (*in)) + *(out++) = *in++; + else { + if (*in == '\0') + break; + if (islower (*in)) { + *(out++) = toupper (*in); + ++in; + } + else { + if (strchr ("-.$_", *in)) + *(out++) = *in++; + else + ++in; + } + } + } + } + +static void ansi_make_VOL1 (VOL1 *vol, const char *ident) + { + memset (vol, ' ', sizeof (*vol)); + memcpy (vol->type, "VOL", 3); + vol->num = '1'; + vol->standard = '3'; + to_ansi_a (vol->ident, ident, sizeof (vol->ident)); + } + +static void ansi_make_HDR1 (HDR1 *hdr1, VOL1 *vol, HDR4 *hdr4, const char *filename) + { + const char *fn; + struct stat statb; + char extra_name_used[3] = "00"; + char *fn_cpy, *c, *ext; + + stat (filename, &statb); + if (!(fn = strrchr (filename, '/')) && !(fn = strrchr (filename, '\\'))) + fn = filename; + else + ++fn; /* skip over slash or backslash */ + fn_cpy = (char *)malloc (strlen (fn) + 1); + strcpy (fn_cpy, fn); + fn = fn_cpy; + ext = strrchr (fn_cpy, '.'); + if (ext) { + while ((c = strchr (fn_cpy, '.')) != ext) + *c = '_'; /* translate extra .'s to _ */ + } + memset (hdr1, ' ', sizeof (*hdr1)); + memcpy (hdr1->type, "HDR", 3); + hdr1->num = '1'; + memset (hdr4, ' ', sizeof (*hdr1)); + memcpy (hdr4->type, "HDR", 3); + hdr4->num = '4'; + to_ansi_a (hdr1->file_ident, fn, sizeof (hdr1->file_ident)); + if (strlen (fn) > 17) { + to_ansi_a (hdr4->extra_name, fn + 17, sizeof (hdr4->extra_name)); + sprintf (extra_name_used, "%02d", (int)(strlen (fn) - 17)); + } + memcpy (hdr4->extra_name_used, extra_name_used, 2); + memcpy (hdr1->file_set, vol->ident, sizeof (hdr1->file_set)); + memcpy (hdr1->file_section, "0001", 4); + memcpy (hdr1->file_sequence, "0001", 4); + memcpy (hdr1->generation_number, "0001", 4); /* generation_number and version_number */ + memcpy (hdr1->version_number, "00", 2); /* combine to produce VMS version # ;1 here */ + ansi_date (statb.st_mtime, hdr1->creation_date); + memcpy (hdr1->expiration_date, " 00000", 6); + memcpy (hdr1->block_count, "000000", 6); + to_ansi_a (hdr1->system_code, "DECFILE11A", sizeof (hdr1->system_code)); + free (fn_cpy); + } + +static void ansi_make_HDR2 (HDR2 *hdr, t_bool fixed_record, size_t block_size, size_t record_size) + { + char size[12]; + + memset (hdr, ' ', sizeof (*hdr)); + memcpy (hdr->type, "HDR", 3); + hdr->num = '2'; + hdr->record_format = (fixed_record ? 'F' : 'D'); + sprintf (size, "%05d", (int)block_size); + memcpy (hdr->block_length, size, sizeof (hdr->block_length)); + sprintf (size, "%05d", (int)record_size); + memcpy (hdr->record_length, size, sizeof (hdr->record_length)); + memcpy (hdr->buffer_offset, "00", 2); + } + +static void ansi_fill_text_buffer (FILE *f, char *buf, size_t bufsize) + { + long start; + char *tmp = (char *)calloc (1 + bufsize, sizeof (*buf)); + size_t offset = 0; + + while (1) { + int rec_size; + + start = ftell (f); + if (!fgets (tmp, bufsize, f)) + break; + rec_size = strlen (tmp); + if ((rec_size + 4) > (int)(bufsize - offset)) { /* room for record? */ + fseek (f, start, SEEK_SET); + break; + } + sprintf (buf + offset, "%04d%*.*s", rec_size + 4, rec_size, rec_size, tmp); + offset += 4 + rec_size; + } + if (bufsize > offset) + memset (buf + offset, '^', bufsize - offset); + free (tmp); + } + +static t_bool ansi_tape_add_block (ANSI_TAPE *tape, uint8 *block, uint32 size) +{ +TAPE_RECORD *rec; + +if (tape->array_size <= tape->record_count) { + TAPE_RECORD **new_records; + new_records = (TAPE_RECORD **)realloc (tape->records, (tape->array_size + 1000) * sizeof (*tape->records)); + if (new_records == NULL) + return TRUE; /* no memory error */ + tape->records = new_records; + memset (tape->records + tape->array_size, 0, 1000 * sizeof (*tape->records)); + tape->array_size += 1000; + } +rec = (TAPE_RECORD *)malloc (sizeof (*rec) + size); +if (rec == NULL) + return TRUE; /* no memory error */ +rec->size = size; +memcpy (rec->data, block, size); +tape->records[tape->record_count++] = rec; +return FALSE; +} + +static int ansi_free_tape (void *vtape) +{ +uint32 i; +ANSI_TAPE *tape = (ANSI_TAPE *)vtape; + +for (i=0; irecord_count; i++) { + free (tape->records[i]); + tape->records[i] = NULL; + } +free (tape->records); +free (tape); +return 0; +} + +ANSI_TAPE *ansi_create_tape (const char *label, uint32 block_size) +{ +ANSI_TAPE *tape = (ANSI_TAPE *)calloc (1, sizeof (*tape)); + +tape->block_size = block_size; +ansi_make_VOL1 (&tape->vol1, label); +ansi_tape_add_block (tape, (uint8 *)&tape->vol1, sizeof (tape->vol1)); +return tape; +} + +static int ansi_classify_file_contents (FILE *f, size_t *max_record_size, t_bool *lf_line_endings, t_bool *crlf_line_endings) +{ +long pos = -1; +long last_cr = -1; +long last_lf = -1; +long line_start = 0; +int chr; +long non_print_chars = 0; +long lf_lines = 0; +long crlf_lines = 0; + +*max_record_size = 0; +*lf_line_endings = FALSE; +*crlf_line_endings = FALSE; +rewind (f); +while (EOF != (chr = fgetc (f))) { + ++pos; + if (!isprint (chr) && (!(chr == '\r')) && (!(chr == '\n'))) + ++non_print_chars; + if (chr == '\r') + last_cr = pos; + if (chr == '\n') { + long line_size; + + if (last_cr == (pos - 1)) { + ++crlf_lines; + line_size = (pos - (line_start - 2)); + } + else { + ++lf_lines; + line_size = (pos - (line_start - 1)); + } + if ((line_size + 4) > (long)(*max_record_size + 4)) + *max_record_size = line_size + 4; + line_start = pos + 1; + last_lf = pos; + } + } +rewind (f); +if (non_print_chars) + *max_record_size = 512; +else { + if ((crlf_lines > 0) && (lf_lines == 0)) { + *lf_line_endings = FALSE; + *crlf_line_endings = TRUE; + } + else { + if ((lf_lines > 0) && (crlf_lines == 0)) { + *lf_line_endings = TRUE; + *crlf_line_endings = FALSE; + } + } + } +return 0; +} + +static int ansi_add_file_to_tape (ANSI_TAPE *tape, const char *filename) +{ +FILE *f; +uint8 *block = NULL; +size_t max_record_size; +t_bool lf_line_endings; +t_bool crlf_line_endings; +char file_sequence[5]; +int block_count = 0; +char block_count_string[17]; +int error = FALSE; +HDR1 hdr1; +HDR2 hdr2; +HDR3 hdr3; +HDR4 hdr4; + +f = fopen (filename, "rb"); +if (f == NULL) { + fprintf (stderr, "Can't open: %s - %s\n", filename, strerror(errno)); + return errno; + } +ansi_classify_file_contents (f, &max_record_size, &lf_line_endings, &crlf_line_endings); +ansi_make_HDR1 (&hdr1, &tape->vol1, &hdr4, filename); +sprintf (file_sequence, "%04d", 1 + tape->file_count); +memcpy (hdr1.file_sequence, file_sequence, sizeof (hdr1.file_sequence)); +ansi_make_HDR2 (&hdr2, !lf_line_endings && !crlf_line_endings, tape->block_size, max_record_size); +if (!lf_line_endings && !crlf_line_endings) + memcpy (&hdr3, HDR3_RMS_FIXED, sizeof (hdr3)); +else { + if (lf_line_endings) + memcpy (&hdr3, HDR3_RMS_STMLF, sizeof (hdr3)); + else + memcpy (&hdr3, HDR3_RMS_STREAM, sizeof (hdr3)); + } +ansi_tape_add_block (tape, (uint8 *)&hdr1, sizeof (hdr1)); +ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2)); +ansi_tape_add_block (tape, (uint8 *)&hdr3, sizeof (hdr3)); +ansi_tape_add_block (tape, (uint8 *)&hdr4, sizeof (hdr4)); +ansi_tape_add_block (tape, NULL, 0); +rewind (f); +block = (uint8 *)malloc (tape->block_size); +while (!feof(f) && !error) { + size_t data_read = tape->block_size; + + if (lf_line_endings || crlf_line_endings) + ansi_fill_text_buffer (f, (char *)block, tape->block_size); + else + data_read = fread (block, 1, tape->block_size, f); + if (data_read > 0) + error = ansi_tape_add_block (tape, block, data_read); + if (!error) + ++block_count; + } +fclose (f); +free (block); +ansi_tape_add_block (tape, NULL, 0); +memcpy (hdr1.type, "EOF", sizeof (hdr1.type)); +memcpy (hdr2.type, "EOF", sizeof (hdr2.type)); +memcpy (hdr3.type, "EOF", sizeof (hdr3.type)); +memcpy (hdr4.type, "EOF", sizeof (hdr4.type)); +sprintf (block_count_string, "%06d", block_count); +memcpy (hdr1.block_count, block_count_string, sizeof (hdr1.block_count)); +ansi_tape_add_block (tape, (uint8 *)&hdr1, sizeof (hdr1)); +ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2)); +ansi_tape_add_block (tape, (uint8 *)&hdr3, sizeof (hdr3)); +ansi_tape_add_block (tape, (uint8 *)&hdr4, sizeof (hdr4)); +ansi_tape_add_block (tape, NULL, 0); +if (sim_switches & SWMASK ('V')) + sim_messagef (SCPE_OK, "%17.17s%62.62s\n\t%d blocks of data\n", hdr1.file_ident, hdr4.extra_name, block_count); +++tape->file_count; +return error; +} + +static void sim_tape_add_ansi_entry (const char *directory, + const char *filename, + t_offset FileSize, + const struct stat *filestat, + void *context) +{ +ANSI_TAPE *tape = (ANSI_TAPE *)context; +char FullPath[PATH_MAX + 1]; + +sprintf (FullPath, "%s%s", directory, filename); + +(void)ansi_add_file_to_tape (tape, FullPath); +} + diff --git a/sim_tape.h b/sim_tape.h index 402d2246..cbf40b94 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -102,6 +102,7 @@ typedef struct { #define MTUF_F_P7B 3 /* P7B format */ #define MTUF_F_AWS 4 /* AWS format */ #define MTUF_F_TAR 5 /* TAR format */ +#define MTUF_F_ANSI 6 /* ANSIFILES format */ #define MTUF_V_UF (MTUF_V_FMT + MTUF_W_FMT) #define MTUF_PNU (1u << MTUF_V_PNU) #define MTUF_WLK (1u << MTUF_V_WLK)