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

Comparing Frodo4/Src/1541t64.cpp (file contents):
Revision 1.2 by cebix, 2003-07-01T17:51:17Z vs.
Revision 1.5 by cebix, 2004-01-12T15:13:20Z

# Line 1 | Line 1
1   /*
2   *  1541t64.cpp - 1541 emulation in .t64/LYNX file
3   *
4 < *  Frodo (C) 1994-1997,2002-2003 Christian Bauer
4 > *  Frodo (C) 1994-1997,2002-2004 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 43 | Line 43
43   #include "Prefs.h"
44  
45  
46 // Access modes
47 enum {
48        FMODE_READ, FMODE_WRITE, FMODE_APPEND
49 };
50
51 // File types
52 enum {
53        FTYPE_PRG, FTYPE_SEQ, FTYPE_USR, FTYPE_REL
54 };
55
56 // Prototypes
57 static bool match(char *p, char *n);
58
59
46   /*
47   *  Constructor: Prepare emulation
48   */
# Line 145 | Line 131 | bool T64Drive::parse_t64_file(void)
131   {
132          uint8 buf[32];
133          uint8 *buf2;
134 <        char *p;
134 >        uint8 *p;
135          int max, i, j;
136  
137          // Read header and get maximum number of files contained
# Line 260 | Line 246 | bool T64Drive::parse_lynx_file(void)
246   *  Open channel
247   */
248  
249 < uint8 T64Drive::Open(int channel, char *filename)
249 > uint8 T64Drive::Open(int channel, const uint8 *name, int name_len)
250   {
251          set_error(ERR_OK);
252  
253          // Channel 15: Execute file name as command
254          if (channel == 15) {
255 <                execute_command(filename);
255 >                execute_cmd(name, name_len);
256                  return ST_OK;
257          }
258  
# Line 276 | Line 262 | uint8 T64Drive::Open(int channel, char *
262                  file[channel] = NULL;
263          }
264  
265 <        if (filename[0] == '#') {
265 >        if (name[0] == '#') {
266                  set_error(ERR_NOCHANNEL);
267                  return ST_OK;
268          }
# Line 286 | Line 272 | uint8 T64Drive::Open(int channel, char *
272                  return ST_OK;
273          }
274  
275 <        if (filename[0] == '$')
276 <                return open_directory(channel, filename+1);
275 >        if (name[0] == '$')
276 >                return open_directory(channel, name + 1, name_len - 1);
277  
278 <        return open_file(channel, filename);
278 >        return open_file(channel, name, name_len);
279   }
280  
281  
# Line 297 | Line 283 | uint8 T64Drive::Open(int channel, char *
283   *  Open file
284   */
285  
286 < uint8 T64Drive::open_file(int channel, char *filename)
286 > uint8 T64Drive::open_file(int channel, const uint8 *name, int name_len)
287   {
288 <        char plainname[NAMEBUF_LENGTH];
289 <        int filemode = FMODE_READ;
290 <        int filetype = FTYPE_PRG;
291 <        int num;
292 <
293 <        convert_filename(filename, plainname, &filemode, &filetype);
294 <
295 <        // Channel 0 is READ PRG, channel 1 is WRITE PRG
296 <        if (!channel) {
297 <                filemode = FMODE_READ;
298 <                filetype = FTYPE_PRG;
299 <        }
300 <        if (channel == 1) {
301 <                filemode = FMODE_WRITE;
302 <                filetype = FTYPE_PRG;
288 >        uint8 plain_name[NAMEBUF_LENGTH];
289 >        int plain_name_len;
290 >        int mode = FMODE_READ;
291 >        int type = FTYPE_PRG;
292 >        int rec_len;
293 >        parse_file_name(name, name_len, plain_name, plain_name_len, mode, type, rec_len);
294 >
295 >        // Channel 0 is READ, channel 1 is WRITE
296 >        if (channel == 0 || channel == 1) {
297 >                mode = channel ? FMODE_WRITE : FMODE_READ;
298 >                if (type == FTYPE_DEL)
299 >                        type = FTYPE_PRG;
300 >        }
301 >
302 >        bool writing = (mode == FMODE_WRITE || mode == FMODE_APPEND);
303 >
304 >        // Wildcards are only allowed on reading
305 >        if (writing && (strchr((const char *)plain_name, '*') || strchr((const char *)plain_name, '?'))) {
306 >                set_error(ERR_SYNTAX33);
307 >                return ST_OK;
308          }
309  
310          // Allow only read accesses
311 <        if (filemode != FMODE_READ) {
311 >        if (writing) {
312                  set_error(ERR_WRITEPROTECT);
313                  return ST_OK;
314          }
315  
316 +        // Relative files are not supported
317 +        if (type == FTYPE_REL) {
318 +                set_error(ERR_UNIMPLEMENTED);
319 +                return ST_OK;
320 +        }
321 +
322          // Find file
323 <        if (find_first_file(plainname, filetype, &num)) {
323 >        int num;
324 >        if (find_first_file(plain_name, plain_name_len, num)) {
325  
326                  // Open temporary file
327                  if ((file[channel] = tmpfile()) != NULL) {
# Line 342 | Line 340 | uint8 T64Drive::open_file(int channel, c
340                          rewind(file[channel]);
341                          delete[] buf;
342  
343 <                        if (filemode == FMODE_READ)     // Read and buffer first byte
343 >                        if (mode == FMODE_READ) // Read and buffer first byte
344                                  read_char[channel] = fgetc(file[channel]);
345                  }
346          } else
# Line 353 | Line 351 | uint8 T64Drive::open_file(int channel, c
351  
352  
353   /*
356 *  Analyze file name, get access mode and type
357 */
358
359 void T64Drive::convert_filename(char *srcname, char *destname, int *filemode, int *filetype)
360 {
361        char *p;
362
363        // Search for ':', p points to first character after ':'
364        if ((p = strchr(srcname, ':')) != NULL)
365                p++;
366        else
367                p = srcname;
368
369        // Remaining string -> destname
370        strncpy(destname, p, NAMEBUF_LENGTH);
371
372        // Search for ','
373        p = destname;
374        while (*p && (*p != ',')) p++;
375
376        // Look for mode parameters seperated by ','
377        p = destname;
378        while ((p = strchr(p, ',')) != NULL) {
379
380                // Cut string after the first ','
381                *p++ = 0;
382
383                switch (*p) {
384                        case 'P':
385                                *filetype = FTYPE_PRG;
386                                break;
387                        case 'S':
388                                *filetype = FTYPE_SEQ;
389                                break;
390                        case 'U':
391                                *filetype = FTYPE_USR;
392                                break;
393                        case 'L':
394                                *filetype = FTYPE_REL;
395                                break;
396                        case 'R':
397                                *filemode = FMODE_READ;
398                                break;
399                        case 'W':
400                                *filemode = FMODE_WRITE;
401                                break;
402                        case 'A':
403                                *filemode = FMODE_APPEND;
404                                break;
405                }
406        }
407 }
408
409
410 /*
354   *  Find first file matching wildcard pattern
355   */
356  
357   // Return true if name 'n' matches pattern 'p'
358 < static bool match(char *p, char *n)
358 > static bool match(const uint8 *p, int p_len, const uint8 *n)
359   {
360 <        if (!*p)                // Null pattern matches everything
418 <                return true;
419 <
420 <        do {
360 >        while (p_len-- > 0) {
361                  if (*p == '*')  // Wildcard '*' matches all following characters
362                          return true;
363                  if ((*p != *n) && (*p != '?'))  // Wildcard '?' matches single character
364                          return false;
365                  p++; n++;
366 <        } while (*p);
366 >        }
367  
368 <        return !(*n);
368 >        return *n == 0;
369   }
370  
371 < bool T64Drive::find_first_file(char *name, int type, int *num)
371 > bool T64Drive::find_first_file(const uint8 *pattern, int pattern_len, int &num)
372   {
373 <        for (int i=0; i<num_files; i++)
374 <                if (match(name, file_info[i].name) && type == file_info[i].type) {
375 <                        *num = i;
373 >        for (int i=0; i<num_files; i++) {
374 >                if (match(pattern, pattern_len, file_info[i].name)) {
375 >                        num = i;
376                          return true;
377                  }
378 <
378 >        }
379          return false;
380   }
381  
# Line 444 | Line 384 | bool T64Drive::find_first_file(char *nam
384   *  Open directory, create temporary file
385   */
386  
387 < uint8 T64Drive::open_directory(int channel, char *filename)
387 > uint8 T64Drive::open_directory(int channel, const uint8 *pattern, int pattern_len)
388   {
449        char buf[] = "\001\004\001\001\0\0\022\042                \042 00 2A";
450        char str[NAMEBUF_LENGTH];
451        char pattern[NAMEBUF_LENGTH];
452        char *p, *q;
453        int i, num;
454        int filemode;
455        int filetype;
456
389          // Special treatment for "$0"
390 <        if (strlen(filename) == 1 && filename[0] == '0')
391 <                filename += 1;
390 >        if (pattern[0] == '0' && pattern_len == 1) {
391 >                pattern++;
392 >                pattern_len--;
393 >        }
394  
395 <        // Convert filename ('$' already stripped), filemode/type are ignored
396 <        convert_filename(filename, pattern, &filemode, &filetype);
395 >        // Skip everything before the ':' in the pattern
396 >        uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len);
397 >        if (t) {
398 >                t++;
399 >                pattern_len -= t - pattern;
400 >                pattern = t;
401 >        }
402  
403          // Create temporary file
404          if ((file[channel] = tmpfile()) == NULL)
405                  return ST_OK;
406  
407          // Create directory title
408 <        p = &buf[8];
409 <        for (i=0; i<16 && dir_title[i]; i++)
410 <                *p++ = dir_title[i];
408 >        uint8 buf[] = "\001\004\001\001\0\0\022\042                \042 00 2A";
409 >        for (int i=0; i<16 && dir_title[i]; i++)
410 >                buf[i + 8] = dir_title[i];
411          fwrite(buf, 1, 32, file[channel]);
412  
413          // Create and write one line for every directory entry
414 <        for (num=0; num<num_files; num++) {
414 >        for (int num=0; num<num_files; num++) {
415  
416                  // Include only files matching the pattern
417 <                if (match(pattern, file_info[num].name)) {
417 >                if (pattern_len == 0 || match(pattern, pattern_len, file_info[num].name)) {
418  
419                          // Clear line with spaces and terminate with null byte
420                          memset(buf, ' ', 31);
421                          buf[31] = 0;
422  
423 <                        p = buf;
423 >                        uint8 *p = buf;
424                          *p++ = 0x01;    // Dummy line link
425                          *p++ = 0x01;
426  
427                          // Calculate size in blocks (254 bytes each)
428 <                        i = (file_info[num].length + 254) / 254;
429 <                        *p++ = i & 0xff;
430 <                        *p++ = (i >> 8) & 0xff;
428 >                        int n = (file_info[num].length + 254) / 254;
429 >                        *p++ = n & 0xff;
430 >                        *p++ = (n >> 8) & 0xff;
431  
432                          p++;
433 <                        if (i < 10) p++;        // Less than 10: add one space
434 <                        if (i < 100) p++;       // Less than 100: add another space
433 >                        if (n < 10) p++;        // Less than 10: add one space
434 >                        if (n < 100) p++;       // Less than 100: add another space
435  
436                          // Convert and insert file name
437 <                        strcpy(str, file_info[num].name);
437 >                        uint8 str[NAMEBUF_LENGTH];
438 >                        memcpy(str, file_info[num].name, 17);
439                          *p++ = '\"';
440 <                        q = p;
441 <                        for (i=0; i<16 && str[i]; i++)
440 >                        uint8 *q = p;
441 >                        for (int i=0; i<16 && str[i]; i++)
442                                  *q++ = str[i];
443                          *q++ = '\"';
444                          p += 18;
# Line 585 | Line 525 | void T64Drive::close_all_channels(void)
525   *  Read from channel
526   */
527  
528 < uint8 T64Drive::Read(int channel, uint8 *byte)
528 > uint8 T64Drive::Read(int channel, uint8 &byte)
529   {
530          int c;
531  
532          // Channel 15: Error channel
533          if (channel == 15) {
534 <                *byte = *error_ptr++;
534 >                byte = *error_ptr++;
535  
536 <                if (*byte != '\r')
536 >                if (byte != '\r')
537                          return ST_OK;
538                  else {  // End of message
539                          set_error(ERR_OK);
# Line 604 | Line 544 | uint8 T64Drive::Read(int channel, uint8
544          if (!file[channel]) return ST_READ_TIMEOUT;
545  
546          // Get char from buffer and read next
547 <        *byte = read_char[channel];
547 >        byte = read_char[channel];
548          c = fgetc(file[channel]);
549          if (c == EOF)
550                  return ST_EOF;
# Line 623 | Line 563 | uint8 T64Drive::Write(int channel, uint8
563   {
564          // Channel 15: Collect chars and execute command on EOI
565          if (channel == 15) {
566 <                if (cmd_len >= 40)
566 >                if (cmd_len >= 58)
567                          return ST_TIMEOUT;
568                  
569 <                cmd_buffer[cmd_len++] = byte;
569 >                cmd_buf[cmd_len++] = byte;
570  
571                  if (eoi) {
572 <                        cmd_buffer[cmd_len] = 0;
572 >                        execute_cmd(cmd_buf, cmd_len);
573                          cmd_len = 0;
634                        execute_command(cmd_buffer);
574                  }
575                  return ST_OK;
576          }
# Line 646 | Line 585 | uint8 T64Drive::Write(int channel, uint8
585  
586  
587   /*
588 < *  Execute command string
588 > *  Execute drive commands
589   */
590  
591 < void T64Drive::execute_command(char *command)
591 > // RENAME:new=old
592 > //        ^   ^
593 > // new_file   old_file
594 > void T64Drive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len)
595   {
596 <        switch (command[0]) {
597 <                case 'I':
598 <                        close_all_channels();
599 <                        set_error(ERR_OK);
600 <                        break;
659 <
660 <                case 'U':
661 <                        if ((command[1] & 0x0f) == 0x0a) {
662 <                                Reset();
663 <                        } else
664 <                                set_error(ERR_SYNTAX30);
665 <                        break;
666 <
667 <                case 'G':
668 <                        if (command[1] != ':')
669 <                                set_error(ERR_SYNTAX30);
670 <                        else
671 <                                cht64_cmd(&command[2]);
672 <                        break;
673 <
674 <                default:
675 <                        set_error(ERR_SYNTAX30);
596 >        // Check if destination file is already present
597 >        int num;
598 >        if (find_first_file(new_file, new_file_len, num)) {
599 >                set_error(ERR_FILEEXISTS);
600 >                return;
601          }
677 }
602  
603 +        // Check if source file is present
604 +        if (!find_first_file(old_file, old_file_len, num)) {
605 +                set_error(ERR_FILENOTFOUND);
606 +                return;
607 +        }
608  
609 < /*
610 < *  Execute 'G' command
682 < */
609 >        set_error(ERR_WRITEPROTECT);
610 > }
611  
612 < void T64Drive::cht64_cmd(char *t64name)
612 > // INITIALIZE
613 > void T64Drive::initialize_cmd(void)
614   {
686        char str[NAMEBUF_LENGTH];
687        char *p = str;
688
689        // Convert .t64 file name
690        for (int i=0; i<NAMEBUF_LENGTH && (*p++ = conv_from_64(*t64name++, false)); i++) ;
691
615          close_all_channels();
616 + }
617  
618 <        // G:. resets the .t64 file name to its original setting
619 <        if (str[0] == '.' && str[1] == 0)
620 <                open_close_t64_file(orig_t64_name);
697 <        else
698 <                open_close_t64_file(str);
699 <
700 <        if (the_file == NULL)
701 <                set_error(ERR_NOTREADY);
618 > // VALIDATE
619 > void T64Drive::validate_cmd(void)
620 > {
621   }
622  
623  
# Line 712 | Line 631 | void T64Drive::Reset(void)
631          cmd_len = 0;    
632          set_error(ERR_STARTUP);
633   }
715
716
717 /*
718 *  Conversion PETSCII->ASCII
719 */
720
721 uint8 T64Drive::conv_from_64(uint8 c, bool map_slash)
722 {
723        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
724                return c ^ 0x20;
725        if ((c >= 0xc1) && (c <= 0xda))
726                return c ^ 0x80;
727        if ((c == '/') && map_slash && ThePrefs.MapSlash)
728                return '\\';
729        return c;
730 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines