diff --git a/.travis.yml b/.travis.yml index 2216bb7..3a9553f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ before_script: - autoreconf -i -f -Wno-portability script: - - ./configure --disable-man --disable-silent-rules + - ./configure --disable-man --disable-silent-rules --disable-glib - make - ./src/util/mdb-array test/data/ASampleDatabase.accdb "Asset Items" - ./src/util/mdb-array test/data/nwind.mdb "Customers" diff --git a/README.md b/README.md index 65a9a22..616e8d7 100644 --- a/README.md +++ b/README.md @@ -51,69 +51,24 @@ Builds on libmdb to provide a SQL engine (aka Jet) Provids command line utilities, including: -### mdb-ver - -Prints the version (JET 3 or 4) of an mdb file. - -### mdb-schema - -Prints DDL for the specified table. - -### mdb-export - -Export table to CSV format. - -### mdb-tables - -A simple dump of table names to be used with shell scripts. - -### mdb-count - -A simple count of number of rows in a table, to be used in shell scripts and ETL pipelines. - -### mdb-header - -Generates a C header to be used in exporting mdb data to a C prog. - -### mdb-parsecsv - -Generates a C program given a CSV file made with mdb-export. - -### mdb-sql - -A simple SQL engine (also used by ODBC and gmdb). - -### prcat - -Prints the catalog table from an mdb file. - -### prkkd - -Dump of information about design view data given the offset to it. - -### prtable - -Dump of a table definition. - -### prdata - -Dump of the data given a table name. - -### prole - -Dump of ole columns given a table name and sargs. - -## odbc - -An ODBC driver for use with unixODBC or iODBC driver manager. Allows one to use MDB files with PHP for example. - -## gmdb2 - -The Gnome MDB File Viewer and debugger. Still alpha, but making great progress. - -## src/extras/mdb-hexdump - -Simple hex dump utility that I've been using to look at mdb files. +| Command | Description | +| ------- | ----------- | +| mdb-ver | Prints the version (JET 3 or 4) of an mdb file. | +| mdb-schema | Prints DDL for the specified table. | +| mdb-export | Export table to CSV format. | +| mdb-tables | A simple dump of table names to be used with shell scripts. | +| mdb-count | A simple count of number of rows in a table, to be used in shell scripts and ETL pipelines. | +| mdb-header | Generates a C header to be used in exporting mdb data to a C prog. | +| mdb-parsecsv | Generates a C program given a CSV file made with mdb-export. | +| mdb-sql | A simple SQL engine (also used by ODBC and gmdb). | +| prcat | Prints the catalog table from an mdb file. | +| prkkd | Dump of information about design view data given the offset to it. | +| prtable | Dump of a table definition. | +| prdata | Dump of the data given a table name. | +| prole | Dump of ole columns given a table name and sargs. | +| odbc | An ODBC driver for use with unixODBC or iODBC driver manager. Allows one to use MDB files with PHP for example. | +| gmdb2 | The Gnome MDB File Viewer and debugger. Still alpha. | +| mdb-hexdump | (in src/extras) Simple hex dump utility that I've been using to look at mdb files. | # License @@ -150,7 +105,7 @@ If you want to generate the html version of the docbook, you'll need Last version is available at https://github.com/evanmiller/mdbtools ```bash -$ autoreconf -i -f +$ autoreconf -i -f -Wno-portability ``` If you want to build the html version of the docbook documentation, you need to @@ -169,6 +124,13 @@ OR for a complete install (requires bison, flex, and unixODBC): $ ./configure --with-unixodbc=/usr/local ``` +By default, MDB Tools is linked against the copy of +[GLib](https://developer.gnome.org/glib/) returned by pkg-config. You can +point to a different GLib installation using the `GLIB_CFLAGS` and `GLIB_LIBS` +enivornment variables. Or, you can disable GLib entirely with the +`--disable-glib` flag, in which case MDB Tools will use an internal +implementation of GLib's functions. + configure can be passed any of the following flags to turn on other capabilities. Note that the options `--with-unixodbc` and `--with-iodbc` are mutually exclusive. diff --git a/appveyor.yml b/appveyor.yml index 9bc1d0e..6d09d47 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,14 +22,12 @@ build_script: if ($env:TOOLCHAIN -eq "msys2") { $env:MSYSTEM="MINGW64" - C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-glib2" C:\msys64\usr\bin\bash -l -c "cd /c/projects/mdbtools && autoreconf -i -f -Wno-portability" C:\msys64\usr\bin\bash -l -c "cd /c/projects/mdbtools && ./configure --disable-man --disable-silent-rules" C:\msys64\usr\bin\bash -l -c "cd /c/projects/mdbtools && make" } else { - C:\cygwin64\setup-x86_64.exe -qP libglib2.0-devel C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && autoreconf -i -f -Wno-portability" C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && ./configure --disable-man --disable-silent-rules" C:\cygwin64\bin\sh -lc "cd /cygdrive/c/projects/mdbtools && make" diff --git a/configure.ac b/configure.ac index 72e1909..a82e721 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,9 @@ AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h limits.h unistd.h) AC_CHECK_HEADERS(wordexp.h) AC_CHECK_LIB(mswstr, DBLCMapStringW) +AC_CHECK_DECLS([program_invocation_short_name], [], [], [[ + #define _GNU_SOURCE + #include ]]) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -46,7 +49,11 @@ AC_MSG_RESULT( no - SQL engine disable); sql=false fi -if ! $YACC -V >/dev/null 2>&1; then +if $YACC -V >/dev/null 2>&1; then + if $YACC -Wno-conflicts-sr -V >/dev/null 2>&1; then + YFLAGS="$YFLAGS -Wno-conflicts-sr" + fi +else sql=false fi @@ -61,9 +68,11 @@ AM_CONDITIONAL(SQL, test x$sql = xtrue) AC_SUBST(SQL) AC_SUBST(LFLAGS) -CFLAGS="$CFLAGS -Wall -Wstrict-prototypes" +CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -Werror" AS_CASE([$host], [*mingw*|*cygwin*], [LDFLAGS="$LDFLAGS -no-undefined"], []) +AS_CASE([$host], + [*mingw*], [LDFLAGS="$LDFLAGS -lWs2_32"], []) dnl Enable -Wl,--as-needed by default to prevent overlinking AC_ARG_ENABLE([as-needed], @@ -146,14 +155,22 @@ pkg-config is required. See pkg-config.freedesktop.org]) fi +dnl See if GLib is present and wanted +AC_ARG_ENABLE(glib, + AS_HELP_STRING([--disable-glib], [do not link with GLib]), + [enable_glib=$enableval], [enable_glib=yes]) -dnl check for glib/gtk/gnome -PKG_CHECK_MODULES([GLIB], [glib-2.0], , - AC_MSG_ERROR([ -glib 2.0 is required by MDB Tools (runtime and devel). -It can be downloaded at www.gtk.org. -])) +if test "$enable_glib" = "yes"; then + PKG_CHECK_MODULES([GLIB], [glib-2.0], HAVE_GLIB=true, HAVE_GLIB=false) + if test "x$HAVE_GLIB" = "xtrue"; then + GLIB_CFLAGS="$GLIB_CFLAGS -DHAVE_GLIB=1" + else + enable_glib=no + fi +fi +AM_CONDITIONAL(FAKE_GLIB, test "x$enable_glib" != "xyes") +dnl check for gtk/gnome PKG_CHECK_MODULES([GNOME], [gtk+-2.0 >= 2.14 libglade-2.0 libgnomeui-2.0], HAVE_GNOME=true, HAVE_GNOME=false) GNOME_DOC_INIT @@ -277,6 +294,8 @@ if test x$sql = xtrue; then summary=${bold_green}enabled; else summary=${bold_re AC_MSG_NOTICE([ SQL : ${summary}${reset}]) if test x$HAVE_ODBC = xtrue; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi AC_MSG_NOTICE([ ODBC : ${summary}${reset}]) +if test x$enable_glib = xyes; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi +AC_MSG_NOTICE([ GLib : ${summary}${reset}]) if test x$build_gmdb2 = xyes; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi AC_MSG_NOTICE([ UI : ${summary}${reset}]) if test x$enable_gtk_doc = xyes; then summary=${bold_green}enabled; else summary=${bold_red}disabled; fi diff --git a/include/Makefile.am b/include/Makefile.am index 073b09c..bc5aa3f 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,2 +1,5 @@ include_HEADERS = mdbtools.h mdbsql.h mdbver.h +if FAKE_GLIB +include_HEADERS += mdbfakeglib.h +endif noinst_HEADERS = mdbprivate.h diff --git a/include/mdbfakeglib.h b/include/mdbfakeglib.h new file mode 100644 index 0000000..1fbc683 --- /dev/null +++ b/include/mdbfakeglib.h @@ -0,0 +1,157 @@ +#ifndef _mdbfakeglib_h_ +#define _mdbfakeglib_h_ + +#include +#include +#include +#include + +// for ntohl +#ifdef _WIN32 +#include +#else +#include +#endif + +typedef uint16_t guint16; +typedef uint32_t guint32; +typedef uint64_t guint64; +typedef int32_t gint32; +typedef char gchar; +typedef int gboolean; +typedef int gint; +typedef unsigned int guint; +typedef void * gpointer; +typedef const void * gconstpointer; +typedef uint8_t guint8; +typedef guint32 GQuark; + +typedef guint (*GHashFunc)(gconstpointer); +typedef int (*GCompareFunc)(gconstpointer, gconstpointer); +typedef gboolean (*GEqualFunc)(gconstpointer, gconstpointer); +typedef void (*GFunc) (gpointer data, gpointer user_data); +typedef void (*GHFunc)(gpointer key, gpointer value, gpointer data); +typedef gboolean (*GHRFunc)(gpointer key, gpointer value, gpointer data); + +typedef struct GPtrArray { + void **pdata; + int len; +} GPtrArray; + +typedef struct GList { + gpointer data; + struct GList *next; + struct GList *prev; +} GList; + +typedef struct GHashTable { + GEqualFunc compare; + GPtrArray *array; +} GHashTable; + +typedef struct GError { + GQuark domain; + gint code; + gchar *message; +} GError; + +typedef enum GOptionArg { + G_OPTION_ARG_NONE, + G_OPTION_ARG_STRING, + G_OPTION_ARG_INT +} GOptionArg; + +typedef enum GOptionFlags { + G_OPTION_FLAG_NONE, + G_OPTION_FLAG_REVERSE +} GOptionFlags; + +typedef struct GOptionEntry { + const gchar *long_name; + gchar short_name; + gint flags; + + GOptionArg arg; + gpointer arg_data; + + const gchar *description; + const gchar *arg_description; +} GOptionEntry; + +typedef struct GOptionContext { + const char *desc; + const GOptionEntry *entries; +} GOptionContext; + +#define g_str_hash NULL + +#define G_GUINT32_FORMAT PRIu32 + +#define g_return_val_if_fail(a, b) if (!a) { return b; } + +#define g_ascii_strcasecmp strcasecmp +#define g_malloc0(len) calloc(1, len) +#define g_malloc malloc +#define g_free free +#define g_realloc realloc + +#define G_STR_DELIMITERS "_-|> <." + +#define g_ptr_array_index(array, i) \ + ((void **)array->pdata)[i] + +#define TRUE 1 +#define FALSE 0 + +#define GUINT16_FROM_LE(l) (uint16_t)l +#define GUINT32_FROM_LE(l) (uint32_t)l +#define GUINT64_FROM_LE(l) (uint64_t)l +#define GINT32_FROM_LE(l) (uint32_t)l +#define GINT32_FROM_BE(l) (int32_t)ntohl(l) +#define GUINT32_SWAP_LE_BE(l) (uint32_t)ntohl(l) +#define GINT32_TO_LE(l) (int32_t)l +#define GINT32_TO_BE(l) (int32_t)ntohl(l) + +/* string functions */ +void *g_memdup(const void *src, size_t len); +int g_str_equal(const void *str1, const void *str2); +char **g_strsplit(const char *haystack, const char *needle, int something); +void g_strfreev(char **dir); +char *g_strconcat(const char *first, ...); +char *g_strdup(const char *src); +char *g_strdup_printf(const char *format, ...); +gchar *g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delimiter); + +/* GHashTable */ +void *g_hash_table_lookup(GHashTable *tree, const void *key); +void g_hash_table_insert(GHashTable *tree, void *key, void *value); +GHashTable *g_hash_table_new(GHashFunc hashes, GEqualFunc equals); +void g_hash_table_foreach(GHashTable *tree, GHFunc function, void *data); +void g_hash_table_foreach_remove(GHashTable *tree, GHRFunc function, void *data); +void g_hash_table_destroy(GHashTable *tree); + +/* GPtrArray */ +void g_ptr_array_sort(GPtrArray *array, GCompareFunc func); +void g_ptr_array_foreach(GPtrArray *array, GFunc function, gpointer user_data); +GPtrArray *g_ptr_array_new(void); +void g_ptr_array_add(GPtrArray *array, void *entry); +void g_ptr_array_free(GPtrArray *array, gboolean something); + +/* GList */ +GList *g_list_append(GList *list, void *data); +GList *g_list_last(GList *list); +GList *g_list_remove(GList *list, void *data); +void g_list_free(GList *list); + +/* GOption */ +GOptionContext *g_option_context_new(const char *description); +void g_option_context_add_main_entries (GOptionContext *context, + const GOptionEntry *entries, + const gchar *translation_domain); +gchar *g_option_context_get_help (GOptionContext *context, + gboolean main_help, void *group); +gboolean g_option_context_parse (GOptionContext *context, + gint *argc, gchar ***argv, GError **error); +void g_option_context_free (GOptionContext *context); + +#endif diff --git a/include/mdbsql.h b/include/mdbsql.h index 951a340..e39d736 100644 --- a/include/mdbsql.h +++ b/include/mdbsql.h @@ -25,7 +25,11 @@ #include #include +#ifdef HAVE_GLIB #include +#else +#include +#endif #include typedef struct { diff --git a/include/mdbtools.h b/include/mdbtools.h index e5f5baa..c553c95 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -30,7 +30,12 @@ #include #include #include + +#ifdef HAVE_GLIB #include +#else +#include +#endif #ifdef HAVE_ICONV #include @@ -284,8 +289,7 @@ typedef struct { int object_type; unsigned long table_pg; /* misnomer since object may not be a table */ //int num_props; please use props->len - GArray *props; /* GArray of MdbProperties */ - GArray *columns; + GPtrArray *props; /* GPtrArray of MdbProperties */ int flags; } MdbCatalogEntry; @@ -575,7 +579,7 @@ extern gint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int /* props.c */ extern void mdb_free_props(MdbProperties *props); extern void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name); -extern GArray* mdb_kkd_to_props(MdbHandle *mdb, void *kkd, size_t len); +extern GPtrArray* mdb_kkd_to_props(MdbHandle *mdb, void *kkd, size_t len); /* worktable.c */ diff --git a/src/libmdb/Makefile.am b/src/libmdb/Makefile.am index aa823ba..2e74a19 100644 --- a/src/libmdb/Makefile.am +++ b/src/libmdb/Makefile.am @@ -1,5 +1,8 @@ lib_LTLIBRARIES = libmdb.la libmdb_la_SOURCES= catalog.c mem.c file.c table.c data.c dump.c backend.c money.c sargs.c index.c like.c write.c stats.c map.c props.c worktable.c options.c iconv.c +if FAKE_GLIB +libmdb_la_SOURCES += fakeglib.c +endif libmdb_la_LDFLAGS = -version-info 2:1:0 -export-symbols-regex '^(mdb_|_mdb_put_int16$$|_mdb_put_int32$$)' AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LIBS = $(GLIB_LIBS) @LIBS@ @LIBICONV@ diff --git a/src/libmdb/backend.c b/src/libmdb/backend.c index 178c587..70a7548 100644 --- a/src/libmdb/backend.c +++ b/src/libmdb/backend.c @@ -184,7 +184,7 @@ enum { MDB_BACKEND_SQLITE, }; -static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data); +static void mdb_drop_backend(gpointer key, gpointer value, gpointer data); static gchar* quote_generic(const gchar *value, gchar quote_char, gchar escape_char) { @@ -451,14 +451,13 @@ mdb_remove_backends()) void _mdb_remove_backends() { - g_hash_table_foreach_remove(mdb_backends, mdb_drop_backend, NULL); + g_hash_table_foreach(mdb_backends, mdb_drop_backend, NULL); g_hash_table_destroy(mdb_backends); } -static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data) +static void mdb_drop_backend(gpointer key, gpointer value, gpointer data) { MdbBackend *backend = (MdbBackend *)value; g_free (backend); - return TRUE; } /** diff --git a/src/libmdb/catalog.c b/src/libmdb/catalog.c index a04eac4..8f3d5a0 100644 --- a/src/libmdb/catalog.c +++ b/src/libmdb/catalog.c @@ -57,8 +57,8 @@ void mdb_free_catalog(MdbHandle *mdb) if (entry) { if (entry->props) { for (j=0; jprops->len; j++) - mdb_free_props(g_array_index(entry->props, MdbProperties*, j)); - g_array_free(entry->props, TRUE); + mdb_free_props(g_ptr_array_index(entry->props, j)); + g_ptr_array_free(entry->props, TRUE); } g_free(entry); } diff --git a/src/libmdb/data.c b/src/libmdb/data.c index 883294c..2b14d59 100644 --- a/src/libmdb/data.c +++ b/src/libmdb/data.c @@ -140,9 +140,9 @@ int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len) mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; *len = next_start - (*start & OFFSET_MASK); - if ((*start & OFFSET_MASK) >= mdb->fmt->pg_size || - next_start > mdb->fmt->pg_size) - return -1; + if ((*start & OFFSET_MASK) >= mdb->fmt->pg_size || + next_start > mdb->fmt->pg_size) + return -1; return 0; } @@ -304,8 +304,8 @@ int mdb_read_row(MdbTableDef *table, unsigned int row) num_fields = mdb_crack_row(table, row_start, row_start + row_size - 1, fields); - if (num_fields < 0) - return 0; + if (num_fields < 0) + return 0; if (!mdb_test_sargs(table, fields, num_fields)) return 0; #if MDB_DEBUG diff --git a/src/libmdb/fakeglib.c b/src/libmdb/fakeglib.c new file mode 100644 index 0000000..8d7ba35 --- /dev/null +++ b/src/libmdb/fakeglib.c @@ -0,0 +1,416 @@ + +#define _GNU_SOURCE +#include "mdbfakeglib.h" + +#include +#include +#include +#include +#include +#include +#include + +/* string functions */ + +void *g_memdup(const void *src, size_t len) { + void *dst = malloc(len); + memcpy(dst, src, len); + return dst; +} + +int g_str_equal(const void *str1, const void *str2) { + return strcmp(str1, str2) == 0; +} + +char **g_strsplit(const char *haystack, const char *needle, int something) { + char **ret = NULL; + char *found = NULL; + size_t components = 1; + + while ((found = strstr(haystack, needle))) { + components++; + haystack = found + strlen(needle); + } + + ret = malloc(components * sizeof(char *)); + + int i = 0; + while ((found = strstr(haystack, needle))) { + // Windows lacks strndup + size_t chunk_len = found - haystack; + char *chunk = malloc(chunk_len + 1); + memcpy(chunk, haystack, chunk_len); + chunk[chunk_len] = 0; + + ret[i++] = chunk; + haystack = found + strlen(needle); + } + ret[i] = strdup(haystack); + + return ret; +} + +void g_strfreev(char **dir) { + int i=0; + while (dir[i]) { + free(dir[i]); + i++; + } + free(dir); +} + +char *g_strconcat(const char *first, ...) { + char *ret = NULL; + size_t len = strlen(first); + char *arg = NULL; + va_list argp; + + va_start(argp, first); + while ((arg = va_arg(argp, char *))) { + len += strlen(arg); + } + va_end(argp); + + ret = malloc(len+1); + + char *pos = strcpy(ret, first) + strlen(first); + + va_start(argp, first); + while ((arg = va_arg(argp, char *))) { + pos = strcpy(pos, arg) + strlen(arg); + } + va_end(argp); + + ret[len] = '\0'; + + return ret; +} + +#if defined _WIN32 +int vasprintf(char **ret, const char *format, va_list ap) { + int len; + int retval; + char *result; + if ((len = _vscprintf(format, ap)) < 0) + return -1; + if ((result = malloc(len+1)) == NULL) + return -1; + if ((retval = vsprintf_s(result, len+1, format, ap)) == -1) { + free(result); + return -1; + } + *ret = result; + return retval; +} +#endif + +char *g_strdup(const char *input) { + size_t len = strlen(input); + return g_memdup(input, len+1); +} + +char *g_strdup_printf(const char *format, ...) { + char *ret = NULL; + va_list argp; + + va_start(argp, format); +#ifdef __CYGWIN__ + size_t len = 0; + ret = vasnprintf(ret, &len, format, argp); +#else + int gcc_is_dumb = vasprintf(&ret, format, argp); + (void)gcc_is_dumb; +#endif + va_end(argp); + + return ret; +} + +gchar *g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delimiter) { + char *orig = string; + if (delimiters == NULL) + delimiters = G_STR_DELIMITERS; + size_t n = strlen(delimiters); + while (*string) { + size_t i; + for (i=0; iarray->len; i++) { + MyNode *node = g_ptr_array_index(table->array, i); + if (table->compare(key, node->key)) + return node->value; + } + return NULL; +} + +void g_hash_table_insert(GHashTable *table, void *key, void *value) { + MyNode *node = calloc(1, sizeof(MyNode)); + node->value = value; + node->key = key; + g_ptr_array_add(table->array, node); +} + +GHashTable *g_hash_table_new(GHashFunc hashes, GEqualFunc equals) { + GHashTable *table = calloc(1, sizeof(GHashTable)); + table->array = g_ptr_array_new(); + table->compare = equals; + return table; +} + +void g_hash_table_foreach(GHashTable *table, GHFunc function, void *data) { + int i; + for (i=0; iarray->len; i++) { + MyNode *node = g_ptr_array_index(table->array, i); + function(node->key, node->value, data); + } +} + +void g_hash_table_destroy(GHashTable *table) { + int i; + for (i=0; iarray->len; i++) { + MyNode *node = g_ptr_array_index(table->array, i); + free(node); + } + g_ptr_array_free(table->array, TRUE); + free(table); +} + +/* GPtrArray */ + +void g_ptr_array_sort(GPtrArray *array, GCompareFunc func) { + qsort(array->pdata, array->len, sizeof(void *), func); +} + +void g_ptr_array_foreach(GPtrArray *array, GFunc function, gpointer user_data) { + int i; + for (i=0; ilen; i++) { + function(g_ptr_array_index(array, i), user_data); + } +} + +GPtrArray *g_ptr_array_new() { + GPtrArray *array = malloc(sizeof(GPtrArray)); + array->len = 0; + array->pdata = NULL; + return array; +} + +void g_ptr_array_add(GPtrArray *array, void *entry) { + array->pdata = realloc(array->pdata, (array->len+1) * sizeof(void *)); + array->pdata[array->len++] = entry; +} + +void g_ptr_array_free(GPtrArray *array, gboolean something) { + free(array->pdata); + free(array); +} + +/* GList */ + +GList *g_list_append(GList *list, void *data) { + GList *new_list = calloc(1, sizeof(GList)); + new_list->data = data; + new_list->next = list; + if (list) + list->prev = new_list; + return new_list; +} + +GList *g_list_last(GList *list) { + while (list && list->next) { + list = list->next; + } + return list; +} + +GList *g_list_remove(GList *list, void *data) { + GList *link = list; + while (link) { + if (link->data == data) { + GList *return_list = list; + if (link->prev) + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + if (link == list) + return_list = link->next; + free(link); + return return_list; + } + link = link->next; + } + return list; +} + +void g_list_free(GList *list) { + GList *next = NULL; + while (list) { + next = list->next; + free(list); + list = next; + } +} + +/* GOption */ + +void g_option_context_add_main_entries (GOptionContext *context, + const GOptionEntry *entries, + const gchar *translation_domain) { + context->entries = entries; +} + +gchar *g_option_context_get_help (GOptionContext *context, + gboolean main_help, void *group) { +#if defined(__APPLE__) || defined(__FreeBSD__) + const char * appname = getprogname(); +#elif HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME + const char * appname = program_invocation_short_name; +#else + const char * appname = "mdb-util"; +#endif + + char *help = malloc(4096); + char *end = help + 4096; + char *p = help; + p += snprintf(p, end - p, + "Usage:\n %s [OPTION\xE2\x80\xA6] %s\n\n", appname, context->desc); + p += snprintf(p, end - p, + "Help Options:\n -h, --%-20s%s\n\n", "help", "Show help options"); + p += snprintf(p, end - p, + "Application Options:\n"); + int i=0; + for (i=0; context->entries[i].long_name; i++) { + p += snprintf(p, end - p, " "); + if (context->entries[i].short_name) { + p += snprintf(p, end - p, "-%c, ", context->entries[i].short_name); + } + p += snprintf(p, end - p, "--"); + if (context->entries[i].arg_description) { + char *long_name = g_strconcat( + context->entries[i].long_name, "=", + context->entries[i].arg_description, NULL); + p += snprintf(p, end - p, "%-20s", long_name); + free(long_name); + } else { + p += snprintf(p, end - p, "%-20s", context->entries[i].long_name); + } + if (!context->entries[i].short_name) { + p += snprintf(p, end - p, " "); + } + p += snprintf(p, end - p, "%s\n", context->entries[i].description); + } + p += snprintf(p, end - p, "\n"); + return help; +} + +GOptionContext *g_option_context_new(const char *description) { + GOptionContext *ctx = calloc(1, sizeof(GOptionContext)); + ctx->desc = description; + return ctx; +} + +gboolean g_option_context_parse(GOptionContext *context, + gint *argc, gchar ***argv, GError **error) { + int i; + int count = 0; + int len = 0; + if (*argc == 2 && + (strcmp((*argv)[1], "-h") == 0 || strcmp((*argv)[1], "--help") == 0)) { + fprintf(stderr, "%s", g_option_context_get_help(context, TRUE, NULL)); + exit(0); + } + for (i=0; context->entries[i].long_name; i++) { + GOptionArg arg = context->entries[i].arg; + count++; + len++; + if (arg == G_OPTION_ARG_STRING || arg == G_OPTION_ARG_INT) { + len++; + } + } + struct option *long_opts = calloc(count+1, sizeof(struct option)); + char *short_opts = calloc(1, len+1); + int j=0; + for (i=0; ientries[i]; + GOptionArg arg = entry->arg; + short_opts[j++] = entry->short_name; + if (arg == G_OPTION_ARG_STRING || arg == G_OPTION_ARG_INT) { + short_opts[j++] = ':'; + } + long_opts[i].name = entry->long_name; + long_opts[i].has_arg = entry->arg == G_OPTION_ARG_NONE ? no_argument : required_argument; + } + int c; + int longindex = 0; + opterr = 0; + while ((c = getopt_long(*argc, *argv, short_opts, long_opts, &longindex)) != -1) { + if (c == '?') { + *error = malloc(sizeof(GError)); + (*error)->message = malloc(100); + if (optopt) { + snprintf((*error)->message, 100, "Unrecognized option: -%c", optopt); + } else { + snprintf((*error)->message, 100, "Unrecognized option: %s", (*argv)[optind-1]); + } + free(short_opts); + free(long_opts); + return FALSE; + } + const GOptionEntry *entry = NULL; + if (c == 0) { + entry = &context->entries[longindex]; + } else { + for (i=0; ientries[i].short_name == c) { + entry = &context->entries[i]; + break; + } + } + } + if (entry->arg == G_OPTION_ARG_NONE) { + *(int *)entry->arg_data = !(entry->flags & G_OPTION_FLAG_REVERSE); + } else if (entry->arg == G_OPTION_ARG_INT) { + char *endptr = NULL; + *(int *)entry->arg_data = strtol(optarg, &endptr, 10); + if (*endptr) { + *error = malloc(sizeof(GError)); + (*error)->message = malloc(100); + snprintf((*error)->message, 100, "Argument to --%s must be an integer", entry->long_name); + free(short_opts); + free(long_opts); + return FALSE; + } + } else if (entry->arg == G_OPTION_ARG_STRING) { + *(char **)entry->arg_data = strdup(optarg); + } + } + *argc -= (optind - 1); + *argv += (optind - 1); + free(short_opts); + free(long_opts); + + return TRUE; +} + +void g_option_context_free(GOptionContext *context) { + free(context); +} diff --git a/src/libmdb/iconv.c b/src/libmdb/iconv.c index 25c1fa3..34dbd17 100644 --- a/src/libmdb/iconv.c +++ b/src/libmdb/iconv.c @@ -23,6 +23,10 @@ #include "dmalloc.h" #endif +#ifndef MIN +#define MIN(a,b) (a>b ? b : a) +#endif + /* * This function is used in reading text data from an MDB table. */ diff --git a/src/libmdb/props.c b/src/libmdb/props.c index 5a59b31..c1a0901 100644 --- a/src/libmdb/props.c +++ b/src/libmdb/props.c @@ -176,16 +176,16 @@ mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name) { /* * That function takes a raw KKD/MR2 binary buffer, * typically read from LvProp in table MSysbjects - * and returns a GArray of MdbProps* + * and returns a GPtrArray of MdbProps* */ -GArray* +GPtrArray* mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) { guint32 record_len; guint16 record_type; size_t pos; GPtrArray *names = NULL; MdbProperties *props; - GArray *result; + GPtrArray *result; #if MDB_DEBUG mdb_buffer_dump(buffer, 0, len); @@ -198,7 +198,7 @@ mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) { return NULL; } - result = g_array_new(0, 0, sizeof(MdbProperties*)); + result = g_ptr_array_new(); pos = 4; while (pos < len) { @@ -219,7 +219,7 @@ mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) { break; } props = mdb_read_props(mdb, names, (char*)buffer+pos+6, record_len - 6); - g_array_append_val(result, props); + g_ptr_array_add(result, props); //mdb_dump_props(props, stderr, 1); break; default: diff --git a/src/libmdb/table.c b/src/libmdb/table.c index 72395cb..a702faa 100644 --- a/src/libmdb/table.c +++ b/src/libmdb/table.c @@ -108,7 +108,7 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) if (entry->props) for (i=0; iprops->len; ++i) { - MdbProperties *props = g_array_index(entry->props, MdbProperties*, i); + MdbProperties *props = g_ptr_array_index(entry->props, i); if (!props->name) table->props = props; } @@ -222,7 +222,7 @@ GPtrArray *mdb_read_columns(MdbTableDef *table) unsigned int i, j; int cur_pos; size_t name_sz; - GArray *allprops; + GPtrArray *allprops; table->columns = g_ptr_array_new(); @@ -315,8 +315,8 @@ GPtrArray *mdb_read_columns(MdbTableDef *table) for (i=0;inum_cols;i++) { pcol = g_ptr_array_index(table->columns, i); for (j=0; jlen; ++j) { - MdbProperties *props = g_array_index(allprops, MdbProperties*, j); - if (props->name && pcol->name && !strcmp(props->name, pcol->name)) { + MdbProperties *props = g_ptr_array_index(allprops, j); + if (props->name && !strcmp(props->name, pcol->name)) { pcol->props = props; break; } diff --git a/src/odbc/connectparams.c b/src/odbc/connectparams.c index 76546b4..ad30d88 100644 --- a/src/odbc/connectparams.c +++ b/src/odbc/connectparams.c @@ -58,7 +58,7 @@ static int GetNextItem (FILE* stream, char** name, char** value); #endif //HAVE_SQLGETPRIVATEPROFILESTRING static void visit (gpointer key, gpointer value, gpointer user_data); -static gboolean cleanup (gpointer key, gpointer value, gpointer user_data); +static void cleanup (gpointer key, gpointer value, gpointer user_data); /* * Allocate create a ConnectParams object @@ -91,7 +91,7 @@ void FreeConnectParams (ConnectParams* params) g_string_free (params->iniFileName, TRUE); if (params->table) { - g_hash_table_foreach_remove (params->table, cleanup, NULL); + g_hash_table_foreach (params->table, cleanup, NULL); g_hash_table_destroy (params->table); } g_free(params); @@ -514,12 +514,10 @@ static void visit (gpointer key, gpointer value, gpointer user_data) fprintf(output, "Parameter: %s, Value: %s\n", (char*)key, (char*)value); } -static gboolean cleanup (gpointer key, gpointer value, gpointer user_data) +static void cleanup (gpointer key, gpointer value, gpointer user_data) { g_free (key); g_free (value); - - return TRUE; } diff --git a/src/sql/Makefile.am b/src/sql/Makefile.am index 94b0838..5c2a7a7 100644 --- a/src/sql/Makefile.am +++ b/src/sql/Makefile.am @@ -1,7 +1,11 @@ +AUTOMAKE_OPTIONS = subdir-objects BUILT_SOURCES = parser.h AM_YFLAGS = -d lib_LTLIBRARIES = libmdbsql.la libmdbsql_la_SOURCES= mdbsql.c parser.y lexer.l +if FAKE_GLIB +libmdbsql_la_SOURCES += ../libmdb/fakeglib.c +endif libmdbsql_la_LDFLAGS = -version-info 2:0:0 -export-symbols-regex '^mdb_sql_' CLEANFILES = parser.c parser.h lexer.c AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 477fb2c..a03c75b 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -1,7 +1,24 @@ +AUTOMAKE_OPTIONS = subdir-objects SUBDIRS = bash-completion bin_PROGRAMS = mdb-export mdb-array mdb-schema mdb-tables mdb-parsecsv mdb-header mdb-sql mdb-ver mdb-prop mdb-count noinst_PROGRAMS = mdb-import prtable prcat prdata prkkd prdump prole updrow prindex -LIBS = $(GLIB_LIBS) @LIBS@ +mdb_export_SOURCES = mdb-export.c +mdb_schema_SOURCES = mdb-schema.c +mdb_tables_SOURCES = mdb-tables.c +mdb_sql_SOURCES = mdb-sql.c +mdb_ver_SOURCES = mdb-ver.c +mdb_import_SOURCES = mdb-import.c +updrow_SOURCES = updrow.c +if FAKE_GLIB +mdb_export_SOURCES += ../libmdb/fakeglib.c +mdb_schema_SOURCES += ../libmdb/fakeglib.c +mdb_tables_SOURCES += ../libmdb/fakeglib.c +mdb_sql_SOURCES += ../libmdb/fakeglib.c +mdb_ver_SOURCES += ../libmdb/fakeglib.c +mdb_import_SOURCES += ../libmdb/fakeglib.c +updrow_SOURCES += ../libmdb/fakeglib.c +endif +LIBS = $(GLIB_LIBS) @LIBS@ DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\" AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LDADD = ../libmdb/libmdb.la diff --git a/src/util/mdb-prop.c b/src/util/mdb-prop.c index e9cfa06..a0a88bb 100644 --- a/src/util/mdb-prop.c +++ b/src/util/mdb-prop.c @@ -91,12 +91,12 @@ main(int argc, char **argv) } void dump_kkd(MdbHandle *mdb, void *kkd, size_t len) { - GArray *aprops = mdb_kkd_to_props(mdb, kkd, len); + GPtrArray *aprops = mdb_kkd_to_props(mdb, kkd, len); int i; if (!aprops) return; for (i=0; ilen; ++i) { - MdbProperties *props = g_array_index(aprops, MdbProperties*, i); + MdbProperties *props = g_ptr_array_index(aprops, i); mdb_dump_props(props, stdout, 1); } }