aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
Diffstat (limited to 'epan')
-rw-r--r--epan/Makefile.am3
-rw-r--r--epan/Makefile.common4
-rw-r--r--epan/Makefile.nmake3
-rw-r--r--epan/uat-int.h67
-rw-r--r--epan/uat.c285
-rw-r--r--epan/uat.h247
-rw-r--r--epan/uat_load.l284
7 files changed, 893 insertions, 0 deletions
diff --git a/epan/Makefile.am b/epan/Makefile.am
index 8103543c75..f2b35d3ae0 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -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
diff --git a/epan/Makefile.common b/epan/Makefile.common
index 3f1e6dd094..666bd0f364 100644
--- a/epan/Makefile.common
+++ b/epan/Makefile.common
@@ -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 \
diff --git a/epan/Makefile.nmake b/epan/Makefile.nmake
index fcf9622516..f8c771e0d7 100644
--- a/epan/Makefile.nmake
+++ b/epan/Makefile.nmake
@@ -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
diff --git a/epan/uat-int.h b/epan/uat-int.h
new file mode 100644
index 0000000000..e3eb29ce47
--- /dev/null
+++ b/epan/uat-int.h
@@ -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
diff --git a/epan/uat.c b/epan/uat.c
new file mode 100644
index 0000000000..41c911b90e
--- /dev/null
+++ b/epan/uat.c
@@ -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);
+}
+
diff --git a/epan/uat.h b/epan/uat.h
new file mode 100644
index 0000000000..54308940c9
--- /dev/null
+++ b/epan/uat.h
@@ -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
+
diff --git a/epan/uat_load.l b/epan/uat_load.l
new file mode 100644
index 0000000000..1bd2474e80
--- /dev/null
+++ b/epan/uat_load.l
@@ -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;
+ }
+}