summaryrefslogtreecommitdiff
path: root/tests/ddb
diff options
context:
space:
mode:
authorHans Ulrich Niedermann <gp@n-dimensional.de>2006-08-18 17:15:20 +0000
committerHans Ulrich Niedermann <gp@n-dimensional.de>2006-08-18 17:15:20 +0000
commit2d2b54d23c50659cbbf65518fc195a39f5c2d9c6 (patch)
treead9e082052657fcc0f4aba0c6ad042a6497291ed /tests/ddb
parent4adadbf835e8f55205c582a0a734c9979dfcc68a (diff)
downloadlibgphoto2-2d2b54d23c50659cbbf65518fc195a39f5c2d9c6.tar.gz
Add experimental code for camlib-external database.
Read tests/ddb/README.ddb if you want to play with it. git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@9104 67ed7778-7388-44ab-90cf-0a291f65f57c
Diffstat (limited to 'tests/ddb')
-rw-r--r--tests/ddb/Makefile.am55
-rw-r--r--tests/ddb/README.ddb67
-rw-r--r--tests/ddb/check-ddb.in41
-rw-r--r--tests/ddb/ddb-common.c3
-rw-r--r--tests/ddb/ddb-common.h63
-rw-r--r--tests/ddb/ddb-txt.l85
-rw-r--r--tests/ddb/ddb-txt.y584
7 files changed, 898 insertions, 0 deletions
diff --git a/tests/ddb/Makefile.am b/tests/ddb/Makefile.am
new file mode 100644
index 000000000..035178314
--- /dev/null
+++ b/tests/ddb/Makefile.am
@@ -0,0 +1,55 @@
+#if HAVE_FLEX_BISON
+flexbison_PROGRAMS_ = test-ddb
+flexbison_check_SCRIPTS_ = check-ddb.sh
+flexbison_BUILT_SOURCES_ = ddb-txt.tab.c ddb-txt.tab.h ddb-txt.yy.c
+flexbison_CLEANFILES_ = ddb-txt.output
+#endif
+
+check_PROGRAMS = $(flexbison_PROGRAMS_)
+
+check_SCRIPTS = \
+ $(flexbison_check_SCRIPTS_)
+
+EXTRA_DIST = \
+ README.ddb \
+ check-ddb.in \
+ ddb-txt.l \
+ ddb-txt.y
+
+TESTS = $(check_SCRIPTS)
+
+BUILT_SOURCES = $(flexbison_BUILT_SOURCES_)
+CLEANFILES = $(check_SCRIPTS) $(BUILT_SOURCES) $(flexbison_CLEANFILES_) gp2ddb.txt
+
+#if HAVE_FLEX_BISON
+test_ddb_SOURCES = $(flexbison_BUILT_SOURCES_) ddb-common.c ddb-common.h
+test_ddb_LDADD = \
+ -lfl \
+ $(top_builddir)/libgphoto2/libgphoto2.la \
+ $(top_builddir)/libgphoto2_port/libgphoto2_port/libgphoto2_port.la \
+ $(LIBEXIF_LIBS) \
+ $(INTLLIBS)
+
+%.yy.c: %.l %.tab.h
+ $(FLEX) -o$@ $<
+
+%.tab.h: %.tab.c
+%.tab.c %.tab.h: %.y
+ $(BISON) -v $<
+#endif
+
+clean-local:
+ rm -f *.s *.i
+
+%.sh: %.in
+ @echo "Creating $@"
+ @sed \
+ -e 's|@top_builddir\@|$(top_builddir)|g' \
+ -e 's|@camlibdir\@|$(camlibdir)|g' \
+ < "$<" > "$@"
+ @chmod +x $@
+
+check-ddb.sh: check-ddb.in $(top_builddir)/packaging/generic/print-camera-list
+
+$(top_builddir)/packaging/generic/print-camera-list:
+ cd $(top_builddir)/packaging/generic && $(MAKE) print-camera-list
diff --git a/tests/ddb/README.ddb b/tests/ddb/README.ddb
new file mode 100644
index 000000000..b6f06e750
--- /dev/null
+++ b/tests/ddb/README.ddb
@@ -0,0 +1,67 @@
+========================================================================
+The gphoto2 device database (gp2ddb)
+========================================================================
+
+Important: This is a prototype the developers can play with. The final
+ version will look much different, so don't invest too much
+ in it.
+
+
+=============================================
+The idea
+========
+
+ * Maintain the database of cameras, their abilities
+ etc. independently from the libgphoto2 camlibs.
+
+ * Updates to the database are much easier to publish than updates to
+ the camlibs which need to be compiled.
+
+
+=============================================
+The implementation
+==================
+
+ * A flex/bison based parser for text based config.
+
+ * The text format is not completely ironed out yet.
+
+ * It is possible to use some HAL device database instead, but do we
+ really want to require HAL? Depends whether we target embedded or
+ desktop environments.
+
+ * print-camera-list prints the current config in the new format
+ (minus camlib internal settings)
+
+ * camlib specific settings can be accommodated using the
+ driver_options { ... }; section.
+
+
+=============================================
+The testcase
+============
+
+ * The testcase check-ddb.sh checks that the CameraAbilitiesList read
+ from the text database is the same one read from the camlibs via
+ gp_abilities_list_load() - for all 700something cameras.
+
+
+=============================================
+How to test it
+==============
+
+ * Add --enable-gp2ddb to your ./configure parameters.
+
+ * Run "make check".
+
+ * Have a look into tests/ddb/.
+
+ * Possibly add the output of
+ (hostname;cat /proc/cpuinfo)|md5sum|cut -d" " -f1
+ to the list in configure.in to avoid the --enable-gp2ddb
+ requirement.
+
+
+========================================================================
+End of file.
+========================================================================
diff --git a/tests/ddb/check-ddb.in b/tests/ddb/check-ddb.in
new file mode 100644
index 000000000..0fa71cd73
--- /dev/null
+++ b/tests/ddb/check-ddb.in
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+set -e
+
+export CAMLIBS="@camlibdir@"
+
+true ./test-ddb<<EOF
+# This is a pre-alpha test example
+
+device "Canon PowerShot G1"
+{
+ driver "canon";
+ operations config;
+
+ interface serial
+ {
+ speeds 9600, 19200, 38400, 57600, 115200;
+ };
+ interface usb
+ {
+ vendor 0x04a9;
+ product 0x3040;
+ };
+};
+
+device "Canon PowerShot G2"
+{
+ driver "canon";
+ interface usb
+ {
+ vendor 0x04a9;
+ product 0x3055;
+ };
+};
+
+EOF
+
+@top_builddir@/packaging/generic/print-camera-list gp2ddb > gp2ddb.txt
+true ./test-ddb gp2ddb.txt
+
+./test-ddb --compare < gp2ddb.txt
diff --git a/tests/ddb/ddb-common.c b/tests/ddb/ddb-common.c
new file mode 100644
index 000000000..ec2499577
--- /dev/null
+++ b/tests/ddb/ddb-common.c
@@ -0,0 +1,3 @@
+#include "ddb-common.h"
+
+YYSTYPE yylval;
diff --git a/tests/ddb/ddb-common.h b/tests/ddb/ddb-common.h
new file mode 100644
index 000000000..0059bac93
--- /dev/null
+++ b/tests/ddb/ddb-common.h
@@ -0,0 +1,63 @@
+#ifndef __DDB_TXT_H__
+#define __DDB_TXT_H__
+
+#define _GPHOTO2_INTERNAL_CODE
+
+#include <gphoto2/gphoto2-abilities-list.h>
+
+typedef union {
+ char *str_val;
+ unsigned int ui_val;
+} symtype;
+
+#define YYSTYPE symtype
+
+extern int yylineno;
+
+void
+yyerror (const char *filename, CameraAbilitiesList *al,
+ const char *str);
+
+int
+yyparse (const char *filenname, CameraAbilitiesList *al);
+
+#define YYLTYPE my_yyltype
+
+typedef struct {
+ int lineno;
+ int column;
+ const char *filename;
+} FilePosition;
+
+typedef struct YYLTYPE {
+ FilePosition begin, end;
+} YYLTYPE;
+
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).begin.lineno = YYRHSLOC(Rhs, 1).begin.lineno; \
+ (Current).begin.column = YYRHSLOC(Rhs, 1).begin.column; \
+ (Current).end.lineno = YYRHSLOC(Rhs, N).end.lineno; \
+ (Current).end.lineno = YYRHSLOC(Rhs, N).end.column; \
+ } \
+ else \
+ { \
+ (Current).begin.lineno = (Current).end.lineno = \
+ YYRHSLOC(Rhs, 0).end.lineno; \
+ (Current).begin.column = (Current).end.column = \
+ YYRHSLOC(Rhs, 0).end.column; \
+ } \
+ while (0)
+
+#define YY_DECL int yylex (void)
+YY_DECL;
+/* #define YYLEX_PARAM void */
+
+// #define YYDEBUG 1
+
+void lexer_reset(const char *_filename);
+
+#endif /* !__DDB_TXT_H__ */
diff --git a/tests/ddb/ddb-txt.l b/tests/ddb/ddb-txt.l
new file mode 100644
index 000000000..10a6566e7
--- /dev/null
+++ b/tests/ddb/ddb-txt.l
@@ -0,0 +1,85 @@
+%option nounput
+%option noyywrap
+%option yylineno
+%option nobackup
+
+%{
+#include <stdlib.h>
+#define _GNU_SOURCE
+#include <string.h>
+#include "ddb-common.h"
+#include "ddb-txt.tab.h"
+
+//#if !(YYDEBUG)
+# define ECHO do {} while (0)
+//#endif
+
+extern char *strndup(const char *s, size_t n);
+
+static char *filename = NULL;
+
+YYSTYPE yylval = { str_val: NULL };
+
+static void lexer_error(const char *msg);
+
+%}
+
+%%
+\#.*$ { /* ignore comment */ }
+"interface" { ECHO; return TOK_INTERFACE; }
+"{" { ECHO; return TOK_BEGIN; }
+"driver" { ECHO; return TOK_DRIVER; }
+"device" { ECHO; return TOK_DEVICE; }
+"}" { ECHO; return TOK_END; }
+"serial" { ECHO; return TOK_SERIAL; }
+"usb" { ECHO; return TOK_USB; }
+"disk" { ECHO; return TOK_DISK; }
+"ptpip" { ECHO; return TOK_PTPIP; }
+"class" { ECHO; return TOK_CLASS; }
+"subclass" { ECHO; return TOK_SUBCLASS; }
+"protocol" { ECHO; return TOK_PROTOCOL; }
+"vendor" { ECHO; return TOK_VENDOR; }
+"product" { ECHO; return TOK_PRODUCT; }
+"speeds" { ECHO; return TOK_SPEEDS; }
+"operations" { ECHO; return TOK_OPERATIONS; }
+"driver_options" { ECHO; return TOK_DRIVER_OPTIONS; }
+"option" { ECHO; return TOK_OPTION; }
+"file_operations" { ECHO; return TOK_FILE_OPERATIONS; }
+"folder_operations" { ECHO; return TOK_FOLDER_OPERATIONS; }
+"driver_status" { ECHO; return TOK_DRIVER_STATUS; }
+"device_type" { ECHO; return TOK_DEVICE_TYPE; }
+("none"|"config"|"capture_image"|"capture_video"|"capture_audio"|"capture_preview"|"delete"|"preview"|"raw"|"audio"|"exif"|"delete_all"|"put_file"|"make_dir"|"remove_dir"|"production"|"testing"|"experimental"|"deprecated"|"still_camera"|"audio_player") {
+ ECHO;
+ yylval.str_val = strndup(yytext, yyleng);
+ return VAL_FLAG;
+ }
+";" { ECHO; return TOK_SEP; }
+"," { ECHO; return TOK_COMMA; }
+\"[A-Za-z0-9\.\+\-<>\|_/()!:,;=\\\$\'@&%\{\}\[\]+#~\* ]+\" { ECHO;
+ yylval.str_val = strndup(yytext, yyleng);
+ return TOK_STRING;
+ }
+(0x)?[0-9a-fA-F]+ {ECHO;
+ yylval.ui_val = strtol(yytext, NULL, 0);
+ return TOK_NUMBER;
+ }
+\n { ECHO; /* ignore newlines */ }
+[ \t\r]+ { ECHO; /* ignore whitespace */ }
+. {
+ static char msg[] = "unexpected character (in string?) '?'";
+ msg[strlen(msg)-2] = yytext[0];
+ lexer_error(msg);
+ }
+%%
+
+void lexer_reset(const char *_filename)
+{
+ filename = (char *) _filename;
+}
+
+static void lexer_error(const char *msg)
+{
+ fprintf(stderr, "%s:%d: lexer error: %s\n",
+ filename, yylineno, msg);
+ exit(4);
+}
diff --git a/tests/ddb/ddb-txt.y b/tests/ddb/ddb-txt.y
new file mode 100644
index 000000000..8798783d7
--- /dev/null
+++ b/tests/ddb/ddb-txt.y
@@ -0,0 +1,584 @@
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _GPHOTO2_INTERNAL_CODE
+#include <gphoto2/gphoto2-abilities-list.h>
+
+#include "ddb-common.h"
+#include "ddb-txt.tab.h"
+
+
+char *current_driver = NULL;
+char *current_device_name = NULL;
+CameraAbilities ca;
+unsigned int speed_index = 0;
+
+extern FILE *yyin;
+
+char *alloc_parse_string(char *s);
+
+char *error_string = NULL;
+
+static void reset_ca(void);
+
+
+#ifdef __GNUC__
+#define __unused__ __attribute__((unused))
+#else
+#define __unused__
+#endif
+
+
+static int
+compare_camera_abilities(const CameraAbilities *a,
+ const CameraAbilities *b);
+
+
+%}
+
+%defines
+
+/* This is supposed to track linenumbers and stuff, but I don't know how to
+ * make it work. */
+%locations
+
+/* Pure yylex. */
+//%pure-parser
+
+/* More than "syntax error" */
+%error-verbose
+
+/* parameters to yyparse() and yyerror() */
+%parse-param { char const *file_name };
+%parse-param { CameraAbilitiesList *al };
+
+/* parameters to yylex() */
+/* %lex-param { CameraAbilitiesList *al }; */
+
+%initial-action
+{
+ lexer_reset(file_name);
+ yyloc.begin.filename = yyloc.end.filename = file_name;
+ yyloc.begin.column = yyloc.end.column = -1;
+ yyloc.begin.lineno = yyloc.end.lineno = -1;
+ @$.begin.filename = @$.end.filename = file_name;
+ error_string = NULL;
+};
+
+%token TOK_SEP TOK_COMMA
+%token TOK_WHITESPACE TOK_NEWLINE
+
+%token <ui_val> TOK_NUMBER
+%token <str_val> TOK_STRING
+
+%token TOK_INTERFACE
+%token TOK_DRIVER
+%token TOK_DEVICE
+%token TOK_BEGIN
+%token TOK_END
+
+%token TOK_SERIAL
+%token TOK_SPEEDS
+
+%token TOK_USB
+%token TOK_PRODUCT
+%token TOK_VENDOR
+%token TOK_CLASS
+%token TOK_SUBCLASS
+%token TOK_PROTOCOL
+
+%token TOK_DISK
+%token TOK_PTPIP
+
+%token TOK_DEVICE_TYPE
+%token TOK_DRIVER_STATUS
+%token TOK_OPERATIONS
+%token TOK_FILE_OPERATIONS
+%token TOK_FOLDER_OPERATIONS
+
+%token TOK_DRIVER_OPTIONS
+%token TOK_OPTION
+
+%token <str_val> VAL_FLAG
+
+ /* %type <ui_val> interface_usb_vendor */
+ /* %type <ui_val> interface_usb_product */
+
+%start devices
+
+%%
+
+devices:
+ /* empty */
+ | devices device
+ ;
+
+device:
+ TOK_DEVICE TOK_STRING TOK_BEGIN
+ {
+ current_device_name = alloc_parse_string($<str_val>2);
+ /* printf("BEGIN_DEVICE <<%s>>\n", current_device_name); */
+ reset_ca();
+ strncpy(ca.model, current_device_name, sizeof(ca.model));
+ ca.model[sizeof(ca.model)-1]='\0';
+ }
+ device_type
+ driver_definition
+ driver_status
+ operations
+ file_operations
+ folder_operations
+ interfaces
+ driver_options
+ TOK_END
+ {
+ //printf("END_DEVICE <<%s>>\n", current_device_name);
+ free(current_device_name); current_device_name = NULL;
+ if (current_driver != NULL) {
+ free(current_driver); current_driver = NULL;
+ }
+ gp_abilities_list_append(al, ca);
+ }
+ TOK_SEP
+ ;
+
+driver_options:
+ /* empty */
+ | TOK_DRIVER_OPTIONS TOK_BEGIN
+ driver_option_list
+ TOK_END TOK_SEP
+ ;
+
+driver_option_list:
+ /* empty */
+ | driver_option_list driver_option_item
+ ;
+
+driver_option_item:
+ TOK_OPTION TOK_STRING TOK_SEP
+ | TOK_OPTION TOK_STRING TOK_STRING TOK_SEP
+ ;
+
+device_type:
+ /* empty */
+ | TOK_DEVICE_TYPE VAL_FLAG TOK_SEP
+ {
+ if (gpi_string_to_enum($<str_val>2, &ca.device_type,
+ gpi_gphoto_device_type_map)) {
+ error_string = $<str_val>2;
+ yyerror(file_name, al,
+ "illegal device_type value");
+ }
+ }
+ ;
+
+driver_definition:
+ TOK_DRIVER TOK_STRING TOK_SEP
+ {
+ const char *camlib_env = getenv(CAMLIBDIR_ENV);
+ const char *camlibs = (camlib_env != NULL)?camlib_env:CAMLIBS;
+ current_driver = alloc_parse_string($<str_val>2);
+ strncpy(ca.library, camlibs, sizeof(ca.library));
+ strncat(ca.library, "/", sizeof(ca.library)-strlen(ca.library)-1);
+ strncat(ca.library, current_driver, sizeof(ca.library)-strlen(ca.library)-1);
+ ca.library[sizeof(ca.library)-1] = '\0';
+ //printf(" DRIVER <<%s>>\n", current_driver);
+ }
+ ;
+
+driver_status:
+ /* empty */
+ | TOK_DRIVER_STATUS VAL_FLAG TOK_SEP
+ {
+ if (gpi_string_to_enum($<str_val>2, &ca.status,
+ gpi_camera_driver_status_map)) {
+ error_string = $<str_val>2;
+ yyerror(file_name, al,
+ "illegal driver_status value");
+ }
+ }
+ ;
+
+folder_operations:
+ /* empty */
+ | TOK_FOLDER_OPERATIONS folder_operations_list TOK_SEP
+ ;
+
+file_operations:
+ /* empty */
+ | TOK_FILE_OPERATIONS file_operations_list TOK_SEP
+ ;
+
+operations:
+ /* empty */
+ | TOK_OPERATIONS operations_list TOK_SEP
+ ;
+
+folder_operations_list:
+ folder_operations_list TOK_COMMA folder_operation
+ | folder_operation
+ ;
+
+file_operations_list:
+ file_operations_list TOK_COMMA file_operation
+ | file_operation
+ ;
+
+operations_list:
+ operations_list TOK_COMMA operation
+ | operation
+ ;
+
+folder_operation:
+ VAL_FLAG
+ {
+ if (gpi_string_or_to_flags($<str_val>1, &ca.folder_operations,
+ gpi_folder_operation_map)) {
+ error_string = $<str_val>1;
+ yyerror(file_name, al,
+ "illegal folder_operation flag");
+ }
+ }
+ ;
+
+file_operation:
+ VAL_FLAG
+ {
+ if (gpi_string_or_to_flags($<str_val>1, &ca.file_operations,
+ gpi_file_operation_map)) {
+ error_string = $<str_val>1;
+ yyerror(file_name, al,
+ "illegal file_operation flag");
+ }
+ }
+ ;
+
+operation:
+ VAL_FLAG
+ {
+ if (gpi_string_or_to_flags($<str_val>1,
+ &ca.operations,
+ gpi_camera_operation_map)) {
+ error_string = $<str_val>1;
+ yyerror(file_name, al,
+ "illegal operation flag");
+ }
+ }
+ ;
+
+interfaces:
+ /* empty */
+ | interfaces interface TOK_SEP
+ ;
+
+interface:
+ interface_serial
+ | interface_usb
+ | TOK_INTERFACE TOK_DISK {
+ ca.port |= GP_PORT_DISK;
+ }
+ | TOK_INTERFACE TOK_PTPIP {
+ ca.port |= GP_PORT_PTPIP;
+ }
+ ;
+
+interface_serial:
+ TOK_INTERFACE TOK_SERIAL
+ {
+ ca.port |= GP_PORT_SERIAL;
+ /* Ideally: Prepare serial entry. */
+ }
+ TOK_BEGIN
+ interface_serial_internal
+ TOK_END
+ {
+ /* Ideally: Add serial entry to database. */
+ }
+ ;
+
+interface_serial_internal:
+ /* empty */
+ | TOK_SPEEDS speed_number_list TOK_SEP
+ {
+ if (speed_index < (sizeof(ca.speed)/sizeof(ca.speed[0]))) {
+ ca.speed[speed_index++] = 0;
+ } else {
+ ca.speed[(sizeof(ca.speed)/sizeof(ca.speed[0]))-1] = 0;
+ }
+ }
+ ;
+
+speed_number_list:
+ speed_number_list TOK_COMMA speed_list_number
+ | speed_list_number
+ ;
+
+speed_list_number:
+ TOK_NUMBER
+ {
+ if (speed_index < (sizeof(ca.speed)/sizeof(ca.speed[0]))) {
+ ca.speed[speed_index++] = $<ui_val>1;
+ }
+ }
+ ;
+
+/* FIXME: Make sure that the CameraAbilities usb_* fields are not
+ * overwritten by multiple definitions
+ */
+
+interface_usb:
+ TOK_INTERFACE TOK_USB
+ TOK_BEGIN
+ {
+ ca.port |= GP_PORT_USB;
+ /* Ideally: Prepare USB entry for this camera */
+ }
+ interface_usb_internal
+ TOK_END
+ {
+ /* Ideally: Commit prepared USB entry to database */
+ }
+ ;
+
+interface_usb_internal:
+ interface_usb_vendor TOK_SEP
+ interface_usb_product TOK_SEP
+ | interface_usb_class_stuff
+ ;
+
+interface_usb_vendor:
+ TOK_VENDOR TOK_NUMBER
+ {
+ ca.usb_vendor = $<ui_val>2;
+ }
+ ;
+
+interface_usb_product:
+ TOK_PRODUCT TOK_NUMBER
+ {
+ ca.usb_product = $<ui_val>2;
+ }
+ ;
+
+interface_usb_class_stuff:
+ interface_usb_class TOK_SEP
+ | interface_usb_class TOK_SEP
+ interface_usb_subclass TOK_SEP
+ | interface_usb_class TOK_SEP
+ interface_usb_subclass TOK_SEP
+ interface_usb_protocol TOK_SEP
+ | interface_usb_class TOK_SEP
+ interface_usb_protocol TOK_SEP
+ ;
+
+interface_usb_class:
+ TOK_CLASS TOK_NUMBER
+ {
+ ca.usb_class = $<ui_val>2;
+ }
+ ;
+
+interface_usb_subclass:
+ TOK_SUBCLASS TOK_NUMBER
+ {
+ ca.usb_subclass = $<ui_val>2;
+ }
+ ;
+
+interface_usb_protocol:
+ TOK_PROTOCOL TOK_NUMBER
+ {
+ ca.usb_protocol = $<ui_val>2;
+ }
+ ;
+
+%%
+
+
+char *alloc_parse_string(char *s)
+ {
+ if (s[0] == '"') {
+ int len = strlen(s);
+ if (s[len-1] == '"') {
+ char *ret = malloc(len-2+1);
+ strncpy(ret, &s[1], len-2);
+ ret[len-2] = '\0';
+ free(s);
+ return ret;
+ } else {
+ fprintf(stderr, "Error: string does not end with quote: <<%s>>\n", s);
+ exit(2);
+ }
+ } else {
+ fprintf(stderr, "Error: string does not start with quote: <<%s>>\n", s);
+ exit(2);
+ }
+ }
+
+
+void yyerror(const char *filename,
+ CameraAbilitiesList __unused__ *al,
+ const char *str)
+{
+ fprintf(stderr, "%s:%d: parse error: %s\n",
+ filename, yylineno, str);
+ if (NULL != error_string) {
+ fprintf(stderr, "%s:%d- <<%s>>\n",
+ filename, yylineno, error_string);
+ error_string = NULL;
+ }
+ exit(4);
+}
+
+CameraAbilitiesList *
+read_abilities_list(const char *filename);
+CameraAbilitiesList *
+read_abilities_list(const char *filename)
+{
+ CameraAbilitiesList *al = NULL;
+ int retval;
+ if (0!=(retval = gp_abilities_list_new(&al))) { return NULL; }
+ if (0!=(retval = yyparse(filename, al))) { goto error; }
+ return al;
+ error:
+ if (al!=NULL)
+ gp_abilities_list_free(al);
+ return NULL;
+}
+
+
+static int
+compare_lists (void)
+{
+ unsigned int errors = 0;
+ CameraAbilitiesList *ddb = read_abilities_list(NULL);
+ CameraAbilitiesList *clb;
+ unsigned int i, n_ddb, n_clb;
+ gp_abilities_list_new(&clb);
+ gp_abilities_list_load(clb, NULL);
+ n_ddb = gp_abilities_list_count(ddb);
+ n_clb = gp_abilities_list_count(clb);
+ fprintf(stderr, "## Comparing ddb with clb ##\n");
+ for (i=0; (i<n_ddb) && (i<n_clb); i++) {
+ CameraAbilities a, b;
+ gp_abilities_list_get_abilities(ddb, i, &a);
+ gp_abilities_list_get_abilities(clb, i, &b);
+ if (compare_camera_abilities(&a, &b)) {
+ errors++;
+ }
+ }
+ gp_abilities_list_free(clb);
+ gp_abilities_list_free(ddb);
+ return (errors == 0)? 0 : 1;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int retval;
+ CameraAbilitiesList *al;
+#if YYDEBUG
+ yydebug = 1;
+#endif
+ if (0!=(retval=gp_abilities_list_new(&al))) {
+ fprintf(stderr, "Could not create CameraAbilitiesList\n");
+ return 6;
+ }
+ if (argc > 1) {
+ for (i=1; i<argc; i++) {
+ if (0==strcmp("--compare", argv[i])) {
+ return compare_lists();
+ } else {
+ const char *filename = argv[i];
+ yyin = fopen(filename, "r");
+ if (NULL == yyin) {
+ fprintf(stderr, "File %s does not exist. Aborting.\n", filename);
+ return 5;
+ }
+ retval = yyparse(filename, al);
+ fclose(yyin);
+ if (retval != 0) {
+ return retval;
+ }
+ }
+ }
+ return 0;
+ } else {
+ yyin = stdin;
+ return yyparse("<stdin>", al);
+ }
+}
+
+
+static void
+reset_ca(void)
+{
+ memset(&ca, 0, sizeof(ca));
+ speed_index = 0;
+}
+
+
+#define CMP_RET_S(cmp_func, field) \
+ do { \
+ int retval = cmp_func(a->field, b->field); \
+ if (retval != 0) { \
+ fprintf(stderr, " difference in .%s: <<%s>> vs <<%s>>\n", \
+ #field, a->field, b->field); \
+ errors++; \
+ } \
+ } while (0)
+
+#define CMP_RET_UI(cmp_func, field) \
+ do { \
+ int retval = cmp_func((unsigned int) (a->field), \
+ (unsigned int) (b->field)); \
+ if (retval != 0) { \
+ fprintf(stderr, " difference in .%s: 0x%x vs 0x%x\n", \
+ #field, (unsigned int) (a->field), \
+ (unsigned int) (b->field)); \
+ errors++; \
+ } \
+ } while (0)
+
+
+static int
+uicmp(unsigned int a, unsigned int b)
+{
+ if (a < b) return -1;
+ else if (a > b) return 1;
+ else return 0;
+}
+
+
+static int
+compare_camera_abilities(const CameraAbilities *a,
+ const CameraAbilities *b)
+{
+ unsigned int errors = 0;
+ int i;
+ CMP_RET_S(strcmp, model);
+ CMP_RET_S(strcmp, library);
+ /* CMP_RET_S(strcmp, id); */
+ CMP_RET_UI(uicmp, port);
+ for (i=0; (a->speed[i] != 0) && (a->speed[i] != 0); i++) {
+ CMP_RET_UI(uicmp, speed[i]);
+ }
+ CMP_RET_UI(uicmp, operations);
+ CMP_RET_UI(uicmp, file_operations);
+ CMP_RET_UI(uicmp, folder_operations);
+ CMP_RET_UI(uicmp, usb_vendor);
+ CMP_RET_UI(uicmp, usb_product);
+ CMP_RET_UI(uicmp, usb_class);
+ CMP_RET_UI(uicmp, usb_subclass);
+ CMP_RET_UI(uicmp, usb_protocol);
+ CMP_RET_UI(uicmp, device_type);
+ if (errors == 0) {
+ return 0;
+ } else {
+ fprintf(stderr, "Difference for <<%s>>\n", a->model);
+ return 1;
+ }
+}