diff options
author | Daniel Serpell <daniel.serpell@gmail.com> | 2019-12-20 21:38:56 -0300 |
---|---|---|
committer | Daniel Serpell <daniel.serpell@gmail.com> | 2019-12-20 21:40:11 -0300 |
commit | a45af65ffcf4172726796b566b2e2a9c894ef390 (patch) | |
tree | d9d062e773c5413e058b7e891d41fea879521fd1 | |
parent | e3431dea05d3d9dc425953e9a73c38c13bd47852 (diff) | |
download | emu2-a45af65ffcf4172726796b566b2e2a9c894ef390.tar.gz |
Implement find-first and find-next FCB.
-rw-r--r-- | src/dos.c | 104 | ||||
-rw-r--r-- | src/dosnames.c | 27 | ||||
-rw-r--r-- | src/dosnames.h | 1 |
3 files changed, 121 insertions, 11 deletions
@@ -269,9 +269,20 @@ static void dos_open_file(int create) free(fname); } +static int get_ex_fcb(void) +{ + return cpuGetAddrDS(cpuGetDX()); +} + +static int get_fcb(void) +{ + int fcb = cpuGetAddrDS(cpuGetDX()); + return memory[fcb] == 255 ? fcb + 7 : fcb; +} + static int get_fcb_handle(void) { - return get16(0x18 + cpuGetAddrDS(cpuGetDX())); + return get16(0x18 + get_fcb()); } static void dos_show_fcb() @@ -298,7 +309,7 @@ static void dos_open_file_fcb(int create) cpuSetFlag(cpuFlag_CF); return; } - int fcb_addr = cpuGetAddrDS(cpuGetDX()); + int fcb_addr = get_fcb(); char *fname = dos_unix_path_fcb(fcb_addr, create); if(!fname) { @@ -352,7 +363,7 @@ static int dos_read_record_fcb(int addr, int update) if(!f) return 1; // no data read - int fcb = cpuGetAddrDS(cpuGetDX()); + int fcb = get_fcb(); unsigned rsize = get16(0x0E + fcb); unsigned pos = rsize * get32(0x21 + fcb); uint8_t *buf = getptr(addr, rsize); @@ -391,7 +402,7 @@ int dos_write_record_fcb(int addr, int update) if(!f) return 1; // no data write - int fcb = cpuGetAddrDS(cpuGetDX()); + int fcb = get_fcb(); unsigned rsize = get16(0x0E + fcb); unsigned pos = rsize * get32(0x21 + fcb); uint8_t *buf = getptr(addr, rsize); @@ -654,6 +665,83 @@ static void int21_4f(void) } } +static void dos_find_next_fcb(void) +{ + struct find_first_dta *p = get_find_first_dta(); + struct dos_file_list *d = p->find_first_ptr; + + if(!d || !p->find_first_ptr->unixname) + { + debug(debug_dos, "\t(end)\n"); + clear_find_first_dta(p); + cpuSetAX(0xFF); + } + else + { + debug(debug_dos, "\t'%s' ('%s')\n", d->dosname, d->unixname); + // Fills output FCB at DTA - use extended or normal depending on input + int ofcb = memory[get_ex_fcb()] == 0xFF ? dosDTA + 7 : dosDTA; + int pos = 1; + for(char *c = d->dosname; *c; c++) + { + if( *c != '.' ) + memory[ofcb+pos++] = *c; + else + while(pos < 9) + memory[ofcb+pos++] = ' '; + } + while(pos < 12) + memory[ofcb+pos++] = ' '; + if( strcmp("//", d->unixname) ) + { + // Get file info + uint32_t td = 0x10001; + uint8_t attr = 0x0; + uint32_t sz = 0; + struct stat st; + // Ignore errors. + if(0 == stat(d->unixname, &st)) + { + td = get_time_date(st.st_mtime); + attr = get_attributes(st.st_mode); + if(st.st_size & ~0x7FFFFFFF) + sz = 0x7FFFFFFF; + else + sz = st.st_size; + } + // Fills file size + memory[ofcb+0x0C] = attr; + put32(ofcb+0x17, td); + put32(ofcb+0x1D, sz); + // Fill drive letter + memory[ofcb] = memory[get_fcb()]; + } + p->find_first_ptr++; + cpuSetAX(0x00); + } +} + +static void dos_find_first_fcb(void) +{ + struct find_first_dta *p = get_find_first_dta(); + // Gets all directory entries + if(p->find_first_list) + dos_free_file_list(p->find_first_list); + + int efcb = get_ex_fcb(); + if( memory[efcb] == 0xFF && memory[efcb+6] == 0x08 ) + { + p->find_first_list = calloc(2, sizeof(struct dos_file_list)); + p->find_first_list[0].unixname = strdup("//"); + memcpy(p->find_first_list[0].dosname, "DISK LABEL", 11); + p->find_first_list[1].unixname = 0; + } + else + p->find_first_list = dos_find_first_file_fcb(get_fcb()); + p->find_first_ptr = p->find_first_list; + return dos_find_next_fcb(); +} + // DOS int 21, ah=57 static void int21_57(void) { @@ -952,6 +1040,12 @@ void int21() dos_show_fcb(); cpuSetAX(dos_close_file(get_fcb_handle()) ? 0xFF : 0); break; + case 0x11: // FIND FIRST FILE USING FCB + dos_find_first_fcb(); + break; + case 0x12: // FIND NEXT FILE USING FCB + dos_find_next_fcb(); + break; case 0x14: // SEQUENTIAL READ USING FCB dos_show_fcb(); cpuSetAX(dos_read_record_fcb(dosDTA, 1)); @@ -991,7 +1085,7 @@ void int21() case 0x27: // BLOCK READ FROM FCB case 0x28: // BLOCK WRITE TO FCB { - int fcb = cpuGetAddrDS(cpuGetDX()); + int fcb = get_fcb(); unsigned count = cpuGetCX(); unsigned rsize = get16(0x0E + fcb); unsigned e = 0; diff --git a/src/dosnames.c b/src/dosnames.c index ffa4634..d0aac31 100644 --- a/src/dosnames.c +++ b/src/dosnames.c @@ -559,14 +559,20 @@ char *dos_unix_path_fcb(int addr, int force) opos = strlen(path); for(int pos=0; pos<8 && opos<63; pos++, opos++) - if( 0 == (path[opos] = dos_valid_char(fcb_name[pos])) ) + if( fcb_name[pos] == '?' ) + path[opos] = '?'; + else if( 0 == (path[opos] = dos_valid_char(fcb_name[pos])) ) break; - if(opos<63 && dos_valid_char(fcb_name[8])) + if(opos<63 && (dos_valid_char(fcb_name[8]) || fcb_name[8] == '?') ) path[opos++] = '.'; for(int pos=8; pos<11 && opos<63; pos++, opos++) - if( 0 == (path[opos] = dos_valid_char(fcb_name[pos])) ) + if( fcb_name[pos] == '?' ) + path[opos] = '?'; + else if( 0 == (path[opos] = dos_valid_char(fcb_name[pos])) ) break; path[opos] = 0; + + debug(debug_dos, "\ttemp name '%s'\n", path); // Get UNIX base path: const char *base = get_base_path(drive); // Adds CWD if path is not absolute @@ -576,10 +582,9 @@ char *dos_unix_path_fcb(int addr, int force) //////////////////////////////////////////////////////////////////// // Implements FindFirstFile -struct dos_file_list *dos_find_first_file(int addr) +// NOTE: this frees fspec before return +static struct dos_file_list *find_first_file(char *fspec) { - // Convert the filespec to a unix path - char *fspec = dos_unix_path(addr, 1); // Now, separate the path to the spec char *glob, *unixpath, *p = rindex(fspec, '/'); if(!p) @@ -601,3 +606,13 @@ struct dos_file_list *dos_find_first_file(int addr) return dirEntries; } + +struct dos_file_list *dos_find_first_file(int addr) +{ + return find_first_file(dos_unix_path(addr, 1)); +} + +struct dos_file_list *dos_find_first_file_fcb(int addr) +{ + return find_first_file(dos_unix_path_fcb(addr, 1)); +} diff --git a/src/dosnames.h b/src/dosnames.h index 38362e6..e7181ed 100644 --- a/src/dosnames.h +++ b/src/dosnames.h @@ -40,6 +40,7 @@ struct dos_file_list // Returns a list with filenames compatibles with the DOS filespec, as pairs // The list will be deleted at the next call struct dos_file_list *dos_find_first_file(int addr); +struct dos_file_list *dos_find_first_file_fcb(int addr); // Frees a fileList. void dos_free_file_list(struct dos_file_list *dl); |