8. Block Ref
8.1. Struct
typedef struct wmp_blkref wmp_blkref;
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
void wmp_blkref_init(wmp_blkref *br);
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
.
void wmp_blkref_free(wmp_blkref *br);
After freeing the strings, the blkref is re-initialized for re-use.
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.
int wmp_blkref_find(wmp_core *c,
unsigned int id,
wmp_blkref *br,
int prog);
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
.
#ifdef SQLITE3_H
<<blkref_funcdefs>>
#endif
int wmp_blkref_lookup_setup(wmp_core *core,
const char *name,
int prog,
sqlite3_stmt **pstmt);
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.
int wmp_blkref_lookup_step(wmp_core *core,
sqlite3_stmt *stmt,
wmp_blkref *br);
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.
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 .
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
.
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);
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.
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.
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.
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.
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.
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.
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;
}
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