ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541fs.cpp
(Generate patch)

Comparing Frodo4/Src/1541fs.cpp (file contents):
Revision 1.1 by cebix, 2003-07-01T17:09:43Z vs.
Revision 1.9 by cebix, 2005-06-27T19:55:48Z

# Line 1 | Line 1
1   /*
2   *  1541fs.cpp - 1541 emulation in host file system
3   *
4 < *  Frodo (C) 1994-1997,2002 Christian Bauer
4 > *  Frodo (C) 1994-1997,2002-2005 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 47 | Line 47
47   #endif
48  
49  
50 // Access modes
51 enum {
52        FMODE_READ, FMODE_WRITE, FMODE_APPEND
53 };
54
55 // File types
56 enum {
57        FTYPE_PRG, FTYPE_SEQ
58 };
59
50   // Prototypes
51 < static bool match(char *p, char *n);
51 > static bool match(const char *p, const char *n);
52  
53  
54   /*
55   *  Constructor: Prepare emulation
56   */
57  
58 < FSDrive::FSDrive(IEC *iec, char *path) : Drive(iec)
58 > FSDrive::FSDrive(IEC *iec, const char *path) : Drive(iec)
59   {
60          strcpy(orig_dir_path, path);
61          dir_path[0] = 0;
# Line 113 | Line 103 | bool FSDrive::change_dir(char *dirpath)
103   #else
104          int Info[4];
105  
106 <        if ((ReadCatalogueInfo(dirpath,Info) & 2) != 0) // Directory or image file
107 <        {
108 <          strcpy(dir_path, dirpath);
109 <          strncpy(dir_title, dir_path, 16);
110 <          return true;
111 <        }
122 <        else
123 <        {
124 <          return false;
125 <        }
106 >        if ((ReadCatalogueInfo(dirpath,Info) & 2) != 0) { // Directory or image file
107 >                strcpy(dir_path, dirpath);
108 >                strncpy(dir_title, dir_path, 16);
109 >                return true;
110 >        } else
111 >                return false;
112   #endif
113   }
114  
# Line 131 | Line 117 | bool FSDrive::change_dir(char *dirpath)
117   *  Open channel
118   */
119  
120 < uint8 FSDrive::Open(int channel, char *filename)
120 > uint8 FSDrive::Open(int channel, const uint8 *name, int name_len)
121   {
122          set_error(ERR_OK);
123  
124          // Channel 15: Execute file name as command
125          if (channel == 15) {
126 <                execute_command(filename);
126 >                execute_cmd(name, name_len);
127                  return ST_OK;
128          }
129  
# Line 147 | Line 133 | uint8 FSDrive::Open(int channel, char *f
133                  file[channel] = NULL;
134          }
135  
136 <        if (filename[0] == '$')
151 <                return open_directory(channel, filename+1);
152 <
153 <        if (filename[0] == '#') {
136 >        if (name[0] == '#') {
137                  set_error(ERR_NOCHANNEL);
138                  return ST_OK;
139          }
140  
141 <        return open_file(channel, filename);
141 >        if (name[0] == '$')
142 >                return open_directory(channel, name + 1, name_len - 1);
143 >
144 >        return open_file(channel, name, name_len);
145   }
146  
147  
# Line 163 | Line 149 | uint8 FSDrive::Open(int channel, char *f
149   *  Open file
150   */
151  
152 < uint8 FSDrive::open_file(int channel, char *filename)
152 > uint8 FSDrive::open_file(int channel, const uint8 *name, int name_len)
153   {
154 <        char plainname[NAMEBUF_LENGTH];
155 <        int filemode = FMODE_READ;
156 <        int filetype = FTYPE_PRG;
157 <        bool wildflag = false;
158 <        char *mode = "rb";
159 <        
160 <        convert_filename(filename, plainname, &filemode, &filetype, &wildflag);
161 <
162 <        // Channel 0 is READ PRG, channel 1 is WRITE PRG
163 <        if (!channel) {
164 <                filemode = FMODE_READ;
165 <                filetype = FTYPE_PRG;
166 <        }
167 <        if (channel == 1) {
168 <                filemode = FMODE_WRITE;
169 <                filetype = FTYPE_PRG;
170 <        }
171 <
172 <        // Wildcards are only allowed on reading
187 <        if (wildflag) {
188 <                if (filemode != FMODE_READ) {
154 >        char plain_name[NAMEBUF_LENGTH];
155 >        int plain_name_len;
156 >        int mode = FMODE_READ;
157 >        int type = FTYPE_PRG;
158 >        int rec_len = 0;
159 >        parse_file_name(name, name_len, (uint8 *)plain_name, plain_name_len, mode, type, rec_len, true);
160 >
161 >        // Channel 0 is READ, channel 1 is WRITE
162 >        if (channel == 0 || channel == 1) {
163 >                mode = channel ? FMODE_WRITE : FMODE_READ;
164 >                if (type == FTYPE_DEL)
165 >                        type = FTYPE_PRG;
166 >        }
167 >
168 >        bool writing = (mode == FMODE_WRITE || mode == FMODE_APPEND);
169 >
170 >        // Expand wildcards (only allowed on reading)
171 >        if (strchr(plain_name, '*') || strchr(plain_name, '?')) {
172 >                if (writing) {
173                          set_error(ERR_SYNTAX33);
174                          return ST_OK;
175 <                }
176 <                find_first_file(plainname);
175 >                } else
176 >                        find_first_file(plain_name);
177 >        }
178 >
179 >        // Relative files are not supported
180 >        if (type == FTYPE_REL) {
181 >                set_error(ERR_UNIMPLEMENTED);
182 >                return ST_OK;
183          }
184  
185          // Select fopen() mode according to file mode
186 <        switch (filemode) {
187 <                case FMODE_READ:
198 <                        mode = "rb";
199 <                        break;
186 >        const char *mode_str = "rb";
187 >        switch (mode) {
188                  case FMODE_WRITE:
189 <                        mode = "wb";
189 >                        mode_str = "wb";
190                          break;
191                  case FMODE_APPEND:
192 <                        mode = "ab";
192 >                        mode_str = "ab";
193                          break;
194          }
195  
# Line 209 | Line 197 | uint8 FSDrive::open_file(int channel, ch
197   #ifndef __riscos__
198          if (chdir(dir_path))
199                  set_error(ERR_NOTREADY);
200 <        else if ((file[channel] = fopen(plainname, mode)) != NULL) {
201 <                if (filemode == FMODE_READ)     // Read and buffer first byte
200 >        else if ((file[channel] = fopen(plain_name, mode_str)) != NULL) {
201 >                if (mode == FMODE_READ || mode == FMODE_M)      // Read and buffer first byte
202                          read_char[channel] = fgetc(file[channel]);
203          } else
204                  set_error(ERR_FILENOTFOUND);
# Line 220 | Line 208 | uint8 FSDrive::open_file(int channel, ch
208            char fullname[NAMEBUF_LENGTH];
209  
210            // On RISC OS make a full filename
211 <          sprintf(fullname,"%s.%s",dir_path,plainname);
211 >          sprintf(fullname,"%s.%s",dir_path,plain_name);
212            if ((file[channel] = fopen(fullname, mode)) != NULL)
213            {
214 <            if (filemode == FMODE_READ)
214 >            if (mode == FMODE_READ || mode == FMODE_M)
215              {
216                read_char[channel] = fgetc(file[channel]);
217              }
# Line 240 | Line 228 | uint8 FSDrive::open_file(int channel, ch
228  
229  
230   /*
243 *  Analyze file name, get access mode and type
244 */
245
246 void FSDrive::convert_filename(char *srcname, char *destname, int *filemode, int *filetype, bool *wildflag)
247 {
248        char *p, *q;
249        int i;
250
251        // Search for ':', p points to first character after ':'
252        if ((p = strchr(srcname, ':')) != NULL)
253                p++;
254        else
255                p = srcname;
256
257        // Convert char set of the remaining string -> destname
258        q = destname;
259        for (i=0; i<NAMEBUF_LENGTH && (*q++ = conv_from_64(*p++, true)); i++) ;
260
261        // Look for mode parameters seperated by ','
262        p = destname;
263        while ((p = strchr(p, ',')) != NULL) {
264
265                // Cut string after the first ','
266                *p++ = 0;
267
268                switch (*p) {
269                        case 'p':
270                                *filetype = FTYPE_PRG;
271                                break;
272                        case 's':
273                                *filetype = FTYPE_SEQ;
274                                break;
275                        case 'r':
276                                *filemode = FMODE_READ;
277                                break;
278                        case 'w':
279                                *filemode = FMODE_WRITE;
280                                break;
281                        case 'a':
282                                *filemode = FMODE_APPEND;
283                                break;
284                }
285        }
286
287        // Search for wildcards
288        *wildflag = (strchr(destname, '?') != NULL) || (strchr(destname, '*') != NULL);
289 }
290
291
292 /*
231   *  Find first file matching wildcard pattern and get its real name
232   */
233  
234   // Return true if name 'n' matches pattern 'p'
235 < static bool match(char *p, char *n)
235 > static bool match(const char *p, const char *n)
236   {
237          if (!*p)                // Null pattern matches everything
238                  return true;
# Line 310 | Line 248 | static bool match(char *p, char *n)
248          return !*n;
249   }
250  
251 < void FSDrive::find_first_file(char *name)
251 > void FSDrive::find_first_file(char *pattern)
252   {
253   #ifndef __riscos__
254          DIR *dir;
# Line 326 | Line 264 | void FSDrive::find_first_file(char *name
264          while (de) {
265  
266                  // Match found? Then copy real file name
267 <                if (match(name, de->d_name)) {
268 <                        strncpy(name, de->d_name, NAMEBUF_LENGTH);
267 >                if (match(pattern, de->d_name)) {
268 >                        strncpy(pattern, de->d_name, NAMEBUF_LENGTH);
269                          closedir(dir);
270                          return;
271                  }
# Line 342 | Line 280 | void FSDrive::find_first_file(char *name
280          char Buffer[NAMEBUF_LENGTH];
281  
282          de.offset = 0; de.buffsize = NAMEBUF_LENGTH; de.match = name;
283 <        do
284 <        {
285 <          de.readno = 1;
286 <          if (ReadDirName(dir_path,Buffer,&de) != NULL) {de.offset = -1;}
287 <          else if (de.offset != -1)
288 <          {
289 <            if (match(name,Buffer))
290 <            {
291 <              strncpy(name, Buffer, NAMEBUF_LENGTH);
354 <              return;
355 <            }
356 <          }
357 <        }
358 <        while (de.offset != -1);
283 >        do {
284 >                de.readno = 1;
285 >                if (ReadDirName(dir_path,Buffer,&de) != NULL)
286 >                        de.offset = -1;
287 >                else if (de.offset != -1 && match(name,Buffer)) {
288 >                        strncpy(name, Buffer, NAMEBUF_LENGTH);
289 >                        return;
290 >                }
291 >        } while (de.readno > 0);
292   #endif
293   }
294  
# Line 364 | Line 297 | void FSDrive::find_first_file(char *name
297   *  Open directory, create temporary file
298   */
299  
300 < uint8 FSDrive::open_directory(int channel, char *filename)
300 > uint8 FSDrive::open_directory(int channel, const uint8 *pattern, int pattern_len)
301   {
302          char buf[] = "\001\004\001\001\0\0\022\042                \042 00 2A";
303          char str[NAMEBUF_LENGTH];
371        char pattern[NAMEBUF_LENGTH];
304          char *p, *q;
305          int i;
306          int filemode;
# Line 381 | Line 313 | uint8 FSDrive::open_directory(int channe
313          struct stat statbuf;
314  
315          // Special treatment for "$0"
316 <        if (filename[0] == '0' && filename[1] == 0)
317 <                filename += 1;
316 >        if (pattern[0] == '0' && pattern[1] == 0) {
317 >                pattern++;
318 >                pattern_len--;
319 >        }
320  
321 <        // Convert filename ('$' already stripped), filemode/type are ignored
322 <        convert_filename(filename, pattern, &filemode, &filetype, &wildflag);
321 >        // Skip everything before the ':' in the pattern
322 >        uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len);
323 >        if (t)
324 >                pattern = t + 1;
325 >
326 >        // Convert pattern to ASCII
327 >        char ascii_pattern[NAMEBUF_LENGTH];
328 >        petscii2ascii(ascii_pattern, pattern, NAMEBUF_LENGTH);
329  
330          // Open directory for reading and skip '.' and '..'
331          if ((dir = opendir(dir_path)) == NULL) {
# Line 405 | Line 345 | uint8 FSDrive::open_directory(int channe
345          // Create directory title
346          p = &buf[8];
347          for (i=0; i<16 && dir_title[i]; i++)
348 <                *p++ = conv_to_64(dir_title[i], false);
348 >                *p++ = ascii2petscii(dir_title[i]);
349          fwrite(buf, 1, 32, file[channel]);
350  
351          // Create and write one line for every directory entry
352          while (de) {
353  
354 <                // Include only files matching the pattern
355 <                if (match(pattern, de->d_name)) {
354 >                // Include only files matching the ascii_pattern
355 >                if (match(ascii_pattern, de->d_name)) {
356  
357                          // Get file statistics
358                          chdir(dir_path);
# Line 441 | Line 381 | uint8 FSDrive::open_directory(int channe
381                          *p++ = '\"';
382                          q = p;
383                          for (i=0; i<16 && str[i]; i++)
384 <                                *q++ = conv_to_64(str[i], true);
384 >                                *q++ = ascii2petscii(str[i]);
385                          *q++ = '\"';
386                          p += 18;
387  
# Line 466 | Line 406 | uint8 FSDrive::open_directory(int channe
406   #else
407          dir_full_info di;
408          dir_env de;
409 +        unsigned char c;
410  
411          // Much of this is very similar to the original
412 <        if ((filename[0] == '0') && (filename[1] == 0)) {filename++;}
413 <        // Concatenate dir_path and pattern in buffer pattern ==> read subdirs!
414 <        strcpy(pattern,dir_path);
415 <        convert_filename(filename, pattern + strlen(pattern), &filemode, &filetype, &wildflag);
412 >        if ((pattern[0] == '0') && (pattern[1] == 0)) {pattern++;}
413 >
414 >        // Concatenate dir_path and ascii_pattern in buffer ascii_pattern ==> read subdirs!
415 >        strcpy(ascii_pattern,dir_path); i = strlen(ascii_pattern); ascii_pattern[i++] = '.'; ascii_pattern[i] = 0;
416 >        convert_filename(pattern, ascii_pattern + i, &filemode, &filetype, &wildflag);
417 >        p = ascii_pattern + i; q = p;
418 >        do {c = *q++; if (c == '.') p = q;} while (c >= 32);
419 >        *(p-1) = 0;  // separate directory-path and ascii_pattern
420 >        if ((uint8)(*p) < 32) {*p = '*'; *(p+1) = 0;}
421  
422          // We don't use tmpfile() -- problems involved!
423          DeleteFile(RO_TEMPFILE);        // first delete it, if it exists
424          if ((file[channel] = fopen(RO_TEMPFILE,"wb+")) == NULL)
425 <        {
426 <          return(ST_OK);
481 <        }
482 <        de.offset = 0; de.buffsize = NAMEBUF_LENGTH; de.match = filename;
425 >                return(ST_OK);
426 >        de.offset = 0; de.buffsize = NAMEBUF_LENGTH; de.match = p;
427  
428          // Create directory title - copied from above
429          p = &buf[8];
# Line 487 | Line 431 | uint8 FSDrive::open_directory(int channe
431                  *p++ = conv_to_64(dir_title[i], false);
432          fwrite(buf, 1, 32, file[channel]);
433  
434 <        do
435 <        {
436 <          de.readno = 1;
437 <          if (ReadDirNameInfo(pattern,&di,&de) != NULL) {de.offset = -1;}
438 <          else if (de.offset != -1)     // don't have to check for match here
439 <          {
440 <            memset(buf,' ',31); buf[31] = 0;    // most of this: see above
441 <            p = buf; *p++ = 0x01; *p++ = 0x01;
442 <            i = (di.length + 254) / 254; *p++ = i & 0xff; *p++ = (i>>8) & 0xff;
443 <            p++;
444 <            if (i < 10)  {*p++ = ' ';}
445 <            if (i < 100) {*p++ = ' ';}
446 <            strcpy(str, di.name);
447 <            *p++ = '\"'; q = p;
448 <            for (i=0; (i<16 && str[i]); i++)
449 <            {
450 <              *q++ = conv_to_64(str[i], true);
451 <            }
452 <            *q++ = '\"'; p += 18;
453 <            if ((di.otype & 2) == 0)
454 <            {
455 <              *p++ = 'P'; *p++ = 'R'; *p++ = 'G';
456 <            }
457 <            else
458 <            {
459 <              *p++ = 'D'; *p++ = 'I'; *p++ = 'R';
516 <            }
517 <            fwrite(buf, 1, 32, file[channel]);
518 <          }
519 <        }
520 <        while (de.offset != -1);
434 >        do {
435 >                de.readno = 1;
436 >                if (ReadDirNameInfo(ascii_pattern,&di,&de) != NULL)
437 >                        de.offset = -1;
438 >                else if (de.readno > 0) {       // don't have to check for match here
439 >                        memset(buf,' ',31); buf[31] = 0;        // most of this: see above
440 >                        p = buf; *p++ = 0x01; *p++ = 0x01;
441 >                        i = (di.length + 254) / 254; *p++ = i & 0xff; *p++ = (i>>8) & 0xff;
442 >                        p++;
443 >                        if (i < 10)
444 >                                *p++ = ' ';
445 >                        if (i < 100)
446 >                                *p++ = ' ';
447 >                        strcpy(str, di.name);
448 >                        *p++ = '\"'; q = p;
449 >                        for (i=0; (i<16 && str[i]); i++)
450 >                                *q++ = conv_to_64(str[i], true);
451 >                        *q++ = '\"'; p += 18;
452 >                        if ((di.otype & 2) == 0) {
453 >                                *p++ = 'P'; *p++ = 'R'; *p++ = 'G';
454 >                        } else {
455 >                                *p++ = 'D'; *p++ = 'I'; *p++ = 'R';
456 >                        }
457 >                        fwrite(buf, 1, 32, file[channel]);
458 >                }
459 >        } while (de.offset != -1);
460   #endif
461  
462          // Final line
# Line 573 | Line 512 | void FSDrive::close_all_channels(void)
512   *  Read from channel
513   */
514  
515 < uint8 FSDrive::Read(int channel, uint8 *byte)
515 > uint8 FSDrive::Read(int channel, uint8 &byte)
516   {
517          int c;
518  
519          // Channel 15: Error channel
520          if (channel == 15) {
521 <                *byte = *error_ptr++;
521 >                byte = *error_ptr++;
522  
523 <                if (*byte != '\r')
523 >                if (byte != '\r')
524                          return ST_OK;
525                  else {  // End of message
526                          set_error(ERR_OK);
# Line 592 | Line 531 | uint8 FSDrive::Read(int channel, uint8 *
531          if (!file[channel]) return ST_READ_TIMEOUT;
532  
533          // Read one byte
534 <        *byte = read_char[channel];
534 >        byte = read_char[channel];
535          c = fgetc(file[channel]);
536          if (c == EOF)
537                  return ST_EOF;
# Line 611 | Line 550 | uint8 FSDrive::Write(int channel, uint8
550   {
551          // Channel 15: Collect chars and execute command on EOI
552          if (channel == 15) {
553 <                if (cmd_len >= 40)
553 >                if (cmd_len >= 58)
554                          return ST_TIMEOUT;
555                  
556 <                cmd_buffer[cmd_len++] = byte;
556 >                cmd_buf[cmd_len++] = byte;
557  
558                  if (eoi) {
559 <                        cmd_buffer[cmd_len] = 0;
559 >                        execute_cmd(cmd_buf, cmd_len);
560                          cmd_len = 0;
622                        execute_command(cmd_buffer);
561                  }
562                  return ST_OK;
563          }
# Line 629 | Line 567 | uint8 FSDrive::Write(int channel, uint8
567                  return ST_TIMEOUT;
568          }
569  
570 <        if (fputc(byte, file[channel]) == EOF) {
571 <                set_error(ERR_WRITEERROR);
570 >        if (putc(byte, file[channel]) == EOF) {
571 >                set_error(ERR_WRITE25);
572                  return ST_TIMEOUT;
573          }
574  
# Line 639 | Line 577 | uint8 FSDrive::Write(int channel, uint8
577  
578  
579   /*
580 < *  Execute command string
580 > *  Execute drive commands
581   */
582  
583 < void FSDrive::execute_command(char *command)
583 > // INITIALIZE
584 > void FSDrive::initialize_cmd(void)
585   {
586 <        switch (command[0]) {
648 <                case 'I':
649 <                        close_all_channels();
650 <                        set_error(ERR_OK);
651 <                        break;
652 <
653 <                case 'U':
654 <                        if ((command[1] & 0x0f) == 0x0a) {
655 <                                Reset();
656 <                        } else
657 <                                set_error(ERR_SYNTAX30);
658 <                        break;
659 <
660 <                case 'G':
661 <                        if (command[1] != ':')
662 <                                set_error(ERR_SYNTAX30);
663 <                        else
664 <                                chdir_cmd(&command[2]);
665 <                        break;
666 <
667 <                default:
668 <                        set_error(ERR_SYNTAX30);
669 <        }
586 >        close_all_channels();
587   }
588  
589 <
590 < /*
674 < *  Execute 'G' command
675 < */
676 <
677 < void FSDrive::chdir_cmd(char *dirpath)
589 > // VALIDATE
590 > void FSDrive::validate_cmd(void)
591   {
679        char str[NAMEBUF_LENGTH];
680        char *p = str;
681
682        close_all_channels();
683
684        // G:. resets the directory path to its original setting
685        if (dirpath[0] == '.' && dirpath[1] == 0) {
686                change_dir(orig_dir_path);
687        } else {
688
689                // Convert directory name
690                for (int i=0; i<NAMEBUF_LENGTH && (*p++ = conv_from_64(*dirpath++, false)); i++) ;
691
692                if (!change_dir(str))
693                        set_error(ERR_NOTREADY);
694        }
592   }
593  
594  
# Line 705 | Line 602 | void FSDrive::Reset(void)
602          cmd_len = 0;    
603          set_error(ERR_STARTUP);
604   }
708
709
710 /*
711 *  Conversion PETSCII->ASCII
712 */
713
714 uint8 FSDrive::conv_from_64(uint8 c, bool map_slash)
715 {
716        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
717                return c ^ 0x20;
718        if ((c >= 0xc1) && (c <= 0xda))
719                return c ^ 0x80;
720        if ((c == '/') && map_slash && ThePrefs.MapSlash)
721 #ifdef __riscos__
722                return '.';     // directory separator is '.' in RO
723        if (c == '.') {return('_');}    // convert dot to underscore
724 #else
725                return '\\';
726 #endif
727        return c;
728 }
729
730
731 /*
732 *  Conversion ASCII->PETSCII
733 */
734
735 uint8 FSDrive::conv_to_64(uint8 c, bool map_slash)
736 {
737        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
738                return c ^ 0x20;
739 #ifdef __riscos__
740        if ((c == '.') && map_slash && ThePrefs.MapSlash)
741 #else
742        if ((c == '\\') && map_slash && ThePrefs.MapSlash)
743 #endif
744                return '/';
745 #ifdef __riscos__
746        if (c == '_') {return('.');}    // convert underscore to dot
747 #endif
748        return c;
749 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines