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