From db26349bd75f2fe796234a3206505e4a14cc661f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 14 May 2019 01:04:18 -0700 Subject: [PATCH] TAPE: Add system specific ANSI tape formats VMS, RSX, RSTS and RT11 These formats are named ANSI-VMS, ANSI-RSX11, ANSI-RSTS and ANSI-RT11 --- README.md | 2 +- doc/simh_doc.doc | Bin 270336 -> 265216 bytes doc/simh_faq.doc | Bin 109056 -> 114688 bytes sim_defs.h | 23 +-- sim_tape.c | 360 +++++++++++++++++++++++++++++++---------------- sim_tape.h | 46 +++--- 6 files changed, 274 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index a987d397..aae83009 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,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 + ANSI-VMS, ANSI-RSX11, ANSI-RSTS, ANSI-RT11 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 7f636454a72f8fa58f7867b3a94ddcdd8ffabcd9..3f11ff96ae5cc72b4319947f7d7e54077ad762f4 100644 GIT binary patch delta 36889 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 delta 21906 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 diff --git a/sim_defs.h b/sim_defs.h index b9fad196..21f0e431 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -648,14 +648,21 @@ struct UNIT { /* These flags are only set dynamically */ -#define UNIT_ATTMULT 0000001 /* Allow multiple attach commands */ -#define UNIT_TM_POLL 0000002 /* TMXR Polling unit */ -#define UNIT_NO_FIO 0000004 /* fileref is NOT a FILE * */ -#define UNIT_DISK_CHK 0000010 /* disk data debug checking (sim_disk) */ -#define UNIT_TMR_UNIT 0000020 /* Unit registered as a calibrated timer */ -#define UNIT_TAPE_MRK 0000040 /* Tape Unit AWS Tapemark */ -#define UNIT_V_DF_TAPE 7 /* Bit offset for Tape Density reservation */ -#define UNIT_S_DF_TAPE 3 /* Bits Reserved for Tape Density */ +#define UNIT_ATTMULT 0000001 /* Allow multiple attach commands */ +#define UNIT_TM_POLL 0000002 /* TMXR Polling unit */ +#define UNIT_NO_FIO 0000004 /* fileref is NOT a FILE * */ +#define UNIT_DISK_CHK 0000010 /* disk data debug checking (sim_disk) */ +#define UNIT_TMR_UNIT 0000200 /* Unit registered as a calibrated timer */ +#define UNIT_TAPE_MRK 0000400 /* Tape Unit AWS Tapemark */ +#define UNIT_TAPE_PNU 0001000 /* Tape Unit Position Not Updated */ +#define UNIT_V_DF_TAPE 10 /* Bit offset for Tape Density reservation */ +#define UNIT_S_DF_TAPE 3 /* Bits Reserved for Tape Density */ +#define UNIT_V_TAPE_FMT 13 /* Bit offset for Tape Format */ +#define UNIT_S_TAPE_FMT 3 /* Bits Reserved for Tape Format */ +#define UNIT_M_TAPE_FMT (((1 << UNIT_S_TAPE_FMT) - 1) << UNIT_V_TAPE_FMT) +#define UNIT_V_TAPE_ANSI 16 /* Bit offset for ANSI Tape Type */ +#define UNIT_S_TAPE_ANSI 4 /* Bits Reserved for ANSI Tape Type */ +#define UNIT_M_TAPE_ANSI (((1 << UNIT_S_TAPE_ANSI) - 1) << UNIT_V_TAPE_ANSI) struct BITFIELD { const char *name; /* field name */ diff --git a/sim_tape.c b/sim_tape.c index 2c1cdcfa..f29e19db 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -100,22 +100,20 @@ #include #endif -struct sim_tape_fmt { +static struct sim_tape_fmt { const char *name; /* name */ - int32 uflags; /* unit flags */ + int32 uflags; /* unit flags */ t_addr bot; /* bot test */ t_addr eom_remnant; /* potentially unprocessed data */ - }; - -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) }, - { "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) }, - { "P7B", 0, 0, 0 }, - { "AWS", 0, 0, 0 }, - { "TAR", 0, 0, 0 }, - { "ANSIFILES", 0, 0, 0 }, - { NULL, 0, 0, 0 } + } fmts[] = { + { "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", UNIT_RO, 0, 0 }, + { "ANSI", UNIT_RO, 0, 0 }, + { NULL, 0, 0, 0 } }; static const uint32 bpi [] = { /* tape density table, indexed by MT_DENS constants */ @@ -411,7 +409,9 @@ typedef struct HDR2 { /* Also EOF2, EOV2 */ char record_format; /* F(fixed)|D(variable)|S(spanned) */ char block_length[5]; /* label ident */ char record_length[5]; /* */ - char reserved_os[35]; /* */ + char reserved_os1[21]; /* */ + char carriage_control; /* A - Fortran CC, M - Record contained CC, space - CR/LF to be added */ + char reserved_os2[13]; /* */ char buffer_offset[2]; /* */ char reserved_std[28]; /* */ } HDR2; @@ -442,15 +442,68 @@ typedef struct TAPE_RECORD { } TAPE_RECORD; typedef struct ANSI_TAPE { - uint32 file_count; - uint32 record_count; - uint32 array_size; - uint32 block_size; + uint32 ansi_type; /* ANSI-VMS, ANSI-RT11, ANSI-RSTS, ANSI-RSX11 */ + uint32 file_count; /* number of labeled files */ + uint32 record_count; /* number of entries in the record array */ + uint32 array_size; /* allocated size of records array */ + uint32 block_size; /* tape block size */ TAPE_RECORD **records; VOL1 vol1; } ANSI_TAPE; -static ANSI_TAPE *ansi_create_tape (const char *label, uint32 block_size); +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 "; +const char HDR3_RMS_VARRSX[] = "HDR300000A020000" + "0000000100000000" + "0000000000000000" + "0000000000000000" + "0000 "; +const char HDR3_RMS_FIXRSX[] = "HDR3020008010000" + "0000000100000000" + "0000000000000000" + "0000000000000000" + "0000 "; + +static struct ansi_tape_parameters { + const char *name; /* operating system */ + const char *system_code; /* */ + t_bool nohdr2; /* no HDR2 records */ + t_bool nohdr3; /* no HDR2 records */ + t_bool fixed_text; /* */ + char vol1_standard; /* 3 or 4 */ + const char *hdr3_fixed; /* HDR3 template for Fixed format files */ + const char *hdr3_lf_line_endings; /* HDR3 template for text with LF line ending files */ + const char *hdr3_crlf_line_endings;/* HDR3 template for text with CRLF line ending files */ + int skip_lf_line_endings; + int skip_crlf_line_endings; + } ansi_args[] = { /* code nohdr2 nohdr3 fixed_text lvl hdr3 fir fuxed hdr3 fir lf hdr3 for crlf */ + {"ANSI-VMS" , "DECFILE11A", FALSE, FALSE, FALSE, '3', HDR3_RMS_FIXED, HDR3_RMS_STMLF, HDR3_RMS_STREAM, 0, 0}, + {"ANSI-RSX11" , "DECFILE11A", FALSE, FALSE, FALSE, '4', HDR3_RMS_FIXRSX, HDR3_RMS_VARRSX, HDR3_RMS_VARRSX, 1, 2}, + {"ANSI-RT11" , "DECRT11A", TRUE, TRUE, TRUE, '3', NULL, NULL, NULL, 0, 0}, + {"ANSI-RSTS" , "DECRSTS/E", FALSE, TRUE, TRUE, '3', NULL, NULL, NULL, 0, 0}, + {NULL} + }; + + +static ANSI_TAPE *ansi_create_tape (const char *label, uint32 block_size, uint32 ansi_type); static int ansi_free_tape (void *vtape); static void sim_tape_add_ansi_entry (const char *directory, const char *filename, @@ -532,7 +585,7 @@ sim_tape_clr_async (uptr); if (sim_asynch_enabled) sim_tape_set_async (uptr, ctx->asynch_io_latency); #endif -if (MT_GET_FMT (uptr) != MTUF_F_ANSI) +if (MT_GET_FMT (uptr) < MTUF_F_ANSI) fflush (uptr->fileref); } @@ -553,6 +606,7 @@ struct tape_context *ctx; uint32 objc; DEVICE *dptr; char gbuf[CBUFSIZE]; +uint32 recsize = 0; t_stat r; t_bool auto_format = FALSE; t_bool had_debug = (sim_deb != NULL); @@ -564,37 +618,43 @@ if ((dptr = find_dev_from_unit (uptr)) == NULL) if (sim_switches & SWMASK ('F')) { /* format spec? */ cptr = get_glyph (cptr, gbuf, 0); /* get spec */ if (*cptr == 0) /* must be more */ - return sim_messagef (SCPE_2FARG, "Missing Format specifier and filename to attach\n"); + return sim_messagef (SCPE_2FARG, "Missing Format specifier and/or filename to attach\n"); if (sim_tape_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK) return sim_messagef (SCPE_ARG, "Invalid Tape Format: %s\n", gbuf); sim_switches = sim_switches & ~(SWMASK ('F')); /* Record Format specifier already processed */ auto_format = TRUE; } -if (MT_GET_FMT (uptr) == MTUF_F_TAR) { - if (sim_switches & SWMASK ('B')) { /* Record Size (blocking factor)? */ - uint32 recsize; - - cptr = get_glyph (cptr, gbuf, 0); /* get spec */ - if (*cptr == 0) /* must be more */ - return sim_messagef (SCPE_2FARG, "Missing Record Size and filename to attach\n"); - recsize = (uint32) get_uint (gbuf, 10, 65536, &r); - if ((r != SCPE_OK) || (recsize == 0)) - return sim_messagef (SCPE_ARG, "Invalid Tape Record Size: %s\n", gbuf); - uptr->recsize = recsize; - sim_switches = sim_switches & ~(SWMASK ('B')); /* Record Blocking Factor */ - } - if (uptr->recsize == 0) - uptr->recsize = TAR_DFLT_RECSIZE; +if (sim_switches & SWMASK ('B')) { /* Record Size (blocking factor)? */ + cptr = get_glyph (cptr, gbuf, 0); /* get spec */ + if (*cptr == 0) /* must be more */ + return sim_messagef (SCPE_2FARG, "Missing Record Size and filename to attach\n"); + recsize = (uint32) get_uint (gbuf, 10, 65536, &r); + if ((r != SCPE_OK) || (recsize == 0)) + return sim_messagef (SCPE_ARG, "Invalid Tape Record Size: %s\n", gbuf); + uptr->recsize = recsize; + sim_switches = sim_switches & ~(SWMASK ('B')); /* Record Blocking Factor */ } if ((MT_GET_FMT (uptr) == MTUF_F_TPC) || (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 */ + sim_switches |= SWMASK ('R'); /* Force ReadOnly attach for TPC, TAR and ANSI tapes */ if (MT_GET_FMT (uptr) == MTUF_F_ANSI) { const char *ocptr = cptr; char label[CBUFSIZE] = "simh"; + ANSI_TAPE *tape; - uptr->fileref = (FILE *)ansi_create_tape (label, 2048); + if ((MT_GET_ANSI_TYP (uptr) == MTAT_F_RT11) || + (MT_GET_ANSI_TYP (uptr) == MTAT_F_RSX11) || + (MT_GET_ANSI_TYP (uptr) == MTAT_F_RSTS)) + uptr->recsize = 512; + if (uptr->recsize == 0) + uptr->recsize = 2048; + else { + if ((uptr->recsize < 512) || (uptr->recsize % 512)) + return sim_messagef (SCPE_ARG, "Block size of %u is below or not a multiple of the required minimum ANSI size of 512.\n", uptr->recsize); + } + tape = ansi_create_tape (label, uptr->recsize, MT_GET_ANSI_TYP (uptr)); + uptr->fileref = (FILE *)tape; if (!uptr->fileref) return SCPE_MEM; while (*cptr != 0) { /* do all mods */ @@ -603,7 +663,7 @@ if (MT_GET_FMT (uptr) == MTUF_F_ANSI) { } if (((ANSI_TAPE *)uptr->fileref)->file_count > 0) { r = SCPE_OK; - ansi_tape_add_block ((ANSI_TAPE *)uptr->fileref, NULL, 0); + ansi_tape_add_block ((ANSI_TAPE *)uptr->fileref, NULL, 0); /* Tape Mark */ uptr->flags |= UNIT_ATT; uptr->filename = (char *)malloc (strlen (ocptr) + 1); strcpy (uptr->filename, ocptr); @@ -757,9 +817,10 @@ 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, 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, " is SIMH, alternatives are E11, TPC, P7B, AWS, TAR, ANSI-VMS,\n"); +fprintf (st, " ANSI-RT11, ANSI-RSX11 or ANSI-RSTS)\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"); fprintf (st, " The default TAR record size is 10240.\n"); fprintf (st, " -V Display some summary information about the record structure\n"); @@ -769,12 +830,15 @@ 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\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, "Notes: ANSI-VMS, ANSI-RT11, ANSI-RSTS, ANSI-RSX11 formats allows one or several\n"); +fprintf (st, " files to be presented to as a read only ANSI Level 3 labeled tape with\n"); +fprintf (st, " file labels that make each individual file accessible directly as files\n"); +fprintf (st, " 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); +fprintf (st, " sim> ATTACH -F %s ANSI-VMS Hobbyist-USE-ONLY-VA.TXT\n\n", dptr->name); +fprintf (st, " sim> ATTACH -F %s ANSI-RSX11 *.TXT,*.ini,*.exe\n", dptr->name); +fprintf (st, " sim> ATTACH -F %s ANSI-RSTS *.TXT,*.SAV\n", dptr->name); +fprintf (st, " sim> ATTACH -F %s ANSI-RT11 *.TXT,*.TSK\n", dptr->name); return SCPE_OK; } @@ -790,14 +854,14 @@ if (sim_deb && ((uptr->dctrl | ctx->dptr->dctrl) & reason)) static int sim_tape_seek (UNIT *uptr, t_addr pos) { -if (MT_GET_FMT (uptr) != MTUF_F_ANSI) +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) +if (MT_GET_FMT (uptr) < MTUF_F_ANSI) return sim_fsize_ex (uptr->fileref); return uptr->tape_eom; } @@ -1524,7 +1588,7 @@ else switch (f) { /* otherwise the read me } break; - case MTUF_F_ANSI: + case MTUF_F_ANSI: if (1) { ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref; @@ -1603,7 +1667,7 @@ if (rbc > max) { /* rec out of range? */ uptr->pos = opos; return MTSE_INVRL; } -if (f != MTUF_F_ANSI) { +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); @@ -1676,7 +1740,7 @@ if (st != MTSE_OK) { *bc = rbc = MTR_L (tbc); /* strip error flag */ if (rbc > max) /* rec out of range? */ return MTSE_INVRL; -if (f != MTUF_F_ANSI) { +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); @@ -2989,14 +3053,27 @@ if (uptr->flags & UNIT_ATT) return SCPE_ALATT; if (cptr == NULL) return SCPE_ARG; -for (f = 0; f < MTUF_N_FMT; f++) { - if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) { - uptr->flags = (uptr->flags & ~MTUF_FMT) | - (f << MTUF_V_FMT) | fmts[f].uflags; +for (f = 0; fmts[f].name; f++) { + if (MATCH_CMD(fmts[f].name, cptr) == 0) { + uint32 a = 0; + + if (f == MTUF_F_ANSI) { + for (a = 0; ansi_args[a].name; a++) + if (MATCH_CMD(ansi_args[a].name, cptr) == 0) + break; + if (ansi_args[a].name == NULL) + return sim_messagef (SCPE_ARG, "Unknown ANSI tape format: %s\n", cptr); + } + uptr->flags &= ~UNIT_RO; + uptr->flags |= fmts[f].uflags; + uptr->dynflags &= ~UNIT_M_TAPE_FMT; + uptr->dynflags |= (f << UNIT_V_TAPE_FMT); + uptr->dynflags &= ~UNIT_M_TAPE_ANSI; + uptr->dynflags |= (a << UNIT_V_TAPE_ANSI); return SCPE_OK; } } -return SCPE_ARG; +return sim_messagef (SCPE_ARG, "Unknown tape format: %s\n", cptr); } /* Show tape format */ @@ -3005,9 +3082,10 @@ t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { int32 f = MT_GET_FMT (uptr); -if (fmts[f].name) +if (f == MTUF_F_ANSI) + fprintf (st, "%s format", ansi_args[MT_GET_ANSI_TYP (uptr)].name); +else fprintf (st, "%s format", fmts[f].name); -else fprintf (st, "invalid format"); return SCPE_OK; } @@ -3233,7 +3311,7 @@ if ((!stop_cpu) && ((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_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); + sim_printf ("Tape Image %s'%s' scanned as %s format.\n", ((MT_GET_FMT (uptr) == MTUF_F_ANSI) ? "made from " : ""), uptr->filename, (MT_GET_FMT (uptr) == MTUF_F_ANSI) ? ansi_args[MT_GET_ANSI_TYP (uptr)].name : fmts[MT_GET_FMT (uptr)].name); if (r != MTSE_EOM) sim_printf ("After processing "); else @@ -3762,27 +3840,6 @@ 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; @@ -3795,6 +3852,11 @@ static void ansi_date (time_t datetime, char date[6]) memcpy (date, buf, 6); } +/* + * This isn't quite ANSI 'a' since several ANSI allowed characters + * are either illegal file names on many DEC systems or are confusing + * to OS file name parsers. + */ static void to_ansi_a (char *out, const char *in, size_t size) { memset (out, ' ', size); @@ -3809,7 +3871,7 @@ static void to_ansi_a (char *out, const char *in, size_t size) ++in; } else { - if (strchr ("-.$_", *in)) + if (strchr ("-.$_/", *in)) *(out++) = *in++; else ++in; @@ -3818,16 +3880,16 @@ static void to_ansi_a (char *out, const char *in, size_t size) } } -static void ansi_make_VOL1 (VOL1 *vol, const char *ident) +static void ansi_make_VOL1 (VOL1 *vol, const char *ident, uint32 ansi_type) { memset (vol, ' ', sizeof (*vol)); memcpy (vol->type, "VOL", 3); vol->num = '1'; - vol->standard = '3'; to_ansi_a (vol->ident, ident, sizeof (vol->ident)); + vol->standard = ansi_args[ansi_type].vol1_standard; } -static void ansi_make_HDR1 (HDR1 *hdr1, VOL1 *vol, HDR4 *hdr4, const char *filename) +static void ansi_make_HDR1 (HDR1 *hdr1, VOL1 *vol, HDR4 *hdr4, const char *filename, uint32 ansi_type) { const char *fn; struct stat statb; @@ -3867,11 +3929,11 @@ static void ansi_make_HDR1 (HDR1 *hdr1, VOL1 *vol, HDR4 *hdr4, const char *filen 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)); + to_ansi_a (hdr1->system_code, ansi_args[ansi_type].system_code, 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) +static void ansi_make_HDR2 (HDR2 *hdr, t_bool fixed_record, size_t block_size, size_t record_size, uint32 ansi_type) { char size[12]; @@ -3883,31 +3945,68 @@ static void ansi_make_HDR2 (HDR2 *hdr, t_bool fixed_record, size_t block_size, s memcpy (hdr->block_length, size, sizeof (hdr->block_length)); sprintf (size, "%05d", (int)record_size); memcpy (hdr->record_length, size, sizeof (hdr->record_length)); + hdr->carriage_control = fixed_record ? 'M' : ' '; memcpy (hdr->buffer_offset, "00", 2); + if (ansi_type == MTAT_F_RSTS) { + hdr->record_format = 'U'; + memcpy (hdr->record_length, "00000", sizeof (hdr->record_length)); + hdr->carriage_control = 'M'; + } } -static void ansi_fill_text_buffer (FILE *f, char *buf, size_t bufsize) +static void ansi_fill_text_buffer (FILE *f, char *buf, size_t buf_size, size_t record_skip_ending, t_bool fixed_text) { long start; - char *tmp = (char *)calloc (1 + bufsize, sizeof (*buf)); + char *tmp = (char *)calloc (2 + buf_size, sizeof (*buf)); size_t offset = 0; while (1) { - int rec_size; + size_t rec_size; + char rec_size_str[16]; start = ftell (f); - if (!fgets (tmp, bufsize, f)) + if (!fgets (tmp, buf_size, f)) break; rec_size = strlen (tmp); - if ((rec_size + 4) > (int)(bufsize - offset)) { /* room for record? */ - fseek (f, start, SEEK_SET); - break; + if (!fixed_text) { + if (rec_size >= record_skip_ending) + rec_size -= record_skip_ending; + if ((rec_size + 4) > (int)(buf_size - offset)) { /* room for record? */ + fseek (f, start, SEEK_SET); + break; + } + sprintf (rec_size_str, "%04u", (int)(rec_size + 4)); + memcpy (buf + offset, rec_size_str, 4); + memcpy (buf + offset + 4, tmp, rec_size); + offset += 4 + rec_size; + } + else { + size_t move_size; + + if ((tmp[rec_size - 2] != '\r') && + (tmp[rec_size - 1] == '\n')) { + memcpy (&tmp[rec_size - 1], "\r\n", 3); + rec_size += 1; + } + if (offset + rec_size < buf_size) + move_size = rec_size; + else + move_size = buf_size - offset; + /* We've got a line that stradles a block boundary */ + memcpy (buf + offset, tmp, move_size); + offset += move_size; + if (offset == buf_size) { + fseek (f, start + move_size, 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); + if (buf_size > offset) { + if (fixed_text) + memset (buf + offset, 0, buf_size - offset); + else + memset (buf + offset, '^', buf_size - offset); + } free (tmp); } @@ -3947,12 +4046,15 @@ free (tape); return 0; } -ANSI_TAPE *ansi_create_tape (const char *label, uint32 block_size) +ANSI_TAPE *ansi_create_tape (const char *label, uint32 block_size, uint32 ansi_type) { ANSI_TAPE *tape = (ANSI_TAPE *)calloc (1, sizeof (*tape)); +if (NULL == tape) + return tape; tape->block_size = block_size; -ansi_make_VOL1 (&tape->vol1, label); +tape->ansi_type = ansi_type; +ansi_make_VOL1 (&tape->vol1, label, ansi_type); ansi_tape_add_block (tape, (uint8 *)&tape->vol1, sizeof (tape->vol1)); return tape; } @@ -3974,7 +4076,7 @@ long crlf_lines = 0; rewind (f); while (EOF != (chr = fgetc (f))) { ++pos; - if (!isprint (chr) && (!(chr == '\r')) && (!(chr == '\n'))) + if (!isprint (chr) && (!(chr == '\r')) && (!(chr == '\n')) && (!(chr == '\t'))) ++non_print_chars; if (chr == '\r') last_cr = pos; @@ -4016,6 +4118,7 @@ return 0; static int ansi_add_file_to_tape (ANSI_TAPE *tape, const char *filename) { FILE *f; +struct ansi_tape_parameters *ansi = &ansi_args[tape->ansi_type]; uint8 *block = NULL; size_t max_record_size; t_bool lf_line_endings; @@ -4035,30 +4138,40 @@ if (f == NULL) { return errno; } ansi_classify_file_contents (f, &max_record_size, &lf_line_endings, &crlf_line_endings); -ansi_make_HDR1 (&hdr1, &tape->vol1, &hdr4, filename); +ansi_make_HDR1 (&hdr1, &tape->vol1, &hdr4, filename, tape->ansi_type); 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)); +if (ansi->fixed_text) + max_record_size = 512; +ansi_make_HDR2 (&hdr2, !lf_line_endings && !crlf_line_endings, tape->block_size, (tape->ansi_type > MTUF_F_ANSI) ? 512 : max_record_size, tape->ansi_type); + +if (!ansi->nohdr3) { /* Need HDR3? */ + if (!lf_line_endings && !crlf_line_endings) /* Binary File? */ + memcpy (&hdr3, ansi->hdr3_fixed, sizeof (hdr3)); + else { /* Text file */ + if ((lf_line_endings) && !(ansi->fixed_text)) + memcpy (&hdr3, ansi->hdr3_lf_line_endings, sizeof (hdr3)); + else + memcpy (&hdr3, ansi->hdr3_crlf_line_endings, 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); +if (!ansi->nohdr2) + ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2)); +if (!ansi->nohdr3) + ansi_tape_add_block (tape, (uint8 *)&hdr3, sizeof (hdr3)); +if ((0 != memcmp (hdr4.extra_name_used, "00", 2)) && !ansi->nohdr3 && !ansi->nohdr2) + ansi_tape_add_block (tape, (uint8 *)&hdr4, sizeof (hdr4)); +ansi_tape_add_block (tape, NULL, 0); /* Tape Mark */ rewind (f); -block = (uint8 *)malloc (tape->block_size); +block = (uint8 *)calloc (tape->block_size, 1); 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); + if (lf_line_endings || crlf_line_endings) /* text file? */ + ansi_fill_text_buffer (f, (char *)block, tape->block_size, + crlf_line_endings ? ansi->skip_crlf_line_endings : ansi->skip_lf_line_endings, + ansi->fixed_text); else data_read = fread (block, 1, tape->block_size, f); if (data_read > 0) @@ -4068,7 +4181,7 @@ while (!feof(f) && !error) { } fclose (f); free (block); -ansi_tape_add_block (tape, NULL, 0); +ansi_tape_add_block (tape, NULL, 0); /* Tape Mark */ memcpy (hdr1.type, "EOF", sizeof (hdr1.type)); memcpy (hdr2.type, "EOF", sizeof (hdr2.type)); memcpy (hdr3.type, "EOF", sizeof (hdr3.type)); @@ -4076,10 +4189,13 @@ 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 (!ansi->nohdr2) + ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2)); +if (!ansi->nohdr3) + ansi_tape_add_block (tape, (uint8 *)&hdr3, sizeof (hdr3)); +if ((0 != memcmp (hdr4.extra_name_used, "00", 2)) && !ansi->nohdr3 && !ansi->nohdr2) + ansi_tape_add_block (tape, (uint8 *)&hdr4, sizeof (hdr4)); +ansi_tape_add_block (tape, NULL, 0); /* Tape Mark */ 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; diff --git a/sim_tape.h b/sim_tape.h index cbf40b94..4ea87292 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -90,39 +90,33 @@ typedef struct { /* Unit flags */ -#define MTUF_V_PNU (UNIT_V_UF + 0) /* position not upd */ -#define MTUF_V_WLK (UNIT_V_UF + 1) /* write locked */ +#define MTUF_V_WLK (UNIT_V_UF + 0) /* write locked */ #define MTUF_V_FMT (UNIT_V_UF + 2) /* tape file format */ -#define MTUF_W_FMT 3 /* 3b of formats */ -#define MTUF_N_FMT (1u << MTUF_W_FMT) /* number of formats */ -#define MTUF_M_FMT ((1u << MTUF_W_FMT) - 1) -#define MTUF_F_STD 0 /* SIMH format */ -#define MTUF_F_E11 1 /* E11 format */ -#define MTUF_F_TPC 2 /* TPC format */ -#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_F_STD 0 /* SIMH format */ +#define MTUF_F_E11 1 /* E11 format */ +#define MTUF_F_TPC 2 /* TPC format */ +#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 /* ANSI format */ + +#define MTAT_F_VMS 0 /* VMS ANSI type */ +#define MTAT_F_RSX11 1 /* RSX-11 ANSI type */ +#define MTAT_F_RSTS 2 /* RSTS ANSI type */ +#define MTAT_F_RT11 3 /* RT-11 ANSI type */ + +#define MTUF_V_UF (MTUF_V_WLK + 1) #define MTUF_WLK (1u << MTUF_V_WLK) -#define MTUF_FMT (MTUF_M_FMT << MTUF_V_FMT) #define MTUF_WRP (MTUF_WLK | UNIT_RO) -#define MT_F_STD (MTUF_F_STD << MTUF_V_FMT) -#define MT_F_E11 (MTUF_F_E11 << MTUF_V_FMT) -#define MT_F_TPC (MTUF_F_TPC << MTUF_V_FMT) -#define MT_F_P7B (MTUF_F_P7B << MTUF_V_FMT) -#define MT_F_AWS (MTUF_F_AWS << MTUF_V_FMT) -#define MT_F_TAR (MTUF_F_TAR << MTUF_V_FMT) - -#define MT_SET_PNU(u) (u)->flags = (u)->flags | MTUF_PNU -#define MT_CLR_PNU(u) (u)->flags = (u)->flags & ~MTUF_PNU -#define MT_TST_PNU(u) ((u)->flags & MTUF_PNU) +#define MT_SET_PNU(u) (u)->dynflags |= UNIT_TAPE_PNU +#define MT_CLR_PNU(u) (u)->dynflags &= ~UNIT_TAPE_PNU +#define MT_TST_PNU(u) ((u)->dynflags & UNIT_TAPE_PNU) #define MT_SET_INMRK(u) (u)->dynflags = (u)->dynflags | UNIT_TAPE_MRK #define MT_CLR_INMRK(u) (u)->dynflags = (u)->dynflags & ~UNIT_TAPE_MRK #define MT_TST_INMRK(u) ((u)->dynflags & UNIT_TAPE_MRK) -#define MT_GET_FMT(u) (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT) +#define MT_GET_FMT(u) (((u)->dynflags >> UNIT_V_TAPE_FMT) & ((1 << UNIT_S_TAPE_FMT) - 1)) +#define MT_GET_ANSI_TYP(u) (((u)->dynflags >> UNIT_V_TAPE_ANSI) & ((1 << UNIT_S_TAPE_ANSI) - 1)) /* sim_tape_position Position Flags */ #define MTPOS_V_REW 3