예제 #1
0
파일: fileops.c 프로젝트: cbmeeks/sd2iec
/**
 * 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;
  }
}
예제 #2
0
파일: fl-gijoe.c 프로젝트: j0ju/sd2iec
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;
      }
    }
  }
}
예제 #3
0
/* 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);
}