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
This commit is contained in:
Mark Pizzolato 2019-05-14 01:04:18 -07:00
parent c9b0e2b00f
commit db26349bd7
6 changed files with 274 additions and 157 deletions

View file

@ -231,7 +231,7 @@ Host platforms which have libSDL available can leverage this functionality.
#### Tape Extensions #### Tape Extensions
AWS format tape support AWS format tape support
TAR 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 #### Embedded ROM support
Simulators which have boot commands which load constant files as part of Simulators which have boot commands which load constant files as part of

Binary file not shown.

Binary file not shown.

View file

@ -648,14 +648,21 @@ struct UNIT {
/* These flags are only set dynamically */ /* These flags are only set dynamically */
#define UNIT_ATTMULT 0000001 /* Allow multiple attach commands */ #define UNIT_ATTMULT 0000001 /* Allow multiple attach commands */
#define UNIT_TM_POLL 0000002 /* TMXR Polling unit */ #define UNIT_TM_POLL 0000002 /* TMXR Polling unit */
#define UNIT_NO_FIO 0000004 /* fileref is NOT a FILE * */ #define UNIT_NO_FIO 0000004 /* fileref is NOT a FILE * */
#define UNIT_DISK_CHK 0000010 /* disk data debug checking (sim_disk) */ #define UNIT_DISK_CHK 0000010 /* disk data debug checking (sim_disk) */
#define UNIT_TMR_UNIT 0000020 /* Unit registered as a calibrated timer */ #define UNIT_TMR_UNIT 0000200 /* Unit registered as a calibrated timer */
#define UNIT_TAPE_MRK 0000040 /* Tape Unit AWS Tapemark */ #define UNIT_TAPE_MRK 0000400 /* Tape Unit AWS Tapemark */
#define UNIT_V_DF_TAPE 7 /* Bit offset for Tape Density reservation */ #define UNIT_TAPE_PNU 0001000 /* Tape Unit Position Not Updated */
#define UNIT_S_DF_TAPE 3 /* Bits Reserved for Tape Density */ #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 { struct BITFIELD {
const char *name; /* field name */ const char *name; /* field name */

View file

@ -100,22 +100,20 @@
#include <pthread.h> #include <pthread.h>
#endif #endif
struct sim_tape_fmt { static struct sim_tape_fmt {
const char *name; /* name */ const char *name; /* name */
int32 uflags; /* unit flags */ int32 uflags; /* unit flags */
t_addr bot; /* bot test */ t_addr bot; /* bot test */
t_addr eom_remnant; /* potentially unprocessed data */ t_addr eom_remnant; /* potentially unprocessed data */
}; } fmts[] = {
{ "SIMH", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) },
static struct sim_tape_fmt fmts[MTUF_N_FMT] = { { "E11", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) },
{ "SIMH", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) }, { "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) },
{ "E11", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) }, { "P7B", 0, 0, 0 },
{ "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) }, { "AWS", 0, 0, 0 },
{ "P7B", 0, 0, 0 }, { "TAR", UNIT_RO, 0, 0 },
{ "AWS", 0, 0, 0 }, { "ANSI", UNIT_RO, 0, 0 },
{ "TAR", 0, 0, 0 }, { NULL, 0, 0, 0 }
{ "ANSIFILES", 0, 0, 0 },
{ NULL, 0, 0, 0 }
}; };
static const uint32 bpi [] = { /* tape density table, indexed by MT_DENS constants */ 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 record_format; /* F(fixed)|D(variable)|S(spanned) */
char block_length[5]; /* label ident */ char block_length[5]; /* label ident */
char record_length[5]; /* */ 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 buffer_offset[2]; /* */
char reserved_std[28]; /* */ char reserved_std[28]; /* */
} HDR2; } HDR2;
@ -442,15 +442,68 @@ typedef struct TAPE_RECORD {
} TAPE_RECORD; } TAPE_RECORD;
typedef struct ANSI_TAPE { typedef struct ANSI_TAPE {
uint32 file_count; uint32 ansi_type; /* ANSI-VMS, ANSI-RT11, ANSI-RSTS, ANSI-RSX11 */
uint32 record_count; uint32 file_count; /* number of labeled files */
uint32 array_size; uint32 record_count; /* number of entries in the record array */
uint32 block_size; uint32 array_size; /* allocated size of records array */
uint32 block_size; /* tape block size */
TAPE_RECORD **records; TAPE_RECORD **records;
VOL1 vol1; VOL1 vol1;
} ANSI_TAPE; } 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 int ansi_free_tape (void *vtape);
static void sim_tape_add_ansi_entry (const char *directory, static void sim_tape_add_ansi_entry (const char *directory,
const char *filename, const char *filename,
@ -532,7 +585,7 @@ sim_tape_clr_async (uptr);
if (sim_asynch_enabled) if (sim_asynch_enabled)
sim_tape_set_async (uptr, ctx->asynch_io_latency); sim_tape_set_async (uptr, ctx->asynch_io_latency);
#endif #endif
if (MT_GET_FMT (uptr) != MTUF_F_ANSI) if (MT_GET_FMT (uptr) < MTUF_F_ANSI)
fflush (uptr->fileref); fflush (uptr->fileref);
} }
@ -553,6 +606,7 @@ struct tape_context *ctx;
uint32 objc; uint32 objc;
DEVICE *dptr; DEVICE *dptr;
char gbuf[CBUFSIZE]; char gbuf[CBUFSIZE];
uint32 recsize = 0;
t_stat r; t_stat r;
t_bool auto_format = FALSE; t_bool auto_format = FALSE;
t_bool had_debug = (sim_deb != NULL); 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? */ if (sim_switches & SWMASK ('F')) { /* format spec? */
cptr = get_glyph (cptr, gbuf, 0); /* get spec */ cptr = get_glyph (cptr, gbuf, 0); /* get spec */
if (*cptr == 0) /* must be more */ 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) if (sim_tape_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
return sim_messagef (SCPE_ARG, "Invalid Tape Format: %s\n", gbuf); return sim_messagef (SCPE_ARG, "Invalid Tape Format: %s\n", gbuf);
sim_switches = sim_switches & ~(SWMASK ('F')); /* Record Format specifier already processed */ sim_switches = sim_switches & ~(SWMASK ('F')); /* Record Format specifier already processed */
auto_format = TRUE; auto_format = TRUE;
} }
if (MT_GET_FMT (uptr) == MTUF_F_TAR) { if (sim_switches & SWMASK ('B')) { /* Record Size (blocking factor)? */
if (sim_switches & SWMASK ('B')) { /* Record Size (blocking factor)? */ cptr = get_glyph (cptr, gbuf, 0); /* get spec */
uint32 recsize; if (*cptr == 0) /* must be more */
return sim_messagef (SCPE_2FARG, "Missing Record Size and filename to attach\n");
cptr = get_glyph (cptr, gbuf, 0); /* get spec */ recsize = (uint32) get_uint (gbuf, 10, 65536, &r);
if (*cptr == 0) /* must be more */ if ((r != SCPE_OK) || (recsize == 0))
return sim_messagef (SCPE_2FARG, "Missing Record Size and filename to attach\n"); return sim_messagef (SCPE_ARG, "Invalid Tape Record Size: %s\n", gbuf);
recsize = (uint32) get_uint (gbuf, 10, 65536, &r); uptr->recsize = recsize;
if ((r != SCPE_OK) || (recsize == 0)) sim_switches = sim_switches & ~(SWMASK ('B')); /* Record Blocking Factor */
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 ((MT_GET_FMT (uptr) == MTUF_F_TPC) || if ((MT_GET_FMT (uptr) == MTUF_F_TPC) ||
(MT_GET_FMT (uptr) == MTUF_F_TAR) || (MT_GET_FMT (uptr) == MTUF_F_TAR) ||
(MT_GET_FMT (uptr) == MTUF_F_ANSI)) (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) { if (MT_GET_FMT (uptr) == MTUF_F_ANSI) {
const char *ocptr = cptr; const char *ocptr = cptr;
char label[CBUFSIZE] = "simh"; 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) if (!uptr->fileref)
return SCPE_MEM; return SCPE_MEM;
while (*cptr != 0) { /* do all mods */ 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) { if (((ANSI_TAPE *)uptr->fileref)->file_count > 0) {
r = SCPE_OK; 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->flags |= UNIT_ATT;
uptr->filename = (char *)malloc (strlen (ocptr) + 1); uptr->filename = (char *)malloc (strlen (ocptr) + 1);
strcpy (uptr->filename, ocptr); 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, " -E Must Exist (if not specified an attempt to create the indicated\n");
fprintf (st, " virtual tape will be attempted).\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, " -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, " is SIMH, alternatives are E11, TPC, P7B, AWS, TAR, ANSI-VMS,\n");
fprintf (st, " -B For TAR format tapes, the record size for data read from the\n"); fprintf (st, " ANSI-RT11, ANSI-RSX11 or ANSI-RSTS)\n");
fprintf (st, " specified file. This record size will be used for all but\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, " possibly the last record which will be what remains unread.\n");
fprintf (st, " The default TAR record size is 10240.\n"); fprintf (st, " The default TAR record size is 10240.\n");
fprintf (st, " -V Display some summary information about the record structure\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, " 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, " -D Causes the internal tape structure information to be displayed\n");
fprintf (st, " while the tape image is scanned.\n\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, "Notes: ANSI-VMS, ANSI-RT11, ANSI-RSTS, ANSI-RSX11 formats allows one or several\n");
fprintf (st, " read only ANSI Level 3 labeled tape with file labels that make each\n"); fprintf (st, " files to be presented to as a read only ANSI Level 3 labeled tape with\n");
fprintf (st, " individual file accessible directly as files on the tape.\n\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, "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 ANSI-VMS 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-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; 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) 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 sim_fseek (uptr->fileref, pos, SEEK_SET);
return 0; return 0;
} }
static t_offset sim_tape_size (UNIT *uptr) 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 sim_fsize_ex (uptr->fileref);
return uptr->tape_eom; return uptr->tape_eom;
} }
@ -1524,7 +1588,7 @@ else switch (f) { /* otherwise the read me
} }
break; break;
case MTUF_F_ANSI: case MTUF_F_ANSI:
if (1) { if (1) {
ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref; ANSI_TAPE *tape = (ANSI_TAPE *)uptr->fileref;
@ -1603,7 +1667,7 @@ if (rbc > max) { /* rec out of range? */
uptr->pos = opos; uptr->pos = opos;
return MTSE_INVRL; 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 */ i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
if (ferror (uptr->fileref)) { /* error? */ if (ferror (uptr->fileref)) { /* error? */
MT_SET_PNU (uptr); MT_SET_PNU (uptr);
@ -1676,7 +1740,7 @@ if (st != MTSE_OK) {
*bc = rbc = MTR_L (tbc); /* strip error flag */ *bc = rbc = MTR_L (tbc); /* strip error flag */
if (rbc > max) /* rec out of range? */ if (rbc > max) /* rec out of range? */
return MTSE_INVRL; 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 */ i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
if (ferror (uptr->fileref)) /* error? */ if (ferror (uptr->fileref)) /* error? */
return sim_tape_ioerr (uptr); return sim_tape_ioerr (uptr);
@ -2989,14 +3053,27 @@ if (uptr->flags & UNIT_ATT)
return SCPE_ALATT; return SCPE_ALATT;
if (cptr == NULL) if (cptr == NULL)
return SCPE_ARG; return SCPE_ARG;
for (f = 0; f < MTUF_N_FMT; f++) { for (f = 0; fmts[f].name; f++) {
if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) { if (MATCH_CMD(fmts[f].name, cptr) == 0) {
uptr->flags = (uptr->flags & ~MTUF_FMT) | uint32 a = 0;
(f << MTUF_V_FMT) | fmts[f].uflags;
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_OK;
} }
} }
return SCPE_ARG; return sim_messagef (SCPE_ARG, "Unknown tape format: %s\n", cptr);
} }
/* Show tape format */ /* 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); 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); fprintf (st, "%s format", fmts[f].name);
else fprintf (st, "invalid format");
return SCPE_OK; 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) || ((uint32)(sim_tape_size (uptr) - (t_offset)uptr->pos) > fmts[MT_GET_FMT (uptr)].eom_remnant) ||
(unique_record_sizes > 2 * tapemark_total))) { (unique_record_sizes > 2 * tapemark_total))) {
remaining_data = (uint32)(sim_tape_size (uptr) - (t_offset)uptr->tape_eom); 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) if (r != MTSE_EOM)
sim_printf ("After processing "); sim_printf ("After processing ");
else else
@ -3762,27 +3840,6 @@ SIM_TEST(sim_tape_test_remove_tape_files (dptr->units, "TapeTestFile1"));
return SCPE_OK; 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]) static void ansi_date (time_t datetime, char date[6])
{ {
struct tm *lt; struct tm *lt;
@ -3795,6 +3852,11 @@ static void ansi_date (time_t datetime, char date[6])
memcpy (date, buf, 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) static void to_ansi_a (char *out, const char *in, size_t size)
{ {
memset (out, ' ', size); memset (out, ' ', size);
@ -3809,7 +3871,7 @@ static void to_ansi_a (char *out, const char *in, size_t size)
++in; ++in;
} }
else { else {
if (strchr ("-.$_", *in)) if (strchr ("-.$_/", *in))
*(out++) = *in++; *(out++) = *in++;
else else
++in; ++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)); memset (vol, ' ', sizeof (*vol));
memcpy (vol->type, "VOL", 3); memcpy (vol->type, "VOL", 3);
vol->num = '1'; vol->num = '1';
vol->standard = '3';
to_ansi_a (vol->ident, ident, sizeof (vol->ident)); 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; const char *fn;
struct stat statb; 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); ansi_date (statb.st_mtime, hdr1->creation_date);
memcpy (hdr1->expiration_date, " 00000", 6); memcpy (hdr1->expiration_date, " 00000", 6);
memcpy (hdr1->block_count, "000000", 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); 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]; 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)); memcpy (hdr->block_length, size, sizeof (hdr->block_length));
sprintf (size, "%05d", (int)record_size); sprintf (size, "%05d", (int)record_size);
memcpy (hdr->record_length, size, sizeof (hdr->record_length)); memcpy (hdr->record_length, size, sizeof (hdr->record_length));
hdr->carriage_control = fixed_record ? 'M' : ' ';
memcpy (hdr->buffer_offset, "00", 2); 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; long start;
char *tmp = (char *)calloc (1 + bufsize, sizeof (*buf)); char *tmp = (char *)calloc (2 + buf_size, sizeof (*buf));
size_t offset = 0; size_t offset = 0;
while (1) { while (1) {
int rec_size; size_t rec_size;
char rec_size_str[16];
start = ftell (f); start = ftell (f);
if (!fgets (tmp, bufsize, f)) if (!fgets (tmp, buf_size, f))
break; break;
rec_size = strlen (tmp); rec_size = strlen (tmp);
if ((rec_size + 4) > (int)(bufsize - offset)) { /* room for record? */ if (!fixed_text) {
fseek (f, start, SEEK_SET); if (rec_size >= record_skip_ending)
break; 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) if (buf_size > offset) {
memset (buf + offset, '^', bufsize - offset); if (fixed_text)
memset (buf + offset, 0, buf_size - offset);
else
memset (buf + offset, '^', buf_size - offset);
}
free (tmp); free (tmp);
} }
@ -3947,12 +4046,15 @@ free (tape);
return 0; 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)); ANSI_TAPE *tape = (ANSI_TAPE *)calloc (1, sizeof (*tape));
if (NULL == tape)
return tape;
tape->block_size = block_size; 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)); ansi_tape_add_block (tape, (uint8 *)&tape->vol1, sizeof (tape->vol1));
return tape; return tape;
} }
@ -3974,7 +4076,7 @@ long crlf_lines = 0;
rewind (f); rewind (f);
while (EOF != (chr = fgetc (f))) { while (EOF != (chr = fgetc (f))) {
++pos; ++pos;
if (!isprint (chr) && (!(chr == '\r')) && (!(chr == '\n'))) if (!isprint (chr) && (!(chr == '\r')) && (!(chr == '\n')) && (!(chr == '\t')))
++non_print_chars; ++non_print_chars;
if (chr == '\r') if (chr == '\r')
last_cr = pos; last_cr = pos;
@ -4016,6 +4118,7 @@ return 0;
static int ansi_add_file_to_tape (ANSI_TAPE *tape, const char *filename) static int ansi_add_file_to_tape (ANSI_TAPE *tape, const char *filename)
{ {
FILE *f; FILE *f;
struct ansi_tape_parameters *ansi = &ansi_args[tape->ansi_type];
uint8 *block = NULL; uint8 *block = NULL;
size_t max_record_size; size_t max_record_size;
t_bool lf_line_endings; t_bool lf_line_endings;
@ -4035,30 +4138,40 @@ if (f == NULL) {
return errno; return errno;
} }
ansi_classify_file_contents (f, &max_record_size, &lf_line_endings, &crlf_line_endings); 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); sprintf (file_sequence, "%04d", 1 + tape->file_count);
memcpy (hdr1.file_sequence, file_sequence, sizeof (hdr1.file_sequence)); 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 (ansi->fixed_text)
if (!lf_line_endings && !crlf_line_endings) max_record_size = 512;
memcpy (&hdr3, HDR3_RMS_FIXED, sizeof (hdr3)); 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);
else {
if (lf_line_endings) if (!ansi->nohdr3) { /* Need HDR3? */
memcpy (&hdr3, HDR3_RMS_STMLF, sizeof (hdr3)); if (!lf_line_endings && !crlf_line_endings) /* Binary File? */
else memcpy (&hdr3, ansi->hdr3_fixed, sizeof (hdr3));
memcpy (&hdr3, HDR3_RMS_STREAM, 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 *)&hdr1, sizeof (hdr1));
ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2)); if (!ansi->nohdr2)
ansi_tape_add_block (tape, (uint8 *)&hdr3, sizeof (hdr3)); ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2));
ansi_tape_add_block (tape, (uint8 *)&hdr4, sizeof (hdr4)); if (!ansi->nohdr3)
ansi_tape_add_block (tape, NULL, 0); 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); rewind (f);
block = (uint8 *)malloc (tape->block_size); block = (uint8 *)calloc (tape->block_size, 1);
while (!feof(f) && !error) { while (!feof(f) && !error) {
size_t data_read = tape->block_size; size_t data_read = tape->block_size;
if (lf_line_endings || crlf_line_endings) if (lf_line_endings || crlf_line_endings) /* text file? */
ansi_fill_text_buffer (f, (char *)block, tape->block_size); 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 else
data_read = fread (block, 1, tape->block_size, f); data_read = fread (block, 1, tape->block_size, f);
if (data_read > 0) if (data_read > 0)
@ -4068,7 +4181,7 @@ while (!feof(f) && !error) {
} }
fclose (f); fclose (f);
free (block); 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 (hdr1.type, "EOF", sizeof (hdr1.type));
memcpy (hdr2.type, "EOF", sizeof (hdr2.type)); memcpy (hdr2.type, "EOF", sizeof (hdr2.type));
memcpy (hdr3.type, "EOF", sizeof (hdr3.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); sprintf (block_count_string, "%06d", block_count);
memcpy (hdr1.block_count, block_count_string, sizeof (hdr1.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 *)&hdr1, sizeof (hdr1));
ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2)); if (!ansi->nohdr2)
ansi_tape_add_block (tape, (uint8 *)&hdr3, sizeof (hdr3)); ansi_tape_add_block (tape, (uint8 *)&hdr2, sizeof (hdr2));
ansi_tape_add_block (tape, (uint8 *)&hdr4, sizeof (hdr4)); if (!ansi->nohdr3)
ansi_tape_add_block (tape, NULL, 0); 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')) 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); 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; ++tape->file_count;

View file

@ -90,39 +90,33 @@ typedef struct {
/* Unit flags */ /* Unit flags */
#define MTUF_V_PNU (UNIT_V_UF + 0) /* position not upd */ #define MTUF_V_WLK (UNIT_V_UF + 0) /* write locked */
#define MTUF_V_WLK (UNIT_V_UF + 1) /* write locked */
#define MTUF_V_FMT (UNIT_V_UF + 2) /* tape file format */ #define MTUF_V_FMT (UNIT_V_UF + 2) /* tape file format */
#define MTUF_W_FMT 3 /* 3b of formats */ #define MTUF_F_STD 0 /* SIMH format */
#define MTUF_N_FMT (1u << MTUF_W_FMT) /* number of formats */ #define MTUF_F_E11 1 /* E11 format */
#define MTUF_M_FMT ((1u << MTUF_W_FMT) - 1) #define MTUF_F_TPC 2 /* TPC format */
#define MTUF_F_STD 0 /* SIMH format */ #define MTUF_F_P7B 3 /* P7B format */
#define MTUF_F_E11 1 /* E11 format */ #define MTUF_F_AWS 4 /* AWS format */
#define MTUF_F_TPC 2 /* TPC format */ #define MTUF_F_TAR 5 /* TAR format */
#define MTUF_F_P7B 3 /* P7B format */ #define MTUF_F_ANSI 6 /* ANSI format */
#define MTUF_F_AWS 4 /* AWS format */
#define MTUF_F_TAR 5 /* TAR format */ #define MTAT_F_VMS 0 /* VMS ANSI type */
#define MTUF_F_ANSI 6 /* ANSIFILES format */ #define MTAT_F_RSX11 1 /* RSX-11 ANSI type */
#define MTUF_V_UF (MTUF_V_FMT + MTUF_W_FMT) #define MTAT_F_RSTS 2 /* RSTS ANSI type */
#define MTUF_PNU (1u << MTUF_V_PNU) #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_WLK (1u << MTUF_V_WLK)
#define MTUF_FMT (MTUF_M_FMT << MTUF_V_FMT)
#define MTUF_WRP (MTUF_WLK | UNIT_RO) #define MTUF_WRP (MTUF_WLK | UNIT_RO)
#define MT_F_STD (MTUF_F_STD << MTUF_V_FMT) #define MT_SET_PNU(u) (u)->dynflags |= UNIT_TAPE_PNU
#define MT_F_E11 (MTUF_F_E11 << MTUF_V_FMT) #define MT_CLR_PNU(u) (u)->dynflags &= ~UNIT_TAPE_PNU
#define MT_F_TPC (MTUF_F_TPC << MTUF_V_FMT) #define MT_TST_PNU(u) ((u)->dynflags & UNIT_TAPE_PNU)
#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_INMRK(u) (u)->dynflags = (u)->dynflags | UNIT_TAPE_MRK #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_CLR_INMRK(u) (u)->dynflags = (u)->dynflags & ~UNIT_TAPE_MRK
#define MT_TST_INMRK(u) ((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 */ /* sim_tape_position Position Flags */
#define MTPOS_V_REW 3 #define MTPOS_V_REW 3