first of all here are the answers (source code pointers): -- grep for AppInfo. definition is in globals.h, "ThisAppInfoType" -- no automatic ("live") sorting in 1.01, it's just a menu command that does a static sort (v2 will have optional live sorting) -- grep for ItemPtr. definition is in globals.h, "Item"
<*>= #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include "pushchar.h" #include "pdblua.h" #include "pdbio.h" #include "pdbrep.h" #include "pdbconv.h" <functions>
P11. An application info structure is intended to be stored in the database's app info block and to contain data relevant to the database. For now we store just category information. Category information is always placed in the beginning where the category.c code expects it.
<functions>= (<-U) [D->] #define MAX_STORES 15 #define MAXSTNAME 32 struct HSAppInfo { struct PDBCategoryAppInfo categories; char padding[1]; unsigned short cStores; /* how many stores */ unsigned short bitStores; /* mask of used bits (or of all stores?) */ unsigned short rgbitStores[MAX_STORES]; /* if store exists, its bitmask */ unsigned short rgcItemsInStore[MAX_STORES+1]; /* [0] is "All Stores" (total) count */ char rgszStoreNames[MAX_STORES][MAXSTNAME+1]; char padding2[1]; };
DefinesMAXSTNAME
,MAX_STORES
(links are to index).
<functions>+= (<-U) [<-D->] static struct HSAppInfo readhsinfo(Text*); static void dumphsi(FILE *out, struct pdb *db, Text txt) { Text *t = &txt; struct HSAppInfo info = readhsinfo(t); int i, last; for (i = 0; i < info.cStores; i++) if (info.rgbitStores[i]) last = i; fprintf(out, "\n {"); fprintf(out, "\n categories = "); unpack_categories(out, &info.categories, 1); fprintf(out,",\n totalItems = %d", info.rgcItemsInStore[0]); fprintf(out,",\n stores = {"); for (i = 0; i < info.cStores; i++) if (info.rgbitStores[i]) fprintf(out, "\n { name = %s, mask = %d, items = %d }%s", QUOTE(info.rgszStoreNames[i]), info.rgbitStores[i], info.rgcItemsInStore[i+1], i < last ? "," : ""); fprintf(out,"\n },"); fprintf(out,"\n bitStores = %d,", info.bitStores); fprintf(out,"\n padding = { %d, %d }", info.padding[0], info.padding2[0]); fprintf(out,"\n }"); }
Definesdumphsi
(links are to index).
<functions>+= (<-U) [<-D->] static int writehsinfo(FILE *fp, struct HSAppInfo *info) { int i, n; long pos = fp ? ftell(fp) : 0; n = catwrite(fp, &info->categories); n += 1 + 2 + 2 + MAX_STORES*2 + (MAX_STORES+1)*2 + sizeof(info->rgszStoreNames) + 1; if (fp) { put_chars(fp, info->padding, 1); put_short(fp, info->cStores); put_short(fp, info->bitStores); for (i = 0; i < MAX_STORES; i++) put_short(fp, info->rgbitStores[i]); for (i = 0; i < MAX_STORES+1; i++) put_short(fp, info->rgcItemsInStore[i]); put_chars(fp, info->rgszStoreNames, sizeof(info->rgszStoreNames)); put_chars(fp, info->padding2, 1); assert(ftell(fp) - pos == n); } return n; }
Defineswritehsinfo
(links are to index).
<functions>+= (<-U) [<-D->] static struct HSAppInfo readhsinfo(Text *t) { struct HSAppInfo info; int i; unsigned char *curp = t->p; info.categories = catread(t); get_chars(info.padding, t, 1); info.cStores = get_short(t); assert(info.cStores <= MAX_STORES); info.bitStores = get_short(t); for (i = 0; i < MAX_STORES; i++) info.rgbitStores[i] = get_short(t); for (i = 0; i < MAX_STORES+1; i++) info.rgcItemsInStore[i] = get_short(t); get_chars(info.rgszStoreNames, t, sizeof(info.rgszStoreNames)); get_chars(info.padding2, t, 1); if (chars_remaining(t) > 0) fprintf(stderr, "Warning: %d unused bytes of HandyShopper info\n", chars_remaining(t)); t->p = (unsigned char *) curp; return info; }
Definesreadhsinfo
(links are to index).
<functions>+= (<-U) [<-D->]
static int pack(FILE *pdb, int appinfo) {
struct HSAppInfo info;
memset(&info, 0, sizeof(info));
if (pdb) {
int i;
<set the fields of the info
structure>
}
return writehsinfo(pdb, &info);
}
Definespack
(links are to index).
<write the info
structure>=
assert(0);
<set the fields of theinfo
structure>= (<-U) info.categories = pack_categories(); if (lua_dostring("info = Database.appInfo")) assert(0); dbcheck("istable(info)", "application info must be a table"); info.padding[0] = intopt("istable(info.padding) and info.padding[1]", 0); info.padding2[0] = intopt("istable(info.padding) and info.padding[2]", 0); info.rgcItemsInStore[0] = intval("info.totalItems"); dbcheck("istable(info.stores)", "application info must have stores list"); info.cStores = intval("listlength(info.stores)"); info.bitStores = intval("info.bitStores"); for (i = 0; i < info.cStores; i++) { lua_beginblock(); <exporti
to Lua, offset by 1> info.rgbitStores[i] = intval("istable(info.stores[i]) and info.stores[i].mask"); setstring(info.rgszStoreNames[i], "istable(info.stores[i]) and info.stores[i].name or info.stores[i]", MAXSTNAME); info.rgcItemsInStore[i+1] = intval("istable(info.stores[i]) and info.stores[i].items"); lua_endblock(); }
<export i
to Lua, offset by 1>= (<-U U->)
(lua_pushnumber((double)(i+1)), lua_setglobal("i"));
<functions>+= (<-U) [<-D->] typedef struct HSRecord { unsigned char flags; /* ?? */ unsigned char namesize; /* length of descriptoin excluding null terminator */ unsigned short stores; /* 16 bits mapping to stores */ unsigned short quantity; unsigned long price; unsigned char aisle; char *name; /* may be longer */ } Item, *ItemPtr;
DefinesItem
,ItemPtr
(links are to index).
<functions>+= (<-U) [<-D->] static struct HSRecord hsread(Text *t, int recnum) { struct HSRecord rec; unsigned char *p = t->p; rec.flags = get_byte(t); rec.namesize = get_byte(t); rec.stores = get_short(t); rec.quantity = get_short(t); rec.price = get_long(t); rec.aisle = get_byte(t); rec.name = malloc(rec.namesize+1); assert(rec.name); get_chars(rec.name, t, rec.namesize+1); assert(rec.name[rec.namesize] == 0); if (chars_remaining(t) > 0) fprintf(stderr, "Warning: %d unused bytes in record %d\n", chars_remaining(t), recnum); t->p = p; return rec; }
Defineshsread
(links are to index).
<functions>+= (<-U) [<-D->] static int hswrite(FILE *fp, struct HSRecord *rec) { int n = 1+1+2+2+4+1+rec->namesize+1; n++; /* paranoia, to pass binary test */ if (fp) { long pos = ftell(fp); put_byte(fp, rec->flags); put_byte(fp, rec->namesize); put_short(fp, rec->stores); put_short(fp, rec->quantity); put_long(fp, rec->price); put_byte(fp, rec->aisle); put_chars(fp, rec->name, rec->namesize+1); putc(0, fp); /* paranoia, to pass binary test */ assert(ftell(fp) - pos == n); } return n; }
Defineshswrite
(links are to index).
<functions>+= (<-U) [<-D->]
#define flagNeed 0x01
#define flagCoupon 0x02
#define flagPrivate 0x80 /* private (home-brewed so we can keep store bits in sync) */
static int packr(FILE *pdb, int i) {
struct HSRecord rec;
<export i
to Lua, offset by 1>
if (lua_dostring(
"$debug\n"
"thisrecord = Database.records[i].data\n"
"if not storemasks then\n"
" storemasks = { }\n"
" j = 1\n"
" while Database.appInfo.stores[j] do\n"
" storemasks[Database.appInfo.stores[j].name] = "
" Database.appInfo.stores[j].mask\n"
" j = j + 1\n"
" end\n"
"end"))
assert(0);
dbcheck("istable(thisrecord)", "record data is not a table");
rec.name = stringval("thisrecord.name");
rec.namesize = strlen(rec.name);
rec.flags = 0;
if (bitval("thisrecord.need")) rec.flags |= flagNeed;
if (bitval("thisrecord.coupon")) rec.flags |= flagCoupon;
if (bitval("thisrecord.private")) rec.flags |= flagPrivate;
if (lua_dostring(
"$debug\n"
"j = istable(thisrecord.stores) or error('thisrecord.stores not a list')\n"
"thisrecord.storemask = 0\n"
"j = 1\n"
"while thisrecord.stores[j] do\n"
" thisrecord.storemask = \n"
" thisrecord.storemask + storemasks[thisrecord.stores[j]]\n"
" j = j + 1\n"
"end\n"
))
assert(0);
rec.stores = intval("thisrecord.storemask");
rec.quantity = intopt("thisrecord.quantity", 0);
rec.price = intopt("thisrecord.price and (100 * thisrecord.price)", 0);
rec.aisle = intopt("thisrecord.aisle", 1);
return hswrite(pdb, &rec);
}
DefinesflagCoupon
,flagNeed
,flagPrivate
,packr
(links are to index).
<functions>+= (<-U) [<-D->] static void dumphsr(FILE *out, struct pdb *db, int i); static struct HSRecord hsread(Text *t, int recnum); #define BIT(x) ((x) ? "1" : "nil") static void dumphsr(FILE *out, struct pdb *db, int recnum) { char *p = db->info.appInfo.chars; struct HSAppInfo info = readhsinfo(&db->info.appInfo); struct HSRecord item; int last, i; p = db->records[recnum].data.chars; item = hsread(&db->records[recnum].data, recnum); fprintf(out, "{"); fprintf(out, "\n name = %s,", QUOTE(item.name)); fprintf(out, "\n quantity = %d, price = %4.02f, aisle = %d,", item.quantity, (double)item.price / 100.0, item.aisle); fprintf(out, "\n need = %s, coupon = %s, private = %s,", BIT(item.flags & flagNeed), BIT(item.flags & flagCoupon), BIT(item.flags & flagPrivate)); fprintf(out, "\n stores = { "); for (i = 0; i < info.cStores; i++) if (item.stores & info.rgbitStores[i]) last = i; for (i = 0; i < info.cStores; i++) if (item.stores & info.rgbitStores[i]) fprintf(out, "%s%s", QUOTE(info.rgszStoreNames[i]), i < last ? ", " : " "); fprintf(out, "}"); fprintf(out, "\n }"); }
DefinesBIT
,dumphsr
(links are to index).
<functions>+= (<-U) [<-D] static char *infodoc[] = { 0 }; static char *recorddoc[] = { 0 }; static char *trailers[] = { 0 }; struct PDBConv handyShopper = { "HandyShop shopping list", "Data", "iShp", { infodoc, dumphsi, pack }, { 0, generic_unpackInfo, generic_packInfo }, { recorddoc, dumphsr, packr }, trailers };
DefineshandyShopper
,infodoc
,recorddoc
,trailers
(links are to index).
i
to Lua, offset by 1>: U1, D2, U3
info
structure>: U1, D2
info
structure>: D1