Bugfix the CP/M FCB parser, and add a test for it.

This commit is contained in:
David Given 2019-06-17 00:41:49 +02:00
parent 6531850462
commit 402468f6fd
4 changed files with 105 additions and 45 deletions

View file

@ -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;

View file

@ -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" },
} }

View 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();
}

View file

@ -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"