TAPE: Add ANSIFILES tape format

This commit is contained in:
Mark Pizzolato 2019-05-07 05:26:20 -07:00
parent 81b48e2ebf
commit 52a31597ec
6 changed files with 590 additions and 67 deletions

View file

@ -1209,8 +1209,9 @@ if ((uptr = tq_getucb (lu))) { /* unit exist? */
if (sts == ST_SUC) { /* ok? */ if (sts == ST_SUC) { /* ok? */
uptr->cpkt = pkt; /* op in progress */ uptr->cpkt = pkt; /* op in progress */
if ((tq_pkt[pkt].d[CMD_MOD] & MD_RWD) && /* rewind? */ if ((tq_pkt[pkt].d[CMD_MOD] & MD_RWD) && /* rewind? */
(!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM))) /* !immediate? */ (!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM))) { /* !immediate? */
sim_activate_after (uptr, 2000000); /* use 2 sec rewind execute time */ sim_activate_after (uptr, tq_rwtime); /* use 2 sec rewind execute time */
}
else { /* otherwise */ else { /* otherwise */
uptr->iostarttime = sim_grtime(); uptr->iostarttime = sim_grtime();
sim_activate (uptr, 0); /* use normal execute time */ sim_activate (uptr, 0); /* use normal execute time */

View file

@ -229,6 +229,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
#### 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

@ -108,13 +108,14 @@ struct sim_tape_fmt {
}; };
static struct sim_tape_fmt fmts[MTUF_N_FMT] = { static struct sim_tape_fmt fmts[MTUF_N_FMT] = {
{ "SIMH", 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) }, { "E11", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) },
{ "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) }, { "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) },
{ "P7B", 0, 0, 0 }, { "P7B", 0, 0, 0 },
{ "AWS", 0, 0, 0 }, { "AWS", 0, 0, 0 },
{ "TAR", 0, 0, 0 }, { "TAR", 0, 0, 0 },
{ NULL, 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 */
@ -375,6 +376,89 @@ return FALSE;
(_callback) (uptr, r); (_callback) (uptr, r);
#endif #endif
typedef struct VOL1 {
char type[3]; /* VOL */
char num; /* 1 */
char ident[6]; /* <ansi <a> 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 */ /* Enable asynchronous operation */
@ -448,7 +532,8 @@ 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
fflush (uptr->fileref); if (MT_GET_FMT (uptr) != MTUF_F_ANSI)
fflush (uptr->fileref);
} }
/* Attach tape unit */ /* Attach tape unit */
@ -502,9 +587,36 @@ if (MT_GET_FMT (uptr) == MTUF_F_TAR) {
uptr->recsize = TAR_DFLT_RECSIZE; 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) ||
sim_switches |= SWMASK ('R'); /* Force ReadOnly attach for TPC and TAR tapes */ (MT_GET_FMT (uptr) == MTUF_F_ANSI))
r = attach_unit (uptr, (CONST char *)cptr); /* attach unit */ 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? */ if (r != SCPE_OK) /* error? */
return sim_messagef (r, "Can't open tape image: %s\n", cptr); return sim_messagef (r, "Can't open tape image: %s\n", cptr);
@ -591,7 +703,13 @@ if (ctx)
sim_tape_clr_async (uptr); sim_tape_clr_async (uptr);
MT_CLR_INMRK (uptr); /* Not within an AWS or TAR tapemark */ 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) if (r != SCPE_OK)
return r; return r;
switch (f) { /* case on format */ 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, " -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 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, " -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, " 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");
@ -650,7 +768,13 @@ fprintf (st, " -L Display detailed record size counts observed durin
fprintf (st, " validation pass\n"); 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"); 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; 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); 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). /* Read record length forward (internal routine).
Inputs: Inputs:
@ -782,7 +920,7 @@ if ((uptr->tape_eom) &&
return MTSE_EOM; /* and quit with I/O error status */ 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 */ MT_SET_PNU (uptr); /* then set position not updated */
return sim_tape_ioerr (uptr); /* and quit with I/O error status */ return sim_tape_ioerr (uptr); /* and quit with I/O error status */
} }
@ -878,7 +1016,7 @@ switch (f) { /* otherwise the read method
else if (*bc == MTR_FHGAP) { /* otherwise if the value if a half gap */ 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 */ 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 */ 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 */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */
break; break;
} }
@ -904,7 +1042,7 @@ switch (f) { /* otherwise the read method
if (status == MTSE_OK) { /* Validate the reverse record size for data records */ if (status == MTSE_OK) { /* Validate the reverse record size for data records */
t_mtrlnt rev_lnt; 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 */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */
break; break;
} }
@ -924,7 +1062,7 @@ switch (f) { /* otherwise the read method
MT_SET_PNU (uptr); /* pos not upd */ MT_SET_PNU (uptr); /* pos not upd */
break; 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 */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */
} }
break; /* otherwise the operation succeeded */ break; /* otherwise the operation succeeded */
@ -976,7 +1114,7 @@ switch (f) { /* otherwise the read method
if (status == MTSE_OK) { if (status == MTSE_OK) {
*bc = sbc; /* save rec lnt */ *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 */ uptr->pos = uptr->pos + sbc; /* spc over record */
if (all_eof) { /* tape mark? */ if (all_eof) { /* tape mark? */
status = MTSE_TMK; status = MTSE_TMK;
@ -1018,7 +1156,7 @@ switch (f) { /* otherwise the read method
uptr->pos += awshdr.nxtlen; /* spc over record */ uptr->pos += awshdr.nxtlen; /* spc over record */
memset (&awshdr, 0, sizeof (t_awslnt)); memset (&awshdr, 0, sizeof (t_awslnt));
saved_pos = (t_addr)sim_ftell (uptr->fileref); 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); (void)sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref);
if (awshdr.rectyp == AWS_TMK) if (awshdr.rectyp == AWS_TMK)
MT_SET_INMRK (uptr); /* within an AWS tapemark */ 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 */ MT_CLR_INMRK (uptr); /* not within an AWS tapemark */
} }
else 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; break;
@ -1038,7 +1176,7 @@ switch (f) { /* otherwise the read method
*bc = (t_mtrlnt)uptr->recsize; /* TAR record size */ *bc = (t_mtrlnt)uptr->recsize; /* TAR record size */
else else
*bc = (t_mtrlnt)(uptr->hwmark - uptr->pos); /* TAR remnant last record */ *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; uptr->pos += *bc;
MT_CLR_INMRK (uptr); MT_CLR_INMRK (uptr);
} }
@ -1052,6 +1190,22 @@ switch (f) { /* otherwise the read method
} }
break; 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: default:
status = MTSE_FMT; status = MTSE_FMT;
} }
@ -1171,9 +1325,9 @@ else switch (f) { /* otherwise the read me
bufcap = sizeof (buffer) /* to the full size of the buffer */ bufcap = sizeof (buffer) /* to the full size of the buffer */
/ sizeof (buffer [0]); / sizeof (buffer [0]);
if (sim_fseek (uptr->fileref, /* seek back to the location */ if (sim_tape_seek (uptr, /* seek back to the location */
uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */ uptr->pos - bufcap * sizeof (t_mtrlnt))) { /* corresponding to the start */
SEEK_SET)) { /* of the buffer; if it fails */ /* of the buffer; if it fails */
status = sim_tape_ioerr (uptr); /* and fail with I/O error status */ status = sim_tape_ioerr (uptr); /* and fail with I/O error status */
break; break;
} }
@ -1213,9 +1367,8 @@ else switch (f) { /* otherwise the read me
uptr->pos = uptr->pos - sizeof (t_mtrlnt) /* position to the start */ uptr->pos = uptr->pos - sizeof (t_mtrlnt) /* position to the start */
- (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */ - (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 */ 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 */ uptr->pos + sizeof (t_mtrlnt))) {/* then return with I/O error status */
SEEK_SET)) {
status = sim_tape_ioerr (uptr); status = sim_tape_ioerr (uptr);
break; break;
} }
@ -1230,7 +1383,7 @@ else switch (f) { /* otherwise the read me
case MTUF_F_TPC: case MTUF_F_TPC:
ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */ 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); (void)sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
*bc = (t_mtrlnt)tpcbc; /* save rec lnt */ *bc = (t_mtrlnt)tpcbc; /* save rec lnt */
@ -1243,7 +1396,7 @@ else switch (f) { /* otherwise the read me
if (*bc == MTR_TMK) /* tape mark? */ if (*bc == MTR_TMK) /* tape mark? */
status = MTSE_TMK; status = MTSE_TMK;
else else
(void)sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); (void)sim_tape_seek (uptr, uptr->pos + sizeof (t_tpclnt));
} }
break; break;
@ -1265,7 +1418,7 @@ else switch (f) { /* otherwise the read me
buf_offset = uptr->pos - (sbc - 1 + BUF_SZ); buf_offset = uptr->pos - (sbc - 1 + BUF_SZ);
read_size = 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); bytes_in_buf = sim_fread (buf, sizeof (uint8), read_size, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */ if (ferror (uptr->fileref)) { /* error? */
status = sim_tape_ioerr (uptr); status = sim_tape_ioerr (uptr);
@ -1286,7 +1439,7 @@ else switch (f) { /* otherwise the read me
if (status == MTSE_OK) { if (status == MTSE_OK) {
uptr->pos = uptr->pos - sbc; /* update position */ uptr->pos = uptr->pos - sbc; /* update position */
*bc = sbc; /* save rec lnt */ *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? */ if (all_eof) /* tape mark? */
status = MTSE_TMK; status = MTSE_TMK;
} }
@ -1300,7 +1453,7 @@ else switch (f) { /* otherwise the read me
status = MTSE_BOT; /* then we're done */ status = MTSE_BOT; /* then we're done */
break; break;
} }
(void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);/* position */ (void)sim_tape_seek (uptr, uptr->pos); /* position */
memset (&awshdr, 0, sizeof (awshdr)); memset (&awshdr, 0, sizeof (awshdr));
rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */ 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 -= sizeof (t_awshdr); /* position to the start of the record */
uptr->pos -= awshdr.prelen; /* Including the data length */ uptr->pos -= awshdr.prelen; /* Including the data length */
if (sim_fseek (uptr->fileref, /* seek to the start of the data area; if it fails */ if (sim_tape_seek (uptr, /* seek to the start of the data area; if it fails */
uptr->pos + sizeof (t_awshdr), uptr->pos + sizeof (t_awshdr))) {
SEEK_SET)) {
status = sim_tape_ioerr (uptr); /* then return with I/O error status */ status = sim_tape_ioerr (uptr); /* then return with I/O error status */
break; break;
} }
@ -1368,7 +1520,19 @@ else switch (f) { /* otherwise the read me
*bc = (t_mtrlnt)uptr->recsize; *bc = (t_mtrlnt)uptr->recsize;
if (*bc) { if (*bc) {
uptr->pos -= *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; break;
@ -1439,12 +1603,20 @@ if (rbc > max) { /* rec out of range? */
uptr->pos = opos; uptr->pos = opos;
return MTSE_INVRL; return MTSE_INVRL;
} }
i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ if (f != MTUF_F_ANSI) {
if (ferror (uptr->fileref)) { /* error? */ i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
if (ferror (uptr->fileref)) { /* error? */
MT_SET_PNU (uptr); MT_SET_PNU (uptr);
uptr->pos = opos; uptr->pos = opos;
return sim_tape_ioerr (uptr); 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 */ for ( ; i < rbc; i++) /* fill with 0's */
buf[i] = 0; buf[i] = 0;
if (f == MTUF_F_P7B) /* p7b? strip SOR */ if (f == MTUF_F_P7B) /* p7b? strip SOR */
@ -1504,9 +1676,17 @@ 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;
i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ if (f != MTUF_F_ANSI) {
if (ferror (uptr->fileref)) /* error? */ i = (t_mtrlnt) sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
if (ferror (uptr->fileref)) /* error? */
return sim_tape_ioerr (uptr); 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 */ for ( ; i < rbc; i++) /* fill with 0's */
buf[i] = 0; buf[i] = 0;
if (f == MTUF_F_P7B) /* p7b? strip SOR */ if (f == MTUF_F_P7B) /* p7b? strip SOR */
@ -1561,7 +1741,7 @@ if (sim_tape_wrp (uptr)) /* write prot? */
return MTSE_WRP; return MTSE_WRP;
if (sbc == 0) /* nothing to do? */ if (sbc == 0) /* nothing to do? */
return MTSE_OK; 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; return MTSE_IOERR;
switch (f) { /* case on format */ switch (f) { /* case on format */
@ -1619,7 +1799,7 @@ size_t rdcnt;
t_bool replacing_record; t_bool replacing_record;
memset (&awshdr, 0, sizeof (t_awshdr)); 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; return MTSE_IOERR;
rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */ if (ferror (uptr->fileref)) { /* error? */
@ -1632,7 +1812,7 @@ if ((!sim_tape_bot (uptr)) &&
MT_SET_PNU (uptr); /* pos not upd */ MT_SET_PNU (uptr); /* pos not upd */
return MTSE_INVRL; 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; return MTSE_IOERR;
replacing_record = (awshdr.nxtlen == (t_awslnt)bc) && (awshdr.rectyp == (bc ? AWS_REC : AWS_TMK)); replacing_record = (awshdr.nxtlen == (t_awslnt)bc) && (awshdr.rectyp == (bc ? AWS_REC : AWS_TMK));
awshdr.nxtlen = (t_awslnt)bc; 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 */ return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */
if (sim_tape_wrp (uptr)) /* write prot? */ if (sim_tape_wrp (uptr)) /* write prot? */
return MTSE_WRP; 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); (void)sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */ if (ferror (uptr->fileref)) { /* error? */
MT_SET_PNU (uptr); 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 */ 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 */ MT_SET_PNU (uptr); /* then set position not updated */
return sim_tape_ioerr (uptr); /* and quit with I/O error status */ return sim_tape_ioerr (uptr); /* and quit with I/O error status */
} }
@ -1943,7 +2123,7 @@ do {
else if (meta == MTR_FHGAP) { /* half gap? */ else if (meta == MTR_FHGAP) { /* half gap? */
uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */ 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 */ 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 */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */
gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */ gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */
@ -1969,7 +2149,7 @@ do {
if (rec_size < gap_needed + min_rec_size) { /* rec too small? */ if (rec_size < gap_needed + min_rec_size) { /* rec too small? */
uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */ 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 */ 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 */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */
gap_alloc = gap_alloc + rec_size; /* allocate record */ gap_alloc = gap_alloc + rec_size; /* allocate record */
@ -2095,7 +2275,7 @@ if (gap_size == meta_size) { /* if the request is for
else /* otherwise */ else /* otherwise */
uptr->pos -= meta_size; /* back up the file pointer */ 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 */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */
(void)sim_fread (&metadatum, meta_size, 1, uptr->fileref);/* read a metadatum */ (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 */ return sim_tape_ioerr (uptr); /* then report the error and quit */
else if (metadatum == MTR_TMK) /* otherwise if a tape mark is present */ 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 */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */
else { /* otherwise */ 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)); sim_debug_unit (ctx->dbit, uptr, "sim_tape_rewind(unit=%d)\n", (int)(uptr-ctx->dptr->units));
} }
uptr->pos = 0; uptr->pos = 0;
if (uptr->flags & UNIT_ATT) if (uptr->flags & UNIT_ATT) {
(void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); (void)sim_tape_seek (uptr, uptr->pos);
}
MT_CLR_PNU (uptr); MT_CLR_PNU (uptr);
MT_CLR_INMRK (uptr); /* Not within an AWS or TAR tapemark */ MT_CLR_INMRK (uptr); /* Not within an AWS or TAR tapemark */
return MTSE_OK; return MTSE_OK;
@ -2851,7 +3032,7 @@ recbuf = (uint8 *)malloc (65536);
tape_size = (t_addr)sim_fsize (uptr->fileref); 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); 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;; ) { 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); i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref);
if (i == 0) /* past or at eof? */ if (i == 0) /* past or at eof? */
break; break;
@ -3015,7 +3196,7 @@ while (r == SCPE_OK) {
break; break;
} }
memset (buf_f, 0, bc_f); memset (buf_f, 0, bc_f);
memset (buf_r, 0, bc_f); memset (buf_r, 0, bc_r);
if (pos_f != pos_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); 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; break;
@ -3049,10 +3230,10 @@ while (r == SCPE_OK) {
uptr->tape_eom = uptr->pos; uptr->tape_eom = uptr->pos;
if ((!stop_cpu) && if ((!stop_cpu) &&
((r != MTSE_EOM) || (sim_switches & SWMASK ('V')) || (sim_switches & SWMASK ('L')) || ((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))) { (unique_record_sizes > 2 * tapemark_total))) {
remaining_data = (uint32)(sim_fsize_ex (uptr->fileref) - (t_offset)uptr->tape_eom); remaining_data = (uint32)(sim_tape_size (uptr) - (t_offset)uptr->tape_eom);
sim_printf ("Tape Image '%s' scanned as %s format.\n", 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, fmts[MT_GET_FMT (uptr)].name);
if (r != MTSE_EOM) if (r != MTSE_EOM)
sim_printf ("After processing "); sim_printf ("After processing ");
else else
@ -3081,7 +3262,7 @@ free (buf_f);
free (buf_r); free (buf_r);
free (rec_sizes); free (rec_sizes);
uptr->pos = saved_pos; uptr->pos = saved_pos;
(void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); (void)sim_tape_seek (uptr, uptr->pos);
return SCPE_OK; return SCPE_OK;
} }
@ -3580,3 +3761,342 @@ 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])
{
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; i<tape->record_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);
}

View file

@ -102,6 +102,7 @@ typedef struct {
#define MTUF_F_P7B 3 /* P7B format */ #define MTUF_F_P7B 3 /* P7B format */
#define MTUF_F_AWS 4 /* AWS format */ #define MTUF_F_AWS 4 /* AWS format */
#define MTUF_F_TAR 5 /* TAR 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_V_UF (MTUF_V_FMT + MTUF_W_FMT)
#define MTUF_PNU (1u << MTUF_V_PNU) #define MTUF_PNU (1u << MTUF_V_PNU)
#define MTUF_WLK (1u << MTUF_V_WLK) #define MTUF_WLK (1u << MTUF_V_WLK)