Move DMCP file operations to separate file.h / file.cc

This will be useful if we want to do more than just reading the on-line help.

Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
Christophe de Dinechin 2023-06-22 18:51:21 +02:00
parent 1d58abd64c
commit 39be6cc0c2
6 changed files with 315 additions and 223 deletions

View file

@ -99,6 +99,7 @@ CXX_SOURCES += \
src/dm42/sysmenu.cc \
src/dm42/main.cc \
src/input.cc \
src/file.cc \
src/stack.cc \
src/util.cc \
src/renderer.cc \

View file

@ -39,6 +39,7 @@ SOURCES += \
../src/util.cc \
../src/renderer.cc \
../src/input.cc \
../src/file.cc \
../src/stack.cc \
../src/settings.cc \
../src/object.cc \

150
src/file.cc Normal file
View file

@ -0,0 +1,150 @@
// ****************************************************************************
// file.cc DB48X project
// ****************************************************************************
//
// File Description:
//
// Abstract interface for the zany DMCP filesystem
//
//
//
//
//
//
//
//
// ****************************************************************************
// (C) 2023 Christophe de Dinechin <christophe@dinechin.org>
// This software is licensed under the terms outlined in LICENSE.txt
// ****************************************************************************
// This file is part of DB48X.
//
// DB48X is free software: you can redistribute it and/or modify
// it under the terms outlined in the LICENSE.txt file
//
// DB48X is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// ****************************************************************************
#include "file.h"
#include "recorder.h"
RECORDER(file, 16, "File operations");
RECORDER(file_error, 16, "File errors");
file::file()
// ----------------------------------------------------------------------------
// Construct a file object
// ----------------------------------------------------------------------------
: data()
{}
file::~file()
// ----------------------------------------------------------------------------
// Close the help file
// ----------------------------------------------------------------------------
{
close();
}
void file::open(cstring path)
// ----------------------------------------------------------------------------
// Open a help file
// ----------------------------------------------------------------------------
{
#if SIMULATOR
data = fopen(path, "r");
if (!data)
{
record(file_error, "Error %s opening %s", strerror(errno), path);
return;
}
#else
FRESULT ok = f_open(&data, path, FA_READ);
if (ok != FR_OK)
{
data.obj.objsize = 0;
return;
}
#endif // SIMULATOR
}
void file::close()
// ----------------------------------------------------------------------------
// Close the help file
// ----------------------------------------------------------------------------
{
if (valid())
fclose(data);
}
unicode file::get()
// ----------------------------------------------------------------------------
// Read UTF8 code at offset
// ----------------------------------------------------------------------------
{
unicode code = valid() ? fgetc(data) : unicode(EOF);
if (code == unicode(EOF))
return 0;
if (code & 0x80)
{
// Reference: Wikipedia UTF-8 description
if ((code & 0xE0) == 0xC0)
code = ((code & 0x1F) << 6)
| (fgetc(data) & 0x3F);
else if ((code & 0xF0) == 0xE0)
code = ((code & 0xF) << 12)
| ((fgetc(data) & 0x3F) << 6)
| (fgetc(data) & 0x3F);
else if ((code & 0xF8) == 0xF0)
code = ((code & 0xF) << 18)
| ((fgetc(data) & 0x3F) << 12)
| ((fgetc(data) & 0x3F) << 6)
| (fgetc(data) & 0x3F);
}
return code;
}
uint file::find(unicode cp)
// ----------------------------------------------------------------------------
// Find a given code point in file looking forward
// ----------------------------------------------------------------------------
// Return position right before code point, position file right after it
{
unicode c;
uint off;
do
{
off = ftell(data);
c = get();
} while (c && c != cp);
return off;
}
uint file::rfind(unicode cp)
// ----------------------------------------------------------------------------
// Find a given code point in file looking backward
// ----------------------------------------------------------------------------
// Return position right before code point, position file right after it
{
uint off = ftell(data);
unicode c;
do
{
if (off == 0)
break;
fseek(data, --off, SEEK_SET);
c = get();
}
while (c != cp);
return off;
}

152
src/file.h Normal file
View file

@ -0,0 +1,152 @@
#ifndef FILE_H
# define FILE_H
// ****************************************************************************
// file.h DB48X project
// ****************************************************************************
//
// File Description:
//
// Abstract the DMCP zany filesystem interface
//
//
//
//
//
//
//
//
// ****************************************************************************
// (C) 2023 Christophe de Dinechin <christophe@dinechin.org>
// This software is licensed under the terms outlined in LICENSE.txt
// ****************************************************************************
// This file is part of DB48X.
//
// DB48X is free software: you can redistribute it and/or modify
// it under the terms outlined in the LICENSE.txt file
//
// DB48X is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// ****************************************************************************
#include "dmcp.h"
#include "types.h"
#include <stdio.h>
struct file
// ----------------------------------------------------------------------------
// Direct access to the help file
// ----------------------------------------------------------------------------
{
file();
~file();
void open(cstring path);
bool valid();
void close();
unicode get();
unicode get(uint offset);
void seek(uint offset);
unicode peek();
uint position();
uint find(unicode cp);
uint rfind(unicode cp);
protected:
#if SIMULATOR
FILE *data;
#else
FIL data;
#endif
};
// ============================================================================
//
// DMCP wrappers
//
// ============================================================================
#ifndef SIMULATOR
#define ftell(f) f_tell(&f)
#define fseek(f,o,w) f_lseek(&f,o)
#define fclose(f) f_close(&f)
static inline int fgetc(FIL &f)
// ----------------------------------------------------------------------------
// Read one character from a file - Wrapper for DMCP filesystem
// ----------------------------------------------------------------------------
{
UINT br = 0;
char c = 0;
if (f_read(&f, &c, 1, &br) != FR_OK || br != 1)
return EOF;
return c;
}
#endif // SIMULATOR
// ============================================================================
//
// Inline functions for simple stuff
//
// ============================================================================
inline bool file::valid()
// ----------------------------------------------------------------------------
// Return true if the input file is OK
// ----------------------------------------------------------------------------
{
#if SIMULATOR
return data != 0;
#else
return f_size(&data) != 0;
#endif
}
inline void file::seek(uint off)
// ----------------------------------------------------------------------------
// Move the read position in the data file
// ----------------------------------------------------------------------------
{
fseek(data, off, SEEK_SET);
}
inline unicode file::peek()
// ----------------------------------------------------------------------------
// Look at what is as current position without moving it
// ----------------------------------------------------------------------------
{
uint off = ftell(data);
unicode result = get();
seek(off);
return result;
}
inline unicode file::get(uint off)
// ----------------------------------------------------------------------------
// Get code point at given offset
// ----------------------------------------------------------------------------
{
seek(off);
return get();
}
inline uint file::position()
// ----------------------------------------------------------------------------
// Return current position in help file
// ----------------------------------------------------------------------------
{
return ftell(data);
}
#endif // FILE_H

View file

@ -1175,192 +1175,6 @@ void input::draw_error()
}
input::file::file()
// ----------------------------------------------------------------------------
// Construct a file object
// ----------------------------------------------------------------------------
: data()
{}
input::file::~file()
// ----------------------------------------------------------------------------
// Close the help file
// ----------------------------------------------------------------------------
{
close();
}
void input::file::open(cstring path)
// ----------------------------------------------------------------------------
// Open a help file
// ----------------------------------------------------------------------------
{
#if SIMULATOR
data = fopen(path, "r");
if (!data)
{
record(help, "Error %s opening %s", strerror(errno), path);
return;
}
#else
FRESULT ok = f_open(&data, path, FA_READ);
if (ok != FR_OK)
{
data.obj.objsize = 0;
return;
}
#define ftell(f) f_tell(&f)
#define fseek(f,o,w) f_lseek(&f,o)
#define fclose(f) f_close(&f)
#endif // SIMULATOR
}
void input::file::close()
// ----------------------------------------------------------------------------
// Close the help file
// ----------------------------------------------------------------------------
{
if (valid())
fclose(data);
}
inline bool input::file::valid()
// ----------------------------------------------------------------------------
// Return true if the input file is OK
// ----------------------------------------------------------------------------
{
#if SIMULATOR
return data != 0;
#else
return f_size(&data) != 0;
#endif
}
#ifndef SIMULATOR
static inline int fgetc(FIL &f)
// ----------------------------------------------------------------------------
// Read one character from a file - Wrapper for DMCP filesystem
// ----------------------------------------------------------------------------
{
UINT br = 0;
char c = 0;
if (f_read(&f, &c, 1, &br) != FR_OK || br != 1)
return EOF;
return c;
}
#endif // SIMULATOR
unicode input::file::get()
// ----------------------------------------------------------------------------
// Read UTF8 code at offset
// ----------------------------------------------------------------------------
{
unicode code = valid() ? fgetc(data) : unicode(EOF);
if (code == unicode(EOF))
return 0;
if (code & 0x80)
{
// Reference: Wikipedia UTF-8 description
if ((code & 0xE0) == 0xC0)
code = ((code & 0x1F) << 6)
| (fgetc(data) & 0x3F);
else if ((code & 0xF0) == 0xE0)
code = ((code & 0xF) << 12)
| ((fgetc(data) & 0x3F) << 6)
| (fgetc(data) & 0x3F);
else if ((code & 0xF8) == 0xF0)
code = ((code & 0xF) << 18)
| ((fgetc(data) & 0x3F) << 12)
| ((fgetc(data) & 0x3F) << 6)
| (fgetc(data) & 0x3F);
}
return code;
}
inline void input::file::seek(uint off)
// ----------------------------------------------------------------------------
// Move the read position in the data file
// ----------------------------------------------------------------------------
{
fseek(data, off, SEEK_SET);
}
inline unicode input::file::peek()
// ----------------------------------------------------------------------------
// Look at what is as current position without moving it
// ----------------------------------------------------------------------------
{
uint off = ftell(data);
unicode result = get();
seek(off);
return result;
}
inline unicode input::file::get(uint off)
// ----------------------------------------------------------------------------
// Get code point at given offset
// ----------------------------------------------------------------------------
{
seek(off);
return get();
}
inline uint input::file::position()
// ----------------------------------------------------------------------------
// Return current position in help file
// ----------------------------------------------------------------------------
{
return ftell(data);
}
inline uint input::file::find(unicode cp)
// ----------------------------------------------------------------------------
// Find a given code point in file looking forward
// ----------------------------------------------------------------------------
// Return position right before code point, position file right after it
{
unicode c;
uint off;
do
{
off = ftell(data);
c = get();
} while (c && c != cp);
return off;
}
inline uint input::file::rfind(unicode cp)
// ----------------------------------------------------------------------------
// Find a given code point in file looking backward
// ----------------------------------------------------------------------------
// Return position right before code point, position file right after it
{
uint off = ftell(data);
unicode c;
do
{
if (off == 0)
break;
fseek(data, --off, SEEK_SET);
c = get();
}
while (c != cp);
return off;
}
void input::load_help(utf8 topic)
// ----------------------------------------------------------------------------

View file

@ -29,10 +29,11 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// ****************************************************************************
#include "dmcp.h"
#include "file.h"
#include "graphics.h"
#include "object.h"
#include "types.h"
#include "dmcp.h"
#include <string>
#include <vector>
@ -177,42 +178,15 @@ protected:
bool autoComplete : 1; // Menu is auto-complete
protected:
// Key mappings
object_p function[NUM_PLANES][NUM_KEYS];
cstring menu_label[NUM_PLANES][NUM_SOFTKEYS];
uint16_t menu_marker[NUM_PLANES][NUM_SOFTKEYS];
bool menu_marker_align[NUM_PLANES][NUM_SOFTKEYS];
static runtime &RT;
friend struct tests;
friend struct runtime;
protected:
struct file
// ------------------------------------------------------------------------
// Direct access to the help file
// ------------------------------------------------------------------------
{
file();
~file();
void open(cstring path);
bool valid();
void close();
unicode get();
unicode get(uint offset);
void seek(uint offset);
unicode peek();
uint position();
uint find(unicode cp);
uint rfind(unicode cp);
protected:
#ifdef SIMULATOR
FILE *data;
#else
FIL data;
#endif
} helpfile;
// Key mappings
object_p function[NUM_PLANES][NUM_KEYS];
cstring menu_label[NUM_PLANES][NUM_SOFTKEYS];
uint16_t menu_marker[NUM_PLANES][NUM_SOFTKEYS];
bool menu_marker_align[NUM_PLANES][NUM_SOFTKEYS];
file helpfile;
static runtime &RT;
friend struct tests;
friend struct runtime;
};