cake
/
libg1m
Archived
1
0
Fork 0

Reorganized some sources, added some manpages and BCD utilities, corrected MCS parsing error

This commit is contained in:
Thomas Touhey 2016-11-21 17:01:24 +01:00
parent 31130131c6
commit ab03cc8228
16 changed files with 527 additions and 102 deletions

46
doc/g1m_error.3.txt Normal file
View File

@ -0,0 +1,46 @@
G1M_ERROR(3)
============
Thomas "Cakeisalie5" Touhey
:Email: thomas@touhey.fr
:man source: libg1m
:man manual: libg1m manual
NAME
----
g1m_error - all errors from libg1m
SYNOPSIS
--------
[source,c]
----
#include <libg1m.h>
int err = g1m_some_function(handle, ...);
if (err) switch (err) {
case g1m_error_...:
/* oh my god! they killed kenny! */
break;
}
----
DESCRIPTION
-----------
Every function in libg1m returns either zero if everything went alright, or
the code of the error that happened. The error codes are the following:
*g1m_error_nostream*::
Provided or generated stream was *NULL*.
*g1m_error_noread*::
Stream was not readable.
*g1m_error_magic*::
File might be corrupted.
*g1m_error_eof*::
Unexpected End Of File.
String descriptions of the error can be dynamically obtained by using
*g1m_strerror*(3).
SEE ALSO
--------
*libg1m*(3),
*g1m_strerror*(3)

36
doc/g1m_fctomb.3.txt Normal file
View File

@ -0,0 +1,36 @@
G1M_FCTOMB(3)
=============
Thomas "Cakeisalie5" Touhey
:Email: thomas@touhey.fr
:man source: libg1m
:man manual: libg1m manual
NAME
----
g1m_fctomb - FONTCHARACTER to multi-byte
SYNOPSIS
--------
[source,c]
----
#include <libg1m.h>
int g1m_fctomb(char *s, FONTCHARACTER fc);
----
DESCRIPTION
-----------
Convert a FONTCHARACTER character to its multibyte representation,
and stores it at the beginning of the character array pointed to by
*s*.
The programmer must ensure that there is room for at least 2 bytes at
*s*.
RETURN VALUE
------------
This function returns the length of the calculated multibyte function.
SEE ALSO
--------
*libg1m*(3), *g1m_mbtofc*(3)

1
doc/g1m_fopen.3.txt Symbolic link
View File

@ -0,0 +1 @@
g1m_open.3.txt

37
doc/g1m_free.3.txt Normal file
View File

@ -0,0 +1,37 @@
G1M_FREE(3)
=========
Thomas "Cakeisalie5" Touhey
:Email: thomas@touhey.fr
:man source: libg1m
:man manual: libg1m manual
NAME
----
g1m_free - free a handle
SYNOPSIS
--------
[source,c]
----
#include <libg1m.h>
void g1m_free(g1m_t *handle);
----
DESCRIPTION
-----------
Frees a handle opened with *g1m_open*(3) or *g1m_fopen*(3).
RETURN VALUE
------------
This function returns zero if everything went well, and the error code
otherwise.
ERRORS
------
See *g1m_error*(3).
SEE ALSO
--------
*libg1m*(3),
*g1m_open*(3)

41
doc/g1m_open.3.txt Normal file
View File

@ -0,0 +1,41 @@
G1M_OPEN(3)
=========
Thomas "Cakeisalie5" Touhey
:Email: thomas@touhey.fr
:man source: libg1m
:man manual: libg1m manual
NAME
----
g1m_open, g1m_fopen - open and decode a file
SYNOPSIS
--------
[source,c]
----
#include <libg1m.h>
int g1m_open(g1m_t **handle, const char *path);
int g1m_fopen(g1m_t **handle, FILE *stream);
----
DESCRIPTION
-----------
Open and decode a file. If everything goes well, the handle is stored at
**handle*.
For *g1m_fopen*, the stream only requires reading (writing and seeking
capabilities are not required).
RETURN VALUE
------------
This function returns zero if everything went well, and the error code
otherwise.
ERRORS
------
See *g1m_error*(3).
SEE ALSO
--------
*libg1m*(3)

32
doc/g1m_strerror.3.txt Normal file
View File

@ -0,0 +1,32 @@
G1M_STRERROR(3)
===============
Thomas "Cakeisalie5" Touhey
:Email: thomas@touhey.fr
:man source: libg1m
:man manual: libg1m manual
NAME
----
g1m_strerror - get error string of a libg1m error
SYNOPSIS
--------
[source,c]
----
#include <libg1m.h>
const char g1m_strerror(int err);
printf("Couldn't perform action: %s\n", g1m_strerror(g1m_error_nostream));
----
DESCRIPTION
-----------
Get the string description of a libg1m error.
Never use an invalid error code! It could cause a segfault.
SEE ALSO
--------
*libg1m*(3),
*g1m_error*(3)

View File

@ -14,12 +14,32 @@ SYNOPSIS
[source,c]
----
#include <libg1m.h>
g1m_t *handle;
int err = g1m_open(&handle, "TEST.g1m");
if (err) {
printf("Could not open file: %s\n", g1m_strerror(err));
if (err == g1m_error_nostream)
printf("Could not open stream because: %s\n", strerror(errno));
exit(0);
}
if (handle->type & g1m_type_addin)
printf("Add-in internal name is '%s'\n", handle->internal_name);
else
printf("Not an add-in!\n");
g1m_free(handle);
----
DESCRIPTION
-----------
libg1m enables reading (parsing) and writing of g** files : g1m, g1a.
libg1m is a library meant to decode CASIO's
g[1-3]* files : g1m/g1r, g1a, g1e, g3a, g3e, g3p.
Its aim is to support everything with a Standard Header.
SEE ALSO
--------
*g1m_open(3)*
*g1m_open*(3),
*g1m_free*(3),
*g1m_error*(3)

View File

@ -35,6 +35,23 @@ struct bcd {
/* ************************************************************************** */
/* BCD utilities */
/* ************************************************************************** */
/* none yet -- TODO */
/* Arithmetic */
int g1m_bcd_is_nonzero(struct bcd *bcd);
/* String/BCD */
char *g1m_bcdtoa(struct bcd *bcd);
/* ************************************************************************** */
/* Inline BCD utilities */
/* ************************************************************************** */
/* check if BCD number is negative */
static inline int g1m_bcd_is_negative(struct bcd *bcd)
{
return ((bcd->BCDval[0] & 0xf0) >= 0x50);
}
/* macros */
# define g1m_bcd_is_positive(B) (~g1m_bcd_is_negative(B) & 1)
# define g1m_bcd_is_zero(B) (!g1m_bcd_is_nonzero(B))
#endif /* LIBG1M_BCD_H */

View File

@ -20,9 +20,14 @@
* Keep in mind that all numbers in the MCS format are BCD-encoded.
* Because of some precision issue, we'll deliver them to the user as is.
*
* So now we are not restricted to only one part. Remember the `number` field
* of the Standard Header? Well, it's the number of parts there is.
* And each part have a header, so let's describe it here. */
* So now we are not restricted to one part. Remember the `number` field in
* the Standard Header? We once thought it was the number of parts to come.
* But no. In general, we have one subpart per part, but in some case, we
* have more, like for the LISTFILEs. And that is how we realized the `number`
* in the Standard Header wasn't the number of parts, but the total number
* of subparts.
*
* Each part have a header, and here it is: */
struct mcs_subheader {
/* main ID ("PROGRAM", zero padded) */

View File

@ -1,18 +1,20 @@
/* ************************************************************************** */
/* _____ _ */
/* utils/bcd.c |_ _|__ _ _| |__ ___ _ _ */
/* libg1m/internals/bcd.h |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/03 01:02:10 |___/ */
/* Last updated: 2016/11/21 16:15:37 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
#ifndef LIBG1M_INTERNALS_BCD_H
# define LIBG1M_INTERNALS_BCD_H
# include <libg1m/bcd.h>
# include <string.h>
# define upr(N) ((bytes[(N)] & 0xf0) >> 4)
# define lwr(N) (bytes[(N)] & 0xf)
/* BCD-related utilities could go here. TODO.
* Things that would be cool:
* - Basic operations (adding, substracting, multiplying);
* - BCD/float conversions.
*
* Things that would be 20% cooler:
* - A GNU libc printf conversion function. */
int g1m_bcd_get_exponent(struct bcd *bcd);
int g1m_bcd_get_exponent_neg(struct bcd *bcd, int *neg);
#endif /* LIBG1M_INTERNALS_BCD_H */

38
src/bcd/get_exponent.c Normal file
View File

@ -0,0 +1,38 @@
/* ************************************************************************** */
/* _____ _ */
/* bcd/get_exponent.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/21 16:14:08 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals/bcd.h>
/**
* g1m_bcd_get_exponent:
* Get exponent.
*/
int g1m_bcd_get_exponent(struct bcd *bcd)
{
unsigned char *bytes = bcd->BCDval;
int exp = upr(0) * 100 + lwr(0) * 10 + upr(1);
return ((exp % 500) - 99);
}
/**
* g1m_bcd_get_exponent_neg:
* Get exponent and if it is negative.
*/
int g1m_bcd_get_exponent_neg(struct bcd *bcd, int *neg)
{
unsigned char *bytes = bcd->BCDval;
*neg = 0;
int exp = upr(0) * 100 + lwr(0) * 10 + upr(1);
if (exp >= 500) exp -= 500, *neg = 1;
return (exp - 99);
}

27
src/bcd/is_nonzero.c Normal file
View File

@ -0,0 +1,27 @@
/* ************************************************************************** */
/* _____ _ */
/* bcd/is_zero.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/21 16:07:53 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals/bcd.h>
/**
* g1m_bcd_is_nonzero:
* Check if a BCD is zero.
*
* @arg bcd pointer to the bcd.
* @return true or false.
*/
int g1m_bcd_is_nonzero(struct bcd *bcd)
{
static struct bcd ref = {.BCDval = {}};
unsigned char *bytes = bcd->BCDval;
return (lwr(1) | memcmp(&bytes[2], &ref.BCDval[2], 7));
}

96
src/bcd/to_ascii.c Normal file
View File

@ -0,0 +1,96 @@
/* ************************************************************************** */
/* _____ _ */
/* bcd/to_ascii.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/21 13:54:41 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals/bcd.h>
#define VISIBLE_PRECISION 5
/**
* g1m_bcdtoa:
* Simple BCD to string function.
*
* @arg bcd The BCD number.
* @return The allocated string.
*/
char *g1m_bcdtoa(struct bcd *bcd)
{
char buf[50], *p = buf;
unsigned char *bytes = bcd->BCDval;
/* get the exponent */
int neg = 0;
int exp = g1m_bcd_get_exponent_neg(bcd, &neg);
if (neg) *p++ = '-';
/* get the mantissa */
char mant[15];
for (int i = 0; i < 15; i += 2)
mant[i] = lwr(i / 2 + 1);
for (int i = 1; i < 15; i += 2)
mant[i] = upr(i / 2 + 2);
/* calculate number of significant digits */
int signif;
for (signif = 15; signif && !mant[signif - 1]; signif--);
if (!signif) exp = 0;
/* put integer part */
int num = 0;
if (exp > 0) {
while (exp > 0 && signif) {
exp--;
signif--;
*p++ = mant[num++] + '0';
}
if (exp > 0 && exp < VISIBLE_PRECISION) while (exp) {
exp--;
*p++ = '0';
}
} else
*p++ = '0';
/* put decimal part */
if (signif) {
*p++ = '.';
/* put some zeroes */
if (exp < 0 && exp > -VISIBLE_PRECISION) while (exp) {
exp++;
*p++ = '0';
}
/* put the numbers */
while (signif--)
*p++ = mant[num++] + '0';
}
/* put exponent */
if (exp) {
*p++ = '^';
int exp_neg = exp < 0;
if (exp_neg) {
*p++ = '(';
*p++ = '-';
exp = -exp;
}
int eprec = 100;
while (exp < eprec)
eprec /= 10;
while (eprec) {
*p++ = exp / eprec + '0';
exp %= eprec;
eprec /= 10;
}
if (exp_neg) *p++ = ')';
}
/* put string end */
*p = 0;
/* duplicate and send to user */
return (strdup(buf));
}

View File

@ -0,0 +1,80 @@
/* ************************************************************************** */
/* _____ _ */
/* fontcharacter/character.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/21 13:29:30 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/fontcharacter.h>
#include <string.h>
/**
* g1m_mbtofc:
* Multi-byte to FONTCHARACTER.
*
* Based on what is said in the fx-9860G SDK.
* Let's hope it stays true.
*
* Based on how `mbtowc` works.
*
* @arg pfc pointer to the FONTCHARACTER character.
* @arg s the multi-byte source string.
* @arg n the size of the source buffer.
* @return the number of bytes used (-1 if error).
*/
int g1m_mbtofc(FONTCHARACTER *pfc, const char *s, size_t n)
{
/* null string? */
if (!s)
return (2);
/* no space? */
if (!n)
return (-1);
/* extended char? */
if (strchr("\x7F\xF7\xF9\xE5\x56\x57", *s))
{
if (n < 2) return (-1);
*pfc = (*s << 8) + *(s + 1);
return (2);
}
/* single-byte character */
*pfc = *s;
return (*s != 0);
}
/**
* g1m_fctomb:
* FONTCHARACTER to multi-byte.
*
* Based on the same document, and on how `wctomb` works.
*
* Do you think a battery has self-consciousness?
*
* @arg s pointer to the multi-byte string.
* @arg fc the FONTCHARACTER character.
* @return the
*/
int g1m_fctomb(char *s, FONTCHARACTER fc)
{
/* no string? */
if (!s)
return (2);
/* extended? */
if (fc > 0xff) {
*s++ = fc >> 8;
*s = fc & 0xff;
return (2);
}
/* normal char. */
*s = fc;
return (fc != 0);
}

View File

@ -1,89 +1,15 @@
/* ************************************************************************** */
/* _____ _ */
/* utils/fontcharacter.c |_ _|__ _ _| |__ ___ _ _ */
/* fontcharacter/string.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/11/03 00:56:55 |___/ */
/* Last updated: 2016/11/21 13:29:30 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
#include <libg1m/fontcharacter.h>
#include <string.h>
/* ************************************************************************** */
/* Single character conversion */
/* ************************************************************************** */
/**
* g1m_mbtofc:
* Multi-byte to FONTCHARACTER.
*
* Based on what is said in the fx-9860G SDK.
* Let's hope it stays true.
*
* Based on how `mbtowc` works.
*
* @arg pfc pointer to the FONTCHARACTER character.
* @arg s the multi-byte source string.
* @arg n the size of the source buffer.
* @return the number of bytes used (-1 if error).
*/
int g1m_mbtofc(FONTCHARACTER *pfc, const char *s, size_t n)
{
/* null string? */
if (!s)
return (2);
/* no space? */
if (!n)
return (-1);
/* extended char? */
if (strchr("\x7F\xF7\xF9\xE5\x56\x57", *s))
{
if (n < 2) return (-1);
*pfc = (*s << 8) + *(s + 1);
return (2);
}
/* single-byte character */
*pfc = *s;
return (*s != 0);
}
/**
* g1m_fctomb:
* FONTCHARACTER to multi-byte.
*
* Based on the same document, and on how `wctomb` works.
*
* Do you think a battery has self-consciousness?
*
* @arg s pointer to the multi-byte string.
* @arg fc the FONTCHARACTER character.
* @return the
*/
int g1m_fctomb(char *s, FONTCHARACTER fc)
{
/* no string? */
if (!s)
return (2);
/* extended? */
if (fc > 0xff) {
*s++ = fc >> 8;
*s = fc & 0xff;
return (2);
}
/* normal char. */
*s = fc;
return (fc != 0);
}
/* ************************************************************************** */
/* String conversion */
/* ************************************************************************** */
/**
* g1m_mbstofcs:
* Multi-byte string to FONTCHARACTER string.

View File

@ -165,7 +165,9 @@ static int g1m_parse_mcs_spreadsheet(g1m_mcsfile_t *handle, FILE *stream,
cells_count++;
/* log it */
log_info("[%ld, %ld] not empty.", c, i);
char *bcd_string = g1m_bcdtoa(&cell);
log_info("[%ld, %ld] contains '%s'.", c, i, bcd_string);
free(bcd_string);
}
/* iterate bit and rd */
@ -236,8 +238,6 @@ static int g1m_parse_mcs_list(g1m_mcsfile_t *handle, FILE *stream,
size_t elsize = sizeof(struct bcd) * elcount;
struct bcd real[elcount];
struct bcd imgn[elcount];
bzero(real, elsize);
bzero(imgn, elsize);
/* browse real elements */
log_info("Browsing %d list elements", elcount);
@ -246,10 +246,11 @@ static int g1m_parse_mcs_list(g1m_mcsfile_t *handle, FILE *stream,
/* browse imaginary elements */
if (size) {
log_info("Browsing their complex parts");
log_info("They have complex parts!");
size_t toread = min(size, elsize);
READ(&imgn, toread)
}
} else
bzero(imgn, elsize);
/* fill final tab */
handle->rows = elcount;
@ -264,6 +265,20 @@ static int g1m_parse_mcs_list(g1m_mcsfile_t *handle, FILE *stream,
/* main copying loop */
for (uint_fast32_t y = 0; y < elcount; y++) {
/* log */
#if LOGLEVEL <= ll_info
char *real_string = g1m_bcdtoa(&real[y]);
if (g1m_bcd_is_zero(&imgn[y]))
log_info("Cell #%ld is %s.", y, real_string);
else {
char *imgn_string = g1m_bcdtoa(&imgn[y]);
log_info("Cell #%ld is %s+%si.", y, real_string, imgn_string);
free(imgn_string);
}
free(real_string);
#endif
/* prepare index and store */
tab[y] = &rws[y];
tab[y][0] = (g1m_mcs_cell_t){
.used = 1,
@ -505,9 +520,10 @@ int g1m_parse_mcs(g1m_t *handle, FILE *stream, uint_fast16_t num)
int err = g1m_error_alloc;
/* No "global" header for MCS parts, because this "global header"
* was the standard header.
* allocate memory for the subparts */
handle->part_count = num;
* was the standard header. */
/* allocate memory for the subparts */
handle->part_count = 0;
handle->_parts_size = num;
handle->parts = malloc(sizeof(g1m_mcs_t*) * num);
if (!handle->parts) return (g1m_error_alloc);
@ -534,9 +550,14 @@ int g1m_parse_mcs(g1m_t *handle, FILE *stream, uint_fast16_t num)
if (!pmcs[i]) goto fail;
g1m_mcs_t *mcs = pmcs[i];
/* increment parts count, and remove to num the "extra" subparts */
handle->part_count++;
num -= hd.subcount - 1;
/* prepare it */
mcs->file_count = hd.subcount;
mcs->_files_size = hd.subcount;
if (!hd.subcount) continue;
mcs->files = malloc(sizeof(g1m_mcsfile_t*) * hd.subcount);
if (!mcs->files) goto fail;
bzero(mcs->files, sizeof(g1m_mcsfile_t*) * hd.subcount);