aboutsummaryrefslogtreecommitdiff
path: root/src/db.c
blob: 2d5df990236a9faac8b653ffcf95b9dc53777b05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
import numpy as np
import matplotlib.cm as cm

def map_to_color(a, range=None, map=cm.hsv, weights=None):
    a = np.asarray(a)
    if range is None:
        range = (a.min(), a.max())

    ax = (a - range[0])/(range[1]-range[0])

    frgba = map(ax)

    if weights is not None:
        frgba[:,0] *= weights
        frgba[:,1] *= weights
        frgba[:,2] *= weights

    rgba = (frgba*255).astype(np.uint32)

    return rgba[:,0] << 16 | rgba[:,1] << 8 | rgba[:,2]
cial { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* Copyright (c) 2019, Anthony Latorre <tlatorre at uchicago>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.

 * This program 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 General Public License for
 * more details.

 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "db.h"
#include <stdio.h> /* for fopen(), etc. */
#include <errno.h> /* for strerror(), etc. */
#include <string.h> /* for strncmp(), etc. */
#include <stdint.h> /* for uint32_t */
#include <stdlib.h> /* for atoi() */
#include "dict.h"
#include "util.h"

char db_err[256];

static uint64_t dbHash(const void *key)
{
    return dictGenHashFunction(key,8);
}

static int dbKeyCompare(void *privdata, const void *key1, const void *key2)
{
    return memcmp(key1,key2,8) == 0;
}

static void dbFree(void *privdata, void *val)
{
    free(val);
}

static dictType titleDB = {
    dbHash,
    NULL,
    NULL,
    dbKeyCompare,
    dbFree,
    dbFree
};

/* Add a bank to the database.
 *
 * If a bank with the same name and id already exists, it will be replaced. */
void replace_bank(dict *db, const char name[4], uint32_t id, dbval *data)
{
    uint32_t *buf = malloc(sizeof(uint32_t)*2);

    memcpy(buf,name,4);
    buf[1] = id;

    /* If the bank already exists, dictReplace will keep the old key, so we
     * have to free `buf`. */
    if (!dictReplace(db, buf, data)) free(buf);
}

/* Add a bank to the database.
 *
 * Returns 0 on success, -1 if the key already exists. */
int add_bank(dict *db, const char name[4], uint32_t id, dbval *data)
{
    uint32_t *buf = malloc(sizeof(uint32_t)*2);

    memcpy(buf,name,4);
    buf[1] = id;

    if (dictAdd(db, buf, data) != DICT_OK) {
        sprintf(db_err, "failed to add bank to database!\n");
        goto err;
    }

    return 0;

err:
    free(buf);
    return -1;
}

/* Get a bank from the database.
 *
 * Returns a pointer to the first value in the bank, or NULL if the bank
 * doesn't exist. */
dbval *get_bank(dict *db, const char name[4], uint32_t id)
{
    uint32_t buf[2];

    memcpy(buf,name,4);
    buf[1] = id;

    return dictFetchValue(db, buf);
}

/* Function to iterate over the fields in a title bank text file. Works sort of
 * like strtok(). Example:
 *
 *     char *item = iter_field(line);
 *     while (item) {
 *          // do something with item
 *          item = iter_field(NULL);
 *     }
 */
static char *iter_field(char *str)
{
    static char *ptr;
    static char buf[81];

    if (!str) str = ptr;

    ptr = buf;

    while (*str != '\x0' && ptr < (buf + 81)) {
        if (ptr == (buf + 2) && buf[0] == '#' && buf[1] == '.') {
            ptr = buf;
            while (*str != '\x0' && *str++ != '#');
            continue;
        }

        if (*str == ' ' || *str == '\n') {
            str++;
            if (ptr == buf) continue;
            break;
        }

        *ptr++ = *str++;
    }

    if (ptr == buf) return NULL;

    *ptr = '\x0';
    ptr = str;
    return buf;
}

/* Create a new database. */
dict *db_init(void)
{
    dict *db = dictCreate(&titleDB, NULL);
    return db;
}

/* Free a database. */
void db_free(dict *db)
{
    dictRelease(db);
}

/* Load a title bank file into the database `db`.
 *
 * If `replace` is 0, then loading an already existing bank will cause an
 * error. Otherwise, the bank will be replaced.
 *
 * Returns 0 on success, -1 on error. */
int load_file(dict *db, const char *filename, int replace)
{
    int i, index;
    char *item, *s;
    char line[256];
    char idh[4];
    uint32_t idn;
    int mul;
    int64_t value;
    double float_value;
    dbval *buf;
    int buf_size;

    buf_size = 10;

    buf = malloc(buf_size*sizeof(dbval));

    if (!buf) {
        strcpy(db_err,strerror(errno));
        return -1;
    }

    FILE *f = open_file(filename, "r");

    if (!f) {
        sprintf(db_err, "unable to open file '%s': %s", filename, strerror(errno));
        free(buf);
        return -1;
    }

    index = 0;
    while (fgets(line, sizeof(line), f)) {
        if (!strncmp(line,"*---",4)) {
            /* Comment. */
            continue;
        } else if (!strncmp(line,"*.--",4)) {
            /* Comment. */
            continue;
        } else if (!strncmp(line, "*LOG",4)) {
            /* Control line which we don't care about. */
            continue;
        } else if (!strncmp(line, "*PRI",4)) {
            /* Control line which we don't care about. */
            continue;
        } else if (!strncmp(line, "*US",3)) {
            /* Control line which we don't care about. */
            continue;
        } else if (!strncmp(line, "*KI",3)) {
            /* Control line which we don't care about. */
            continue;
        } else if (!strncmp(line, "*ANYWAY",7)) {
            /* Control line which we don't care about. */
            continue;
        } else if (!strncmp(line, "*FIN",4)) {
            /* Control line which we don't care about. */
            continue;
        } else if (!strncmp(line, "*DO",3)) {
            if (index > 0) {
                /* Save previous bank. */
                buf = realloc(buf,sizeof(dbval)*index);

                if (replace) {
                    replace_bank(db, idh, idn, buf);
                } else if (add_bank(db, idh, idn, buf) == DICT_ERR) {
                    sprintf(db_err, "bank '%.4s' already exists in the database", idh);
                    goto err;
                }

                buf_size = 10;

                buf = malloc(buf_size*sizeof(dbval));

                index = 0;
            }

            item = iter_field(line);
            item = iter_field(NULL);
            strncpy(idh,item,4);
            item = iter_field(NULL);
            idn = atoi(item);

            continue;
        }

        item = iter_field(line);
        while (item) {
            mul = 1;
            if ((s = strchr(item,'*'))) {
                *s = '\0';
                mul = atoi(item);
                item = s+1;
            }

            while (buf_size < (index+mul)*sizeof(dbval)) {
                buf_size *= 2;
                buf = realloc(buf, buf_size*sizeof(dbval));
            }

            if (!strncmp(item,"#x",2)) {
                /* Hexadecimal input. */
                value = strtol(item+2,NULL,16);
                for (i = 0; i < mul; i++) buf[index++].u32 = value;
            } else if (strchr(item,'E') || strchr(item,'.')) {
                /* Floating point input. */
                float_value = strtod(item,NULL);
                for (i = 0; i < mul; i++) buf[index++].f = float_value;
            } else {
                /* Assume it's an integer. */
                value = strtol(item,NULL,10);
                for (i = 0; i < mul; i++) buf[index++].u32 = value;
            }
            item = iter_field(NULL);
        }
    }

    buf = realloc(buf,sizeof(dbval)*index);

    if (replace) {
        replace_bank(db, idh, idn, buf);
    } else if (add_bank(db, idh, idn, buf) == DICT_ERR) {
        sprintf(db_err, "bank '%.4s' already exists in the database", idh);
        goto err;
    }

    fclose(f);

    return 0;

err:

    if (buf) free(buf);
    fclose(f);
    return -1;
}