cake
/
libg1m
Archived
1
0
Fork 0
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libg1m/src/type/mcs.c

529 lines
14 KiB
C

/* *****************************************************************************
* type/mcs.c -- get the MCS type out of raw identification data.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libg1m.
* libg1m is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libg1m 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.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libg1m/internals.h>
/* ************************************************************************** */
/* Local types */
/* ************************************************************************** */
/* Type flags */
#define noarg 0x0000
#define arg 0x0001
#define arg_is_num 0x0002
#define arg_is_let 0x0000
#define weight_by_gid 0x0004
#define groupable 0x0008
/* Correspondance type */
struct type_corresp {
/* identification */
unsigned int rawtype;
const char *name; /* NULL: don't check */
unsigned int flags; /* TODO: move */
/* information for logging and re-constituting information */
const char *dirname;
const char *info;
/* libg1m information */
g1m_mcstype_t type;
};
/* Group correspondance type */
struct group_corresp {
/* identification */
const char *name; /* NULL = don't check */
unsigned int flags;
/* types */
struct type_corresp *types;
};
/* ************************************************************************** */
/* Correspondances */
/* ************************************************************************** */
/* All correspondances. Some remarks:
* - I think files with "PROGRAM" group are split because it was originally
* planned they would be in groups like 'PROGRAM <name>', like for captures
* or lists, but they abandoned that. Why they made such groups, I have no
* idea yet.
* - 0xfe is more or less the generic type ID for "data".
* - Types with a directory name starting with '@' are app-specific files, with
* the dirname being the internal name of the related application. */
#define TTERM {0, NULL, 0, NULL, NULL, 0}
static struct group_corresp mcs_groups[] = {
/* Main Memory */
{"SETUP", noarg, (struct type_corresp[]){
{0x14, "SETUP", 0, "$GLOBAL",
"setup", g1m_mcstype_setup},
{0x00, "SETUP", 0, "$GLOBAL", /* setup is also with 0x00...? */
"setup", g1m_mcstype_setup},
TTERM
}},
{"ALPHA MEM", noarg, (struct type_corresp[]){
{0x00, "ALPHA MEM", 0, "$GLOBAL",
"alpha memory", g1m_mcstype_alphamem},
{0x00, "", arg | arg_is_let, "$GLOBAL",
"variable", g1m_mcstype_variable},
TTERM
}},
{"STRING ", arg | arg_is_num, (struct type_corresp[]){
{0x04, "STR", arg | arg_is_num, "main",
"string", g1m_mcstype_string},
TTERM
}},
{"LIST ", arg | arg_is_num, (struct type_corresp[]){
{0x05, "1LIST", arg | arg_is_num, "main",
"list", g1m_mcstype_list},
TTERM
}},
{"LISTFILE ", arg | arg_is_num | weight_by_gid, (struct type_corresp[]){
{0x05, "1LIST", arg | arg_is_num | weight_by_gid, "main",
"list", g1m_mcstype_list},
TTERM
}},
{"MAT ", arg | arg_is_let, (struct type_corresp[]){
{0x06, "MAT_", arg | arg_is_let, "main",
"matrix", g1m_mcstype_mat},
TTERM
}},
{"VCT ", arg | arg_is_let, (struct type_corresp[]){
{0x06, "VCT_", arg | arg_is_let, "main",
"vector", g1m_mcstype_vct},
TTERM
}},
{"PROGRAM", noarg, (struct type_corresp[]){
{0x01, NULL, 0, "system",
"program", g1m_mcstype_program},
TTERM
}},
{"Y=DATA", noarg, (struct type_corresp[]){
{0x02, NULL /* e.g. "1" */, 0, "main",
"unknown", 0x00},
{0x05, NULL /* "VWIN" */, 0, "main",
"unknown", 0x00},
TTERM
}},
{"V-WIN ", arg | arg_is_num, (struct type_corresp[]){
{0x05, "VMEM", arg | arg_is_num, "main",
"unknown", 0x00},
TTERM
}},
{"PICTURE ", arg | arg_is_num, (struct type_corresp[]){
{0x07, "PICT", arg | arg_is_num, "main",
"picture", g1m_mcstype_pict},
TTERM
}},
/* more or less main memory */
{"CAPT ", arg | arg_is_num, (struct type_corresp[]){
{0x0A, "CAPT", arg | arg_is_num, "@REV2",
"capture", g1m_mcstype_capt},
TTERM
}},
/* application-specific data */
{"SYSTEM", noarg, (struct type_corresp[]){
{0xFE, NULL /* REPLAY/RUN2D1 */, 0, "@RUNMAT",
"replay", 0x00},
{0x0A, NULL /* CLIP/NAT_CLIP */, 0, "@REV2",
"clip", 0x00},
TTERM
}},
{"S-SHEET", noarg, (struct type_corresp[]){
{0xFE, "@SNAME", 0, "@SSHEET",
"spreadsheet name?", 0x00},
{0xFE, NULL, 0, "@SSHEET",
"spreadsheet", g1m_mcstype_spreadsheet},
TTERM
}},
{"CONICS", noarg, (struct type_corresp[]){
{0xFE, NULL /* "conicmem" */, 0, "@CONICS",
"conics data", 0x00},
TTERM
}},
{"DYNA MEM", noarg, (struct type_corresp[]){
{0xFE, NULL /* "COND" */, 0, "@DYNA",
"dyna data", 0x00},
TTERM
}},
{"Econ3Now", noarg, (struct type_corresp[]){
{0xFE, NULL /* "Econ3Now" */, 0, "@E-CON2",
"econ3 data", 0x00},
TTERM
}},
{"ECON4_", arg | arg_is_num, (struct type_corresp[]){
{0xFE, "Econ4N", arg | arg_is_num, "@E-CON2",
"econ4 data", 0x00},
TTERM
}},
{"FINANCIAL", noarg, (struct type_corresp[]){
{0xFE, NULL /* "fina_mem" */, 0, "@FINANCE",
"financial data", 0x00},
TTERM
}},
{"RECURSION", noarg, (struct type_corresp[]){
{0xFE, NULL /* "RECRG" */, 0, "@RECUR",
"recursion data", 0x00},
TTERM
}},
{"STAT", noarg, (struct type_corresp[]){
{0xFE, "G_CND", 0, "@STAT",
"stat data?", 0x00},
{0xFE, "G_CNDEX", 0, "@STAT",
"stat data?", 0x00},
{0xFE, "C_CND", 0, "@STAT",
"stat data?", 0x00},
{0xFE, "STATap", 0, "@STAT",
"stat data?", 0x00},
{0xFE, "STATapX", 0, "@STAT",
"stat data?", 0x00},
{0x05, "STATV", arg | arg_is_num, "main",
"stat data?", 0x00},
TTERM
}},
{"TABLE", noarg, (struct type_corresp[]){
{0xFE, "RANGE", 0, "@TABLE",
"range data?", 0x00},
TTERM
}},
{"3DGRAPH", noarg, (struct type_corresp[]){
{0xFE, "AREACOL", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "LINECOL", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "SELECT", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "TEMPLATE", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "SETUP", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "TYPE", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "VWIN", 0, "@3DGRAPH",
"???", 0x00},
{0xFE, "Z", arg | arg_is_num /* 1 to 3 */, "@3DGRAPH",
"???", 0x00},
TTERM
}},
{"@GEOM", noarg, (struct type_corresp[]){
{0xFE, NULL, 0, "@GEOM",
"???", 0x00},
TTERM
}},
{"@PROBSIM", noarg, (struct type_corresp[]){
{0xFE, "ProbRand", 0, "@PROBSIM",
"???", 0x00},
{0xFE, "ProbAdv", 0, "@PROBSIM",
"???", 0x00},
{0xFE, "ProbSeed", 0, "@PROBSIM",
"???", 0x00},
{0xFE, "ProbSet", 0, "@PROBSIM",
"???", 0x00},
{0xFE, "ProbVer", 0, "@PROBSIM",
"???", 0x00},
TTERM
}},
{"PICTPLOT", noarg, (struct type_corresp[]){
{0x05, "PGRAPH", arg | arg_is_num /* 0 to 3 */, "main",
"???", 0x00},
{0xFE, "PATH", 0, "@PICTPLT",
"???", 0x00},
{0xFE, "@SC_CNT", 0, "@PICTPLT",
"???", 0x00},
{0xFE, "@SG_CND", 0, "@PICTPLT",
"???", 0x00},
{0xFE, "@SG_CDX", 0, "@PICTPLT",
"???", 0x00},
{0xFE, "SETUP", 0, "@PICTPLT",
"???", 0x00},
TTERM
}},
/* terminating entry */
{NULL, 0, NULL}
};
/* ************************************************************************** */
/* Main functions */
/* ************************************************************************** */
/**
* get_number:
* Get number from string.
*
* @arg s the string.
* @arg num pointer to the num to fill.
* @arg isnum is it a number or a letter?
* @return if there was an error (0 if ok).
*/
static int get_number(const char *s, int *num, int isnum)
{
if (!strcmp(s, "Ans"))
*num = g1m_ans;
else if (!strcmp(s, "\xCE"))
*num = g1m_theta;
else if (!strcmp(s, "\xCD"))
*num = g1m_r;
else if (isnum) {
if (!(*num = atoi(s))) return (1);
} else {
if (*s < 'A' || *s > 'Z')
return (1);
*num = *s - 'A' + 1;
}
return (0);
}
/**
* g1m_maketype_mcs:
* Get libg1m type from rawtype.
*
* @arg head the head to fill.
* @arg gname the group name.
* @arg dname the directory name.
* @arg fname the filename.
* @arg rawtype the raw numerical type.
* @return if the type was not found (0 if yes).
*/
int g1m_maketype_mcs(g1m_mcshead_t *head,
const char *gname, const char *dname,
const char *fname, unsigned int rawtype)
{
/* log what we're looking for */
log_info("Looking for type with '%.8s' group, '%.8s' name and "
"0x%02X raw type", gname, fname, rawtype);
/* copy raw information */
memset(head, 0, sizeof(g1m_mcshead_t));
head->flags |= g1m_mcsinfo_mcs;
memcpy(head->name, fname, 8);
head->name[8] = 0;
memcpy(head->_group, gname, 16);
head->_group[16] = 0;
head->_rawtype = rawtype;
if (dname) {
memcpy(head->_dirname, dname, 8);
head->_dirname[8] = 0;
} else
memset(head->_dirname, 0, 9);
/* look for group correspondance */
int gid = 0;
struct group_corresp *g = mcs_groups - 1;
while ((++g)->types) {
size_t pl = strlen(g->name);
/* check if pattern is there */
if (strncmp(g->name, gname, pl))
continue;
if ((g->flags & arg)
&& get_number(&gname[pl], &gid, g->flags & arg_is_num))
continue;
break;
}
if (!g->types)
goto notfound;
/* look for type correspondance */
struct type_corresp *t = g->types - 1; int fid = 0;
while ((++t)->dirname) {
if (t->rawtype != rawtype)
continue;
/* check if pattern */
if (t->name) {
size_t fl = strlen(t->name);
if (strncmp(t->name, fname, fl))
continue;
fid = 0;
if ((t->flags & arg)
&& get_number(&fname[fl], &fid, t->flags & arg_is_num))
continue;
if (t->flags & weight_by_gid)
fid |= (gid << 5);
}
break;
}
if (!t->dirname)
goto notfound;
/* fill in info and return */
head->type = t->type;
head->id = fid;
return (0);
notfound:
log_info("Type with '%s' group, '%s' name and 0x%02x type "
"wasn't recognized.", gname, fname, rawtype);
head->type = 0;
head->id = 0;
return (1);
}
/**
* g1m_correct_mcsfile_head:
* Correct information.
*
* @arg head the mcs head to correct.
* @return if an error was encountered.
*/
int g1m_correct_mcsfile_head(g1m_mcshead_t *head)
{
/* check if there is a type */
if (!head) return (0);
if (!head->type
&& (!head->_group[0] || !head->name[0] || !head->_dirname[0]))
return (g1m_error_op);
/* find the group/type */
struct group_corresp *g;
struct type_corresp *t;
for (g = mcs_groups; g->types; g++) for (t = g->types; t->dirname; t++) {
/* check if the libg1m type corresponds */
if (t->type != head->type) continue;
/* check if id is weighted by major */
if (g1m_get_id_major(head->id)) {
if (~t->flags & weight_by_gid)
continue;
} else
continue;
/* we have found the entry! */
goto found;
}
/* not found... */
return (g1m_error_unknown);
found:;
/* put the group name */
char *gr = (char*)head->_group;
if (g->flags & arg) {
int grid = g1m_get_id_major(head->id);
if ((t->flags & arg) && ~t->flags & weight_by_gid)
grid = g1m_get_id_minor(head->id);
if (grid == g1m_ans)
sprintf(gr, "%sAns", g->name);
else if (grid == g1m_theta)
sprintf(gr, "%s\xCE", g->name);
else if (grid == g1m_r)
sprintf(gr, "%s\xCD", g->name);
else if (g->flags & arg_is_num)
sprintf(gr, "%s%d", g->name, grid);
else
sprintf(gr, "%s%c", g->name, grid + 'A' - 1);
} else
strcpy(gr, g->name);
/* put the directory name */
strcpy((char*)head->_dirname, t->dirname);
/* put the filename */
char *nm = (char*)head->name;
if (t->flags & arg) {
int namid = g1m_get_id_minor(head->id);
if (namid == g1m_ans)
sprintf(nm, "%sAns", t->name);
else if (namid == g1m_theta)
sprintf(nm, "%s\xCE", t->name);
else if (namid == g1m_r)
sprintf(nm, "%s\xCD", t->name);
else if (t->flags & arg_is_num)
sprintf(nm, "%s%d", t->name, namid);
else
sprintf(nm, "%s%c", t->name, namid + 'A' - 1);
} else if (t->name)
strcpy(nm, t->name);
/* no error */
return (0);
}
/* ************************************************************************** */
/* Compare function */
/* ************************************************************************** */
/**
* find_offset_in_group:
* Find offset in a group.
*
* @arg group the group correspondance.
* @arg file the file.
* @return the offset (-1 if not there).
*/
static int find_offset_in_group(struct group_corresp *g,
const g1m_mcsfile_t *file)
{
/* group check */
if (strcmp((char*)file->head._group, g->name))
return (-1);
/* file check */
struct type_corresp *f; int i;
for (f = g->types, i = 0; f->info; f++, i++) {
if (strcmp((char*)file->head._group, f->name)
|| file->head._rawtype != f->rawtype)
continue;
return (i);
}
/* not found, but shouldn't look for it in other groups */
return (-2);
}
/**
* g1m_compare_mcsfiles:
* Compare MCS files using their heads, for sorting.
*
* @arg first the first file.
* @arg second the second file.
* @return negative value if the 1st is considered less than the 2nd,
* positive value otherwise.
*/
int g1m_compare_mcsfiles(const g1m_mcsfile_t *first,
const g1m_mcsfile_t *second)
{
/* find the group correspondance */
int offset1 = -1, offset2 = -1;
struct group_corresp *g; for (g = mcs_groups; g->types; g++) {
/* get offsets */
if (offset1 >= -1) offset1 = find_offset_in_group(g, first);
if (offset2 >= -1) offset2 = find_offset_in_group(g, second);
/* check if the first one corresponds */
if (offset1 < 0 && offset2 < 0) continue;
if (offset1 == offset2) break;
if (offset1 < offset2) return (-1);
if (offset1 > offset2) return (1);
}
/* so they're equal, huh... */
return (0);
}