8. Block Ref

8.1. Struct

Known as wmp_blkref.

<<typedefs>>=
typedef struct wmp_blkref wmp_blkref;
<<structs>>=
struct wmp_blkref {
    unsigned int id;
    int ref;
    int pos;
    char *section;
    char *filename;
    int linum;
    int next;
    int prog;
    int segoff;
    int prev_lastseg;
};

8.2. init

<<function_declarations>>=
void wmp_blkref_init(wmp_blkref *br);
<<functions>>=
void wmp_blkref_init(wmp_blkref *br)
{
    br->id = -1;
    br->ref = -1;
    br->section = NULL;
    br->filename = NULL;
    br->linum = -1;
    br->next = -1;
    br->prog = -1;
    br->segoff = -1;
    br->prev_lastseg = -1;
    br->pos = -1;
}

8.3. Free

It is freed using wmp_blkref_free.

<<function_declarations>>=
void wmp_blkref_free(wmp_blkref *br);

After freeing the strings, the blkref is re-initialized for re-use.

<<functions>>=
void wmp_blkref_free(wmp_blkref *br)
{
    if (br->filename != NULL) free(br->filename);
    if (br->section != NULL) free(br->section);

    /* re-initialize */
    wmp_blkref_init(br);
}

8.4. Find

Just get the blkref data, given an id and program number.

<<function_declarations>>=
int wmp_blkref_find(wmp_core *c,
                    unsigned int id,
                    wmp_blkref *br,
                    int prog);
<<functions>>=
int wmp_blkref_find(wmp_core *c,
                    unsigned int id,
                    wmp_blkref *br,
                    int prog)
{
    sqlite3 *db;
    int rc;
    sqlite3_stmt *stmt;

    rc = 0;

    db = wmp_core_db(c);

    sqlite3_prepare_v2(db,
                       "SELECT "
                         "id, "
                         "ref, "
                         "section, "
                         "filename, "
                         "linum, "
                         "next, "
                         "program, "
                         "segoff, "
                         "prev_lastseg, "
                         "pos "
                       "FROM blkref "
                       "WHERE(id== ?1) AND "
                       "(program == ?2);"
                       ,
                       -1,
                       &stmt,
                       NULL);
    sqlite3_bind_int(stmt, 1, id);
    sqlite3_bind_int(stmt, 2, prog);

    rc = sqlite3_step(stmt);

    if (rc == SQLITE_ROW) {
        int nbytes;
        const char *sec;
        const char *fname;
        br->id = sqlite3_column_int(stmt, 0);
        br->ref = sqlite3_column_int(stmt, 1);

        nbytes = sqlite3_column_bytes(stmt, 2);
        br->section = calloc(1, nbytes + 1);
        sec = (const char *)sqlite3_column_text(stmt, 2);
        strncpy(br->section, sec, nbytes);

        nbytes = sqlite3_column_bytes(stmt, 3);
        br->filename = calloc(1, nbytes + 1);
        fname = (const char *)sqlite3_column_text(stmt, 3);
        strncpy(br->filename, fname, nbytes);

        br->linum = sqlite3_column_int(stmt, 4);

        br->next = sqlite3_column_int(stmt, 5);

        br->prog = sqlite3_column_int(stmt, 6);

        br->segoff = sqlite3_column_int(stmt, 7);

        br->prev_lastseg = sqlite3_column_int(stmt, 8);

        br->pos = sqlite3_column_int(stmt, 9);

        rc = WMP_OK;
    } else {
        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
        rc = WMP_NOT_OK;
    }

    sqlite3_finalize(stmt);
    return rc;
}

8.5. Lookup

This function is interesting because it is only possible to do with a SQL query; Worgle has no way of doing this internally in C.

Due to the SQL-yness of this operation, this functionality needs to be broken up into 2 parts.

The first part sets up the SQLite query. This creats a sqlite3_stmt.

<<function_declarations>>=
#ifdef SQLITE3_H
<<blkref_funcdefs>>
#endif
<<blkref_funcdefs>>=
int wmp_blkref_lookup_setup(wmp_core *core,
                            const char *name,
                            int prog,
                            sqlite3_stmt **pstmt);
<<functions>>=
int wmp_blkref_lookup_setup(wmp_core *core,
                            const char *name,
                            int prog,
                            sqlite3_stmt **pstmt)
{
    sqlite3 *db;
    int rc;
    wmp_block b;

    wmp_block_init(&b);
    rc = wmp_lookup_block(core, name, &b, prog);

    if (!rc) return rc;

    db = wmp_core_db(core);

    sqlite3_prepare_v2(db,
                       "SELECT "
                         "id, "
                         "ref, "
                         "section, "
                         "filename, "
                         "linum, "
                         "next, "
                         "program, "
                         "segoff, "
                         "prev_lastseg, "
                         "pos "
                       "FROM blkref "
                       "WHERE(program == ?1) AND "
                       "(ref == ?2);"
                       ,
                       -1,
                       pstmt,
                       NULL);
    sqlite3_bind_int(*pstmt, 1, prog);
    sqlite3_bind_int(*pstmt, 2, b.id);
    wmp_block_free(&b);

    return 1;
}

The second part steps through the query and gets called until there are no more values to return.

<<blkref_funcdefs>>=
int wmp_blkref_lookup_step(wmp_core *core,
                           sqlite3_stmt *stmt,
                           wmp_blkref *br);
<<functions>>=
int wmp_blkref_lookup_step(wmp_core *core,
                           sqlite3_stmt *stmt,
                           wmp_blkref *br)
{
    int rc;

    rc = sqlite3_step(stmt);

    if (rc == SQLITE_DONE) {
        wmp_blkref_free(br);
        sqlite3_finalize(stmt);
        return 0;
    }

    if (rc == SQLITE_ROW) {
        int nbytes;
        const char *sec;
        const char *fname;

        /* clear/free the blkref */
        wmp_blkref_free(br);

        br->id = sqlite3_column_int(stmt, 0);
        br->ref = sqlite3_column_int(stmt, 1);

        nbytes = sqlite3_column_bytes(stmt, 2);
        br->section = calloc(1, nbytes + 1);
        sec = (const char *)sqlite3_column_text(stmt, 2);
        strncpy(br->section, sec, nbytes);

        nbytes = sqlite3_column_bytes(stmt, 3);
        br->filename = calloc(1, nbytes + 1);
        fname = (const char *)sqlite3_column_text(stmt, 3);
        strncpy(br->filename, fname, nbytes);

        br->linum = sqlite3_column_int(stmt, 4);

        br->next = sqlite3_column_int(stmt, 5);

        br->prog = sqlite3_column_int(stmt, 6);

        br->segoff = sqlite3_column_int(stmt, 7);

        br->prev_lastseg = sqlite3_column_int(stmt, 8);

        br->pos = sqlite3_column_int(stmt, 9);
    } else {
        sqlite3 *db;

        db = wmp_core_db(core);
        fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        return WMP_NOT_OK;
    }

    return WMP_OK;
}

8.6. Blockref Neighbor lookup

Given a block reference, find the id another block reference at local position p. If nothing pops up, an invalid id of 0 gets returned.

<<function_declarations>>=
unsigned int wmp_blkref_neighbor(wmp_core *c,
                                 wmp_blkref *br,
                                 int pos);

The SQLite query looks like this:

select id from blkref where ref=?1 and pos=?2 and program=?3;

Where ?1 ref is the block reference id, found in the passed in blkref, and ?2 pos is the local position. The program ?3 is .

<<functions>>=
unsigned int wmp_blkref_neighbor(wmp_core *c,
                                 wmp_blkref *br,
                                 int pos)
{
    sqlite3 *db;
    int rc;
    sqlite3_stmt *stmt;
    unsigned int id;

    db = wmp_core_db(c);

    id = 0;

    sqlite3_prepare_v2(db,
                       "SELECT id "
                       "FROM blkref "
                       "WHERE(ref == ?1) AND "
                       "(pos == ?2) AND "
                       "(program == ?3);"
                       ,
                       -1,
                       &stmt,
                       NULL);
    sqlite3_bind_int(stmt, 1, br->ref);
    sqlite3_bind_int(stmt, 2, pos);
    sqlite3_bind_int(stmt, 3, br->prog);

    rc = sqlite3_step(stmt);

    if (rc == SQLITE_ROW) {
        id = sqlite3_column_int(stmt, 0);
    }

    sqlite3_finalize(stmt);
    return id;
}

8.7. Code Block Regeneration

The function wmp_blkref_codeblock will reproduce a portion of a code block, referred to as a subblock, given a block reference. This will return the code in the subblock as an array of segments.

Since the segment list is dynamically allocated, it must be also freed explicitly with wmp_blkref_codeblock_free.

<<function_declarations>>=
int wmp_blkref_codeblock(wmp_core *c,
                         wmp_blkref *br,
                         wmp_segment **segs,
                         int *nsegs);
void wmp_blkref_codeblock_free(wmp_core *c,
                               wmp_segment **segs,
                               int nsegs);
<<functions>>=
int wmp_blkref_codeblock(wmp_core *c,
                         wmp_blkref *br,
                         wmp_segment **segs,
                         int *nsegs)
{
    wmp_blkref next_br;
    unsigned int next_br_id;
    int rc;
    int len;
    wmp_segment *list;
    wmp_segment head;
    wmp_segment prevseg;
    wmp_block blk;
    int ok;
    int i;
    wmp_segment seg;

    ok = WMP_OK;
    len = 0;
    rc = -1;
    next_br_id = 0;
    list = NULL;

    wmp_blkref_init(&next_br);
    wmp_segment_init(&head);
    wmp_segment_init(&seg);
    wmp_segment_init(&prevseg);
    wmp_block_init(&blk);

<<retrieve_next_block_reference>>
<<retrieve_block_from_reference>>
<<calculate_number_of_segments>>
<<allocate_segment_list>>
<<obtain_first_segment>>
<<populate_segment_list>>

    (*nsegs) = len;
    *segs = list;


    cleanup:
    wmp_blkref_free(&next_br);
    wmp_block_free(&blk);
    wmp_segment_free(&prevseg);
    /* do not free head or seg, will be freed later */
    return ok;
}

From the block reference, retrieve the next block reference (if it exists). This will be needed later on. This can be retrieved using the pos value in the block reference schema and the magic of SQLite. pos + 1 will get the next block reference.

<<retrieve_next_block_reference>>=
next_br_id = wmp_blkref_neighbor(c, br, br->pos + 1);
if (next_br_id > 0) {
    rc = wmp_blkref_find(c, next_br_id, &next_br, br->prog);
    if (rc != WMP_OK) {
        wmp_blkref_free(&next_br);
        ok = WMP_NOT_OK;
        goto cleanup;
    }
}

Retrieve the block and make sure it exists. This may be in certain edge cases.

<<retrieve_block_from_reference>>=
rc = wmp_find_block(c, br->ref, &blk, br->prog);
if (rc != WMP_OK) {
    ok = WMP_NOT_OK;
    goto cleanup;
}

The number of segments in the subblock is calculated from segoff, or the segment offset. The segment offset stores the starting segment position relative to the block. Subtracting segoff of the next subblock will get the size. If there is no next reference, the offset can be subtracted from the total number of segments in the top-level block.

<<calculate_number_of_segments>>=
if (next_br_id > 0) {
    len = next_br.segoff - br->segoff;
} else {
    len = blk.nsegs - br->segoff;
}

The output segment list is then allocated with this value.

<<allocate_segment_list>>=
if (len > 0) {
    list = malloc(sizeof(wmp_segment) * len);
}

The first segment is obtained from prev_lastseg. It holds the id of the last segment of the previous block reference. Getting the next id from this segment will get the first segment of the current subblock.

If no prev_lastseg is found, use the segment found in the top-block.

<<obtain_first_segment>>=
if (br->prev_lastseg > 0) {
    rc = wmp_find_segment(c, br->prev_lastseg, &prevseg, br->prog);

    if (rc != WMP_OK) {
        ok = WMP_NOT_OK;
        goto cleanup;
    }

    rc = wmp_find_segment(c, prevseg.nxtseg, &head, br->prog);

    if (rc != WMP_OK) {
        ok = WMP_NOT_OK;
        goto cleanup;
    }
} else {
    rc = wmp_find_segment(c, blk.head_segment, &head, br->prog);
    if (rc != WMP_OK) {
        ok = WMP_NOT_OK;
        goto cleanup;
    }
}

After the first segment and total number of segments is found, the rest of the procedure works like a linked list operation, with each segment entry has a ID value pointing to the next segment. The contents of each segment get copied to their respective position in the segment list.

<<populate_segment_list>>=
list[0] = head;
seg = head;
for (i = 1; i < len; i++) {
    unsigned int nxt;
    nxt = seg.nxtseg;
    wmp_segment_init(&seg);
    rc = wmp_find_segment(c, nxt, &seg, br->prog);
    if (rc != WMP_OK) {
        ok = WMP_NOT_OK;
        len = i;
        goto cleanup;
    }
    list[i] = seg;
}
<<functions>>=
void wmp_blkref_codeblock_free(wmp_core *c,
                               wmp_segment **segs,
                               int nsegs)
{
    int i;
    wmp_segment *lst;

    lst = *segs;

    for (i = 0; i < nsegs; i++) {
        wmp_segment_free(&lst[i]);
    }

    free(lst);
}



prev | home | next