#!/bin/bash # # Using the event_rpcgen.py output, grab the global_header_start=( "#ifndef DB_GEN_H\n" "#define DB_GEN_H 1\n" ) global_code_start=( "#include \"db.gen.h\"\n" "bool schema_register(evapp_ctx *ctx) {\n" " bool status = true;\n" ) global_code_end=( " return status;\n" "}\n" ) global_header_end=( "bool schema_register(evapp_ctx *ctx);\n" "#endif" ) header_template=$(cat < #include #include #include #include #include #include #include #include #include "app.h" #include "schema.gen.h" /* Interface functions for opaque event rpc marshalling to and from HDF */ bool %%TYPE%%_raw_to_hdf(evapp_ctx *ctx, void *data, size_t size, HDF **hdf); bool %%TYPE%%_load(evapp_ctx *ctx, u_int64_t id, struct %%TYPE%% **%%TYPE%%); bool %%TYPE%%_save(evapp_ctx *ctx, u_int64_t id, struct %%TYPE%% *%%TYPE%%); bool %%TYPE%%_hdf_load(evapp_ctx *ctx, u_int64_t id, HDF **hdf); bool %%TYPE%%_hdf_save(evapp_ctx *ctx, u_int64_t id, HDF *hdf); bool %%TYPE%%_del(evapp_ctx *ctx, u_int64_t id); /* Takes advantage of incomplete RPC objects by converting them to HDF * and using the empty/default HDF to scaffold pages. */ bool %%TYPE%%_template(evapp_ctx *ctx, HDF **hdf); /* Cleans up any static state stored in the generated file */ bool %%TYPE%%_cleanup(void); /* Used by schema_register to add the database. It can be called manually * if schema_register is too automated */ bool %%TYPE%%_register(evapp_ctx *ctx, const char *dbname, bool (*validate)(evapp_ctx*, HDF*)); bool %%TYPE%%_register_indices(evapp_ctx *ctx, const char *dbname); #endif EOF) code_template=$(cat < #include #include #include #include #include #include #include "schema.gen.h" // mm mm globals! static evapp_db *db = NULL; static HDF *%%TYPE%%_hdf = NULL; bool %%TYPE%%_cleanup() { if (%%TYPE%%_hdf) hdf_destroy(&%%TYPE%%_hdf); %%TYPE%%_hdf = NULL; db = NULL; return true; } bool %%TYPE%%_template(evapp_ctx *ctx, HDF **hdf) { struct %%TYPE%% *%%TYPE%%; NEOERR *err = NULL; // XXX: this will become unreachable and will be lost on shutdown if (!ctx || !hdf) return false; // Duplicated the stored template if this has been done before. if (%%TYPE%%_hdf) { err = hdf_init(hdf); if (!*hdf) return false; if (err != STATUS_OK) { nerr_ignore(&err); hdf_destroy(hdf); return false; } err = hdf_copy(*hdf, "", %%TYPE%%_hdf); if (err != STATUS_OK) { nerr_ignore(&err); hdf_destroy(hdf); return false; } return true; } %%TYPE%% = %%TYPE%%_new(); if (!%%TYPE%%) { return false; } *hdf = %%TYPE%%_to_hdf(%%TYPE%%); %%TYPE%%_free(%%TYPE%%); if (!*hdf) return false; /* make a copy for later use. * if this fails, still return true */ err = hdf_init(&%%TYPE%%_hdf); if (!%%TYPE%%_hdf) return true; if (err != STATUS_OK) { nerr_ignore(&err); hdf_destroy(&%%TYPE%%_hdf); return true; } err = hdf_copy(%%TYPE%%_hdf, "", *hdf); if (err != STATUS_OK) { nerr_ignore(&err); hdf_destroy(hdf); } return true; } bool %%TYPE%%_raw_to_hdf(evapp_ctx *ctx, void *data, size_t size, HDF **hdf) { struct %%TYPE%% *%%TYPE%%; struct evbuffer *databuf; if (data == NULL || size == 0 || !hdf) return false; databuf = evbuffer_new(); if (!databuf) { return false; } evbuffer_add(databuf, data, size); %%TYPE%% = %%TYPE%%_new(); if (!%%TYPE%%) { evbuffer_free(databuf); return false; } if (%%TYPE%%_unmarshal(%%TYPE%%, databuf) == -1) { evbuffer_free(databuf); %%TYPE%%_free(%%TYPE%%); return false; } evbuffer_free(databuf); *hdf = %%TYPE%%_to_hdf(%%TYPE%%); // note the id wont be included.. %%TYPE%%_free(%%TYPE%%); return true; } bool %%TYPE%%_load(evapp_ctx *ctx, u_int64_t id, struct %%TYPE%% **%%TYPE%%) { struct evbuffer *databuf; DBT key, data; if (!db) { db = evapp_db_select(ctx, "%%TYPE%%"); if (!db) return false; } memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); key.data = &id; key.ulen = key.size = sizeof(id); key.flags = DB_DBT_USERMEM; // XXX: longer term, we could keep some pre-allocated space // around for storing the bdb data. data.flags = DB_DBT_MALLOC; db->p->get(db->p, NULL, &key, &data, 0); if (data.size == 0 || !data.data) { return false; } databuf = evbuffer_new(); if (!databuf) { free(data.data); return false; } evbuffer_add(databuf, data.data, data.size); free(data.data); *%%TYPE%% = %%TYPE%%_new(); if (!*%%TYPE%%) { evbuffer_free(databuf); return false; } if (%%TYPE%%_unmarshal(*%%TYPE%%, databuf) == -1) { evbuffer_free(databuf); %%TYPE%%_free(*%%TYPE%%); return false; } evbuffer_free(databuf); return true; } bool %%TYPE%%_save(evapp_ctx *ctx, u_int64_t id, struct %%TYPE%% *%%TYPE%%) { DBT key, data; struct evbuffer *buffer; int r = 0; if (!%%TYPE%%) return false; if (!db) { db = evapp_db_select(ctx, "%%TYPE%%"); if (!db) return false; } if (%%TYPE%%_complete(%%TYPE%%) == -1) { //fprintf(stderr, "[%%TYPE%%_save] incomplete\n"); return false; } memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); key.data = &id; key.ulen = key.size = sizeof(id); key.flags = DB_DBT_USERMEM; buffer = evbuffer_new(); if (!buffer) return false; evbuffer_drain(buffer, -1); if (buffer) { %%TYPE%%_marshal(buffer, %%TYPE%%); data.data = EVBUFFER_DATA(buffer); data.size = EVBUFFER_LENGTH(buffer); if ((r = db->p->put(db->p, NULL, &key, &data, 0)) != 0) { // XXX: LOG //db->p->err(db->p, r, "[%%TYPE%%_save] put failed"); evbuffer_free(buffer); return false; } evbuffer_free(buffer); } return true; } bool %%TYPE%%_hdf_load(evapp_ctx *ctx, u_int64_t id, HDF **hdf) { struct %%TYPE%% *%%TYPE%%; // 21 should be large enough for the largest int64. // XXX: make this a define somewhere. char numbuf[21]; if (!%%TYPE%%_load(ctx, id, &%%TYPE%%)) return false; *hdf = %%TYPE%%_to_hdf(%%TYPE%%); %%TYPE%%_free(%%TYPE%%); /* Drop the id in for good measure. */ snprintf(numbuf, sizeof(numbuf), "%llu", id); hdf_set_value(*hdf, "Data.%%TYPE%%.id", numbuf); return true; } bool %%TYPE%%_hdf_save(evapp_ctx *ctx, u_int64_t id, HDF *hdf) { struct %%TYPE%% *%%TYPE%%; %%TYPE%% = %%TYPE%%_from_hdf(hdf); if (!%%TYPE%%) return false; if (!%%TYPE%%_save(ctx, id, %%TYPE%%)) { %%TYPE%%_free(%%TYPE%%); return false; } %%TYPE%%_free(%%TYPE%%); return true; } bool %%TYPE%%_del(evapp_ctx *ctx, u_int64_t id) { DBT key; int r = 0; if (!db) { db = evapp_db_select(ctx, "%%TYPE%%"); // XXX: should this check if the db->p is there? if (!db) return false; } memset(&key, 0, sizeof(DBT)); key.data = &id; key.ulen = key.size = sizeof(id); key.flags = DB_DBT_USERMEM; if ((r = db->p->del(db->p, NULL, &key, 0)) != 0) { //db->p->err(db->p, r, "[%%TYPE%%_del] del failed"); // XXX: log return false; } return true; } bool %%TYPE%%_register_indices(evapp_ctx *ctx, const char *dbname); bool %%TYPE%%_register(evapp_ctx *ctx, const char *dbname, bool (*validate)(evapp_ctx*, HDF*)) { bool status = true; status = evapp_db_add(ctx, dbname, "%%TYPE%%.db", &%%TYPE%%_hdf_load, &%%TYPE%%_hdf_save, &%%TYPE%%_del, &%%TYPE%%_raw_to_hdf, &%%TYPE%%_template, %%TYPE%%_cleanup, validate); if (status) %%TYPE%%_register_indices(ctx, dbname); return status; } EOF) callback_inner_int=$(cat <flags = DB_DBT_APPMALLOC; skey->data = num; skey->size = sizeof(uint32_t); } else { success = false; } } EOF) callback_inner_int64=$(cat <flags = DB_DBT_APPMALLOC; skey->data = num; skey->size = sizeof(uint64_t); } else { success = false; } } EOF) callback_inner_string=$(cat <flags = DB_DBT_APPMALLOC; skey->data = strdup(data); skey->size = strlen(data)+1; if (!skey->data) success = false; } EOF) callback_start=$(cat <data, pdata->size); %%TYPE%% = %%TYPE%%_new(); if (!%%TYPE%%) { evbuffer_free(databuf); // XXX: log serious error! fprintf(stderr, "%s: failed to create new %%TYPE%%\n", __func__); return DB_DONOTINDEX; } if (%%TYPE%%_unmarshal(%%TYPE%%, databuf) == -1) { evbuffer_free(databuf); %%TYPE%%_free(%%TYPE%%); fprintf(stderr, "%s: failed to unmarshal\n", __func__); return DB_DONOTINDEX; } evbuffer_free(databuf); EOF) callback_end=$(cat < db.gen.h echo -e "${global_code_start[*]}" > db.gen.c grep '^struct \(\w*\);' $file | cut -f2 -d' ' | cut -f1 -d';' | while read obj; do echo "[*] Generating code for $obj..." echo "${header_template//\%\%TYPE\%\%/$obj}" > ${obj}_db.gen.h echo "${code_template//\%\%TYPE\%\%/$obj}" > ${obj}_db.gen.c # Create any needed index callback functions from magic # comments in schema.rpc. grep "/\\*\\^\\*[ \\t]*index=${obj}:" $schema | cut -f2- -d= | cut -f1 -d';' | cut -f2- -d: | while read field_pair; do field=$(echo $field_pair | cut -f1 -d:) fieldtype=$(echo $field_pair | cut -f2 -d:) # Hope the field types dont have slashes :-P echo "${callback_start//\%\%TYPE\%\%/$obj}" | sed "s/\\%\\%FTYPE\\%\\%/${fieldtype}/g" | sed "s/\\%\\%FIELD\\%\\%/${field}/g" >> ${obj}_db.gen.c if [[ "$fieldtype" == "int" ]]; then echo "${callback_inner_int//\%\%TYPE\%\%/$obj}" | sed "s/\\%\\%FTYPE\\%\\%/${fieldtype}/g" | sed "s/\\%\\%FIELD\\%\\%/${field}/g" >> ${obj}_db.gen.c elif [[ "$fieldtype" == "int64" ]]; then echo "${callback_inner_int64//\%\%TYPE\%\%/$obj}" | sed "s/\\%\\%FTYPE\\%\\%/${fieldtype}/g" | sed "s/\\%\\%FIELD\\%\\%/${field}/g" >> ${obj}_db.gen.c elif [[ "$fieldtype" == "string" ]]; then echo "${callback_inner_string//\%\%TYPE\%\%/$obj}" | sed "s/\\%\\%FTYPE\\%\\%/${fieldtype}/g" | sed "s/\\%\\%FIELD\\%\\%/${field}/g" >> ${obj}_db.gen.c else echo "Unknown type: index=${obj}:${field_pair};" exit 1 fi echo "${callback_end//\%\%TYPE\%\%/$obj}" | sed "s/\\%\\%FTYPE\\%\\%/${fieldtype}/g" | sed "s/\\%\\%FIELD\\%\\%/${field}/g" >> ${obj}_db.gen.c done # Now create the register_indices function echo "${index_header//\%\%TYPE\%\%/$obj}" >> ${obj}_db.gen.c grep "/\\*\\^\\*[ \\t]*index=${obj}:" $schema | cut -f2- -d= | cut -f1 -d';' | cut -f2- -d: | while read field_pair; do field=$(echo $field_pair | cut -f1 -d:) fieldtype=$(echo $field_pair | cut -f2 -d:) # Hope the field types dont have slashes :-P echo "${index_body//\%\%TYPE\%\%/$obj}" | sed "s/\\%\\%FTYPE\\%\\%/${fieldtype}/g" | sed "s/\\%\\%FIELD\\%\\%/${field}/g" >> ${obj}_db.gen.c done echo "${index_footer//\%\%TYPE\%\%/$obj}" >> ${obj}_db.gen.c # Update global declarations echo "#include \"${obj}_db.gen.h\"" >> db.gen.h # Write overarching registration function to automate the addition # of all of the tables echo " status &= ${obj}_register(ctx,\"${obj}\", NULL);" >> db.gen.c done echo -e "${global_code_end[*]}" >> db.gen.c echo -e "${global_header_end[*]}" >> db.gen.h