00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "sysdeps.h"
00024
00025 #include "1541fs.h"
00026 #include "IEC.h"
00027 #include "main.h"
00028 #include "Prefs.h"
00029
00030 #ifdef __riscos__
00031 #include "ROlib.h"
00032 #endif
00033
00034
00035
00036 enum {
00037 FMODE_READ, FMODE_WRITE, FMODE_APPEND
00038 };
00039
00040
00041 enum {
00042 FTYPE_PRG, FTYPE_SEQ
00043 };
00044
00045
00046 static bool match(char *p, char *n);
00047
00048
00049
00050
00051
00052
00053 FSDrive::FSDrive(IEC *iec, char *path) : Drive(iec)
00054 {
00055 __CHECK_NULL(iec);
00056 __CHECK_NULL(path);
00057
00058 strcpy(orig_dir_path, path);
00059 dir_path[0] = 0;
00060
00061 if (change_dir(orig_dir_path)) {
00062 for (int i=0; i<16; i++)
00063 file[i] = NULL;
00064
00065 Reset();
00066
00067 Ready = true;
00068 }
00069
00070 CTOR(FSDrive);
00071
00072 }
00073
00074
00075
00076
00077
00078
00079 FSDrive::~FSDrive()
00080 {
00081 if (Ready) {
00082 close_all_channels();
00083 Ready = false;
00084 }
00085
00086 DTOR(FSDrive);
00087 }
00088
00089
00090
00091
00092
00093
00094 bool FSDrive::change_dir(char *dirpath)
00095 {
00096 #ifndef __riscos__
00097 DIR *dir;
00098
00099 if ((dir = opendir(dirpath)) != NULL) {
00100 closedir(dir);
00101 strcpy(dir_path, dirpath);
00102 strncpy(dir_title, dir_path, 16);
00103 return true;
00104 } else
00105 return false;
00106 #else
00107 int Info[4];
00108
00109 if ((ReadCatalogueInfo(dirpath,Info) & 2) != 0)
00110 {
00111 strcpy(dir_path, dirpath);
00112 strncpy(dir_title, dir_path, 16);
00113 return true;
00114 }
00115 else
00116 {
00117 return false;
00118 }
00119 #endif
00120 }
00121
00122
00123
00124
00125
00126
00127 uint8 FSDrive::Open(int channel, char *filename)
00128 {
00129 set_error(ERR_OK);
00130
00131
00132 if (channel == 15) {
00133 execute_command(filename);
00134 return ST_OK;
00135 }
00136
00137
00138 if (file[channel]) {
00139 fclose(file[channel]);
00140 file[channel] = NULL;
00141 }
00142
00143 if (filename[0] == '$')
00144 return open_directory(channel, filename+1);
00145
00146 if (filename[0] == '#') {
00147 set_error(ERR_NOCHANNEL);
00148 return ST_OK;
00149 }
00150
00151 return open_file(channel, filename);
00152 }
00153
00154
00155
00156
00157
00158
00159 uint8 FSDrive::open_file(int channel, char *filename)
00160 {
00161 char plainname[NAMEBUF_LENGTH];
00162 int filemode = FMODE_READ;
00163 int filetype = FTYPE_PRG;
00164 bool wildflag = false;
00165 char *mode = "rb";
00166
00167 convert_filename(filename, plainname, &filemode, &filetype, &wildflag);
00168
00169
00170 if (!channel) {
00171 filemode = FMODE_READ;
00172 filetype = FTYPE_PRG;
00173 }
00174 if (channel == 1) {
00175 filemode = FMODE_WRITE;
00176 filetype = FTYPE_PRG;
00177 }
00178
00179
00180 if (wildflag) {
00181 if (filemode != FMODE_READ) {
00182 set_error(ERR_SYNTAX33);
00183 return ST_OK;
00184 }
00185 find_first_file(plainname);
00186 }
00187
00188
00189 switch (filemode) {
00190 case FMODE_READ:
00191 mode = "rb";
00192 break;
00193 case FMODE_WRITE:
00194 mode = "wb";
00195 break;
00196 case FMODE_APPEND:
00197 mode = "ab";
00198 break;
00199 }
00200
00201
00202 #ifndef __riscos__
00203 if (chdir_cmd(dir_path))
00204 set_error(ERR_NOTREADY);
00205 else if ((file[channel] = fopen(plainname, mode)) != NULL) {
00206 if (filemode == FMODE_READ)
00207 read_char[channel] = fgetc(file[channel]);
00208 } else
00209 set_error(ERR_FILENOTFOUND);
00210 chdir_cmd(AppDirPath);
00211 #else
00212 {
00213 char fullname[NAMEBUF_LENGTH];
00214
00215
00216 sprintf(fullname,"%s.%s",dir_path,plainname);
00217 if ((file[channel] = fopen(fullname, mode)) != NULL)
00218 {
00219 if (filemode == FMODE_READ)
00220 {
00221 read_char[channel] = fgetc(file[channel]);
00222 }
00223 }
00224 else
00225 {
00226 set_error(ERR_FILENOTFOUND);
00227 }
00228 }
00229 #endif
00230
00231 return ST_OK;
00232 }
00233
00234
00235
00236
00237
00238
00239 void FSDrive::convert_filename(char *srcname, char *destname, int *filemode, int *filetype, bool *wildflag)
00240 {
00241 char *p, *q;
00242 int i;
00243
00244
00245 if ((p = strchr(srcname, ':')) != NULL)
00246 p++;
00247 else
00248 p = srcname;
00249
00250
00251 q = destname;
00252 for (i=0; i<NAMEBUF_LENGTH && (*q++ = conv_from_64(*p++, true)); i++) ;
00253
00254
00255 p = destname;
00256 while ((p = strchr(p, ',')) != NULL) {
00257
00258
00259 *p++ = 0;
00260
00261 switch (*p) {
00262 case 'p':
00263 *filetype = FTYPE_PRG;
00264 break;
00265 case 's':
00266 *filetype = FTYPE_SEQ;
00267 break;
00268 case 'r':
00269 *filemode = FMODE_READ;
00270 break;
00271 case 'w':
00272 *filemode = FMODE_WRITE;
00273 break;
00274 case 'a':
00275 *filemode = FMODE_APPEND;
00276 break;
00277 }
00278 }
00279
00280
00281 *wildflag = (strchr(destname, '?') != NULL) || (strchr(destname, '*') != NULL);
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 static bool match(char *p, char *n)
00291 {
00292 if (!*p)
00293 return true;
00294
00295 do {
00296 if (*p == '*')
00297 return true;
00298 if ((*p != *n) && (*p != '?'))
00299 return false;
00300 p++; n++;
00301 } while (*p);
00302
00303 return !*n;
00304 }
00305
00306 void FSDrive::find_first_file(char *name)
00307 {
00308 #ifndef __riscos__
00309 DIR *dir;
00310 struct dirent *de;
00311
00312
00313 if ((dir = opendir(dir_path)) == NULL)
00314 return;
00315 de = readdir(dir);
00316 while (de && (0 == strcmp(".", de->d_name) || 0 == strcmp("..", de->d_name)))
00317 de = readdir(dir);
00318
00319 while (de) {
00320
00321
00322 if (match(name, de->d_name)) {
00323 strncpy(name, de->d_name, NAMEBUF_LENGTH);
00324 closedir(dir);
00325 return;
00326 }
00327
00328
00329 de = readdir(dir);
00330 }
00331
00332 closedir(dir);
00333 #else
00334 dir_env de;
00335 char Buffer[NAMEBUF_LENGTH];
00336
00337 de.offset = 0; de.buffsize = NAMEBUF_LENGTH; de.match = name;
00338 do
00339 {
00340 de.readno = 1;
00341 if (ReadDirName(dir_path,Buffer,&de) != NULL) {de.offset = -1;}
00342 else if (de.offset != -1)
00343 {
00344 if (match(name,Buffer))
00345 {
00346 strncpy(name, Buffer, NAMEBUF_LENGTH);
00347 return;
00348 }
00349 }
00350 }
00351 while (de.offset != -1);
00352 #endif
00353 }
00354
00355
00356
00357
00358
00359
00360 uint8 FSDrive::open_directory(int channel, char *filename)
00361 {
00362 char buf[] = "\001\004\001\001\0\0\022\042 \042 00 2A";
00363 char str[NAMEBUF_LENGTH];
00364 char pattern[NAMEBUF_LENGTH];
00365 char *p, *q;
00366 int i;
00367 int filemode;
00368 int filetype;
00369 bool wildflag;
00370
00371 #ifndef __riscos__
00372 DIR *dir;
00373 struct dirent *de;
00374 struct stat statbuf;
00375
00376
00377 if (filename[0] == '0' && filename[1] == 0)
00378 filename += 1;
00379
00380
00381 convert_filename(filename, pattern, &filemode, &filetype, &wildflag);
00382
00383
00384 if ((dir = opendir(dir_path)) == NULL) {
00385 set_error(ERR_NOTREADY);
00386 return ST_OK;
00387 }
00388 de = readdir(dir);
00389 while (de && (0 == strcmp(".", de->d_name) || 0 == strcmp("..", de->d_name)))
00390 de = readdir(dir);
00391
00392
00393 if ((file[channel] = tmpfile()) == NULL) {
00394 closedir(dir);
00395 return ST_OK;
00396 }
00397
00398
00399 p = &buf[8];
00400 for (i=0; i<16 && dir_title[i]; i++)
00401 *p++ = conv_to_64(dir_title[i], false);
00402 fwrite(buf, 1, 32, file[channel]);
00403
00404
00405 while (de) {
00406
00407
00408 if (match(pattern, de->d_name)) {
00409
00410
00411 chdir_cmd(dir_path);
00412 stat(de->d_name, &statbuf);
00413 chdir_cmd(AppDirPath);
00414
00415
00416 memset(buf, ' ', 31);
00417 buf[31] = 0;
00418
00419 p = buf;
00420 *p++ = 0x01;
00421 *p++ = 0x01;
00422
00423
00424 i = (statbuf.st_size + 254) / 254;
00425 *p++ = i & 0xff;
00426 *p++ = (i >> 8) & 0xff;
00427
00428 p++;
00429 if (i < 10) p++;
00430 if (i < 100) p++;
00431
00432
00433 strcpy(str, de->d_name);
00434 *p++ = '\"';
00435 q = p;
00436 for (i=0; i<16 && str[i]; i++)
00437 *q++ = conv_to_64(str[i], true);
00438 *q++ = '\"';
00439 p += 18;
00440
00441
00442 if (S_ISDIR(statbuf.st_mode)) {
00443 *p++ = 'D';
00444 *p++ = 'I';
00445 *p++ = 'R';
00446 } else {
00447 *p++ = 'P';
00448 *p++ = 'R';
00449 *p++ = 'G';
00450 }
00451
00452
00453 fwrite(buf, 1, 32, file[channel]);
00454 }
00455
00456
00457 de = readdir(dir);
00458 }
00459 #else
00460 dir_full_info di;
00461 dir_env de;
00462
00463
00464 if ((filename[0] == '0') && (filename[1] == 0)) {filename++;}
00465
00466 strcpy(pattern,dir_path);
00467 convert_filename(filename, pattern + strlen(pattern), &filemode, &filetype, &wildflag);
00468
00469
00470 DeleteFile(RO_TEMPFILE);
00471 if ((file[channel] = fopen(RO_TEMPFILE,"wb+")) == NULL)
00472 {
00473 return(ST_OK);
00474 }
00475 de.offset = 0; de.buffsize = NAMEBUF_LENGTH; de.match = filename;
00476
00477
00478 p = &buf[8];
00479 for (i=0; i<16 && dir_title[i]; i++)
00480 *p++ = conv_to_64(dir_title[i], false);
00481 fwrite(buf, 1, 32, file[channel]);
00482
00483 do
00484 {
00485 de.readno = 1;
00486 if (ReadDirNameInfo(pattern,&di,&de) != NULL) {de.offset = -1;}
00487 else if (de.offset != -1)
00488 {
00489 memset(buf,' ',31); buf[31] = 0;
00490 p = buf; *p++ = 0x01; *p++ = 0x01;
00491 i = (di.length + 254) / 254; *p++ = i & 0xff; *p++ = (i>>8) & 0xff;
00492 p++;
00493 if (i < 10) {*p++ = ' ';}
00494 if (i < 100) {*p++ = ' ';}
00495 strcpy(str, di.name);
00496 *p++ = '\"'; q = p;
00497 for (i=0; (i<16 && str[i]); i++)
00498 {
00499 *q++ = conv_to_64(str[i], true);
00500 }
00501 *q++ = '\"'; p += 18;
00502 if ((di.otype & 2) == 0)
00503 {
00504 *p++ = 'P'; *p++ = 'R'; *p++ = 'G';
00505 }
00506 else
00507 {
00508 *p++ = 'D'; *p++ = 'I'; *p++ = 'R';
00509 }
00510 fwrite(buf, 1, 32, file[channel]);
00511 }
00512 }
00513 while (de.offset != -1);
00514 #endif
00515
00516
00517 fwrite("\001\001\0\0BLOCKS FREE. \0\0", 1, 32, file[channel]);
00518
00519
00520 rewind(file[channel]);
00521 read_char[channel] = fgetc(file[channel]);
00522
00523 #ifndef __riscos
00524
00525 closedir(dir);
00526 #endif
00527
00528 return ST_OK;
00529 }
00530
00531
00532
00533
00534
00535
00536 uint8 FSDrive::Close(int channel)
00537 {
00538 if (channel == 15) {
00539 close_all_channels();
00540 return ST_OK;
00541 }
00542
00543 if (file[channel]) {
00544 fclose(file[channel]);
00545 file[channel] = NULL;
00546 }
00547
00548 return ST_OK;
00549 }
00550
00551
00552
00553
00554
00555
00556 void FSDrive::close_all_channels(void)
00557 {
00558 for (int i=0; i<15; i++)
00559 Close(i);
00560
00561 cmd_len = 0;
00562 }
00563
00564
00565
00566
00567
00568
00569 uint8 FSDrive::Read(int channel, uint8 *byte)
00570 {
00571 int c;
00572
00573
00574 if (channel == 15) {
00575 *byte = *error_ptr++;
00576
00577 if (*byte != '\r')
00578 return ST_OK;
00579 else {
00580 set_error(ERR_OK);
00581 return ST_EOF;
00582 }
00583 }
00584
00585 if (!file[channel]) return ST_READ_TIMEOUT;
00586
00587
00588 *byte = read_char[channel];
00589 c = fgetc(file[channel]);
00590 if (c == EOF)
00591 return ST_EOF;
00592 else {
00593 read_char[channel] = c;
00594 return ST_OK;
00595 }
00596 }
00597
00598
00599
00600
00601
00602
00603 uint8 FSDrive::Write(int channel, uint8 byte, bool eoi)
00604 {
00605
00606 if (channel == 15) {
00607 if (cmd_len >= 40)
00608 return ST_TIMEOUT;
00609
00610 cmd_buffer[cmd_len++] = byte;
00611
00612 if (eoi) {
00613 cmd_buffer[cmd_len] = 0;
00614 cmd_len = 0;
00615 execute_command(cmd_buffer);
00616 }
00617 return ST_OK;
00618 }
00619
00620 if (!file[channel]) {
00621 set_error(ERR_FILENOTOPEN);
00622 return ST_TIMEOUT;
00623 }
00624
00625 if (fputc(byte, file[channel]) == EOF) {
00626 set_error(ERR_WRITEERROR);
00627 return ST_TIMEOUT;
00628 }
00629
00630 return ST_OK;
00631 }
00632
00633
00634
00635
00636
00637
00638 void FSDrive::execute_command(char *command)
00639 {
00640 switch (command[0]) {
00641 case 'I':
00642 close_all_channels();
00643 set_error(ERR_OK);
00644 break;
00645
00646 case 'U':
00647 if ((command[1] & 0x0f) == 0x0a) {
00648 Reset();
00649 } else
00650 set_error(ERR_SYNTAX30);
00651 break;
00652
00653 case 'G':
00654 if (command[1] != ':')
00655 set_error(ERR_SYNTAX30);
00656 else
00657 chdir_cmd(&command[2]);
00658 break;
00659
00660 default:
00661 set_error(ERR_SYNTAX30);
00662 }
00663 }
00664
00665
00666
00667
00668
00669
00670 int FSDrive::chdir_cmd(char *dirpath)
00671 {
00672 char str[NAMEBUF_LENGTH];
00673 char *p = str;
00674
00675 close_all_channels();
00676
00677
00678 if (dirpath[0] == '.' && dirpath[1] == 0) {
00679 change_dir(orig_dir_path);
00680 } else {
00681
00682
00683 for (int i=0; i<NAMEBUF_LENGTH && (*p++ = conv_from_64(*dirpath++, false)); i++) ;
00684
00685 if (!change_dir(str))
00686 {
00687 set_error(ERR_NOTREADY);
00688 return 1;
00689 }
00690 }
00691 return 0;
00692 }
00693
00694
00695
00696
00697
00698
00699 void FSDrive::Reset(void)
00700 {
00701 close_all_channels();
00702 cmd_len = 0;
00703 set_error(ERR_STARTUP);
00704
00705 ELOG1(_L8("FS drive reset\n"));
00706 }
00707
00708
00709
00710
00711
00712
00713 uint8 FSDrive::conv_from_64(uint8 c, bool map_slash)
00714 {
00715 if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
00716 return c ^ 0x20;
00717 if ((c >= 0xc1) && (c <= 0xda))
00718 return c ^ 0x80;
00719 if ((c == '/') && map_slash)
00720 #ifdef __riscos__
00721 return '.';
00722 if (c == '.') {return('_');}
00723 #else
00724 return '\\';
00725 #endif
00726 return c;
00727 }
00728
00729
00730
00731
00732
00733
00734 uint8 FSDrive::conv_to_64(uint8 c, bool map_slash)
00735 {
00736 if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
00737 return c ^ 0x20;
00738 #ifdef __riscos__
00739 if ((c == '.') && map_slash && ThePrefs.MapSlash)
00740 #else
00741 if ((c == '\\') && map_slash)
00742 #endif
00743 return '/';
00744 #ifdef __riscos__
00745 if (c == '_') {return('.');}
00746 #endif
00747 return c;
00748 }