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 <stdlib.h>
#include <cpm.h>
#include <string.h>
#include <ctype.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 user = cpm_get_user();
char c;
memset(fcb, 0, sizeof(FCB));
memset(fcb->f, ' ', sizeof(fcb->f));
if (strchr(filename, ':'))
{
char c = *filename++;
if (isdigit(c))
const char* colon = strchr(filename, ':');
if (colon)
{
user = c - '0';
c = *filename++;
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 = toupper(c);
if (isalpha(c))
{
fcb->dr = c - '@';
c = *filename++;
}
while (c != ':')
c = *filename++;
filename = colon + 1;
}
}
/* Read filename part. */
{
uint8_t i = 8;
uint8_t* p = &fcb->f[0];
while (i--)
{
char c = toupper(*filename++);
if (c == '.')
break;
if (!c)
goto exit;
*p++ = c;
}
}
filename = fill(&fcb->f[0], filename, 8);
filename = strchr(filename, '.');
if (filename)
fill(&fcb->f[8], filename+1, 3);
/* 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)
fcb->dr = cpm_get_current_drive() + 1;
return user;

View file

@ -4,5 +4,6 @@ plat_testsuite {
name = "tests",
plat = "cpm",
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" },
sets = { type="table", default={"core", "b", "bugs", "m2", "floats"}},
skipsets = { type="table", default={}},
tests = { type="targets", default={} },
},
function(e)
-- Remember this is executed from the caller's directory; local
-- target names will resolve there.
local testfiles = {}
local testfiles = e.tests
local skipsets = {}
for _, set in ipairs(e.skipsets) do
skipsets[set] = true
@ -39,7 +40,7 @@ definerule("plat_testsuite",
local tests = {}
for _, f in ipairs(testfiles) do
local fs = replace(basename(f), "%.[^.]+$", "")
local fs = replace(basename(filenamesof(f)[1]), "%.[^.]+$", "")
local _, _, lang = fs:find("_([^_]+)$")
if not lang then
lang = "e"