4. Variables

4.1. Variables Overview

A variable type in zet is a thing that can be chaned over time. The format is "$key:value". The message starts with "$" to inidicate the type flag. The variable name "key" is inbetween the "$" and the ":". The remaining part of the message is the value, which can be treated like another zet value.

4.2. Create a New Variable

A variable must be explicitely created before it can be used. This is done to minimize typo-related errors. (At the time of writing, zet doesn't isn't great at removing or editing commands). wwzet_var_new will create a new variable var and tie it to a item with UUID id. The value will be set to be empty.

<<funcdefs>>=
int wwzet_var_new(weewiki_d *ww,
                  wwzet_uuid *id,
                  const char *var,
                  int sz);
<<funcs>>=
int wwzet_var_new(weewiki_d *ww,
                  wwzet_uuid *id,
                  const char *var,
                  int sz)
{
    sqlite3 *db;
    sqlite3_stmt *stmt;
    int rc;
    int err;
    db = weewiki_db(ww);

    err = 0;

    sqlite3_prepare_v2(db,
    "INSERT INTO wikizet(time, UUID, value) "
    "SELECT datetime(), ?1, '$' || ?2 || ':' "
    "WHERE NOT EXISTS (SELECT 1 from wikizet WHERE "
    "UUID LIKE ?1 AND "
    "VALUE like '$' || ?2 || ':%');",
    -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, id->str, -1, NULL);
    sqlite3_bind_text(stmt, 2, var, sz, NULL);

    rc = sqlite3_step(stmt);

    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
        err = 1;
    }

    sqlite3_finalize(stmt);

    return err;
}

4.3. Setting a Variable to be a Link

A variable can be set to link to another UUID with wwzet_var_link.

<<funcdefs>>=
int wwzet_var_link(weewiki_d *ww,
                   wwzet_uuid *id,
                   const char *var, int sz,
                   wwzet_uuid *ref);
<<funcs>>=
int wwzet_var_link(weewiki_d *ww,
                   wwzet_uuid *id,
                   const char *var, int sz,
                   wwzet_uuid *ref)
{
    sqlite3 *db;
    sqlite3_stmt *stmt;
    int rc;
    int err;
    db = weewiki_db(ww);

    err = 0;

    sqlite3_prepare_v2(db,
    "UPDATE wikizet "
    "SET time = datetime(), "
    "value = '$' || ?1 || ':#' || ?2"
    "WHERE (UUID is ?3 AND "
    "value LIKE '$' || ?1 || ':%');",
    -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, var, sz, NULL);
    sqlite3_bind_text(stmt, 2, ref->str, -1, NULL);
    sqlite3_bind_text(stmt, 3, id->str, -1, NULL);

    rc = sqlite3_step(stmt);

    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
        err = 1;
    }

    if (sqlite3_changes(db) == 0) {
        err = 1;
    }

    sqlite3_finalize(stmt);

    return err;
}

4.4. Setting a Variable to be a Message

A variable can be set to be a message with wwzet_var_message.

<<funcdefs>>=
int wwzet_var_message(weewiki_d *ww,
                      wwzet_uuid *id,
                      const char *var, int vsz,
                      const char *msg, int msz);
<<funcs>>=
int wwzet_var_message(weewiki_d *ww,
                      wwzet_uuid *id,
                      const char *var, int vsz,
                      const char *msg, int msz)
{
    sqlite3 *db;
    sqlite3_stmt *stmt;
    int rc;
    int err;
    db = weewiki_db(ww);

    err = 0;

    sqlite3_prepare_v2(db,
    "UPDATE wikizet "
    "SET time = datetime(), "
    "value = '$' || ?1 || ':>' || ?2"
    "WHERE (UUID is ?3 AND "
    "value LIKE '$' || ?1 || ':%');",
    -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, var, vsz, NULL);
    sqlite3_bind_text(stmt, 2, msg, msz, NULL);
    sqlite3_bind_text(stmt, 3, id->str, -1, NULL);

    rc = sqlite3_step(stmt);

    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
        err = 1;
    }

    if (sqlite3_changes(db) == 0) {
        err = 1;
    }

    sqlite3_finalize(stmt);

    return err;
}

4.5. Touching A Variable

wwzet_var_touch will touch a variable in a UUID, updating the timestamp to the present. Touch gets its name from the Unix command which is used in a similar way.

If the variable can't be found or another error happens, a non-zero value will be returned.

<<funcdefs>>=
int wwzet_var_touch(weewiki_d *ww,
                    wwzet_uuid *id,
                    const char *var, int vsz);
<<funcs>>=
int wwzet_var_touch(weewiki_d *ww,
                    wwzet_uuid *id,
                    const char *var, int vsz)
{
    sqlite3 *db;
    sqlite3_stmt *stmt;
    int rc;
    int err;
    db = weewiki_db(ww);

    err = 0;

    sqlite3_prepare_v2(db,
    "UPDATE wikizet "
    "SET time = datetime() "
    "WHERE (UUID is ?2 AND "
    "value LIKE '$' || ?1 || ':%');",
    -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, var, vsz, NULL);
    sqlite3_bind_text(stmt, 2, id->str, -1, NULL);

    rc = sqlite3_step(stmt);

    if (rc != SQLITE_DONE) {
        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
        err = 1;
    }

    if (sqlite3_changes(db) == 0) {
        err = 1;
    }

    sqlite3_finalize(stmt);

    return err;
}

4.6. Command Line Interface

Here are some command line operations, all under the subcommand "var"

4.6.1. Top Level

All variable subcommands get here.

<<static_funcdefs>>=
static int zet_var(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int zet_var(weewiki_d *ww, int argc, char *argv[])
{
    argc--;
    argv++;

    if (argc <= 0) {
        fprintf(stderr, "Please enter a command.\n");
        return 1;
    }

    if (!strcmp(argv[0], "new")) {
        return p_varnew(ww, argc, argv);
    } else if (!strcmp(argv[0], "link")) {
        return p_varlink(ww, argc, argv);
    } else if (!strcmp(argv[0], "list")) {
        return p_varlist(ww, argc, argv);
    } else if (!strcmp(argv[0], "set")) {
        return p_varset(ww, argc, argv);
    } else if (!strcmp(argv[0], "touch")) {
        return p_vartouch(ww, argc, argv);
    } else if (!strcmp(argv[0], "get")) {
        return p_varget(ww, argc, argv);
    } else if (!strcmp(argv[0], "create")) {
        return p_varcreate(ww, argc, argv);
    } else {
        fprintf(stderr, "Could not find command '%s'\n", argv[0]);
    }
    return 1;
}

4.6.2. New

usage: new uuid name

creates a new variable called name. with a uuid uuid.

<<static_funcdefs>>=
static int p_varnew(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_varnew(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    wwzet_uuid id;
    const char *idstr;
    const char *name;

    if (argc < 3) {
        fprintf(stderr, "Usage: new UUID name\n");
        return 1;
    }

    idstr = argv[1];
    name = argv[2];

    rc = wwzet_uuid_resolve(ww, idstr, strlen(idstr), &id);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", idstr);
        return 1;
    }

    rc = wwzet_var_new(ww, &id, name, strlen(name));

    if (rc) {
        fprintf(stderr,
                "Issue with creating variable '%s'\n",
                name);
        return 1;
    }

    return 0;
}

4.6.3. Link

usage: link uuid name value

sets a variable to link with an existing item. value can be a UUID, group, page, or anything else that the zet can resolve.

<<static_funcdefs>>=
static int p_varlink(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_varlink(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    wwzet_uuid id;
    const char *idstr;
    const char *name;
    wwzet_uuid ref;
    const char *refstr;

    if (argc < 4) {
        fprintf(stderr, "Usage: link UUID name value\n");
        return 1;
    }

    idstr = argv[1];
    name = argv[2];
    refstr = argv[3];

    rc = wwzet_uuid_resolve(ww, idstr, strlen(idstr), &id);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", idstr);
        return 1;
    }

    rc = wwzet_uuid_resolve(ww, refstr, strlen(refstr), &ref);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", refstr);
        return 1;
    }

    rc = wwzet_var_link(ww, &id, name, strlen(name), &ref);

    if (rc) {
        fprintf(stderr,
                "Issue linking variable '%s' (does it exist?)\n",
                name);
        return 1;
    }

    return 0;
}

4.6.4. List

usage: list name item

List UUIDs with the variable name and item name item. For example, running list state @TODO would list all UUIDs with the variable state pointing to the TODO group.

These will be ordered by timestamp in ascending order.

<<static_funcdefs>>=
static int p_varlist(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_varlist(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    const char *name;
    wwzet_uuid ref;
    const char *refstr;
    sqlite3 *db;
    sqlite3_stmt *stmt;

    if (argc < 3) {
        fprintf(stderr, "Usage: list name value\n");
        return 1;
    }

    name = argv[1];
    refstr = argv[2];

    rc = wwzet_uuid_resolve(ww, refstr, strlen(refstr), &ref);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", refstr);
        return 1;
    }

    db = weewiki_db(ww);

    sqlite3_prepare_v2(db,
    "SELECT datetime(time, 'localtime'), UUID, value FROM wikizet "
    "WHERE UUID in (SELECT UUID from wikizet "
    "WHERE VALUE LIKE '$' || ?1 || ':#' || ?2 "
    "ORDER by strftime(time) ASC);", -1, &stmt, NULL);

    sqlite3_bind_text(stmt, 1, name, -1, NULL);
    sqlite3_bind_text(stmt, 2, ref.str, -1, NULL);

    rc = sqlite3_step(stmt);

    while (rc == SQLITE_ROW) {
        const char *t, *u, *v;

        t = (const char *)sqlite3_column_text(stmt, 0);
        u = (const char *)sqlite3_column_text(stmt, 1);
        v = (const char *)sqlite3_column_text(stmt, 2);

        printf("%s\t%s\t%s\n", (t == NULL ? "-" : t), u, v);

        rc = sqlite3_step(stmt);
    }


    sqlite3_finalize(stmt);
    return 0;
}

4.6.5. Set

usage: set uuid name value

Sets the variable name to be value. Note that this implicitely sets the value type to be a message.

<<static_funcdefs>>=
static int p_varset(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_varset(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    wwzet_uuid id;
    const char *idstr;
    const char *name;
    const char *msg;
    char *line;

    line = NULL;

    if (argc < 3) {
        fprintf(stderr, "Usage: set UUID name value\n");
        return 1;
    }

    idstr = argv[1];
    name = argv[2];

    if (argc == 4) {
        msg = argv[3];
    } else {
        line = linenoise("set: ");
        msg = line;
    }

    rc = wwzet_uuid_resolve(ww, idstr, strlen(idstr), &id);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", idstr);
        return 1;
    }

    rc = wwzet_var_message(ww, &id,
                           name, strlen(name),
                           msg, strlen(msg));

    if (rc) {
        fprintf(stderr,
                "Issue setting variable '%s' (does it exist?)\n",
                name);
        return 1;
    }


    if (line != NULL) free(line);

    return 0;
}

4.6.6. Get

usage: get uuid name

gets the variable name associated with uuid.

<<static_funcdefs>>=
static int p_varget(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_varget(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    wwzet_uuid id;
    const char *idstr;
    const char *name;
    sqlite3 *db;
    sqlite3_stmt *stmt;
    int e;

    e = 0;

    if (argc < 2) {
        fprintf(stderr, "Usage: get UUID name\n");
        return 1;
    }

    idstr = argv[1];
    name = argv[2];

    rc = wwzet_uuid_resolve(ww, idstr, strlen(idstr), &id);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", idstr);
        return 1;
    }


    db = weewiki_db(ww);

    rc = sqlite3_prepare_v2(db,
                       "SELECT substr(value, length(?2) + 3) FROM wikizet "
                       "WHERE UUID is ?1 "
                       "AND value LIKE '$'||?2||':%' "
                       "LIMIT 1 "
                       ";", -1, &stmt, NULL);

    sqlite3_bind_text(stmt, 1, id.str, -1, NULL);
    sqlite3_bind_text(stmt, 2, name, -1, NULL);

    rc = sqlite3_step(stmt);

    if (rc != SQLITE_ROW) {
        fprintf(stderr, "Could not find variable '%s'\n", name);
        e = 1;
    } else {
        fwrite(sqlite3_column_text(stmt, 0), 1,
               sqlite3_column_bytes(stmt, 0), stdout);
        fflush(stdout);
    }

    sqlite3_finalize(stmt);

    return e;
}

4.6.7. Touch

usage: touch uuid varname

Update the timestamp of a variable to the present. Useful in programs like zetdo where lists are ordered chronologically.

<<static_funcdefs>>=
static int p_vartouch(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_vartouch(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    wwzet_uuid id;
    const char *idstr;
    const char *name;

    if (argc < 3) {
        fprintf(stderr, "Usage: touch UUID varname\n");
        return 1;
    }

    idstr = argv[1];
    name = argv[2];

    rc = wwzet_uuid_resolve(ww, idstr, strlen(idstr), &id);

    if (rc) {
        fprintf(stderr, "Could not resolve '%s'\n", idstr);
        return 1;
    }

    rc = wwzet_var_touch(ww, &id, name, strlen(name));

    if (rc) {
        fprintf(stderr,
                "Issue setting variable '%s' (does it exist?)\n",
                name);
        return 1;
    }

    return 0;
}

4.6.8. Create

usage: create name

The create command creates a brand new zet entry with UUID with a variable. This is similar to new, except that a UUID doesn't need to exist.

<<static_funcdefs>>=
static int p_varcreate(weewiki_d *ww, int argc, char *argv[]);
<<funcs>>=
static int p_varcreate(weewiki_d *ww, int argc, char *argv[])
{
    int rc;
    wwzet_uuid id;
    const char *name;

    if (argc < 2) {
        fprintf(stderr, "Usage: create name\n");
        return 1;
    }

    wwzet_uuid_rng_init();
    wwzet_uuid_init(&id);
    wwzet_uuid_generate(&id);

    name = argv[1];

    rc = wwzet_var_new(ww, &id, name, strlen(name));

    if (rc) {
        fprintf(stderr,
                "Issue with creating variable '%s'\n",
                name);
        return 1;
    }

    printf("%s\n", id.str);

    return 0;
}



prev | home | next