/** * file_open - open a file on given secondary * @secondary: secondary address used in OPEN call * * This function opens the file named in command_buffer on the given * secondary address. All special names and prefixes/suffixed are handled * here, e.g. $/#/@/,S,W */ void file_open(uint8_t secondary) { buffer_t *buf; uint8_t i = 0; uint8_t recordlen = 0; /* If the secondary is already in use, close the existing buffer */ buf = find_buffer(secondary); if (buf != NULL) { /* FIXME: What should we do if an error occurs? */ cleanup_and_free_buffer(buf); } /* Assume everything will go well unless proven otherwise */ set_error(ERROR_OK); /* Strip 0x0d characters from end of name (C2BD-C2CA) */ if (command_length > 1) { if (command_buffer[command_length-1] == 0x0d) command_length -= 1; else if (command_buffer[command_length-2] == 0x0d) command_length -= 2; } /* Clear the remainder of the command buffer, simplifies parsing */ memset(command_buffer+command_length, 0, sizeof(command_buffer)-command_length); uart_trace(command_buffer,0,command_length); /* Direct access? */ if (command_buffer[0] == '#') { open_buffer(secondary); return; } /* Parse type+mode suffixes */ uint8_t *ptr = command_buffer; enum open_modes mode = OPEN_READ; uint8_t filetype = TYPE_DEL; while(i++ < 2 && *ptr && (ptr = ustrchr(ptr, ','))) { *ptr = 0; ptr++; switch (*ptr) { case 0: break; case 'R': /* Read */ mode = OPEN_READ; break; case 'W': /* Write */ mode = OPEN_WRITE; break; case 'A': /* Append */ mode = OPEN_APPEND; break; case 'M': /* Modify */ mode = OPEN_MODIFY; break; case 'D': /* DEL */ filetype = TYPE_DEL; break; case 'S': /* SEQ */ filetype = TYPE_SEQ; break; case 'P': /* PRG */ filetype = TYPE_PRG; break; case 'U': /* USR */ filetype = TYPE_USR; break; case 'L': /* REL */ filetype = TYPE_REL; mode = OPEN_WRITE; if((ptr = ustrchr(ptr, ','))) recordlen = *(++ptr); i = 2; // stop the scan break; } } /* Load directory? */ if (command_buffer[0] == '$') { load_directory(secondary); return; } /* Parse path+partition numbers */ uint8_t *fname; int8_t res; cbmdirent_t dent; path_t path; /* Parse path and file name */ if (parse_path(command_buffer, &path, &fname, 0)) return; #ifdef CONFIG_M2I /* For M2I only: Remove trailing spaces from name */ if (partition[path.part].fop == &m2iops) { res = ustrlen(fname); while (--res && fname[res] == ' ') fname[res] = 0; } #endif /* Filename matching */ if (opendir(&matchdh, &path)) return; do { res = next_match(&matchdh, fname, NULL, NULL, FLAG_HIDDEN, &dent); if (res > 0) /* Error, abort */ return; /* Don't match on DEL or DIR */ if ((dent.typeflags & TYPE_MASK) != TYPE_DEL && (dent.typeflags & TYPE_MASK) != TYPE_DIR) break; /* But do match if it's for writing */ if (mode == OPEN_WRITE || secondary == 1) break; } while (res == 0); if(res && filetype == TYPE_REL && !recordlen) { set_error(ERROR_SYNTAX_UNABLE); return; } /* If match found is a REL... */ if(!res && (dent.typeflags & TYPE_MASK) == TYPE_REL) { /* requested type must be REL or DEL */ if(filetype != TYPE_REL && filetype != TYPE_DEL) { set_error(ERROR_FILE_TYPE_MISMATCH); return; } filetype = TYPE_REL; mode = OPEN_MODIFY; } /* Force mode+type for secondaries 0/1 */ switch (secondary) { case 0: mode = OPEN_READ; if (filetype == TYPE_DEL) filetype = TYPE_PRG; break; case 1: mode = OPEN_WRITE; if (filetype == TYPE_DEL) filetype = TYPE_PRG; break; default: if (filetype == TYPE_DEL) filetype = TYPE_SEQ; } if (mode == OPEN_WRITE) { if (res == 0) { /* Match found */ if (command_buffer[0] == '@') { /* Make sure there is a free buffer to open the new file later */ if (!check_free_buffers()) { set_error(ERROR_NO_CHANNEL); return; } /* Copy dent because file_delete may change it */ cbmdirent_t dentcopy = dent; /* Rewrite existing file: Delete the old one */ if (file_delete(&path, &dentcopy) == 255) return; /* Force fatops to create a new name based on the (long) CBM- */ /* name instead of creating one with the old SFN and no LFN. */ if (dent.opstype == OPSTYPE_FAT || dent.opstype == OPSTYPE_FAT_X00) dent.pvt.fat.realname[0] = 0; } else { /* Write existing file without replacement: Raise error */ set_error(ERROR_FILE_EXISTS); return; } } else { /* Normal write or non-existing rewrite */ /* Doesn't exist: Copy name to dent */ memset(&dent, 0, sizeof(dent)); ustrncpy(dent.name, fname, CBM_NAME_LENGTH); set_error(ERROR_OK); // because first_match has set FNF } } else if (res != 0) { /* File not found */ set_error(ERROR_FILE_NOT_FOUND); return; } /* Grab a buffer */ buf = alloc_buffer(); if (!buf) return; buf->secondary = secondary; if(filetype == TYPE_REL) { display_filename_write(path.part,CBM_NAME_LENGTH,dent.name); open_rel(&path, &dent, buf, recordlen, (mode == OPEN_MODIFY)); return; } switch (mode) { case OPEN_MODIFY: case OPEN_READ: /* Modify is the same as read, but allows reading *ed files. */ /* FAT doesn't have anything equivalent, so both are mapped to READ */ display_filename_read(path.part,CBM_NAME_LENGTH,dent.name); open_read(&path, &dent, buf); break; case OPEN_WRITE: case OPEN_APPEND: display_filename_write(path.part,CBM_NAME_LENGTH,dent.name); open_write(&path, &dent, filetype, buf, (mode == OPEN_APPEND)); break; } }
void load_gijoe(UNUSED_PARAMETER) { buffer_t *buf; set_data(1); set_clock(1); set_atn_irq(0); /* Wait until the bus has settled */ delay_ms(10); while (!IEC_DATA || !IEC_CLOCK) ; while (1) { /* Handshake */ set_clock(0); while (IEC_DATA) if (check_keys()) return; set_clock(1); uart_flush(); /* First byte is ignored */ if (gijoe_read_byte() < 0) return; /* Read two file name characters */ command_buffer[0] = gijoe_read_byte(); command_buffer[1] = gijoe_read_byte(); set_clock(0); command_buffer[2] = '*'; command_buffer[3] = 0; command_length = 3; /* Open the file */ file_open(0); uart_flush(); buf = find_buffer(0); if (!buf) { set_clock(1); gijoe_send_byte(0xfe); gijoe_send_byte(0xfe); gijoe_send_byte(0xac); gijoe_send_byte(0xf7); continue; } /* file is open, transfer */ while (1) { uint8_t i = buf->position; set_clock(1); delay_us(2); do { if (buf->data[i] == 0xac) gijoe_send_byte(0xac); gijoe_send_byte(buf->data[i]); } while (i++ < buf->lastused); /* Send end marker and wait for the next name */ if (buf->sendeoi) { gijoe_send_byte(0xac); gijoe_send_byte(0xff); cleanup_and_free_buffer(buf); break; } /* Send "another sector following" marker */ gijoe_send_byte(0xac); gijoe_send_byte(0xc3); delay_us(50); set_clock(0); /* Read next block */ if (buf->refill(buf)) { /* Send error marker */ gijoe_send_byte(0xfe); gijoe_send_byte(0xfe); gijoe_send_byte(0xac); gijoe_send_byte(0xf7); cleanup_and_free_buffer(buf); break; } } } }
/* DolphinDOS XQ command */ void load_dolphin(void) { /* find the already open buffer */ buffer_t *buf = find_buffer(0); if (!buf) return; buf->position = 2; /* initial handshaking */ // note about the delays: 100us work, not optimized // (doesn't matter much outside the loop) delay_us(100); // experimental delay parallel_set_dir(PARALLEL_DIR_OUT); set_clock(0); parallel_clear_rxflag(); delay_us(100); // experimental delay parallel_send_handshake(); uart_flush(); delay_us(100); // experimental delay /* every sector except the last */ uint8_t i; while (!buf->sendeoi) { iec_bus_t bus_state = iec_bus_read(); /* transmit first byte */ dolphin_write_hs(buf->data[2]); /* check DATA state before transmission */ if (bus_state & IEC_BIT_DATA) { cleanup_and_free_buffer(buf); return; } /* transmit the rest of the sector */ for (i = 3; i != 0; i++) dolphin_write_hs(buf->data[i]); /* read next sector */ if (buf->refill(buf)) { cleanup_and_free_buffer(buf); return; } } /* last sector */ i = 2; do { dolphin_write_hs(buf->data[i]); } while (i++ < buf->lastused); /* final handshake */ set_clock(1); while (!IEC_DATA) ; parallel_send_handshake(); parallel_set_dir(PARALLEL_DIR_IN); cleanup_and_free_buffer(buf); }