--- Frodo4/Src/1541fs.cpp 2003/07/09 13:54:22 1.3 +++ Frodo4/Src/1541fs.cpp 2005/06/27 19:55:48 1.9 @@ -1,7 +1,7 @@ /* * 1541fs.cpp - 1541 emulation in host file system * - * Frodo (C) 1994-1997,2002-2003 Christian Bauer + * Frodo (C) 1994-1997,2002-2005 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,25 +47,15 @@ #endif -// Access modes -enum { - FMODE_READ, FMODE_WRITE, FMODE_APPEND -}; - -// File types -enum { - FTYPE_PRG, FTYPE_SEQ -}; - // Prototypes -static bool match(char *p, char *n); +static bool match(const char *p, const char *n); /* * Constructor: Prepare emulation */ -FSDrive::FSDrive(IEC *iec, char *path) : Drive(iec) +FSDrive::FSDrive(IEC *iec, const char *path) : Drive(iec) { strcpy(orig_dir_path, path); dir_path[0] = 0; @@ -127,13 +117,13 @@ bool FSDrive::change_dir(char *dirpath) * Open channel */ -uint8 FSDrive::Open(int channel, char *filename) +uint8 FSDrive::Open(int channel, const uint8 *name, int name_len) { set_error(ERR_OK); // Channel 15: Execute file name as command if (channel == 15) { - execute_command(filename); + execute_cmd(name, name_len); return ST_OK; } @@ -143,15 +133,15 @@ uint8 FSDrive::Open(int channel, char *f file[channel] = NULL; } - if (filename[0] == '$') - return open_directory(channel, filename+1); - - if (filename[0] == '#') { + if (name[0] == '#') { set_error(ERR_NOCHANNEL); return ST_OK; } - return open_file(channel, filename); + if (name[0] == '$') + return open_directory(channel, name + 1, name_len - 1); + + return open_file(channel, name, name_len); } @@ -159,45 +149,47 @@ uint8 FSDrive::Open(int channel, char *f * Open file */ -uint8 FSDrive::open_file(int channel, char *filename) +uint8 FSDrive::open_file(int channel, const uint8 *name, int name_len) { - char plainname[NAMEBUF_LENGTH]; - int filemode = FMODE_READ; - int filetype = FTYPE_PRG; - bool wildflag = false; - char *mode = "rb"; - - convert_filename(filename, plainname, &filemode, &filetype, &wildflag); - - // Channel 0 is READ PRG, channel 1 is WRITE PRG - if (!channel) { - filemode = FMODE_READ; - filetype = FTYPE_PRG; - } - if (channel == 1) { - filemode = FMODE_WRITE; - filetype = FTYPE_PRG; - } - - // Wildcards are only allowed on reading - if (wildflag) { - if (filemode != FMODE_READ) { + char plain_name[NAMEBUF_LENGTH]; + int plain_name_len; + int mode = FMODE_READ; + int type = FTYPE_PRG; + int rec_len = 0; + parse_file_name(name, name_len, (uint8 *)plain_name, plain_name_len, mode, type, rec_len, true); + + // Channel 0 is READ, channel 1 is WRITE + if (channel == 0 || channel == 1) { + mode = channel ? FMODE_WRITE : FMODE_READ; + if (type == FTYPE_DEL) + type = FTYPE_PRG; + } + + bool writing = (mode == FMODE_WRITE || mode == FMODE_APPEND); + + // Expand wildcards (only allowed on reading) + if (strchr(plain_name, '*') || strchr(plain_name, '?')) { + if (writing) { set_error(ERR_SYNTAX33); return ST_OK; - } - find_first_file(plainname); + } else + find_first_file(plain_name); + } + + // Relative files are not supported + if (type == FTYPE_REL) { + set_error(ERR_UNIMPLEMENTED); + return ST_OK; } // Select fopen() mode according to file mode - switch (filemode) { - case FMODE_READ: - mode = "rb"; - break; + const char *mode_str = "rb"; + switch (mode) { case FMODE_WRITE: - mode = "wb"; + mode_str = "wb"; break; case FMODE_APPEND: - mode = "ab"; + mode_str = "ab"; break; } @@ -205,8 +197,8 @@ uint8 FSDrive::open_file(int channel, ch #ifndef __riscos__ if (chdir(dir_path)) set_error(ERR_NOTREADY); - else if ((file[channel] = fopen(plainname, mode)) != NULL) { - if (filemode == FMODE_READ) // Read and buffer first byte + else if ((file[channel] = fopen(plain_name, mode_str)) != NULL) { + if (mode == FMODE_READ || mode == FMODE_M) // Read and buffer first byte read_char[channel] = fgetc(file[channel]); } else set_error(ERR_FILENOTFOUND); @@ -216,10 +208,10 @@ uint8 FSDrive::open_file(int channel, ch char fullname[NAMEBUF_LENGTH]; // On RISC OS make a full filename - sprintf(fullname,"%s.%s",dir_path,plainname); + sprintf(fullname,"%s.%s",dir_path,plain_name); if ((file[channel] = fopen(fullname, mode)) != NULL) { - if (filemode == FMODE_READ) + if (mode == FMODE_READ || mode == FMODE_M) { read_char[channel] = fgetc(file[channel]); } @@ -236,61 +228,11 @@ uint8 FSDrive::open_file(int channel, ch /* - * Analyze file name, get access mode and type - */ - -void FSDrive::convert_filename(char *srcname, char *destname, int *filemode, int *filetype, bool *wildflag) -{ - char *p, *q; - int i; - - // Search for ':', p points to first character after ':' - if ((p = strchr(srcname, ':')) != NULL) - p++; - else - p = srcname; - - // Convert char set of the remaining string -> destname - q = destname; - for (i=0; id_name)) { - strncpy(name, de->d_name, NAMEBUF_LENGTH); + if (match(pattern, de->d_name)) { + strncpy(pattern, de->d_name, NAMEBUF_LENGTH); closedir(dir); return; } @@ -355,11 +297,10 @@ void FSDrive::find_first_file(char *name * Open directory, create temporary file */ -uint8 FSDrive::open_directory(int channel, char *filename) +uint8 FSDrive::open_directory(int channel, const uint8 *pattern, int pattern_len) { char buf[] = "\001\004\001\001\0\0\022\042 \042 00 2A"; char str[NAMEBUF_LENGTH]; - char pattern[NAMEBUF_LENGTH]; char *p, *q; int i; int filemode; @@ -372,11 +313,19 @@ uint8 FSDrive::open_directory(int channe struct stat statbuf; // Special treatment for "$0" - if (filename[0] == '0' && filename[1] == 0) - filename += 1; + if (pattern[0] == '0' && pattern[1] == 0) { + pattern++; + pattern_len--; + } - // Convert filename ('$' already stripped), filemode/type are ignored - convert_filename(filename, pattern, &filemode, &filetype, &wildflag); + // Skip everything before the ':' in the pattern + uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len); + if (t) + pattern = t + 1; + + // Convert pattern to ASCII + char ascii_pattern[NAMEBUF_LENGTH]; + petscii2ascii(ascii_pattern, pattern, NAMEBUF_LENGTH); // Open directory for reading and skip '.' and '..' if ((dir = opendir(dir_path)) == NULL) { @@ -396,14 +345,14 @@ uint8 FSDrive::open_directory(int channe // Create directory title p = &buf[8]; for (i=0; i<16 && dir_title[i]; i++) - *p++ = conv_to_64(dir_title[i], false); + *p++ = ascii2petscii(dir_title[i]); fwrite(buf, 1, 32, file[channel]); // Create and write one line for every directory entry while (de) { - // Include only files matching the pattern - if (match(pattern, de->d_name)) { + // Include only files matching the ascii_pattern + if (match(ascii_pattern, de->d_name)) { // Get file statistics chdir(dir_path); @@ -432,7 +381,7 @@ uint8 FSDrive::open_directory(int channe *p++ = '\"'; q = p; for (i=0; i<16 && str[i]; i++) - *q++ = conv_to_64(str[i], true); + *q++ = ascii2petscii(str[i]); *q++ = '\"'; p += 18; @@ -460,14 +409,14 @@ uint8 FSDrive::open_directory(int channe unsigned char c; // Much of this is very similar to the original - if ((filename[0] == '0') && (filename[1] == 0)) {filename++;} + if ((pattern[0] == '0') && (pattern[1] == 0)) {pattern++;} - // Concatenate dir_path and pattern in buffer pattern ==> read subdirs! - strcpy(pattern,dir_path); i = strlen(pattern); pattern[i++] = '.'; pattern[i] = 0; - convert_filename(filename, pattern + i, &filemode, &filetype, &wildflag); - p = pattern + i; q = p; + // Concatenate dir_path and ascii_pattern in buffer ascii_pattern ==> read subdirs! + strcpy(ascii_pattern,dir_path); i = strlen(ascii_pattern); ascii_pattern[i++] = '.'; ascii_pattern[i] = 0; + convert_filename(pattern, ascii_pattern + i, &filemode, &filetype, &wildflag); + p = ascii_pattern + i; q = p; do {c = *q++; if (c == '.') p = q;} while (c >= 32); - *(p-1) = 0; // separate directory-path and pattern + *(p-1) = 0; // separate directory-path and ascii_pattern if ((uint8)(*p) < 32) {*p = '*'; *(p+1) = 0;} // We don't use tmpfile() -- problems involved! @@ -484,7 +433,7 @@ uint8 FSDrive::open_directory(int channe do { de.readno = 1; - if (ReadDirNameInfo(pattern,&di,&de) != NULL) + if (ReadDirNameInfo(ascii_pattern,&di,&de) != NULL) de.offset = -1; else if (de.readno > 0) { // don't have to check for match here memset(buf,' ',31); buf[31] = 0; // most of this: see above @@ -563,15 +512,15 @@ void FSDrive::close_all_channels(void) * Read from channel */ -uint8 FSDrive::Read(int channel, uint8 *byte) +uint8 FSDrive::Read(int channel, uint8 &byte) { int c; // Channel 15: Error channel if (channel == 15) { - *byte = *error_ptr++; + byte = *error_ptr++; - if (*byte != '\r') + if (byte != '\r') return ST_OK; else { // End of message set_error(ERR_OK); @@ -582,7 +531,7 @@ uint8 FSDrive::Read(int channel, uint8 * if (!file[channel]) return ST_READ_TIMEOUT; // Read one byte - *byte = read_char[channel]; + byte = read_char[channel]; c = fgetc(file[channel]); if (c == EOF) return ST_EOF; @@ -601,15 +550,14 @@ uint8 FSDrive::Write(int channel, uint8 { // Channel 15: Collect chars and execute command on EOI if (channel == 15) { - if (cmd_len >= 40) + if (cmd_len >= 58) return ST_TIMEOUT; - cmd_buffer[cmd_len++] = byte; + cmd_buf[cmd_len++] = byte; if (eoi) { - cmd_buffer[cmd_len] = 0; + execute_cmd(cmd_buf, cmd_len); cmd_len = 0; - execute_command(cmd_buffer); } return ST_OK; } @@ -619,8 +567,8 @@ uint8 FSDrive::Write(int channel, uint8 return ST_TIMEOUT; } - if (fputc(byte, file[channel]) == EOF) { - set_error(ERR_WRITEERROR); + if (putc(byte, file[channel]) == EOF) { + set_error(ERR_WRITE25); return ST_TIMEOUT; } @@ -629,59 +577,18 @@ uint8 FSDrive::Write(int channel, uint8 /* - * Execute command string + * Execute drive commands */ -void FSDrive::execute_command(char *command) +// INITIALIZE +void FSDrive::initialize_cmd(void) { - switch (command[0]) { - case 'I': - close_all_channels(); - set_error(ERR_OK); - break; - - case 'U': - if ((command[1] & 0x0f) == 0x0a) { - Reset(); - } else - set_error(ERR_SYNTAX30); - break; - - case 'G': - if (command[1] != ':') - set_error(ERR_SYNTAX30); - else - chdir_cmd(&command[2]); - break; - - default: - set_error(ERR_SYNTAX30); - } + close_all_channels(); } - -/* - * Execute 'G' command - */ - -void FSDrive::chdir_cmd(char *dirpath) +// VALIDATE +void FSDrive::validate_cmd(void) { - char str[NAMEBUF_LENGTH]; - char *p = str; - - close_all_channels(); - - // G:. resets the directory path to its original setting - if (dirpath[0] == '.' && dirpath[1] == 0) { - change_dir(orig_dir_path); - } else { - - // Convert directory name - for (int i=0; iASCII - */ - -uint8 FSDrive::conv_from_64(uint8 c, bool map_slash) -{ - if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z')) - return c ^ 0x20; - if ((c >= 0xc1) && (c <= 0xda)) - return c ^ 0x80; - if ((c == '/') && map_slash && ThePrefs.MapSlash) -#ifdef __riscos__ - return '.'; // directory separator is '.' in RO - if (c == '.') {return('_');} // convert dot to underscore - if (c == ' ') {return(0xa0);} // space --> hard space -#else - return '\\'; -#endif - return c; -} - - -/* - * Conversion ASCII->PETSCII - */ - -uint8 FSDrive::conv_to_64(uint8 c, bool map_slash) -{ - if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z')) - return c ^ 0x20; -#ifdef __riscos__ - if ((c == '.') && map_slash && ThePrefs.MapSlash) -#else - if ((c == '\\') && map_slash && ThePrefs.MapSlash) -#endif - return '/'; -#ifdef __riscos__ - if (c == '_') {return('.');} // convert underscore to dot - if (c == 0xa0) {return(' ');} // hard space -> space -#endif - return c; -}