Richard said:
dfighter said:
Well, well, well. Even a stopped clock is right twice a day.
That's pretty tiny - okay, quite a large tiny, but nevertheless well
within Usenet limits (put LONG in the subject line as a warning to
the modem users amongst us, and you're covered). This isn't IRC.
Sometimes that isn't within our control. When I moved ISP, I left a
number of pages behind that I can no longer maintain. Worse still,
they're still there, so few people realise that the pages are no
longer maintained.
I hope this won't happen again (not because I won't move ISPs again,
but because I now do my own hosting, with Web forwarding).
ANYWAY - I did actually look through your code. I didn't have time
for a full review, I'm afraid, but before I realised this I did
spot a few minor conformance issues (the one I remember being
leading underscores on identifiers) and a design consideration (as
a matter of robustness you might want to take T** in your
destructors, rather than T*, so that you can set *p to NULL when
you're done).
Thank you Richard for you observations. Since you told me it's ok to
post larger codebases too, I'm posting it now.
------------------------------SOURCECODE--------------------------------------
ui.h:
#ifndef __DBUI__
#define __DBUI__
#define TABLE_OK 0
#define TABLE_ALREADY_EXISTS 1
#define TABLE_ERROR -1
void ui_mainmenu(void);
#endif
tree.h:
#ifndef __MYTREE_H__
#define __MYTREE_H__
#define MAXFIELDNAMELENGTH 100
#define SIGLENGTH 6
#define SIG "DBTBL"
#define FILECORRUPT -1
typedef struct __mytreeinfo__ {
unsigned char numfields;
unsigned long numrecords;
unsigned char *afieldtypes;
char **afieldnames;
}treeinfo_t;
typedef struct __mytreenode__ {
struct __mytreenode__ *parent;
struct __mytreenode__ *left;
struct __mytreenode__ *right;
void **field;
}treenode_t;
typedef struct __mytreefilehdr__{
char signature[SIGLENGTH];
unsigned long numrecords;
unsigned char numfields;
unsigned char *afieldtypes;
char **afieldnames;
}treefilehdr_t;
/*
*
* Tree handling functions
*
**/
void treeinfo_init(treeinfo_t *info, unsigned char numfields, unsigned
char *afieldtypes);
void treeinfo_setfieldname(treeinfo_t *info, unsigned char fid, char *s);
void treeinfo_destroy(treeinfo_t *info);
void treenode_destroy(treenode_t *node, unsigned char numfields);
treenode_t* treenode_allocate(unsigned char numfields, unsigned char
*afieldtypes);
void tree_destroy(treenode_t *root, unsigned char numfields);
treenode_t* tree_addnode_nr(treenode_t *root, treeinfo_t *info, void**
fields);
void tree_dump(treenode_t *root, treeinfo_t *info);
unsigned long tree_serialize(treenode_t *root, treeinfo_t *info, FILE *fp);
unsigned long tree_writeheader(treeinfo_t *info, FILE *fp);
unsigned long tree_readhdr(treeinfo_t **info, FILE *fp, int *error);
unsigned long tree_deserialize(treenode_t **root, treeinfo_t *info, FILE
*fp);
#endif
table.h:
#ifndef __TABLE_H__
#define __TABLE_H__
int table_exists(void);
int table_create(unsigned char numfields, unsigned char *fieldtypes);
void table_destroy(void);
void table_setfieldname(unsigned char fid, char *s);
char* table_fieldname(int fid);
unsigned char table_numfields(void);
unsigned char table_fieldtype(int fid);
int table_addrecord(void **v);
void table_dump(void);
unsigned char* table_afieldtypes(void);
void* table_tableroot(void);
void table_save(void);
void table_load(void);
#endif
search.h:
#ifndef __SEARCH_H__
#define __SEARCH_H__
#define RESET 1
#define SEARCH 0
void search_search(unsigned char keyid, void *value, unsigned char
orderbyfield);
searchres_t* search_result_node(unsigned char reset);
void search_dropresults(void);
#endif
list.h:
#ifndef __LIST_H__
#define __LIST_H__
typedef struct list{
struct list* next;
unsigned char dummy;
void **field;
}list_t;
void listnode_destroy(list_t *node, unsigned char numfields);
void list_destroy(list_t *root, int numfields);
list_t* listnode_allocate(unsigned char dummy, unsigned char numfields,
unsigned char *afieldtypes);
list_t* list_addnode_ordered(list_t *root, void** values, unsigned char*
afieldtypes, unsigned char numfields, unsigned char orderbyfieldno);
#endif
common.h:
#ifndef __COMMON_H__
#define __COMMON_H__
typedef struct search_result{
void **v;
unsigned char fieldnum;
unsigned char* afieldtypes;
}searchres_t;
enum fieldtypes { CHAR,INT,DOUBLE };
void* field_allocate(unsigned char type);
int field_compare(void* val1, void* val2, unsigned char type);
void field_setvalue(void *field, void *value, unsigned char type);
#endif
ui.c:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "ui.h"
#include "common.h"
#include "table.h"
#include "search.h"
#define MAXINPUTLINELENGTH 255
#define MAXFIELDS 255
#define MAXFIELDNAMELENGTH 100
#define QUITKEY 'q'
#define BACKKEY 'b'
static char *ui_menu_main_szitem[] = {
"Table",
"Quit",
NULL
};
static char *ui_menu_table_szitems[] = {
"Create",
"Destroy",
"Load",
"Save",
"Query",
"Dump",
"Back",
NULL
};
static char *ui_menu_table_query[] = {
"New record",
"Search",
"Back",
NULL
};
static char ui_menu_kmain[] = {
't',
'q',
0
};
static char ui_menu_ktable[] = {
'c',
'd',
'l',
's',
'q',
'p',
'b',
0
};
static char ui_menu_ktablequery[] = {
'n',
's',
'b',
0
};
static char *sztypes[] = {
"CHAR",
"INT",
"DOUBLE"
};
static char *header = "dfighterdb UI";
static char *separator = "-------------";
static void ui_trim(char *s){
int i = 0;
for(i = 0; s
!= '\0'; i++)
;
while(i > 0 && !isalnum(s))
i--;
s[i+1] = '\0';
}
static int ui_getmenuchoice(void){
char line[MAXINPUTLINELENGTH];
fgets(line,MAXINPUTLINELENGTH,stdin);
return line[0];
}
static int ui_getINT(int *error){
char line[MAXINPUTLINELENGTH];
int value = 0;
fgets(line,MAXINPUTLINELENGTH,stdin);
if(!isdigit(line[0]))
*error = -1;
else value = (int)atof(line);
return value;
}
static double ui_getDOUBLE(int *error){
char line[MAXINPUTLINELENGTH];
double value = 0.0;
fgets(line,MAXINPUTLINELENGTH,stdin);
if(!isdigit(line[0]) && line[0] != '+' && line[0] != '-')
*error = -1;
else value = atof(line);
return value;
}
static int ui_getSTRING(char *s){
fgets(s,MAXINPUTLINELENGTH,stdin);
ui_trim(s);
if(!isalpha(s[0]))
return -1;
else return 0;
}
static void ui_tablemenu_create(void){
int status = 0;
int numfields = 0;
int error = 0;
int i = 0;
int type = 0;
unsigned char fieldtypes[MAXFIELDS];
char fieldnames[MAXFIELDS][MAXFIELDNAMELENGTH];
char name[MAXINPUTLINELENGTH];
status = table_exists();
if(status == TABLE_ALREADY_EXISTS){
printf("table already exists\n");
return;
}
printf("create new table\n");
printf("%s\n",separator);
error = 0;
do{
printf("number of fields:");
numfields = ui_getINT(&error);
if(error != 0)
printf("invalid input.\n");
}while(error != 0);
if(numfields > MAXFIELDS)
numfields = MAXFIELDS;
printf("possible field types:\n\n");
for(i = 0; i < 3; i++)
printf("%s - %d\n",sztypes, i);
putchar('\n');
for(i = 0; i < numfields; i++){
error = 0;
do{
printf("name of field%d:",i);
error = ui_getSTRING(name);
}while(error != 0);
/* table_setfieldname(i,name); */
strncpy(fieldnames,name,MAXFIELDNAMELENGTH);
}
for(i = 0; i < numfields; i++){
error = 0;
do{
printf("type of \"%s\":",fieldnames);
type = ui_getINT(&error);
if(error != 0 || type > 2)
printf("invalid input.\n");
}while(error != 0);
fieldtypes = (unsigned char)type;
}
printf("Creating table...");
if(table_create((unsigned char)numfields,fieldtypes) == TABLE_OK){
for(i = 0; i < numfields; i++)
table_setfieldname((unsigned char)i,fieldnames);
printf("done.\n");
}
else printf("error.\n");
}
static void ui_tablemenu_destroy(void){
if(table_exists() != TABLE_ALREADY_EXISTS)
printf("Nothing to destroy.");
else{
printf("destroying table..");
table_destroy();
}
}
void ui_tablemenu_query_new(void){
unsigned char numfields = table_numfields();
int i = 0;
void **v = NULL;
unsigned char type = 0;
char *fieldname = NULL;
int error = 0;
char cval = 0;
int ival = 0;
double dval = 0;
v = malloc(numfields*sizeof(void*));
if(v == NULL){
printf("ERROR: not enough memory\n");
return;
}
for(i = 0; i < numfields; i++){
type = table_fieldtype(i);
v = NULL;
switch(type){
case CHAR: v = malloc(sizeof(char)); break;
case INT: v = malloc(sizeof(int)); break;
case DOUBLE: v = malloc(sizeof(double)); break;
}
if(v == NULL){
i--;
while(i >= 0)
free(v);
free(v);
printf("ERROR: not enough memory.\n");
return;
}
}
/* getting and setting the values */
for(i = 0; i < numfields; i++){
type = table_fieldtype(i);
fieldname = table_fieldname(i);
printf("%s (%s):",fieldname,sztypes[type]);
error = 0;
do{
switch(type){
case CHAR: cval = (unsigned char)ui_getmenuchoice();
field_setvalue(v,&cval,type); break;
case INT: ival = ui_getINT(&error); field_setvalue(v,&ival,type);
break;
case DOUBLE: dval = ui_getDOUBLE(&error);
field_setvalue(v,&dval,type); break;
}
}while(error != 0);
}
error = table_addrecord(v);
if(error == TABLE_OK)
printf("Record added successfully.\n");
else printf("Record couldn't be added.\n");
/* freeing the array */
for(i = 0; i < numfields; i++){
free(v);
v = NULL;
}
free(v);
v = NULL;
}
void ui_tablemenu_query_search(void){
unsigned char i = 0;
unsigned char j = 0;
unsigned char numfields = table_numfields();
char *name = NULL;
int error = 0;
unsigned char keyid = 0;
char cval = 0;
int ival = 0;
double dval = 0.0;
searchres_t *sr = NULL;
void *val = NULL;
int orderkeyid = 0;
search_dropresults();
printf("Search:\n");
printf("%s\n",separator);
printf("Possible search keys:\n");
for(i = 0; i < numfields; i++){
name = table_fieldname(i);
printf("%d.) %s\n",i,name);
}
putchar('\n');
error = 0;
do{
printf("Search key id:");
keyid = (unsigned char)ui_getINT(&error);
}while(error != 0);
error = 0;
do{
printf("Value:");
switch(table_fieldtype(keyid)){
case CHAR: cval = (char)ui_getmenuchoice(); val = (void*)&cval; break;
case INT: ival = ui_getINT(&error); val = (void*)&ival; break;
case DOUBLE: dval = ui_getDOUBLE(&error); val = (void*)&dval; break;
}
}while(error != 0);
printf("Fields:\n");
for(i = 0; i < numfields; i++){
name = table_fieldname(i);
printf("%d.) %s\n",i,name);
}
putchar('\n');
do{
printf("Order by:");
orderkeyid = ui_getINT(&error);
}while(error != 0 && orderkeyid < 0);
printf("Searching... ");
search_search(keyid,val,(unsigned char)orderkeyid);
search_result_node(1);
printf("Done.\n");
printf("Results:\n");
for(sr = search_result_node(SEARCH); sr != NULL; sr =
search_result_node(SEARCH)){
for(j = 0; j < sr->fieldnum; j++){
printf("%s: ",table_fieldname(j));
switch(sr->afieldtypes[j]){
case CHAR: printf("%c",*(char*)sr->v[j]); break;
case INT: printf("%d",*(int*)sr->v[j]); break;
case DOUBLE: printf("%lf",*(double*)sr->v[j]); break;
}
putchar('\n');
}
putchar('\n');
}
}
void ui_tablemenu_query(void){
int i = 0;
int ch = 0;
if(table_exists() == TABLE_ERROR){
printf("nothing to query.\n\n");
return;
}
do{
printf("query table\n");
printf("%s\n",separator);
for(i = 0; ui_menu_ktablequery != 0; i++)
printf("%c.) %s\n",ui_menu_ktablequery,ui_menu_table_query);
putchar('\n');
putchar('#');
ch = ui_getmenuchoice();
switch(ch){
case 'n': ui_tablemenu_query_new(); break;
case 's': ui_tablemenu_query_search(); break;
}
}while(ch != BACKKEY);
}
static void ui_tablemenu(void){
int i = 0;
int ch = 0;
do{
printf("%s\n","table");
printf("%s\n",separator);
for(i = 0; ui_menu_table_szitems; i++)
printf("%c.) %s\n",ui_menu_ktable,ui_menu_table_szitems);
putchar('\n');
putchar('#');
ch = ui_getmenuchoice();
ch = tolower(ch);
switch(ch){
case 'c': ui_tablemenu_create(); break;
case 'd': ui_tablemenu_destroy(); break;
case 'q': ui_tablemenu_query(); break;
case 's': table_save(); break;
case 'l': table_load(); break;
case 'p': table_dump(); break;
}
}while(ch != EOF && ch != BACKKEY );
}
void ui_mainmenu(void){
int i = 0;
int ch = 0;
do{
printf("%s\n",header);
printf("%s\n",separator);
for(i = 0; i < 2; i++)
printf("%c.) %s\n",ui_menu_kmain,ui_menu_main_szitem);
printf("\n#");
ch = ui_getmenuchoice();
ch = tolower(ch);
switch(ch){
case 't': ui_tablemenu(); break;
}
printf("\n\n");
}while(ch != EOF && ch != QUITKEY);
search_dropresults();
if(table_exists() == TABLE_ALREADY_EXISTS)
table_destroy();
}
tree.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tree.h"
#include "common.h"
/* TreeInfo structure manipulating functions */
void treeinfo_init(treeinfo_t *info, unsigned char numfields, unsigned
char *afieldtypes){
int i = 0;
info->numfields = numfields;
info->afieldtypes = malloc(numfields*sizeof(unsigned char));
info->afieldnames = malloc(numfields*sizeof(char*));
info->numrecords = 0;
for(i = 0; i < numfields; i++)
info->afieldtypes = afieldtypes;
for(i = 0; i < numfields; i++)
info->afieldnames = malloc(MAXFIELDNAMELENGTH*sizeof(char));
}
void treeinfo_setfieldname(treeinfo_t *info, unsigned char fid, char *s){
strncpy(info->afieldnames[fid],s,MAXFIELDNAMELENGTH);
}
void treeinfo_destroy(treeinfo_t *info){
int i = 0;
if(info->afieldtypes != NULL)
free(info->afieldtypes);
for(i = 0; i < info->numfields; i++)
if(info->afieldnames != NULL && info->afieldnames != NULL)
free(info->afieldnames);
if(info->afieldnames != NULL)
free(info->afieldnames);
}
/* Treenode manipulating functions */
void treenode_destroy(treenode_t *node, unsigned char numfields){
int i = 0;
for(i = 0; i < numfields; i++)
if(node->field != NULL)
free(node->field);
free(node->field);
free(node);
}
treenode_t* treenode_allocate(unsigned char numfields, unsigned char
*afieldtypes){
treenode_t *newnode = NULL;
int i = 0;
int error = 0;
newnode = malloc(sizeof(treenode_t));
if(newnode == NULL)
return NULL;
newnode->field = NULL;
newnode->field = malloc(numfields*sizeof(void*));
if(newnode->field == NULL){
free(newnode);
return NULL;
}
for(i = 0; i < numfields; i++){
newnode->field = NULL;
newnode->field = field_allocate(afieldtypes);
}
for(i = 0; i < numfields; i++){
if(newnode->field == NULL){
error = 1;
break;
}
}
if(error == 1){
treenode_destroy(newnode,numfields);
newnode = NULL;
}
return newnode;
}
void tree_destroy(treenode_t *root, unsigned char numfields){
if(root == NULL)
return;
tree_destroy(root->left,numfields);
tree_destroy(root->right,numfields);
treenode_destroy(root,numfields);
}
/* for diagnostic purposes only, will have to be removed/disabled later */
void tree_dump(treenode_t *root, treeinfo_t *info){
int i = 0;
if(root == NULL)
return;
tree_dump(root->left,info);
for(i = 0; i < info->numfields; i++){
switch(info->afieldtypes){
case CHAR: printf("%c ",*(char*)root->field); break;
case INT: printf("%d ",*(int*)root->field); break;
case DOUBLE: printf("%lf ",*(double*)root->field); break;
}
putchar('\n');
}
putchar('\n');
tree_dump(root->right,info);
}
/* Adding the new node non-recursively */
treenode_t* tree_addnode_nr(treenode_t *root, treeinfo_t *info, void**
fields){
treenode_t *newnode = NULL;
treenode_t *current = NULL;
treenode_t *prev = NULL;
int i = 0;
newnode = treenode_allocate(info->numfields,info->afieldtypes);
if(newnode == NULL)
return root;
newnode->left = NULL;
newnode->right = NULL;
for(i = 0; i < info->numfields; i++)
field_setvalue(newnode->field,fields,info->afieldtypes);
if(root == NULL){
root = newnode;
}else{
current = prev = root;
while(current != NULL)
if(field_compare(fields[0],current->field[0],info->afieldtypes[0]) >= 0){
prev = current;
current = current->right;
}else{
prev = current;
current = current->left;
}
if(field_compare(fields[0],prev->field[0],info->afieldtypes[0]) >= 0){
prev->right = newnode;
newnode->parent = prev;
}else{
prev->left = newnode;
newnode->parent = prev;
}
}
info->numrecords += 1;
return root;
}
unsigned long tree_writeheader(treeinfo_t *info, FILE *fp){
unsigned long written = 0;
int i = 0;
written += fwrite( "DBTBL", SIGLENGTH*sizeof(char), 1, fp);
written += fwrite( &info->numrecords, sizeof(unsigned long), 1, fp);
written += fwrite( &info->numfields, sizeof(unsigned char), 1, fp);
written += fwrite( info->afieldtypes, info->numfields * sizeof(unsigned
char), 1, fp);
for(i = 0; i < info->numfields; i++){
written += fwrite( info->afieldnames, MAXFIELDNAMELENGTH *
sizeof(char), 1, fp);
}
return written;
}
unsigned long tree_readhdr(treeinfo_t **info, FILE *fp, int *error){
unsigned long read = 0;
int i = 0;
char name[MAXFIELDNAMELENGTH];
char sig[SIGLENGTH];
unsigned long numrecords = 0;
unsigned char numfields = 0;
unsigned char *afieldtypes = NULL;
if(info == NULL || *info != NULL)
return 0;
read += fread(sig, SIGLENGTH*sizeof(char), 1, fp);
if(strcmp(sig, SIG) != 0){
*error = FILECORRUPT;
return 0;
}
read += fread(&numrecords, sizeof(unsigned long), 1, fp);
if(&numrecords == 0){
*error = FILECORRUPT;
return 0;
}
read += fread(&numfields, sizeof(unsigned char), 1, fp);
if(&numfields == 0){
*error = FILECORRUPT;
return 0;
}
afieldtypes = malloc(numfields * sizeof(unsigned char));
for(i = 0; i < numfields; i++)
afieldtypes = 0;
*info = malloc(sizeof(treeinfo_t));
treeinfo_init(*info,numfields,afieldtypes);
free(afieldtypes);
afieldtypes = NULL;
(*info)->numfields = numfields;
(*info)->numrecords = numrecords;
read += fread((*info)->afieldtypes, (*info)->numfields *
sizeof(unsigned char), 1, fp);
for(i = 0; i < (*info)->numfields; i++){
read += fread(name, MAXFIELDNAMELENGTH * sizeof(char), 1, fp);
strncpy((*info)->afieldnames, name, MAXFIELDNAMELENGTH);
}
return read;
}
unsigned long tree_serialize(treenode_t *root, treeinfo_t *info, FILE *fp){
unsigned long written = 0;
int i = 0;
if(root == NULL || info == NULL)
return 0;
written += tree_serialize(root->left,info,fp);
written += tree_serialize(root->right,info,fp);
for(i = 0; i < info->numfields; i++){
switch(info->afieldtypes){
case CHAR: fwrite(root->field, sizeof(char), 1, fp); break;
case INT: fwrite(root->field, sizeof(int), 1, fp); break;
case DOUBLE: fwrite(root->field, sizeof(double), 1, fp); break;
}
}
written += 1;
return written;
}
unsigned long tree_deserialize(treenode_t **root, treeinfo_t *info, FILE
*fp){
unsigned long read = 0;
unsigned long i = 0;
unsigned long numrecords = 0;
int j = 0;
void **v = NULL;
if(info == NULL || info->numrecords == 0)
return 0;
numrecords = info->numrecords;
info->numrecords = 0;
v = malloc(info->numfields * sizeof(void*));
if(v == NULL){
printf("ERROR: not enough memory.\n");
return 0;
}
for(i = 0; i < info->numfields; i++){
v = field_allocate(info->afieldtypes);
}
for(i = 0; i < numrecords; i++){
for(j = 0; j < info->numfields; j++){
switch(info->afieldtypes[j]){
case CHAR: fread(v[j], sizeof(char), 1, fp); break;
case INT: fread(v[j], sizeof(int), 1, fp); break;
case DOUBLE: fread(v[j], sizeof(double), 1, fp); break;
}
}
*root = tree_addnode_nr(*root, info, v);
read += 1;
}
return read;
}
table.c:
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
#include "list.h"
#include "common.h"
#include "ui.h"
static treeinfo_t *tableinfo = NULL;
static treenode_t *tableroot = NULL;
void* table_tableroot(void){
return tableroot;
}
int table_create(unsigned char numfields, unsigned char *fieldtypes){
tableinfo = malloc(sizeof(treeinfo_t));
if(tableinfo == NULL)
return TABLE_ERROR;
treeinfo_init(tableinfo,numfields,fieldtypes);
return TABLE_OK;
}
void table_setfieldname(unsigned char fid, char *s){
treeinfo_setfieldname(tableinfo,fid,s);
}
char* table_fieldname(int fid){
return tableinfo->afieldnames[fid];
}
unsigned char table_numfields(void){
return tableinfo->numfields;
}
unsigned char table_fieldtype(int fid){
return tableinfo->afieldtypes[fid];
}
unsigned char* table_afieldtypes(void){
return tableinfo->afieldtypes;
}
void table_destroy(void){
if(tableinfo == NULL)
return;
if(tableroot != NULL)
tree_destroy(tableroot,tableinfo->numfields);
treeinfo_destroy(tableinfo);
free(tableinfo);
tableinfo = NULL;
tableroot = NULL;
}
int table_exists(void){
if(tableinfo != NULL)
return TABLE_ALREADY_EXISTS;
else return TABLE_ERROR;
}
int table_addrecord(void **v){
treenode_t *tp = NULL;
tp = tree_addnode_nr(tableroot,tableinfo,v);
if(tp != NULL){
tableroot = tp;
return TABLE_OK;
}else return TABLE_ERROR;
}
void table_dump(void){
printf("Dumping records:\n\n");
tree_dump(tableroot,tableinfo);
}
void table_save(void){
FILE *fp = NULL;
unsigned long written = 0;
if(tableinfo == NULL || tableroot == NULL || tableinfo->numrecords == 0){
printf("Nothing to save.\n");
return;
}
printf("Saving table... ");
fp = fopen("table.dat","wb");
if(fp == NULL){
printf("\nERROR: cannot open file.\n");
return;
}
written = tree_writeheader(tableinfo,fp);
if(written == 0){
printf("ERROR: cannot write to file.\n");
fclose(fp);
return;
}
written = tree_serialize(tableroot,tableinfo,fp);
if(written != tableinfo->numrecords){
printf("ERROR: Couldn't save 1 or more records.\n");
fclose(fp);
return;
}
printf("done.\n");
fclose(fp);
}
void table_load(void){
int errval = 0;
FILE *fp = NULL;
if(tableinfo != NULL || tableroot != NULL){
printf("Table already loaded.\n");
return;
}
printf("Loading table... ");
fp = fopen("table.dat","rb");
if(fp == NULL){
printf("\nERROR: cannot open file.\n");
return;
}
tree_readhdr(&tableinfo,fp,&errval);
tree_deserialize(&tableroot,tableinfo,fp);
printf("done.\n");
fclose(fp);
}
search.c:
#include <stdio.h>
#include "list.h"
#include "tree.h"
#include "table.h"
#include "common.h"
typedef struct searchparam{
treenode_t *root;
unsigned char keyid;
void* value;
unsigned char orderby;
unsigned char numfields;
unsigned char *fieldtypes;
}search_t;
static unsigned long numresults = 0;
static list_t *results = NULL;
static search_t search_struct;
static searchres_t searchres;
static void search_buildresultlist(treenode_t *root, search_t *searchs){
if(root == NULL)
return;
search_buildresultlist(root->left,searchs);
search_buildresultlist(root->right,searchs);
if(field_compare(searchs->value,
root->field[searchs->keyid],searchs->fieldtypes[searchs->keyid]) == 0)
results =
list_addnode_ordered(results,root->field,searchs->fieldtypes,
searchs->numfields, searchs->orderby);
}
void search_search(unsigned char keyid, void *value, unsigned char
orderbyfield){
search_struct.root = table_tableroot();
search_struct.keyid = keyid;
search_struct.value = value;
search_struct.orderby = orderbyfield;
search_struct.numfields = table_numfields();
search_struct.fieldtypes = table_afieldtypes();
search_buildresultlist(search_struct.root,&search_struct);
}
void search_dropresults(void){
list_destroy(results,search_struct.numfields);
results = NULL;
}
searchres_t* search_result_node(unsigned char reset){
static list_t *currnode = NULL;
if(results == NULL)
return NULL;
if(reset == 1){
currnode = results;
return NULL;
}
currnode = currnode->next;
if(currnode == NULL || currnode->dummy == 1){
currnode = NULL;
return NULL;
}
searchres.v = currnode->field;
searchres.afieldtypes = search_struct.fieldtypes;
searchres.fieldnum = search_struct.numfields;
return &searchres;
}
main.c:
#include <stdio.h>
#include "ui.h"
void list_test(void);
int main(void){
ui_mainmenu();
return 0;
}
list.c:
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "list.h"
#define DUMMY 1
#define NODE 0
void listnode_destroy(list_t *node, unsigned char numfields){
int i = 0;
if(node->dummy == 0){
for(i = 0; i < numfields; i++)
free(node->field);
free(node->field);
}
free(node);
}
list_t* listnode_allocate(unsigned char dummy, unsigned char numfields,
unsigned char *afieldtypes){
list_t *newnode = NULL;
int i = 0;
int error = 0;
newnode = malloc(sizeof(list_t));
if(newnode == NULL)
return NULL;
newnode->next = NULL;
if(dummy == 0){
newnode->field = malloc(numfields*sizeof(void*));
if(newnode->field == NULL){
free(newnode);
return NULL;
}
for(i = 0; i < numfields; i++){
newnode->field = field_allocate(afieldtypes);
}
for(i = 0; i < numfields; i++){
if(newnode->field == NULL){
error = 1;
break;
}
}
if(error == 1){
listnode_destroy(newnode,numfields);
newnode = NULL;
}
}
newnode->dummy = dummy;
return newnode;
}
list_t* list_addnode_ordered(list_t *root, void** values, unsigned char*
afieldtypes, unsigned char numfields, unsigned char orderbyfieldno){
list_t *newnode = NULL;
list_t *dummy1 = NULL;
list_t *dummy2 = NULL;
list_t *current = NULL;
list_t *prev = NULL;
int i = 0;
newnode = listnode_allocate(NODE,numfields,afieldtypes);
if(newnode == NULL)
return root;
for(i = 0; i < numfields; i++)
field_setvalue(newnode->field,values,afieldtypes);
if(root == NULL){
dummy1 = listnode_allocate(DUMMY,0,NULL);
dummy2 = listnode_allocate(DUMMY,0,NULL);
if(dummy1 == NULL || dummy2 == NULL)
return root;
root = dummy1;
dummy1->next = newnode;
newnode->next = dummy2;
}else{
current = root->next;
prev = root;
while(current->dummy == 0 &&
field_compare(values[orderbyfieldno],current->field[orderbyfieldno],afieldtypes[orderbyfieldno])
prev = current;
current = current->next;
}
prev->next = newnode;
newnode->next = current;
}
return root;
}
void list_destroy(list_t *root, int numfields){
list_t *current = NULL;
list_t *prev = NULL;
if(root == NULL)
return;
current = prev = root;
while(current != NULL){
prev = current;
current = current->next;
listnode_destroy(prev,(unsigned char)numfields);
}
}
void list_test(void){
list_t *mylist = NULL;
list_t *current = NULL;
void **v = NULL;
unsigned char *a = NULL;
unsigned char numfields = 3;
int i = 0;
int j = 0;
printf("testing the list engine....\n");
a = malloc(3*sizeof(unsigned char));
a[0] = DOUBLE;
a[1] = INT;
a[2] = CHAR;
v = malloc(numfields*sizeof(void*));
for(i = 0; i < numfields; i++){
switch(a){
case CHAR: v = malloc(sizeof(char)); break;
case INT: v = malloc(sizeof(int)); break;
case DOUBLE: v = malloc(sizeof(double)); break;
}
}
for(i = 0; i < 10; i++){
*(int*)v[1] = i;
*(double*)v[0] = i*1.66;
*(char*)v[2] = 'z'-(char)i;
mylist = list_addnode_ordered(mylist,v,a,numfields,0);
}
current = mylist->next;
for(j = 0; j < 10; j++){
for(i = 0; i < numfields; i++){
if(current->dummy == 0)
switch(a){
case CHAR: printf("%c ",*(char*)current->field); break;
case INT: printf("%d ",*(int*)current->field); break;
case DOUBLE: printf("%lf ",*(double*)current->field); break;
}
}
current = current->next;
putchar('\n');
}
list_destroy(mylist,numfields);
for(i = 0; i < numfields; i++)
free(v);
free(v);
free(a);
}
common.c:
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
void* field_allocate(unsigned char type){
void* fieldptr = NULL;
switch(type){
case CHAR: fieldptr = malloc(sizeof(char)); break;
case INT: fieldptr = malloc(sizeof(int)); break;
case DOUBLE: fieldptr = malloc(sizeof(double)); break;
default: return NULL; break;
}
return fieldptr;
}
int field_compare(void* val1, void* val2, unsigned char type){
int retval = 0;
switch(type){
case CHAR:{
if(*(char*)val1 > *(char*)val2)
retval = 1;
else
if(*(char*)val1 < *(char*)val2)
retval = -1;
}break;
case INT:{
if(*(int*)val1 > *(int*)val2)
retval = 1;
else if(*(int*)val1 < *(int*)val2)
retval = -1;
}break;
case DOUBLE:{
if(*(double*)val1 > *(double*)val2)
retval = 1;
else
if(*(double*)val1 < *(double*)val2)
retval = -1;
}break;
}
return retval;
}
void field_setvalue(void *field, void *value, unsigned char type){
switch(type){
case CHAR: *(char*)field = *(char*)value; break;
case INT: *(int*)field = *(int*)value; break;
case DOUBLE: *(double*)field = *(double*)value; break;
}
}
--------------------------END OF SOURCECODE---------------------------
dfighter