Bugfix the CP/M FCB parser, and add a test for it.
This commit is contained in:
parent
6531850462
commit
402468f6fd
|
@ -1,71 +1,63 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <cpm.h>
|
#include <cpm.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "cpmsys.h"
|
#include "cpmsys.h"
|
||||||
|
|
||||||
|
static const char* fill(uint8_t* dest, const char* src, int len)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char c = toupper(*src);
|
||||||
|
if (!c || (c == '.'))
|
||||||
|
c = ' ';
|
||||||
|
else if (c == '*')
|
||||||
|
c = '?';
|
||||||
|
else
|
||||||
|
src++;
|
||||||
|
*dest++ = c;
|
||||||
|
}
|
||||||
|
while (--len);
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t cpm_parse_filename(FCB* fcb, const char* filename)
|
uint8_t cpm_parse_filename(FCB* fcb, const char* filename)
|
||||||
{
|
{
|
||||||
uint8_t user = cpm_get_user();
|
uint8_t user = cpm_get_user();
|
||||||
|
char c;
|
||||||
|
|
||||||
memset(fcb, 0, sizeof(FCB));
|
memset(fcb, 0, sizeof(FCB));
|
||||||
memset(fcb->f, ' ', sizeof(fcb->f));
|
memset(fcb->f, ' ', sizeof(fcb->f));
|
||||||
|
|
||||||
if (strchr(filename, ':'))
|
|
||||||
{
|
{
|
||||||
char c = *filename++;
|
const char* colon = strchr(filename, ':');
|
||||||
if (isdigit(c))
|
if (colon)
|
||||||
{
|
{
|
||||||
user = c - '0';
|
|
||||||
c = *filename++;
|
c = *filename++;
|
||||||
if (isdigit(c))
|
if (isdigit(c))
|
||||||
{
|
{
|
||||||
user = (user*10) + (c - '0');
|
user = strtol(filename-1, &filename, 10);
|
||||||
|
c = *filename++;
|
||||||
|
}
|
||||||
|
c = toupper(c);
|
||||||
|
if (isalpha(c))
|
||||||
|
{
|
||||||
|
fcb->dr = c - '@';
|
||||||
c = *filename++;
|
c = *filename++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
c = toupper(c);
|
|
||||||
if (isalpha(c))
|
|
||||||
{
|
|
||||||
fcb->dr = c - '@';
|
|
||||||
c = *filename++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (c != ':')
|
filename = colon + 1;
|
||||||
c = *filename++;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read filename part. */
|
/* Read filename part. */
|
||||||
|
|
||||||
{
|
filename = fill(&fcb->f[0], filename, 8);
|
||||||
uint8_t i = 8;
|
filename = strchr(filename, '.');
|
||||||
uint8_t* p = &fcb->f[0];
|
if (filename)
|
||||||
while (i--)
|
fill(&fcb->f[8], filename+1, 3);
|
||||||
{
|
|
||||||
char c = toupper(*filename++);
|
|
||||||
if (c == '.')
|
|
||||||
break;
|
|
||||||
if (!c)
|
|
||||||
goto exit;
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read extension part. */
|
|
||||||
|
|
||||||
{
|
|
||||||
uint8_t i = 3;
|
|
||||||
uint8_t* p = &fcb->f[8];
|
|
||||||
while (i--)
|
|
||||||
{
|
|
||||||
char c = toupper(*filename++);
|
|
||||||
if (!c)
|
|
||||||
goto exit;
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
if (fcb->dr == 0)
|
if (fcb->dr == 0)
|
||||||
fcb->dr = cpm_get_current_drive() + 1;
|
fcb->dr = cpm_get_current_drive() + 1;
|
||||||
return user;
|
return user;
|
||||||
|
|
|
@ -4,5 +4,6 @@ plat_testsuite {
|
||||||
name = "tests",
|
name = "tests",
|
||||||
plat = "cpm",
|
plat = "cpm",
|
||||||
method = "plat/cpm/emu+emu",
|
method = "plat/cpm/emu+emu",
|
||||||
skipsets = {"floats"},
|
skipsets = {"floats"},
|
||||||
|
tests = { "./*.c" },
|
||||||
}
|
}
|
||||||
|
|
66
plat/cpm/tests/parsefcb_c.c
Normal file
66
plat/cpm/tests/parsefcb_c.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <cpm.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
struct testcase
|
||||||
|
{
|
||||||
|
const char* input;
|
||||||
|
uint8_t drive;
|
||||||
|
uint8_t user;
|
||||||
|
const char filename[11];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct testcase tests[] =
|
||||||
|
{
|
||||||
|
{ "12345678.ABC", 'A', 0, "12345678ABC" },
|
||||||
|
{ "12345678.A", 'A', 0, "12345678A " },
|
||||||
|
{ "12345678", 'A', 0, "12345678 " },
|
||||||
|
{ "1", 'A', 0, "1 " },
|
||||||
|
{ ".X", 'A', 0, " X " },
|
||||||
|
|
||||||
|
{ "B:FOO", 'B', 0, "FOO " },
|
||||||
|
{ "Z:FOO", 'Z', 0, "FOO " },
|
||||||
|
{ "1Z:FOO", 'Z', 1, "FOO " },
|
||||||
|
{ "23Z:FOO", 'Z', 23, "FOO " },
|
||||||
|
|
||||||
|
{ "*.*", 'A', 0, "???????????" },
|
||||||
|
{ "FOO*.*", 'A', 0, "FOO????????" },
|
||||||
|
{ "FOO*", 'A', 0, "FOO????? " },
|
||||||
|
{ "FOO.*", 'A', 0, "FOO ???" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int failed = 0;
|
||||||
|
|
||||||
|
static void do_test(int i, struct testcase* test)
|
||||||
|
{
|
||||||
|
static FCB fcb;
|
||||||
|
uint8_t got_user = cpm_parse_filename(&fcb, test->input);
|
||||||
|
|
||||||
|
if ((got_user == test->user)
|
||||||
|
&& (fcb.dr == (test->drive - '@'))
|
||||||
|
&& (memcmp(fcb.f, test->filename, 11) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("Want: %s -> %d%c:'%.11s' but got %d%c:'%.11s'\n",
|
||||||
|
test->input,
|
||||||
|
test->user, test->drive, test->filename,
|
||||||
|
got_user, fcb.dr+'@', fcb.f);
|
||||||
|
|
||||||
|
failed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
failed = 0;
|
||||||
|
cpm_select_drive(0); /* A: */
|
||||||
|
cpm_set_user(0);
|
||||||
|
|
||||||
|
for (i=0; i<sizeof(tests)/sizeof(*tests); i++)
|
||||||
|
do_test(i, &tests[i]);
|
||||||
|
|
||||||
|
if (failed)
|
||||||
|
fail(0);
|
||||||
|
finished();
|
||||||
|
}
|
|
@ -6,11 +6,12 @@ definerule("plat_testsuite",
|
||||||
method = { type="string" },
|
method = { type="string" },
|
||||||
sets = { type="table", default={"core", "b", "bugs", "m2", "floats"}},
|
sets = { type="table", default={"core", "b", "bugs", "m2", "floats"}},
|
||||||
skipsets = { type="table", default={}},
|
skipsets = { type="table", default={}},
|
||||||
|
tests = { type="targets", default={} },
|
||||||
},
|
},
|
||||||
function(e)
|
function(e)
|
||||||
-- Remember this is executed from the caller's directory; local
|
-- Remember this is executed from the caller's directory; local
|
||||||
-- target names will resolve there.
|
-- target names will resolve there.
|
||||||
local testfiles = {}
|
local testfiles = e.tests
|
||||||
local skipsets = {}
|
local skipsets = {}
|
||||||
for _, set in ipairs(e.skipsets) do
|
for _, set in ipairs(e.skipsets) do
|
||||||
skipsets[set] = true
|
skipsets[set] = true
|
||||||
|
@ -39,7 +40,7 @@ definerule("plat_testsuite",
|
||||||
|
|
||||||
local tests = {}
|
local tests = {}
|
||||||
for _, f in ipairs(testfiles) do
|
for _, f in ipairs(testfiles) do
|
||||||
local fs = replace(basename(f), "%.[^.]+$", "")
|
local fs = replace(basename(filenamesof(f)[1]), "%.[^.]+$", "")
|
||||||
local _, _, lang = fs:find("_([^_]+)$")
|
local _, _, lang = fs:find("_([^_]+)$")
|
||||||
if not lang then
|
if not lang then
|
||||||
lang = "e"
|
lang = "e"
|
||||||
|
|
Loading…
Reference in a new issue