static int vdrive_command_copy(vdrive_t *vdrive, char *dest, int length) { char *name, *files, *p, c; int status = 0; /* Split command line */ if (!dest || !(files = (char *)memchr(++dest, '=', length)) ) { return CBMDOS_IPE_SYNTAX; } *files++ = 0; #ifdef DEBUG_DRIVE log_debug("COPY: dest= '%s', orig= '%s'.", dest, files); #endif if (vdrive_iec_open(vdrive, (BYTE *)dest, (unsigned int)strlen(dest), 1, NULL)) return CBMDOS_IPE_FILE_EXISTS; name = p = files; while (*name) { /* Loop for given files. */ for (; *p && *p != ','; p++) ; *p = 0; /* Skip optional colon. */ if ((files = strchr(name, ':'))) name = files + 1; #ifdef DEBUG_DRIVE log_debug("searching for file '%s'.", name); #endif if (vdrive_iec_open(vdrive, (BYTE *)name, (unsigned int)strlen(name), 0, NULL)) { vdrive_iec_close(vdrive, 1); return CBMDOS_IPE_NOT_FOUND; } do { status = vdrive_iec_read(vdrive, (BYTE *)&c, 0); if (vdrive_iec_write(vdrive, c, 1)) { vdrive_iec_close(vdrive, 0); /* No space on disk. */ vdrive_iec_close(vdrive, 1); return CBMDOS_IPE_DISK_FULL; } } while (status == SERIAL_OK); vdrive_iec_close(vdrive, 0); name = p + 1; /* Next file */ } vdrive_iec_close(vdrive, 1); return CBMDOS_IPE_OK; }
int autostart_prg_with_disk_image(const char *file_name, fileio_info_t *fh, log_t log, const char *image_name) { const int drive = 8; const int secondary = 1; autostart_prg_t *prg; vdrive_t *vdrive; int i; int old_tde_state; int file_name_size; BYTE data; unsigned int disk_image_type; int result, result2; /* identify disk image type */ switch (drive_get_disk_drive_type(drive - 8)) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: case DRIVE_TYPE_1551: case DRIVE_TYPE_1570: case DRIVE_TYPE_2031: disk_image_type = DISK_IMAGE_TYPE_D64; break; case DRIVE_TYPE_2040: case DRIVE_TYPE_3040: case DRIVE_TYPE_4040: disk_image_type = DISK_IMAGE_TYPE_D67; break; case DRIVE_TYPE_1571: case DRIVE_TYPE_1571CR: disk_image_type = DISK_IMAGE_TYPE_D71; break; case DRIVE_TYPE_1581: case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: disk_image_type = DISK_IMAGE_TYPE_D81; break; case DRIVE_TYPE_8050: disk_image_type = DISK_IMAGE_TYPE_D80; break; case DRIVE_TYPE_8250: case DRIVE_TYPE_1001: disk_image_type = DISK_IMAGE_TYPE_D82; break; default: log_error(log, "No idea what disk image format to use."); return -1; } /* read prg file */ prg = load_prg(file_name, fh, log); if (prg == NULL) { return -1; } /* disable TDE */ resources_get_int("DriveTrueEmulation", &old_tde_state); if (old_tde_state != 0) { log_message(log, "Turning true drive emulation off."); resources_set_int("DriveTrueEmulation", 0); } do { result = -1; /* create empty image */ if (vdrive_internal_create_format_disk_image(image_name, (char *)"AUTOSTART", disk_image_type) < 0) { log_error(log, "Error creating autostart disk image: %s", image_name); break; } /* attach disk image */ if (file_system_attach_disk(drive, image_name) < 0) { log_error(log, "Could not attach disk image: %s", image_name); break; } /* get vdrive */ vdrive = file_system_get_vdrive((unsigned int)drive); if (vdrive == NULL) { break; } /* get file name size */ file_name_size = strlen((const char *)fh->name); if (file_name_size > 16) { file_name_size = 16; } /* open file on disk */ if (vdrive_iec_open(vdrive, (const BYTE *)fh->name, file_name_size, secondary, NULL) != SERIAL_OK) { log_error(log, "Could not open file"); break; } result2 = 0; /* write PRG data to file */ for (i = -2; i < (int)prg->size; i++) { switch (i) { case -2: data = (BYTE)prg->start_addr; break; case -1: data = (BYTE)(prg->start_addr >> 8); break; default: data = prg->data[i]; break; } if (vdrive_iec_write(vdrive, data, secondary) != SERIAL_OK) { log_error(log, "Could not write file"); result2 = -1; break; } } /* close file */ if (vdrive_iec_close(vdrive, secondary) != SERIAL_OK) { log_error(log, "Could not close file"); break; } result = result2; } while (0); /* free prg file */ free_prg(prg); /* re-enable TDE */ if (old_tde_state != 0) { log_message(log, "Turning true drive emulation on."); resources_set_int("DriveTrueEmulation", old_tde_state); } /* ready */ return result; }
int vdrive_iec_open(vdrive_t *vdrive, const BYTE *name, unsigned int length, unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse_ext) { bufferinfo_t *p = &(vdrive->buffers[secondary]); BYTE *slot; /* Current directory entry */ int rc, status = SERIAL_OK; /* FIXME: This should probably be set to zero */ cbmdos_cmd_parse_t cmd_parse_stat; cbmdos_cmd_parse_t *cmd_parse; BYTE name_stat[17]; unsigned int opentype; if (cmd_parse_ext != NULL) { cmd_parse = cmd_parse_ext; memset(name_stat, 0, sizeof(name_stat)); strncpy((char *)name_stat, cmd_parse->parsecmd, sizeof(name_stat) - 1); name = name_stat; length = (unsigned int)strlen((char *)name); secondary = cmd_parse->secondary; } else { cmd_parse = &cmd_parse_stat; } if (cmd_parse_ext == NULL && (!name || !*name) && p->mode != BUFFER_COMMAND_CHANNEL) { return SERIAL_NO_DEVICE; } /* No floppy in drive? */ if (vdrive->image == NULL && p->mode != BUFFER_COMMAND_CHANNEL && secondary != 15 && *name != '#') { vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0); log_message(vdrive_iec_log, "Drive not ready."); return SERIAL_ERROR; } #ifdef DEBUG_DRIVE log_debug("VDRIVE#%i: OPEN: Name '%s' (%d) on ch %d.", vdrive->unit, name, length, secondary); #endif /* * If channel is command channel, name will be used as write. Return only * status of last write ... */ if (p->mode == BUFFER_COMMAND_CHANNEL) { unsigned int n; for (n = 0; n < length; n++) { status = vdrive_iec_write(vdrive, name[n], secondary); } if (length) { p->readmode = CBMDOS_FAM_WRITE; } else { p->readmode = CBMDOS_FAM_READ; } return status; } /* * Clear error flag */ vdrive_command_set_error(vdrive, CBMDOS_IPE_OK, 0, 0); /* * In use ? */ if (p->mode != BUFFER_NOT_IN_USE) { #ifdef DEBUG_DRIVE log_debug("Cannot open channel %d. Mode is %d.", secondary, p->mode); #endif vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_CHANNEL, 0, 0); return SERIAL_ERROR; } if (cmd_parse_ext == NULL) { cmd_parse->cmd = name; cmd_parse->cmdlength = length; cmd_parse->secondary = secondary; /* make sure this is zero, since it isn't set below */ cmd_parse->recordlength = 0; cmd_parse->drive = -1; rc = cbmdos_command_parse(cmd_parse); if (rc != CBMDOS_IPE_OK) { status = SERIAL_ERROR; goto out; } #ifdef DEBUG_DRIVE log_debug("Raw file name: `%s', length: %i.", name, length); log_debug("Parsed file name: `%s', reallength: %i. drive: %i", cmd_parse->parsecmd, cmd_parse->parselength, cmd_parse->drive); #endif if (cmd_parse->drive != -1) { /* a drive number was specified in the filename */ if ((vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) || (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8250) || (vdrive->image_format == VDRIVE_IMAGE_FORMAT_2040)) { /* FIXME: dual disk drives not supported */ if (cmd_parse->drive == 0) { /* FIXME: use drive 0 */ } else if (cmd_parse->drive == 1) { /* FIXME: use drive 1 */ /* since some software gets confused when it sees the same disk in both drives, we bail out with an error instead. */ log_warning(LOG_DEFAULT, "second drive of dual disk drive is not supported"); vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0); status = SERIAL_ERROR; goto out; } else { /* FIXME: what exactly does the drive do if drivenumber is > 1, look up the file on both drives perhaps ? */ } } else { /* single disk drives seem to ignore the drive number, *except* if it is 1, which will result in an error. */ if (cmd_parse->drive == 1) { vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0); status = SERIAL_ERROR; goto out; } } } } /* Limit file name to 16 chars. */ if (cmd_parse->parselength > 16) { cmd_parse->parselength = 16; } /* * Internal buffer ? */ if (*name == '#') { vdrive_alloc_buffer(p, BUFFER_MEMORY_BUFFER); /* the pointer is actually 1 on the real drives. */ /* this probably relates to the B-R and B-W commands. */ /* 1541 firmware: $cb84 - open channel, $cc0f bp = 1 */ p->bufptr = 1; /* we need a length to support the original B-R and B-W commands. */ p->length = 256; status = SERIAL_OK; goto out; } /* Clear update flag */ p->needsupdate = 0; /* * Directory read * A little-known feature of the 1541: open 1,8,2,"$" (or even 1,8,1). * It gives you the BAM+DIR as a sequential file, containing the data * just as it appears on disk. -Olaf Seibert */ if (*name == '$') { p->readmode = CBMDOS_FAM_READ; status = iec_open_read_directory(vdrive, secondary, cmd_parse); goto out; } /* * Check that there is room on directory. */ if (cmd_parse->readmode == CBMDOS_FAM_READ || cmd_parse->readmode == CBMDOS_FAM_APPEND) { opentype = cmd_parse->filetype; } else { opentype = CBMDOS_FT_DEL; } vdrive_dir_find_first_slot(vdrive, cmd_parse->parsecmd, cmd_parse->parselength, opentype, &p->dir); /* * Find the first non-DEL entry in the directory (if it exists). */ do { slot = vdrive_dir_find_next_slot(&p->dir); } while (slot && ((slot[SLOT_TYPE_OFFSET] & 0x07) == CBMDOS_FT_DEL)); p->readmode = cmd_parse->readmode; p->slot = slot; /* Call REL function if we are creating OR opening one */ if (cmd_parse->filetype == CBMDOS_FT_REL || ( slot && (slot[SLOT_TYPE_OFFSET] & 0x07) == CBMDOS_FT_REL)) { /* Make sure the record length of the opening command is the same as the record length in the directory slot, if not DOS ERROR 50 */ if (slot && cmd_parse->recordlength > 0 && slot[SLOT_RECORD_LENGTH] != cmd_parse->recordlength) { vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0); status = SERIAL_ERROR; goto out; } /* At this point the record lengths are the same (or will be), so set them equal. */ if (slot) { cmd_parse->recordlength = slot[SLOT_RECORD_LENGTH]; } status = vdrive_rel_open(vdrive, secondary, cmd_parse, name); goto out; } if (cmd_parse->readmode == CBMDOS_FAM_READ) { status = iec_open_read(vdrive, secondary); } else { status = iec_open_write(vdrive, secondary, cmd_parse, name); } out: lib_free(cmd_parse->parsecmd); return status; }
int autostart_prg_with_disk_image(const char *file_name, fileio_info_t *fh, const char *image_name) { const int drive = 8; const int secondary = 1; autostart_prg_t *prg; vdrive_t *vdrive; int i; int old_tde_state; int file_name_size; BYTE lo,hi; /* read prg file */ prg = load_prg(file_name, fh); if (prg == NULL) { return -1; } /* disable TDE */ resources_get_int("DriveTrueEmulation", &old_tde_state); if (old_tde_state != 0) resources_set_int("DriveTrueEmulation", 0); /* create empty image */ if (vdrive_internal_create_format_disk_image(image_name, (char *)"AUTOSTART", DISK_IMAGE_TYPE_D64) <0 ) { //log_error(log, "Error creating autostart disk image: %s", image_name); free_prg(prg); return -1; } /* attach disk image */ if (file_system_attach_disk(drive, image_name) < 0) { //log_error(log, "Could not attach disk image: %s", image_name); free_prg(prg); return -1; } /* copy file to disk */ vdrive = file_system_get_vdrive((unsigned int)drive); if (vdrive == NULL) { free_prg(prg); return -1; } /* get file name size */ file_name_size = strlen((const char *)fh->name); if (file_name_size > 16) { file_name_size = 16; } /* open file on disk */ if (vdrive_iec_open(vdrive, (const BYTE *)fh->name, file_name_size, secondary, NULL) != SERIAL_OK) { //log_error(log, "Could not open file"); free_prg(prg); return -1; } /* write start address to file */ lo = (BYTE)(prg->start_addr & 0xff); hi = (BYTE)((prg->start_addr >> 8) & 0xff); if ((vdrive_iec_write(vdrive, lo, secondary) != SERIAL_OK) || (vdrive_iec_write(vdrive, hi, secondary) != SERIAL_OK)) { //log_error(log, "Could not write file"); free_prg(prg); return -1; } /* write PRG data to file */ for (i = 0; i < prg->size; i++) { if (vdrive_iec_write(vdrive, prg->data[i], secondary) != SERIAL_OK) { //log_error(log, "Could not write file"); free_prg(prg); return -1; } } /* close file */ if (vdrive_iec_close(vdrive, secondary) != SERIAL_OK) { //log_error(log, "Could not close file"); free_prg(prg); return -1; } /* free prg file */ free_prg(prg); /* re-enable TDE */ if (old_tde_state != 0) resources_set_int("DriveTrueEmulation", old_tde_state); /* ready */ return 0; }