Although yet untested (but it compiles and is still unused) add UAT to the repo.

UAT is an API to handle User Accessible Tables,
an UAT is basically an array of arbitrary structs that has a file representation
as a mean for mantaining things like:
- the snmp_users_table
- dfilter macros
- ipsec/ssl key bindings
- k12 configuration,
- and many other table-like user modifiable preferences

comming soon gtk's uat_window() and prefs_add_uat()

uat.h is fairly doc[uo]m[m]?ented, a README with a simple example of how is to be used will be available as I write them


svn path=/trunk/; revision=20586
This commit is contained in:
Luis Ontanon 2007-01-28 10:31:32 +00:00
parent c4b562e988
commit 88e699977c
7 changed files with 893 additions and 0 deletions

View File

@ -116,6 +116,9 @@ radius_dict.c: radius_dict.l
load_snmp_users_file.c: load_snmp_users_file.l
$(LEX) -oload_snmp_users_file.c $(srcdir)/load_snmp_users_file.l
uat_load.c: uat_load.l
$(LEX) -ouat_load.c $(srcdir)/uat_load.l
dtd_parse.c : dtd_parse.l
$(LEX) -odtd_parse.c $(srcdir)/dtd_parse.l

View File

@ -88,6 +88,8 @@ LIBWIRESHARK_SRC = \
to_str.c \
tvbparse.c \
tvbuff.c \
uat.c \
uat_load.c \
unicode-utils.c \
value_string.c \
xdlc.c \
@ -185,6 +187,8 @@ LIBWIRESHARK_INCLUDES = \
to_str.h \
tvbparse.h \
tvbuff.h \
uat.h \
uat-int.h \
unicode-utils.h \
value_string.h \
x264_prt_id.h \

View File

@ -210,6 +210,9 @@ dtd_preparse.c : dtd_preparse.l
load_snmp_users_file.c : load_snmp_users_file.l
$(LEX) -oload_snmp_users_file.c load_snmp_users_file.l
uat_load.c : uat_load.l
$(LEX) -ouat_load.c uat_load.l
dtd_grammar.h: dtd_grammar.c
LEMON=..\tools\lemon

67
epan/uat-int.h Normal file
View File

@ -0,0 +1,67 @@
/*
* uat-int.h
*
* User Accessible Tables
* Mantain an array of user accessible data strucures
* Internal interface
*
* (c) 2007, Luis E. Garcia Ontanon
*
*/
#ifndef _UAT_INT_H_
#define _UAT_INT_H_
#include "uat.h"
typedef struct _uat_fld_rep_t uat_fld_rep_t;
typedef struct _uat_rep_t uat_rep_t;
typedef void (*uat_rep_fld_free_cb_t)(uat_fld_rep_t*);
typedef void (*uat_rep_free_cb_t)(uat_rep_t*);
typedef struct _uat_fld_t {
char* name;
uat_text_mode_t mode;
uat_fld_chk_cb_t chk_cb;
uat_fld_set_cb_t set_cb;
uat_fld_tostr_cb_t tostr_cb;
guint colnum;
uat_fld_rep_t* rep;
uat_rep_fld_free_cb_t free_rep;
struct _uat_fld_t* next;
} uat_fld_t;
struct _uat_t {
char* name;
size_t record_size;
char* filename;
void** user_ptr;
guint* nrows_p;
uat_copy_cb_t copy_cb;
uat_update_cb_t update_cb;
uat_free_cb_t free_cb;
uat_fld_t* fields;
guint ncols;
GArray* user_data;
gboolean finalized;
gboolean locked;
uat_rep_t* rep;
uat_rep_free_cb_t free_rep;
};
gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing);
void uat_init(void);
void uat_reset(void);
void* uat_add_record(uat_t*, const void* orig_rec_ptr);
void uat_remove_record_idx(uat_t*, guint rec_idx);
void uat_destroy(uat_t*);
gboolean uat_save(uat_t* dt, char** error);
gboolean uat_load(uat_t* dt, char** error);
#define UAT_UPDATE(uat) do { *((uat)->user_ptr) = (void*)((uat)->user_data->data); *((uat)->nrows_p) = (uat)->user_data->len; } while(0)
#endif

285
epan/uat.c Normal file
View File

@ -0,0 +1,285 @@
/*
* uat.c
*
* User Accessible Tables
* Mantain an array of user accessible data strucures
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <glib.h>
#include <epan/emem.h>
#include <epan/filesystem.h>
#include "uat-int.h"
static GPtrArray* all_uats = NULL;
void uat_init(void) {
all_uats = g_ptr_array_new();
}
uat_t* uat_start(const char* name,
size_t size,
char* filename,
void** data_ptr,
guint* num_items_ptr,
uat_copy_cb_t copy_cb,
uat_update_cb_t update_cb,
uat_free_cb_t free_cb) {
uat_t* uat = g_malloc(sizeof(uat_t));
g_ptr_array_add(all_uats,uat);
g_assert(name && size && filename && data_ptr && num_items_ptr);
uat->name = g_strdup(name);
uat->record_size = size;
uat->filename = g_strdup(filename);
uat->user_ptr = data_ptr;
uat->nrows_p = num_items_ptr;
uat->copy_cb = copy_cb;
uat->update_cb = update_cb;
uat->free_cb = free_cb;
uat->fields = NULL;
uat->ncols = 0;
uat->user_data = g_array_new(FALSE,FALSE,uat->record_size);
uat->finalized = FALSE;
uat->rep = NULL;
uat->free_rep = NULL;
return uat;
}
void uat_add_field(uat_t* uat,
const char* name,
uat_text_mode_t mode,
uat_fld_chk_cb_t chk_cb,
uat_fld_set_cb_t set_cb,
uat_fld_tostr_cb_t tostr_cb) {
uat_fld_t* f = g_malloc(sizeof(uat_fld_t));
g_assert( name && set_cb && tostr_cb && (! uat->finalized )
&& (mode == PT_TXTMOD_STRING || mode == PT_TXTMOD_HEXBYTES) );
f->name = g_strdup(name);
f->mode = mode;
f->chk_cb = chk_cb;
f->set_cb = set_cb;
f->tostr_cb = tostr_cb;
f->rep = NULL;
f->free_rep = NULL;
f->colnum = uat->ncols;
f->next = NULL;
uat->ncols++;
if (uat->fields) {
uat_fld_t* c;
for (c = uat->fields; c->next; c = c->next) ;
c->next = f;
} else {
uat->fields = f;
}
}
void uat_finalize(uat_t* uat) {
UAT_UPDATE(uat);
uat->finalized = TRUE;
}
uat_t* uat_new(const char* uat_name,
size_t size,
char* filename,
void** data_ptr,
guint* numitems_ptr,
uat_copy_cb_t copy_cb,
uat_update_cb_t update_cb,
uat_free_cb_t free_cb,
...) {
uat_t* uat = uat_start(uat_name, size, filename, data_ptr, numitems_ptr, copy_cb, update_cb, free_cb);
va_list ap;
char* name;
uat_text_mode_t mode;
uat_fld_chk_cb_t chk_cb;
uat_fld_set_cb_t set_cb;
uat_fld_tostr_cb_t tostr_cb;
va_start(ap,free_cb);
name = va_arg(ap,char*);
do {
mode = va_arg(ap,uat_text_mode_t);
chk_cb = va_arg(ap,uat_fld_chk_cb_t);
set_cb = va_arg(ap,uat_fld_set_cb_t);
tostr_cb = va_arg(ap,uat_fld_tostr_cb_t);
uat_add_field(uat, name, mode, chk_cb, set_cb, tostr_cb);
name = va_arg(ap,char*);
} while (name);
va_end(ap);
uat_finalize(uat);
return uat;
}
void* uat_add_record(uat_t* uat, const void* data) {
void* rec;
g_assert( uat->finalized );
g_array_append_vals (uat->user_data, data, 1);
rec = uat->user_data->data + (uat->record_size * (uat->user_data->len-1));
if (uat->copy_cb) {
uat->copy_cb(rec, data, uat->record_size);
}
UAT_UPDATE(uat);
return rec;
}
void uat_remove_record_idx(uat_t* uat, guint idx) {
g_assert( uat->finalized && idx < uat->user_data->len);
g_array_remove_index(uat->user_data, idx);
UAT_UPDATE(uat);
}
gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing) {
gchar* pers_fname = get_persconffile_path(uat->filename,for_writing);
if (! file_exists(pers_fname)) {
gchar* data_fname = get_datafile_path(uat->filename);
if (file_exists(data_fname)) {
return data_fname;
}
}
return pers_fname;
}
static void putfld(FILE* fp, void* rec, uat_fld_t* f) {
guint fld_len;
char* fld_ptr;
f->tostr_cb(rec,&fld_ptr,&fld_len);
switch(f->mode){
case PT_TXTMOD_STRING: {
guint i;
putc('"',fp);
for(i=0;i<fld_len;i++) {
char c = fld_ptr[i];
if (c == '"') {
fputs("\134\042",fp);
} else if (isprint(c)) {
putc(c,fp);
} else {
fprintf(fp,"\\x%.2x",c);
}
}
putc('"',fp);
return;
}
case PT_TXTMOD_HEXBYTES: {
guint i;
for(i=0;i<fld_len;i++) {
fprintf(fp,"%.2x",fld_ptr[i]);
}
return;
}
default:
g_assert_not_reached();
}
}
gboolean uat_save(uat_t* uat, char** error) {
guint i;
gchar* fname = uat_get_actual_filename(uat,TRUE);
FILE* fp = fopen(fname,"w");
if (!fp) {
*error = ep_strdup_printf("uat_save: error opening '%s': %s",fname,strerror(errno));
return FALSE;
}
*error = NULL;
for ( i = 0 ; i < uat->user_data->len - 1 ; i++ ) {
void* rec = uat->user_data->data + (uat->record_size * (uat->user_data->len-1));
uat_fld_t* f;
f = uat->fields;
putfld(fp, rec, f);
while (( f = f->next )) {
fputs(",",fp);
putfld(fp, rec, f);
}
fputs("\n",fp);
}
fclose(fp);
return TRUE;
}
void uat_destroy(uat_t* uat) {
g_ptr_array_remove(all_uats,uat);
}
void* uat_dup(uat_t* uat, guint* len_p) {
guint size = (uat->record_size * uat->user_data->len);
*len_p = size;
return size ? g_memdup(uat->user_data->data,size) : NULL ;
}
void* uat_se_dup(uat_t* uat, guint* len_p) {
guint size = (uat->record_size * uat->user_data->len);
*len_p = size;
return size ? se_memdup(uat->user_data->data,size) : NULL ;
}
void uat_cleanup(void) {
while( all_uats->len ) {
uat_destroy((uat_t*)all_uats->pdata);
}
g_ptr_array_free(all_uats,TRUE);
}

247
epan/uat.h Normal file
View File

@ -0,0 +1,247 @@
/*
* uat.h
*
* User Accessible Tables
* Mantain an array of user accessible data strucures
*
* (c) 2007, Luis E. Garcia Ontanon
*
*/
#ifndef _UAT_H_
#define _UAT_H_
/*
* uat mantains a dynamically allocated table accessible to the user
* via a file and/or gui tables.
*
* the file is located either in userdir(when first read or when writen) or
* in datadir for defaults (read only , it will be always written to userdir).
*
* the behaviour of the table is controlled by a series of callbacks
* the caller must provide.
*
* BEWARE that the user can change an uat at (almost) any time,
* That is pointers to records in an uat are valid only during the call
* to the function that obtains them (do not store them).
*
* UATs are meant for short tables of user data (passwords and such) there's
* no quick access, you must iterate through them each time to fetch the record
* you are looking for. Use uat_dup() or uat_se_dup() if necessary.
*
* Only users via gui or editing the file can add/remove records your code cannot.
*/
/* obscure data type to handle an uat */
typedef struct _uat_t uat_t;
/********************************************
* Callbacks:
* these instruct uat on how to deal with user info and data in records
********************************************/
/********
* Callbacks for the entire table (these deal with entire records)
********/
/*
* Copy CB
* used to copy a record
* optional, memcpy will be used if not given
* copy(dest,orig,len)
*/
typedef void* (*uat_copy_cb_t)(void*, const void*, unsigned);
/*
*
* Free CB
*
* destroy a record's child data
* (do not free the container, it will be handled by uat)
* it is optional, no child data will be freed if no present
* free(record)
*/
typedef void (*uat_free_cb_t)(void*);
/*
* Update CB
*
* to be called after all record fields has been updated
* optional, record will be updated always if not given
* update(record,&error)
*/
typedef void (*uat_update_cb_t)(void* , char** );
/*******
* Callbacks for single fields (these deal with single values)
* the caller should provide one of these for every field!
********/
/*
* given an input string (ptr, len) checks if the value is OK for a field in the record.
* it will return TRUE if OK or else
* it will return FALSE and may set *error to inform the user on what's
* wrong with the given input
* optional, if not given any input is considered OK and the set cb will be called
* chk(record, ptr, len, &error)
*/
typedef gboolean (*uat_fld_chk_cb_t)(void*, const char*, unsigned, char**);
/*
* Set Field CB
*
* given an input string (ptr, len) sets the value of a field in the record,
* it will return TRUE if OK or else
* it will return FALSE and may set *error to inform the user on what's
* wrong with the given input
* it is mandatory
* set(record, ptr, len)
*/
typedef void (*uat_fld_set_cb_t)(void*, const char*, unsigned);
/*
* given a record returns a string representation of the field
* mandatory
* tostr(record, &ptr, &len)
*/
typedef void (*uat_fld_tostr_cb_t)(void*, char**, unsigned*);
/***********
* Text Mode
*
* used for file and dialog representation of fileds in columns,
* when the file is read it modifies the way the value is passed back to the fld_set_cb
* (see definition bellow for description)
***********/
typedef enum _uat_text_mode_t {
PT_TXTMOD_NONE,
/* not used */
PT_TXTMOD_STRING,
/*
file:
reads:
,"\x20\x00\x30", as " \00",3
,"", as "",0
,, as NULL,0
writes:
,"\x20\x30\x00\x20", for " 0\0 ",4
,"", for *, 0
,, for NULL, *
dialog:
accepts \x?? and other escapes
gets "",0 on empty string
*/
PT_TXTMOD_HEXBYTES,
/*
file:
reads:
,A1b2C3d4, as "\001\002\003\004",4
,, as NULL,0
writes:
,, on NULL, *
,a1b2c3d4, on "\001\002\003\004",4
dialog:
"a1b2c3d4" as "\001\002\003\004",4
"a1 b2:c3d4" as "\001\002\003\004",4
"" as NULL,0
"invalid" as NULL,3
"a1b" as NULL, 1
*/
} uat_text_mode_t;
/*
* uat_new()
*
* creates a new uat
*
* name: the name of the table
*
* data_ptr: a pointer to a null terminated array of pointers to the data
*
* default_data: a pinter to a struct containing default values
*
* size: the size of the structure
*
* filename: the filename to be used (either in userdir or datadir)
*
* copy_cb: a function that copies the data in the struct
*
* update_cb: will be called when a record is updated
*
* free_cb: will be called to destroy a struct in the dataset
*
*
* followed by a list of N quintuplets terminated by a NULL, each quituplet has:
*
* field_name: a string with the name of the field ([a-zA-Z0-9_-]+)
*
* field_mode: see comments for enum _uat_text_mode_t below
*
* field_chk_cb: a function that given a string will check the given value
*
* field_set_cb: a function that given a string will set the value in the data structure
*
* field_tostr_cb: a function that given a record generates a string,len pair representing this file
*
*/
uat_t* uat_new(const char* name,
size_t size,
char* filename,
void** data_ptr,
guint* num_items,
uat_copy_cb_t copy_cb,
uat_update_cb_t update_cb,
uat_free_cb_t free_cb,
...);
/*
* uat_start()
* as uat_new() but leaves the dyntable without fields
*/
uat_t* uat_start(const char* name,
size_t size,
char* filename,
void** data_ptr,
guint* num_items,
uat_copy_cb_t copy_cb,
uat_update_cb_t update_cb,
uat_free_cb_t free_cb);
/*
* uat_add_field()
* adds a field to a uat created with uat_start(),
* see uat_new() for description of arguments
*/
void uat_add_field(uat_t*,
const char* name,
uat_text_mode_t mode,
uat_fld_chk_cb_t chk_cb,
uat_fld_set_cb_t set_cb,
uat_fld_tostr_cb_t tostr_cb);
/*
* uat_finalize()
* once fields have been added it makes the uat usable, leaves it locked.
*/
void uat_finalize(uat_t*);
/*
* uat_dup()
* uat_se_dup()
* make a reliable copy of an uat for internal use,
* so that pointers to records can be kept through calls.
* return NULL on zero len.
*/
void* uat_dup(uat_t*, guint* len_p); /* to be freed */
void* uat_se_dup(uat_t*, guint* len_p);
#endif

284
epan/uat_load.l Normal file
View File

@ -0,0 +1,284 @@
%option noyywrap
%option nounput
%option prefix="uat_load_"
%option never-interactive
%{
/*
* one parser to fit them all
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <glib.h>
#include <epan/emem.h>
#include "uat-int.h"
static uat_t* uat;
static uat_fld_t* uat_fld;
static gchar* ptr;
static guint len;
static gchar* error;
static void* record;
static char* unbinstring(const char* si, guint in_len, guint* len_p);
static char* undquote(const char* si, guint in_len, guint* len_p);
#define ERROR(txt) do { error = txt; yyterminate(); } while(0)
#define SET_FIELD() \
{ gchar* err; \
if (uat_fld->chk_cb) { \
if ( ! uat_fld->chk_cb(record, ptr, len, &err) ) { \
ERROR(err); \
}\
}\
uat_fld->set_cb(record, ptr, len);\
g_free(ptr);\
} while(0)
%}
quoted_string \042([^\042]|\134\042)*\042
binstring ([0-9a-zA-Z][0-9a-zA-Z])+
separator ,
newline [ \t]*[\r]?\n
%x START_OF_LINE NEXT_FIELD SEPARATOR END_OF_RECORD
%%
<START_OF_LINE,NEXT_FIELD>{quoted_string} {
ptr = undquote(yytext,yyleng,&len);
if (( uat_fld = uat_fld->next )) {
BEGIN SEPARATOR;
} else {
BEGIN END_OF_RECORD;
}
}
<START_OF_LINE,NEXT_FIELD>{binstring} {
ptr = unbinstring(yytext,yyleng,&len);
if (!ptr) {
ERROR("uneven hexstring");
}
if (( uat_fld = uat_fld->next )) {
BEGIN SEPARATOR;
} else {
BEGIN END_OF_RECORD;
}
}
<SEPARATOR>{separator} {
SET_FIELD();
uat_fld = uat_fld->next;
if (! uat_fld ) {
ERROR("more fields than required");
}
}
<END_OF_RECORD>{newline} {
void* rec;
gchar* err = NULL;
SET_FIELD();
rec = uat_add_record(uat, record);
if (uat->update_cb)
uat->update_cb(rec,&err);
if (err) {
ERROR(err);
}
uat_fld = uat->fields;
ptr = NULL;
len = 0;
memset(record,0,uat->record_size);
BEGIN START_OF_LINE;
}
{newline} { ERROR("incomplete record"); }
. { ERROR("unexpected input"); }
%%
static int xton(char d) {
switch(d) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: return -1;
}
}
static char* unbinstring(const char* si, guint in_len, guint* len_p) {
char* buf;
guint len = in_len/2;
int i = 0;
if (in_len%2) {
return NULL;
}
buf= g_malloc(len); /* wastes one byte for every '\\' in text */
*len_p = len;
while(in_len) {
int d1 = xton(*(si++));
int d0 = xton(*(si++));
buf[i++] = (d1 * 16) + d0;
in_len -= 2;
}
return buf;
}
static char* undquote(const char* si, guint in_len, guint* len_p) {
char* buf = g_malloc(in_len); /* wastes one byte for every '\\' in text */
char* p = buf;
guint len = 0;
char* end = buf+in_len;
const guint8* s = (void*)si;
for (s++; p < end; s++) {
switch(*s) {
case '\0':
*(p-1) = '\0';
goto done;
case '\\':
switch(*(++s)) {
case 'a': *(p++) = '\a'; len++; break;
case 'b': *(p++) = '\b'; len++; break;
case 'e': *(p++) = '\e'; len++; break;
case 'f': *(p++) = '\f'; len++; break;
case 'n': *(p++) = '\n'; len++; break;
case 'r': *(p++) = '\r'; len++; break;
case 't': *(p++) = '\t'; len++; break;
case 'v': *(p++) = '\v'; len++; break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{
int c0 = 0;
int c1 = 0;
int c2 = 0;
int c = 0;
c0 = (*s) - '0';
if ( s[1] >= '0' && s[1] <= '7' ) {
c1 = c0;
c0 = (*++s) - '0';
if ( s[1] >= '0' && s[1] <= '7' ) {
c2 = c1;
c1 = c0;
c0 = (*++s) - '0';
}
}
c = (64 * c2) + (8 * c1) + c0;
*(p++) = (char) (c > 255 ? 255 : c);
len++;
break;
}
case 'x':
{
char c1 = *(s+1);
char c0 = *(s+2);
if (isxdigit(c1) && isxdigit(c0)) {
*(p++) = (xton(c1) * 0x10) + xton(c0);
s += 2;
} else {
*(p++) = *s;
}
len++;
break;
}
default:
*p++ = *s;
break;
}
break;
default:
*(p++) = *s;
len++;
break;
}
}
done:
while ( p < end ) *(p++) = '\0';
buf[len] = '\0';
len--;
if (len_p) *len_p = len;
return buf;
}
gboolean uat_load(uat_t* dt_in, char** err) {
gchar* fname = uat_get_actual_filename(uat, FALSE);
g_assert(uat->finalized && uat->locked);
uat = dt_in;
;
if (!(yyin = fopen(fname,"r"))) {
*err = strerror(errno);
return FALSE;
}
error = NULL;
uat_fld = uat->fields;
record = g_malloc0(uat->record_size);
BEGIN START_OF_LINE;
yylex();
if (error) {
UAT_UPDATE(uat);
*err = ep_strdup(error);
return FALSE;
} else {
UAT_UPDATE(uat);
*err = NULL;
return TRUE;
}
}