diff options
author | Hans Ulrich Niedermann <gp@n-dimensional.de> | 2006-08-18 17:15:20 +0000 |
---|---|---|
committer | Hans Ulrich Niedermann <gp@n-dimensional.de> | 2006-08-18 17:15:20 +0000 |
commit | 2d2b54d23c50659cbbf65518fc195a39f5c2d9c6 (patch) | |
tree | ad9e082052657fcc0f4aba0c6ad042a6497291ed /tests/ddb | |
parent | 4adadbf835e8f55205c582a0a734c9979dfcc68a (diff) | |
download | libgphoto2-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.am | 55 | ||||
-rw-r--r-- | tests/ddb/README.ddb | 67 | ||||
-rw-r--r-- | tests/ddb/check-ddb.in | 41 | ||||
-rw-r--r-- | tests/ddb/ddb-common.c | 3 | ||||
-rw-r--r-- | tests/ddb/ddb-common.h | 63 | ||||
-rw-r--r-- | tests/ddb/ddb-txt.l | 85 | ||||
-rw-r--r-- | tests/ddb/ddb-txt.y | 584 |
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; + } +} |