Read new .cfg file, update drive structure (#949)
This commit is contained in:
9
ide.cpp
9
ide.cpp
@@ -13,6 +13,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "support/x86/x86.h"
|
||||
#include "support/vhd/vhdcfg.h"
|
||||
#include "support/minimig/minimig_hdd.h"
|
||||
#include "support/minimig/minimig_config.h"
|
||||
#include "spi.h"
|
||||
@@ -106,6 +107,7 @@ int ide_img_mount(fileTYPE *f, const char *name, int rw)
|
||||
writable = rw && FileCanWrite(name);
|
||||
ret = FileOpenEx(f, name, writable ? (O_RDWR | O_SYNC) : O_RDONLY);
|
||||
if (!ret) printf("Failed to open file %s\n", name);
|
||||
else strcpy(f->path, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,7 +469,12 @@ void ide_img_set(uint32_t drvnum, fileTYPE *f, int cd, int sectors, int heads, i
|
||||
{
|
||||
if (drive->present)
|
||||
{
|
||||
ide_set_geometry(drive, sectors, heads);
|
||||
if (!drive->chd_f)
|
||||
{
|
||||
if (parse_vhd_config(drive)) ide_set_geometry(drive, sectors, heads);
|
||||
else ide_set_geometry(drive, drive->spt, drive->heads);
|
||||
}
|
||||
else ide_set_geometry(drive, sectors, heads);
|
||||
if (offset && drive->cylinders < 65535) drive->cylinders++;
|
||||
drive->offset = offset;
|
||||
drive->type = type;
|
||||
|
||||
15
support/vhd/vhdcfg.h
Normal file
15
support/vhd/vhdcfg.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef VHD_CFG_H
|
||||
#define VHD_CFG_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "ide.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VHD_NOERROR = 0, VHD_NO_CONFIG, VHD_INVALID_CONFIG, VHD_INVALID_SIZE, VHD_MISSING_CONFIG
|
||||
} vhd_error;
|
||||
|
||||
vhd_error parse_vhd_config(drive_t *drive);
|
||||
|
||||
#endif // VHD_CFG_H
|
||||
246
support/vhd/vhdcgf.cpp
Normal file
246
support/vhd/vhdcgf.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
// vhdcfg.cpp uses simplified code from cfg.cpp
|
||||
// 2015, rok.krajnc@gmail.com
|
||||
// 2017+, Sorgelig
|
||||
|
||||
#include <cctype>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vhdcfg.h"
|
||||
#include "file_io.h"
|
||||
|
||||
/* ATA Spec:
|
||||
Sectors: 8-bit
|
||||
Heads: 4-bit
|
||||
Cylinders: 16-bit
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VHD_UINT8 = 0, VHD_UINT16
|
||||
} vhd_cfg_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
void* var;
|
||||
vhd_cfg_type_t type;
|
||||
uint16_t min;
|
||||
uint16_t max;
|
||||
} vhd_var_t;
|
||||
|
||||
#define CFG_LINE_SIZE 64
|
||||
#define CHAR_IS_LINEEND(c) (((c) == '\n'))
|
||||
|
||||
fileTYPE cfg_file;
|
||||
|
||||
int cfg_pt = 0;
|
||||
static char cfg_getch()
|
||||
{
|
||||
static uint8_t buf[512];
|
||||
if (!(cfg_pt & 0x1ff)) FileReadSec(&cfg_file, buf);
|
||||
if (cfg_pt >= cfg_file.size) return 0;
|
||||
return buf[(cfg_pt++) & 0x1ff];
|
||||
}
|
||||
|
||||
static int cfg_getline(char* line)
|
||||
{
|
||||
char c, ignore = 0, skip = 1;
|
||||
int i = 0;
|
||||
|
||||
while ((c = cfg_getch()))
|
||||
{
|
||||
if (!std::isspace(c)) skip = 0;
|
||||
if (i >= (CFG_LINE_SIZE - 1)) ignore = 1;
|
||||
|
||||
if (CHAR_IS_LINEEND(c)) break;
|
||||
if ((std::isspace(c) || std::isalnum(c)) && !ignore && !skip) line[i++] = c;
|
||||
}
|
||||
line[i] = 0;
|
||||
while (i > 0 && std::isspace(line[i - 1])) line[--i] = 0;
|
||||
return c == 0;
|
||||
}
|
||||
|
||||
static vhd_error ini_parse_numeric(const vhd_var_t *var, const char *text, void *out)
|
||||
{
|
||||
uint32_t u32 = 0;
|
||||
char *endptr = nullptr;
|
||||
|
||||
bool out_of_range = true;
|
||||
bool invalid_format = false;
|
||||
|
||||
u32 = strtoul(text, &endptr, 0);
|
||||
if (u32 < var->min) u32 = var->min;
|
||||
else if (u32 > var->max) u32 = var->max;
|
||||
else out_of_range = false;
|
||||
|
||||
if (*endptr)
|
||||
{
|
||||
printf("VHD CFG ERROR: %s: \'%s\' not a number\n", var->name, text);
|
||||
return VHD_INVALID_CONFIG;
|
||||
}
|
||||
else if (out_of_range)
|
||||
{
|
||||
printf("VHD CFG ERROR: %s: \'%s\' out of range\n", var->name, text);
|
||||
return VHD_INVALID_CONFIG;
|
||||
}
|
||||
else if (invalid_format)
|
||||
{
|
||||
printf("VHD CFG ERROR: %s: \'%s\' invalid format\n", var->name, text);
|
||||
return VHD_INVALID_CONFIG;
|
||||
}
|
||||
|
||||
switch (var->type)
|
||||
{
|
||||
case VHD_UINT8: *(uint8_t*)out = u32; break;
|
||||
case VHD_UINT16: *(uint16_t*)out = u32; break;
|
||||
default: break;
|
||||
}
|
||||
return VHD_NOERROR;
|
||||
}
|
||||
|
||||
static vhd_error ini_parse_var(char* buf, vhd_var_t vars[], size_t var_count)
|
||||
{
|
||||
// find var
|
||||
int i = 0;
|
||||
while (1)
|
||||
{
|
||||
if (buf[i] == '=' || std::isspace(buf[i]))
|
||||
{
|
||||
buf[i] = 0;
|
||||
break;
|
||||
}
|
||||
else if (!buf[i]) return VHD_NOERROR;
|
||||
i++;
|
||||
}
|
||||
|
||||
// parse var
|
||||
int var_id = -1;
|
||||
for (size_t j = 0; j < var_count; j++)
|
||||
{
|
||||
if (!strcasecmp(buf, vars[j].name)) var_id = j;
|
||||
}
|
||||
|
||||
if (var_id == -1)
|
||||
{
|
||||
printf("VHD CFG ERROR: %s: unknown option\n", buf);
|
||||
return VHD_INVALID_CONFIG;
|
||||
}
|
||||
else // get data
|
||||
{
|
||||
i++;
|
||||
while (std::isspace(buf[i])) i++;
|
||||
|
||||
const vhd_var_t *var = &vars[var_id];
|
||||
return ini_parse_numeric(var, &buf[i], var->var);
|
||||
}
|
||||
}
|
||||
|
||||
static vhd_error cfg_parse(const char *name, vhd_var_t vars[], size_t var_count)
|
||||
{
|
||||
char line[CFG_LINE_SIZE];
|
||||
int eof;
|
||||
vhd_error res = VHD_NOERROR;
|
||||
|
||||
memset(line, 0, sizeof(line));
|
||||
memset(&cfg_file, 0, sizeof(cfg_file));
|
||||
|
||||
if (!FileOpen(&cfg_file, name)) return VHD_NO_CONFIG;
|
||||
|
||||
cfg_pt = 0;
|
||||
|
||||
// parse ini
|
||||
while (1)
|
||||
{
|
||||
// get line
|
||||
eof = cfg_getline(line);
|
||||
res = ini_parse_var(line, vars, var_count);
|
||||
if (res != VHD_NOERROR)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// if end of file, stop
|
||||
if (eof) break;
|
||||
}
|
||||
|
||||
FileClose(&cfg_file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// make sure the values make sense
|
||||
vhd_error validate(drive_t *drive, uint8_t sectors, uint8_t heads, uint16_t cylinders)
|
||||
{
|
||||
// Both sectors and heads must be defined
|
||||
if (!sectors || !heads) return VHD_MISSING_CONFIG;
|
||||
|
||||
__off64_t config_size = heads * sectors * 512;
|
||||
if (cylinders == 0 && drive->f->size < config_size)
|
||||
{
|
||||
return VHD_INVALID_SIZE;
|
||||
}
|
||||
else if (cylinders == 0) return VHD_NOERROR;
|
||||
|
||||
config_size = config_size * cylinders;
|
||||
if (drive->f->size < config_size) return VHD_INVALID_SIZE;
|
||||
|
||||
if (drive->f->size != config_size)
|
||||
{
|
||||
printf("config override: new size %lli\n", config_size);
|
||||
drive->total_sectors = config_size / 512;
|
||||
}
|
||||
return VHD_NOERROR;
|
||||
}
|
||||
|
||||
// parse_vhd_config will take a filename and replace the extension with `.cfg` then attempt to parse
|
||||
// CHS values into a provided `vhd_config_t`.
|
||||
vhd_error parse_vhd_config(drive_t *drive)
|
||||
{
|
||||
const char *name = drive->f->path;
|
||||
struct
|
||||
{
|
||||
uint8_t sectors;
|
||||
uint8_t heads;
|
||||
uint16_t cylinders;
|
||||
} parsed_values;
|
||||
|
||||
// vhd_var_t defines the possible values that can be specified for a given image.
|
||||
// If this file exists, both `sectors` and `heads` must be defined for it to parse
|
||||
// successfully. Cylinders may also be specified if the entire file shouldn't be
|
||||
// used, i.e. -- avoid overwriting a footer.
|
||||
vhd_var_t vhd_vars[] =
|
||||
{
|
||||
{ "SECTORS", (void*)(&(parsed_values.sectors)), VHD_UINT8, 17, 256 },
|
||||
{ "HEADS", (void*)(&(parsed_values.heads)), VHD_UINT8, 2, 16 },
|
||||
{ "CYLINDERS", (void*)(&(parsed_values.cylinders)), VHD_UINT16, 0, 65535 }
|
||||
};
|
||||
|
||||
char cfg_name[256];
|
||||
|
||||
const char *ext = strrchr(name, '.');
|
||||
if (!ext || ext == name || ext == name + strlen(name) - 1)
|
||||
{
|
||||
return VHD_NO_CONFIG;
|
||||
}
|
||||
|
||||
// find the length of the name before the extension
|
||||
size_t name_len = ext - name;
|
||||
strncpy(cfg_name, name, name_len);
|
||||
strncpy(cfg_name+name_len, ".cfg", 4);
|
||||
|
||||
vhd_error result = cfg_parse(cfg_name, vhd_vars, sizeof(vhd_vars)/sizeof(vhd_var_t));
|
||||
if (result == VHD_NOERROR)
|
||||
{
|
||||
result = validate(drive, parsed_values.sectors, parsed_values.heads, parsed_values.cylinders);
|
||||
if (result == VHD_NOERROR)
|
||||
{
|
||||
printf("config override: cylinders %d heads %d sectors %d\n", parsed_values.cylinders, parsed_values.heads, parsed_values.sectors);
|
||||
drive->cylinders=parsed_values.cylinders;
|
||||
drive->heads=parsed_values.heads;
|
||||
drive->spt=parsed_values.sectors;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user