/* function definition to parse a string instead of a file
*/
#include "types.h"
/* Parse a string with Flex+Bison instead of a file / stdout */
int grammar_parse_string(const GString *buf) {
int res;
yy_scan_string(buf->str);
res = yyparse();
yylex_destroy();
return res;
}
/* Create a BotExpenseEntry with data fed from the parser. If 'previous' is null, initialize as first expense and 'totalAmount' will be 0
* Returns NULL if error getting local time.
*/
BotExpenseEntry *create_bot_expense_entry
(
const BotExpenseEntry *previous,
const BotCommand cmd,
const double value,
GString* user,
GString* notes
)
{
unsigned int id;
double totalAmount;
double signedValue = value;
BotExpenseEntry *entry = malloc(sizeof *entry); // TODO this should be freed once it's written to registry
struct tm *lt = malloc(sizeof *lt);
time_t t = time(NULL);
/* get the local time */
localtime_r(&t, lt);
if(lt == NULL) {
fprintf(stderr, "Unable to get localtime.\n");
return NULL;
}
if(cmd == BOT_CMD_OUT) {
signedValue = -value;
}
if(previous == NULL) {
id = 1;
totalAmount = signedValue;
} else {
id = previous->id + 1;
totalAmount = previous->totalAmount + signedValue; /* value can be negative */
}
entry->id = id;
entry->time = *lt;
entry->value = signedValue;
entry->totalAmount = totalAmount;
entry->user = user; /* we are setting the pointer here, not copying! */
entry->notes = notes;
entry->_serialized = false;
return entry;
}
/* FP should not be null. This assumes that it has been initialized with an header line as well
* Returns NULL in case 'entry' is uninitialized.
*/
GString *serialize_bot_expense_entry_csv
(
BotExpenseEntry *entry
)
{
/* will be automatically expanded by g_string_printf */
GString *tstr = g_string_new(NULL);
GString *result = g_string_new(NULL);
if(entry == NULL) {
fprintf(stderr, "BotExpenseEntry 'entry' is NULL. Initialize it before calling 'serialize_bot_expense_entry_csv'\n");
return NULL;
}
/* Time in ISO 8061 */
g_string_printf(tstr,
"%d-%02d-%02d %02d:%02d:%02d",
entry->time.tm_year + 1900,
entry->time.tm_mon + 1,
entry->time.tm_mday,
entry->time.tm_hour,
entry->time.tm_min,
entry->time.tm_sec);
g_string_printf(result,
"%u,%s,%.2f,%.2f,%s,%s\n",
entry->id,
tstr->str,
entry->value,
entry->totalAmount,
entry->user->str,
entry->notes->str
);
entry->_serialized = true;
return result;
}
/* returns the number of bytes written, following the convention of fprintf.
* Returns negative in case of error
*/
int write_bot_expense_entry
(
FILE *fp,
BotExpenseEntry *entry
)
{
GString *line = serialize_bot_expense_entry_csv(entry);
if(fp == NULL) {
fprintf(stderr, "File pointer to CSV is NULL. Initialize it before calling 'serialize_bot_expense_entry_csv'\n");
return -1;
}
if(line == NULL) {
return -1;
}
/* line is terminated with '\n' */
return fprintf(fp, "%s", line->str);
}
/* To be called after it has been serialized */
void free_bot_expense_entry
(
BotExpenseEntry *entry
)
{
if(!entry->_serialized) {
/* TODO could fail here instead */
fprintf(stderr, "WARNING: freeing an entry that wasn't serialized!\n");
}
/* Also free underlying string, we don't need it anymore */
g_string_free(entry->user, TRUE);
g_string_free(entry->notes, TRUE);
free(entry);
}