diff options
Diffstat (limited to 'sanei')
-rw-r--r-- | sanei/Makefile.in | 95 | ||||
-rw-r--r-- | sanei/sanei_codec_ascii.c | 345 | ||||
-rw-r--r-- | sanei/sanei_codec_bin.c | 139 | ||||
-rw-r--r-- | sanei/sanei_init_debug.c | 133 | ||||
-rw-r--r-- | sanei/sanei_load_values.c | 207 | ||||
-rw-r--r-- | sanei/sanei_save_values.c | 169 | ||||
-rw-r--r-- | sanei/sanei_thread.c | 425 | ||||
-rw-r--r-- | sanei/sanei_wire.c | 694 |
8 files changed, 2207 insertions, 0 deletions
diff --git a/sanei/Makefile.in b/sanei/Makefile.in new file mode 100644 index 0000000..eca6cbd --- /dev/null +++ b/sanei/Makefile.in @@ -0,0 +1,95 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +distdir = $(top_srcdir)/$(PACKAGE)-$(VERSION) + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +configdir = ${sysconfdir}/sane.d +sanedatadir = ${datadir}/sane + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +RANLIB = @RANLIB@ + +CC = @CC@ +INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ @SANE_CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +DEFS = @DEFS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +MCOMP = --mode=compile +MLINK = --mode=link + +@SET_MAKE@ + +LIBSANEI_OBJS = sanei_init_debug.o \ + sanei_wire.o sanei_codec_ascii.o sanei_codec_bin.o \ + sanei_save_values.o sanei_load_values.o + +LIBSANEI_LTOBJS = sanei_init_debug.lo \ + sanei_wire.lo sanei_codec_ascii.lo sanei_codec_bin.lo \ + sanei_save_values.lo sanei_load_values.lo + +TARGETS = libsanei.a + +DISTFILES = Makefile.in sanei_codec_ascii.c sanei_codec_bin.c \ + sanei_init_debug.c sanei_load_values.c sanei_save_values.c \ + sanei_thread.c sanei_wire.c + +.PHONY: all install check depend clean distclean uninstall dist + +.SUFFIXES: +.SUFFIXES: .c .o +.c.o: + $(COMPILE) $< + @test -f $@ || $(COMPILE) $< + +all: $(TARGETS) + +libsanei.a: $(LIBSANEI_OBJS) + ar r $@ $(LIBSANEI_OBJS) + $(RANLIB) $@ + +install: + +uninstall: + +depend: + makedepend -I. -I../include *.c + +clean: + rm -f *.out *.o *.lo *~ *.a *.bak $(OBJS) + rm -rf .libs + +distclean: clean + rm -f Makefile + +dist: $(DISTFILES) + for file in $(DISTFILES); do \ + ln $$file $(distdir)/sanei 2> /dev/null \ + || cp -p $$file $(distdir)/sanei ; \ + done diff --git a/sanei/sanei_codec_ascii.c b/sanei/sanei_codec_ascii.c new file mode 100644 index 0000000..220d0f4 --- /dev/null +++ b/sanei/sanei_codec_ascii.c @@ -0,0 +1,345 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <sane/sane.h> +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +static const char *hexdigit = "0123456789abcdef"; + +static void +skip_ws (Wire *w) +{ + while (1) + { + sanei_w_space (w, 1); + if (w->status != 0) + return; + + if (!isspace (*w->buffer.curr)) + return; + + ++w->buffer.curr; + } +} + +static unsigned +get_digit (Wire *w) +{ + unsigned digit; + + sanei_w_space (w, 1); + digit = tolower(*w->buffer.curr++) - '0'; + if (digit > 9) + digit -= 'a' - ('9' + 1); + if (digit > 0xf) + { + w->status = EINVAL; + return 0; + } + return digit; +} + +static SANE_Byte +get_byte (Wire *w) +{ + return get_digit (w) << 4 | get_digit (w); +} + +static void +ascii_w_byte (Wire *w, void *v) +{ + SANE_Byte *b = v; + + switch (w->direction) + { + case WIRE_ENCODE: + sanei_w_space (w, 3); + *w->buffer.curr++ = hexdigit[(*b >> 4) & 0x0f]; + *w->buffer.curr++ = hexdigit[(*b >> 0) & 0x0f]; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + skip_ws (w); + *b = get_byte (w); + break; + + case WIRE_FREE: + break; + } +} + +static void +ascii_w_char (Wire *w, void *v) +{ + SANE_Char *c = v; + + switch (w->direction) + { + case WIRE_ENCODE: + sanei_w_space (w, 5); + *w->buffer.curr++ = '\''; + if (*c == '\'' || *c == '\\') + *w->buffer.curr++ = '\\'; + *w->buffer.curr++ = *c; + *w->buffer.curr++ = '\''; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + sanei_w_space (w, 4); + if (*w->buffer.curr++ != '\'') + { + w->status = EINVAL; + return; + } + *c = *w->buffer.curr++; + if (*c == '\\') + { + sanei_w_space (w, 2); + *c = *w->buffer.curr++; + } + if (*w->buffer.curr++ != '\'') + { + w->status = EINVAL; + return; + } + break; + + case WIRE_FREE: + break; + } +} + +static void +ascii_w_string (Wire *w, void *v) +{ + size_t len, alloced_len; + SANE_String *s = v; + char * str, ch; + int done; + + switch (w->direction) + { + case WIRE_ENCODE: + if (*s) + { + sanei_w_space (w, 1); + *w->buffer.curr++ = '"'; + str = *s; + while ((ch = *str++)) + { + sanei_w_space (w, 2); + if (ch == '"' || ch == '\\') + *w->buffer.curr++ = '\\'; + *w->buffer.curr++ = ch; + } + *w->buffer.curr++ = '"'; + } + else + { + sanei_w_space (w, 5); + *w->buffer.curr++ = '('; + *w->buffer.curr++ = 'n'; + *w->buffer.curr++ = 'i'; + *w->buffer.curr++ = 'l'; + *w->buffer.curr++ = ')'; + } + sanei_w_space (w, 1); + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + skip_ws (w); + sanei_w_space (w, 1); + ch = *w->buffer.curr++; + if (ch == '"') + { + alloced_len = len = 0; + str = 0; + done = 0; + do + { + sanei_w_space (w, 1); + if (w->status != 0) + return; + + ch = *w->buffer.curr++; + if (ch == '"') + done = 1; + + if (ch == '\\') + { + sanei_w_space (w, 1); + ch = *w->buffer.curr++; + } + + if (len >= alloced_len) + { + alloced_len += 1024; + if (!str) + str = malloc (alloced_len); + else + str = realloc (str, alloced_len); + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + str[len++] = ch; + } + while (!done); + + str[len - 1] = '\0'; + *s = realloc (str, len); + + if (*s == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + else if (ch == '(') + { + sanei_w_space (w, 4); + if ( *w->buffer.curr++ != 'n' + || *w->buffer.curr++ != 'i' + || *w->buffer.curr++ != 'l' + || *w->buffer.curr++ != ')') + { + w->status = EINVAL; + return; + } + *s = 0; + } + else + { + w->status = EINVAL; + return; + } + break; + + case WIRE_FREE: + if (*s) + free (*s); + break; + } +} + +static void +ascii_w_word (Wire *w, void *v) +{ + SANE_Word val, *word = v; + int i, is_negative = 0; + char buf[16]; + + switch (w->direction) + { + case WIRE_ENCODE: + val = *word; + i = sizeof (buf) - 1; + if (val < 0) + { + is_negative = 1; + val = -val; + } + do + { + buf[i--] = '0' + (val % 10); + val /= 10; + } + while (val); + if (is_negative) + buf[i--] = '-'; + + sanei_w_space (w, sizeof (buf) - i); + memcpy (w->buffer.curr, buf + i + 1, sizeof (buf) - i - 1); + w->buffer.curr += sizeof (buf) - i - 1; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + skip_ws (w); + val = 0; + sanei_w_space (w, 1); + if (*w->buffer.curr == '-') + { + is_negative = 1; + ++w->buffer.curr; + } + while (1) + { + sanei_w_space (w, 1); + if (w->status != 0) + return; + + if (!isdigit (*w->buffer.curr)) + break; + + val = 10*val + (*w->buffer.curr++ - '0'); + } + *word = is_negative ? -val : val; + break; + + case WIRE_FREE: + break; + } +} + +void +sanei_codec_ascii_init (Wire *w) +{ + w->codec.w_byte = ascii_w_byte; + w->codec.w_char = ascii_w_char; + w->codec.w_word = ascii_w_word; + w->codec.w_string = ascii_w_string; +} diff --git a/sanei/sanei_codec_bin.c b/sanei/sanei_codec_bin.c new file mode 100644 index 0000000..4347825 --- /dev/null +++ b/sanei/sanei_codec_bin.c @@ -0,0 +1,139 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <sane/sane.h> +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_bin.h" + +static void +bin_w_byte (Wire *w, void *v) +{ + SANE_Byte *b = v; + + sanei_w_space (w, 1); + if (w->status) + return; + + switch (w->direction) + { + case WIRE_ENCODE: + *w->buffer.curr++ = *b; + break; + + case WIRE_DECODE: + *b = *w->buffer.curr++; + break; + + case WIRE_FREE: + break; + } +} + +static void +bin_w_string (Wire *w, void *v) +{ + SANE_Word len; + SANE_String *s = v; + + if (w->direction != WIRE_DECODE) + { + len = 0; + if (*s) + len = strlen (*s) + 1; + } + sanei_w_array (w, &len, v, w->codec.w_byte, 1); + + if (w->direction == WIRE_DECODE) + { + if (len == 0) + *s = 0; + else if (w->status == 0) + *(*s + len - 1) = '\0'; + } +} + +static void +bin_w_word (Wire *w, void *v) +{ + SANE_Word val, *word = v; + + sanei_w_space (w, 4); + if (w->status) + return; + switch (w->direction) + { + case WIRE_ENCODE: + val = *word; + /* store in bigendian byte-order: */ + w->buffer.curr[0] = (val >> 24) & 0xff; + w->buffer.curr[1] = (val >> 16) & 0xff; + w->buffer.curr[2] = (val >> 8) & 0xff; + w->buffer.curr[3] = (val >> 0) & 0xff; + w->buffer.curr += 4; + break; + + case WIRE_DECODE: + val = ( ((w->buffer.curr[0] & 0xff) << 24) + | ((w->buffer.curr[1] & 0xff) << 16) + | ((w->buffer.curr[2] & 0xff) << 8) + | ((w->buffer.curr[3] & 0xff) << 0)); + *word = val; + w->buffer.curr += 4; + break; + + case WIRE_FREE: + break; + } +} + +void +sanei_codec_bin_init (Wire *w) +{ + w->codec.w_byte = bin_w_byte; + w->codec.w_char = bin_w_byte; + w->codec.w_word = bin_w_word; + w->codec.w_string = bin_w_string; +} diff --git a/sanei/sanei_init_debug.c b/sanei/sanei_init_debug.c new file mode 100644 index 0000000..62fed63 --- /dev/null +++ b/sanei/sanei_init_debug.c @@ -0,0 +1,133 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1996, 1997 David Mosberger-Tang and Andreas Beck + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <string.h> +#include <stdarg.h> +#include <syslog.h> +#ifdef HAVE_OS2_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <sys/stat.h> + +#ifdef HAVE_OS2_H +# define INCL_DOS +# include <os2.h> +#endif + +#define BACKEND_NAME sanei_debug +#include "../include/sane/sanei_debug.h" + +void +sanei_init_debug (const char * backend, int * var) +{ + char ch, buf[256] = "SANE_DEBUG_"; + const char * val; + unsigned int i; + + *var = 0; + + for (i = 11; (ch = backend[i - 11]) != 0; ++i) + { + if (i >= sizeof (buf) - 1) + break; + buf[i] = toupper(ch); + } + buf[i] = '\0'; + + val = getenv (buf); + + if (!val) + return; + + *var = atoi (val); + + DBG (0, "Setting debug level of %s to %d.\n", backend, *var); +} + +void +sanei_debug_msg + (int level, int max_level, const char *be, const char *fmt, va_list ap) +{ + char *msg; + + if (max_level >= level) + { + if ( 1 == isfdtype(fileno(stderr), S_IFSOCK) ) + { + msg = (char *)malloc (sizeof(char) * (strlen(be) + strlen(fmt) + 4)); + if (msg == NULL) + { + syslog (LOG_DEBUG, "[sanei_debug] malloc() failed\n"); + vsyslog (LOG_DEBUG, fmt, ap); + } + else + { + sprintf (msg, "[%s] %s", be, fmt); + vsyslog(LOG_DEBUG, msg, ap); + free (msg); + } + } + else + { + fprintf (stderr, "[%s] ", be); + vfprintf (stderr, fmt, ap); + } + + } +} + +#ifdef NDEBUG +void +sanei_debug_ndebug (int level, const char *fmt, ...) +{ + /* this function is never called */ +} +#endif diff --git a/sanei/sanei_load_values.c b/sanei/sanei_load_values.c new file mode 100644 index 0000000..01c8e42 --- /dev/null +++ b/sanei/sanei_load_values.c @@ -0,0 +1,207 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + + This file implements a routine to restore option values saved to a + file (using sanei_save_values()). This is a bit tricky since + setting an option may change the availability of other options. + The problem is that we don't know the order of the set-value calls + that resulted in the saved set of option values. One solution + might be to simply keep setting all option values until we no + longer get any changes to the option value set. However, that has + the potential for live-lock. Instead, we keep track of what + options caused a SANE_INFO_RELOAD_OPTIONS. For such options, their + value is set exactly once. This guarantees convergence after a + bounded (and usually small) number of iterations. The resulting + value set is guaranteed to be the desired (saved) one as long as + setting an option that affects availability of other options does + not "lose" its value by setting another option. I don't think any + sane backend would do this and since this is SANE, we just proved + that this algorithm works perfectly. */ + +#ifdef __TANDEM +#include <floss.h> +#endif + +#ifdef _AIX +# include <lalloca.h> /* MUST come first for AIX! */ +#endif + +#include "sane/config.h" +#include <lalloca.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#ifdef HAVE_LIBC_H +# include <libc.h> /* NeXTStep/OpenStep */ +#endif + +#include <sane/sane.h> +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +#define BITS_PER_LONG (8*sizeof (u_long)) + +#define SET(set, bit) \ + ((set)[(bit)/BITS_PER_LONG] |= (1UL << (bit)%BITS_PER_LONG)) +#define IS_SET(set, bit) \ + (((set)[(bit)/BITS_PER_LONG] & (1UL << (bit)%BITS_PER_LONG)) != 0) + +int +sanei_load_values (int fd, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + SANE_Word *word_array; + SANE_String name, str; + u_long *caused_reload; + SANE_Int num_options; + SANE_Status status; + int i, keep_going; + SANE_Word word; + SANE_Int info; + off_t offset; + size_t size; + char *buf; + Wire w; + + offset = lseek (fd, 0, SEEK_CUR); + w.io.fd = fd; +#ifdef __TANDEM + w.io.read = floss_read; + w.io.write = floss_write; +#else + w.io.read = read; + w.io.write = write; +#endif + sanei_w_init (&w, sanei_codec_ascii_init); + sanei_w_set_dir (&w, WIRE_DECODE); + keep_going = 0; + + sane_control_option (device, 0, SANE_ACTION_GET_VALUE, &num_options, 0); + size = (num_options + BITS_PER_LONG - 1) / BITS_PER_LONG * sizeof (long); + caused_reload = alloca (size); + memset (caused_reload, 0, size); + + while (1) + { + sanei_w_space (&w, 3); + + if (!w.status) + sanei_w_string (&w, &name); + + if (w.status) + { + if (keep_going) + { + lseek (fd, offset, SEEK_SET); + sanei_w_set_dir (&w, WIRE_DECODE); + keep_going = 0; + continue; + } + return 0; + } + + status = SANE_STATUS_GOOD; + info = 0; + for (i = 1; (opt = sane_get_option_descriptor (device, i)); ++i) + { + if (!opt->name || strcmp (opt->name, name) != 0) + continue; + + if (IS_SET(caused_reload, i)) + continue; + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof (SANE_Word)) + { + sanei_w_word (&w, &word); + status = sane_control_option (device, i, + SANE_ACTION_SET_VALUE, + &word, &info); + } + else + { + SANE_Int len; + + sanei_w_array (&w, &len, (void **) &word_array, + (WireCodecFunc) sanei_w_word, + sizeof (SANE_Word)); + status = sane_control_option (device, i, + SANE_ACTION_SET_VALUE, + word_array, &info); + w.direction = WIRE_FREE; + sanei_w_array (&w, &len, (void **) &word_array, + (WireCodecFunc) sanei_w_word, + sizeof (SANE_Word)); + w.direction = WIRE_DECODE; + } + break; + + case SANE_TYPE_STRING: + sanei_w_string (&w, &str); + buf = malloc (opt->size); + strncpy (buf, str, opt->size); + buf[opt->size - 1] = '\0'; + sanei_w_free (&w, (WireCodecFunc) sanei_w_string, &str); + + status = sane_control_option (device, i, SANE_ACTION_SET_VALUE, + buf, &info); + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + break; + } + break; + } + sanei_w_free (&w, (WireCodecFunc) sanei_w_string, &name); + + if (status == SANE_STATUS_GOOD && (info & SANE_INFO_RELOAD_OPTIONS)) + { + SET (caused_reload, i); + keep_going = 1; + } + } + return 0; +} diff --git a/sanei/sanei_save_values.c b/sanei/sanei_save_values.c new file mode 100644 index 0000000..195947c --- /dev/null +++ b/sanei/sanei_save_values.c @@ -0,0 +1,169 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#ifdef __TANDEM +#include <floss.h> +#endif + +#include "sane/config.h" + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#ifdef HAVE_LIBC_H +# include <libc.h> /* NeXTStep/OpenStep */ +#endif + +#include <sane/sane.h> +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +int +sanei_save_values (int fd, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + size_t word_array_size = 0; + SANE_Word *word_array = 0; + size_t str_size = 0; + SANE_String str = 0; + SANE_Word word; + Wire w; + int i; + + w.io.fd = fd; +#ifdef __TANDEM + w.io.read = floss_read; + w.io.write = floss_write; +#else + w.io.read = read; + w.io.write = write; +#endif + sanei_w_init (&w, sanei_codec_ascii_init); + sanei_w_set_dir (&w, WIRE_ENCODE); + + for (i = 0; (opt = sane_get_option_descriptor (device, i)); ++i) + { + if ((opt->cap & (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT)) + != (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT) + || !opt->name) + /* if we can't query AND set the option, don't bother saving it */ + continue; + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof (SANE_Word)) + { + if (sane_control_option (device, i, SANE_ACTION_GET_VALUE, + &word, 0) + != SANE_STATUS_GOOD) + continue; + sanei_w_string (&w, (SANE_String *) &opt->name); + sanei_w_word (&w, &word); + } + else + { + SANE_Int len = opt->size / sizeof (SANE_Word); + + if (opt->size > word_array_size) + { + word_array_size = + ((opt->size + 32*sizeof (SANE_Word)) + & ~(32*sizeof (SANE_Word) - 1)); + if (word_array) + word_array = realloc (word_array, word_array_size); + else + word_array = malloc (word_array_size); + + if (word_array == 0) + { + /* Malloc failed, so return an error. */ + w.status = ENOMEM; + return 1; + } + } + if (sane_control_option (device, i, SANE_ACTION_GET_VALUE, + word_array, 0) + != SANE_STATUS_GOOD) + continue; + sanei_w_string (&w, (SANE_String *) &opt->name); + sanei_w_array (&w, &len, (void **) &word_array, + (WireCodecFunc) sanei_w_word, sizeof (SANE_Word)); + } + break; + + case SANE_TYPE_STRING: + if (opt->size > str_size) + { + str_size = (opt->size + 1024) & ~1023; + if (str) + str = realloc (str, str_size); + else + str = malloc (str_size); + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w.status = ENOMEM; + return 1; + } + } + if (sane_control_option (device, i, SANE_ACTION_GET_VALUE, str, 0) + != SANE_STATUS_GOOD) + continue; + sanei_w_string (&w, (SANE_String *) &opt->name); + sanei_w_string (&w, &str); + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + break; + } + } + sanei_w_set_dir (&w, WIRE_DECODE); + + if (word_array) + free (word_array); + if (str) + free (str); + return 0; +} diff --git a/sanei/sanei_thread.c b/sanei/sanei_thread.c new file mode 100644 index 0000000..0c95fdb --- /dev/null +++ b/sanei/sanei_thread.c @@ -0,0 +1,425 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1998-2001 Yuri Dario + Copyright (C) 2003-2004 Gerhard Jaeger (pthread/process support) + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + + OS/2 + Helper functions for the OS/2 port (using threads instead of forked + processes). Don't use them in the backends, they are used automatically by + macros. + + Other OS: + use this lib, if you intend to let run your reader function within its own + task (thread or process). Depending on the OS and/or the configure settings + pthread or fork is used to achieve this goal. +*/ + +#include "sane/config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_OS2_H +# define INCL_DOSPROCESS +# include <os2.h> +#endif +#if !defined USE_PTHREAD && !defined HAVE_OS2_H +# include <sys/wait.h> +#endif +#if defined USE_PTHREAD +# include <pthread.h> +#endif + +#define BACKEND_NAME sanei_thread /**< name of this module for debugging */ + +#include <sane/sane.h> +#include "../include/sane/sanei_debug.h" +#include "../include/sane/sanei_thread.h" + +#ifndef _VAR_NOT_USED +# define _VAR_NOT_USED(x) ((x)=(x)) +#endif + +typedef struct { + + int (*func)( void* ); + SANE_Status status; + void *func_data; + +} ThreadDataDef, *pThreadDataDef; + +static ThreadDataDef td; + +/** for init issues - here only for the debug output + */ +void +sanei_thread_init( void ) +{ + DBG_INIT(); + + memset( &td, 0, sizeof(ThreadDataDef)); + td.status = SANE_STATUS_GOOD; +} + +SANE_Bool +sanei_thread_is_forked( void ) +{ +#if defined USE_PTHREAD || defined HAVE_OS2_H + return SANE_FALSE; +#else + return SANE_TRUE; +#endif +} + +int +sanei_thread_kill( int pid ) +{ + DBG(2, "sanei_thread_kill() will kill %d\n", (int)pid); +#ifdef USE_PTHREAD +#if defined (__APPLE__) && defined (__MACH__) + return pthread_kill((pthread_t)pid, SIGUSR2); +#else + return pthread_cancel((pthread_t)pid); +#endif +#elif defined HAVE_OS2_H + return DosKillThread(pid); +#else + return kill( pid, SIGTERM ); +#endif +} + +#ifdef HAVE_OS2_H + +static void +local_thread( void *arg ) +{ + pThreadDataDef ltd = (pThreadDataDef)arg; + + DBG( 2, "thread started, calling func() now...\n" ); + ltd->status = ltd->func( ltd->func_data ); + + DBG( 2, "func() done - status = %d\n", ltd->status ); + _endthread(); +} + +/* + * starts a new thread or process + * parameters: + * star address of reader function + * args pointer to scanner data structure + * + */ +int +sanei_thread_begin( int (*func)(void *args), void* args ) +{ + int pid; + + td.func = func; + td.func_data = args; + + pid = _beginthread( local_thread, NULL, 1024*1024, (void*)&td ); + if ( pid == -1 ) { + DBG( 1, "_beginthread() failed\n" ); + return -1; + } + + DBG( 2, "_beginthread() created thread %d\n", pid ); + return pid; +} + +int +sanei_thread_waitpid( int pid, int *status ) +{ + if (status) + *status = 0; + return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/ +} + +int +sanei_thread_sendsig( int pid, int sig ) +{ + return 0; +} + +#else /* HAVE_OS2_H */ + +#ifdef USE_PTHREAD + +/* seems to be undefined in MacOS X */ +#ifndef PTHREAD_CANCELED +# define PTHREAD_CANCELED ((void *) -1) +#endif + +/** + */ +#if defined (__APPLE__) && defined (__MACH__) +static void +thread_exit_handler( int signo ) +{ + DBG( 2, "signal(%i) caught, calling pthread_exit now...\n", signo ); + pthread_exit( PTHREAD_CANCELED ); +} +#endif + + +static void* +local_thread( void *arg ) +{ + static int status; + pThreadDataDef ltd = (pThreadDataDef)arg; + +#if defined (__APPLE__) && defined (__MACH__) + struct sigaction act; + + sigemptyset(&(act.sa_mask)); + act.sa_flags = 0; + act.sa_handler = thread_exit_handler; + sigaction( SIGUSR2, &act, 0 ); +#else + int old; + + pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &old ); + pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS, &old ); +#endif + + DBG( 2, "thread started, calling func() now...\n" ); + + status = ltd->func( ltd->func_data ); + + /* so sanei_thread_get_status() will work correctly... */ + ltd->status = status; + + DBG( 2, "func() done - status = %d\n", status ); + + /* return the status, so pthread_join is able to get it*/ + pthread_exit((void*)&status ); +} + +/** + */ +static void +restore_sigpipe( void ) +{ + struct sigaction act; + + if( sigaction( SIGPIPE, NULL, &act ) == 0 ) { + + if( act.sa_handler == SIG_IGN ) { + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + act.sa_handler = SIG_DFL; + + DBG( 2, "restoring SIGPIPE to SIG_DFL\n" ); + sigaction( SIGPIPE, &act, NULL ); + } + } +} + +#else /* the process stuff */ + +static int +eval_wp_result( int pid, int wpres, int pf ) +{ + int retval = SANE_STATUS_IO_ERROR; + + if( wpres == pid ) { + + if( WIFEXITED(pf)) { + retval = WEXITSTATUS(pf); + } else { + + if( !WIFSIGNALED(pf)) { + retval = SANE_STATUS_GOOD; + } else { + DBG( 1, "Child terminated by signal %d\n", WTERMSIG(pf)); + if( WTERMSIG(pf) == SIGTERM ) + retval = SANE_STATUS_GOOD; + } + } + } + return retval; +} +#endif + +int +sanei_thread_begin( int (func)(void *args), void* args ) +{ + int pid; +#ifdef USE_PTHREAD + struct sigaction act; + pthread_t thread; + + /* if signal handler for SIGPIPE is SIG_DFL, replace by SIG_IGN */ + if( sigaction( SIGPIPE, NULL, &act ) == 0 ) { + + if( act.sa_handler == SIG_DFL ) { + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + + DBG( 2, "setting SIGPIPE to SIG_IGN\n" ); + sigaction( SIGPIPE, &act, NULL ); + } + } + + td.func = func; + td.func_data = args; + + pid = pthread_create( &thread, NULL, local_thread, &td ); + usleep( 1 ); + + if ( pid != 0 ) { + DBG( 1, "pthread_create() failed with %d\n", pid ); + return -1; + } + + DBG( 2, "pthread_create() created thread %d\n", (int)thread ); + return (int)thread; +#else + pid = fork(); + if( pid < 0 ) { + DBG( 1, "fork() failed\n" ); + return -1; + } + + if( pid == 0 ) { + + /* run in child context... */ + int status = func( args ); + + /* don't use exit() since that would run the atexit() handlers */ + _exit( status ); + } + + /* parents return */ + return pid; +#endif +} + +int +sanei_thread_sendsig( int pid, int sig ) +{ +#ifdef USE_PTHREAD + DBG(2, "sanei_thread_sendsig() %d to thread(id=%d)\n", sig, pid); + return pthread_kill((pthread_t)pid, sig ); +#else + DBG(2, "sanei_thread_sendsig() %d to process (id=%d)\n", sig, pid); + return kill( pid, sig ); +#endif +} + +int +sanei_thread_waitpid( int pid, int *status ) +{ +#ifdef USE_PTHREAD + int *ls; +#else + int ls; +#endif + int result, stat; + + stat = 0; + + DBG(2, "sanei_thread_waitpid() - %d\n", pid); +#ifdef USE_PTHREAD + result = pthread_join((pthread_t)pid, (void*)&ls ); + + if( 0 == result ) { + if( PTHREAD_CANCELED == ls ) { + DBG(2, "* thread has been canceled!\n" ); + stat = SANE_STATUS_GOOD; + } else { + stat = *ls; + } + DBG(2, "* result = %d (%p)\n", stat, (void*)status ); + result = pid; + } + /* call detach in any case to make sure that the thread resources + * will be freed, when the thread has terminated + */ + DBG(2, "* detaching thread(%d)\n", pid ); + pthread_detach((pthread_t)pid); + if (status) + *status = stat; + + restore_sigpipe(); +#else + result = waitpid( pid, &ls, 0 ); + if((result < 0) && (errno == ECHILD)) { + stat = SANE_STATUS_GOOD; + result = pid; + } else { + stat = eval_wp_result( pid, result, ls ); + DBG(2, "* result = %d (%p)\n", stat, (void*)status ); + } + if( status ) + *status = stat; +#endif + return result; +} + +#endif /* HAVE_OS2_H */ + +SANE_Status +sanei_thread_get_status( int pid ) +{ +#if defined USE_PTHREAD || defined HAVE_OS2_H + _VAR_NOT_USED( pid ); + + return td.status; +#else + int ls, stat, result; + + stat = SANE_STATUS_IO_ERROR; + if( pid > 0 ) { + + result = waitpid( pid, &ls, WNOHANG ); + + stat = eval_wp_result( pid, result, ls ); + } + return stat; +#endif +} + +/* END sanei_thread.c .......................................................*/ diff --git a/sanei/sanei_wire.c b/sanei/sanei_wire.c new file mode 100644 index 0000000..7f56639 --- /dev/null +++ b/sanei/sanei_wire.c @@ -0,0 +1,694 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> + +#include <sane/sane.h> +#include "../include/sane/sanei_wire.h" + +#define BACKEND_NAME sanei_wire +#include "../include/sane/sanei_debug.h" + +void +sanei_w_space (Wire * w, size_t howmuch) +{ + size_t nbytes, left_over; + int fd = w->io.fd; + ssize_t nread, nwritten; + + DBG (3, "sanei_w_space: %lu bytes for wire %d\n", (u_long) howmuch, fd); + + if (howmuch > w->buffer.size) + DBG (2, "sanei_w_space: bigger than buffer (%lu bytes), " + "may be flush()\n", (u_long) w->buffer.size); + + if (w->status != 0) + { + DBG (1, "sanei_w_space: wire is in invalid state %d\n", + w->status); + return; + } + + if (w->buffer.curr + howmuch > w->buffer.end) + { + DBG (4, "sanei_w_space: free buffer size is %lu\n", + (u_long) (w->buffer.end - w->buffer.curr)); + switch (w->direction) + { + case WIRE_ENCODE: + nbytes = w->buffer.curr - w->buffer.start; + w->buffer.curr = w->buffer.start; + DBG (4, "sanei_w_space: ENCODE: sending %lu bytes\n", + (u_long) nbytes); + while (nbytes > 0) + { + nwritten = (*w->io.write) (fd, w->buffer.curr, nbytes); + if (nwritten < 0) + { + DBG (1, "sanei_w_space: ENCODE: write failed (%d)\n", errno); + w->status = errno; + return; + } + w->buffer.curr += nwritten; + nbytes -= nwritten; + } + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + w->buffer.size; + DBG (4, "sanei_w_space: ENCODE: free buffer is now %lu\n", + (u_long) w->buffer.size); + break; + + case WIRE_DECODE: + left_over = w->buffer.end - w->buffer.curr; + + if ((signed) left_over < 0) + { + DBG (1, "sanei_w_space: DECODE: buffer underflow\n"); + return; + } + + if (left_over) + { + DBG (4, "sanei_w_space: DECODE: %lu bytes left in buffer\n", + (u_long) left_over); + memmove (w->buffer.start, w->buffer.curr, left_over); + } + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + left_over; + + DBG (4, "sanei_w_space: DECODE: receiving data\n"); + do + { + nread = (*w->io.read) (fd, w->buffer.end, + w->buffer.size - left_over); + if (nread <= 0) + { + DBG (2, "sanei_w_space: DECODE: no data received (%d)\n", + errno); + if (nread == 0) + errno = EINVAL; + w->status = errno; + return; + } + left_over += nread; + w->buffer.end += nread; + } + while (left_over < howmuch); + DBG (4, "sanei_w_space: DECODE: %lu bytes read\n", + (u_long) (w->buffer.end - w->buffer.start)); + break; + + case WIRE_FREE: + DBG (4, "sanei_w_space: FREE: doing nothing for free operation\n"); + break; + } + } + DBG (4, "sanei_w_space: done\n"); +} + +void +sanei_w_void (Wire * w) +{ + DBG (3, "sanei_w_void: wire %d (void debug output)\n", w->io.fd); +} + +void +sanei_w_array (Wire * w, SANE_Word * len_ptr, void **v, + WireCodecFunc w_element, size_t element_size) +{ + SANE_Word len; + char *val; + int i; + + DBG (3, "sanei_w_array: wire %d, elements of size %lu\n", w->io.fd, + (u_long) element_size); + + if (w->direction == WIRE_FREE) + { + if (*len_ptr && *v) + { + DBG (4, "sanei_w_array: FREE: freeing array (%d elements)\n", + *len_ptr); + val = *v; + for (i = 0; i < *len_ptr; ++i) + { + (*w_element) (w, val); + val += element_size; + } + free (*v); + w->allocated_memory -= (*len_ptr * element_size); + } + else + DBG (1, "sanei_w_array: FREE: tried to free array but *len_ptr or *v " + "was NULL\n"); + + DBG (4, "sanei_w_array: FREE: done\n"); + return; + } + + if (w->direction == WIRE_ENCODE) + len = *len_ptr; + DBG (4, "sanei_w_array: send/receive array length\n"); + sanei_w_word (w, &len); + + if (w->status) + { + DBG (1, "sanei_w_array: bad status: %d\n", w->status); + return; + } + DBG (4, "sanei_w_array: array has %d elements\n", len); + + if (w->direction == WIRE_DECODE) + { + *len_ptr = len; + if (len) + { + if (((unsigned int) len) > MAX_MEM + || ((unsigned int) len * element_size) > MAX_MEM + || (w->allocated_memory + len * element_size) > MAX_MEM) + { + DBG (0, "sanei_w_array: DECODE: maximum amount of allocated memory " + "exceeded (limit: %u, new allocation: %u, total: %u bytes)\n", + MAX_MEM, len * element_size, MAX_MEM + len * element_size); + w->status = ENOMEM; + return; + } + *v = malloc (len * element_size); + if (*v == 0) + { + /* Malloc failed, so return an error. */ + DBG (1, "sanei_w_array: DECODE: not enough free memory\n"); + w->status = ENOMEM; + return; + } + memset (*v, 0, len * element_size); + w->allocated_memory += (len * element_size); + } + else + *v = 0; + } + + val = *v; + DBG (4, "sanei_w_array: transferring array elements\n"); + for (i = 0; i < len; ++i) + { + (*w_element) (w, val); + val += element_size; + if (w->status) + { + DBG (1, "sanei_w_array: bad status: %d\n", w->status); + return; + } + } + DBG (4, "sanei_w_array: done\n"); +} + +void +sanei_w_ptr (Wire * w, void **v, WireCodecFunc w_value, size_t value_size) +{ + SANE_Word is_null; + + DBG (3, "sanei_w_ptr: wire %d, value pointer at is %lu bytes\n", w->io.fd, + (u_long) value_size); + + if (w->direction == WIRE_FREE) + { + if (*v && value_size) + { + DBG (4, "sanei_w_ptr: FREE: freeing value\n"); + (*w_value) (w, *v); + free (*v); + w->allocated_memory -= value_size; + } + else + DBG (1, "sanei_w_ptr: FREE: tried to free value but *v or value_size " + "was NULL\n"); + + DBG (4, "sanei_w_ptr: FREE: done\n"); + return; + } + if (w->direction == WIRE_ENCODE) + is_null = (*v == 0); + + DBG (4, "sanei_w_ptr: send/receive is_null\n"); + sanei_w_word (w, &is_null); + if (w->status) + { + DBG (1, "sanei_w_ptr: bad status: %d\n", w->status); + return; + } + + if (!is_null) + { + if (w->direction == WIRE_DECODE) + { + DBG (4, "sanei_w_ptr: DECODE: receive data pointed at\n"); + if (value_size > MAX_MEM) + { + DBG (0, "sanei_w_ptr: DECODE: maximum amount of allocated memory " + "exceeded (limit: %u, new allocation: %u, total: %u bytes)\n", + MAX_MEM, value_size, (w->allocated_memory + value_size)); + w->status = ENOMEM; + return; + } + + *v = malloc (value_size); + if (*v == 0) + { + /* Malloc failed, so return an error. */ + DBG (1, "sanei_w_ptr: DECODE: not enough free memory\n"); + w->status = ENOMEM; + return; + } + w->allocated_memory += value_size; + memset (*v, 0, value_size); + } + (*w_value) (w, *v); + } + else if (w->direction == WIRE_DECODE) + *v = 0; + + DBG (4, "sanei_w_ptr: done\n"); +} + +void +sanei_w_byte (Wire * w, SANE_Byte * v) +{ + DBG (3, "sanei_w_byte: wire %d\n", w->io.fd); + (*w->codec.w_byte) (w, v); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_byte: value = %d\n", *v); +} + +void +sanei_w_char (Wire * w, SANE_Char * v) +{ + DBG (3, "sanei_w_char: wire %d\n", w->io.fd); + (*w->codec.w_char) (w, v); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_char: value = %d\n", *v); +} + +void +sanei_w_word (Wire * w, SANE_Word * v) +{ + DBG (3, "sanei_w_word: wire %d\n", w->io.fd); + (*w->codec.w_word) (w, v); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_word: value = %d\n", *v); +} + +void +sanei_w_string (Wire * w, SANE_String * v) +{ + DBG (3, "sanei_w_string: wire %d\n", w->io.fd); + (*w->codec.w_string) (w, v); + if (w->direction != WIRE_FREE && w->status == 0) + DBG (4, "sanei_w_string: value = %s\n", *v); +} + +void +sanei_w_status (Wire * w, SANE_Status * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_status: wire %d\n", w->io.fd); + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_status: value = %d\n", word); +} + +void +sanei_w_bool (Wire * w, SANE_Bool * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_bool: wire %d\n", w->io.fd); + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_bool: value = %s\n", + ((word == SANE_TRUE) ? ("true") : ("false"))); +} + +void +sanei_w_constraint_type (Wire * w, SANE_Constraint_Type * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_constraint_type: wire %d\n", w->io.fd); + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_constraint_type: value = %d\n", word); +} + +void +sanei_w_value_type (Wire * w, SANE_Value_Type * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_value_type: wire %d\n", w->io.fd); + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_value_type: value = %d\n", word); +} + +void +sanei_w_unit (Wire * w, SANE_Unit * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_unit: wire %d\n", w->io.fd); + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_unit: value = %d\n", word); + /* gosh... all the sane_w_something should be a macro or something */ +} + +void +sanei_w_action (Wire * w, SANE_Action * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_action: wire %d\n", w->io.fd); + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_action: value = %d\n", word); +} + +void +sanei_w_frame (Wire * w, SANE_Frame * v) +{ + SANE_Word word = *v; + + DBG (3, "sanei_w_frame: wire %d\n", w->io.fd); + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_frame: value = %d\n", word); +} + +void +sanei_w_range (Wire * w, SANE_Range * v) +{ + DBG (3, "sanei_w_range: wire %d\n", w->io.fd); + sanei_w_word (w, &v->min); + sanei_w_word (w, &v->max); + sanei_w_word (w, &v->quant); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_range: min/max/step = %f/%f/%f\n", + SANE_UNFIX (v->min), SANE_UNFIX (v->max), SANE_UNFIX (v->quant)); +} + +void +sanei_w_device (Wire * w, SANE_Device * v) +{ + DBG (3, "sanei_w_device: wire %d\n", w->io.fd); + sanei_w_string (w, (SANE_String *) & v->name); + sanei_w_string (w, (SANE_String *) & v->vendor); + sanei_w_string (w, (SANE_String *) & v->model); + sanei_w_string (w, (SANE_String *) & v->type); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_device: %s %s from %s (%s)\n", v->name, v->model, + v->vendor, v->type); +} + +void +sanei_w_device_ptr (Wire * w, SANE_Device ** v) +{ + DBG (3, "sanei_w_device_ptr: wire %d\n", w->io.fd); + sanei_w_ptr (w, (void **) v, (WireCodecFunc) sanei_w_device, sizeof (**v)); + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_device_ptr: device struct at %p\n", *v); +} + +void +sanei_w_option_descriptor (Wire * w, SANE_Option_Descriptor * v) +{ + SANE_Word len; + + DBG (3, "sanei_w_option_descriptor: wire %d\n", w->io.fd); + + sanei_w_string (w, (SANE_String *) & v->name); + sanei_w_string (w, (SANE_String *) & v->title); + sanei_w_string (w, (SANE_String *) & v->desc); + sanei_w_value_type (w, &v->type); + sanei_w_unit (w, &v->unit); + sanei_w_word (w, &v->size); + sanei_w_word (w, &v->cap); + sanei_w_constraint_type (w, &v->constraint_type); + + if (w->direction != WIRE_FREE) + DBG (4, "sanei_w_option_descriptor: option %s\n", v->name); + + switch (v->constraint_type) + { + case SANE_CONSTRAINT_NONE: + break; + + case SANE_CONSTRAINT_RANGE: + sanei_w_ptr (w, (void **) &v->constraint.range, + (WireCodecFunc) sanei_w_range, sizeof (SANE_Range)); + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (w->direction != WIRE_DECODE) + len = v->constraint.word_list[0] + 1; + sanei_w_array (w, &len, (void **) &v->constraint.word_list, + w->codec.w_word, sizeof (SANE_Word)); + break; + + case SANE_CONSTRAINT_STRING_LIST: + if (w->direction != WIRE_DECODE) + { + for (len = 0; v->constraint.string_list[len]; ++len); + ++len; /* send NULL string, too */ + } + sanei_w_array (w, &len, (void **) &v->constraint.string_list, + w->codec.w_string, sizeof (SANE_String)); + break; + } + DBG (4, "sanei_w_option_descriptor: done\n"); +} + +void +sanei_w_option_descriptor_ptr (Wire * w, SANE_Option_Descriptor ** v) +{ + DBG (3, "sanei_w_option_descriptor_ptr: wire %d\n", w->io.fd); + sanei_w_ptr (w, (void **) v, + (WireCodecFunc) sanei_w_option_descriptor, sizeof (**v)); + DBG (4, "sanei_w_option_descriptor_ptr: done\n"); +} + +void +sanei_w_parameters (Wire * w, SANE_Parameters * v) +{ + DBG (3, "sanei_w_parameters: wire %d\n", w->io.fd); + sanei_w_frame (w, &v->format); + sanei_w_bool (w, &v->last_frame); + sanei_w_word (w, &v->bytes_per_line); + sanei_w_word (w, &v->pixels_per_line); + sanei_w_word (w, &v->lines); + sanei_w_word (w, &v->depth); + if (w->direction != WIRE_FREE) + DBG (4, + "sanei_w_parameters: format/last/bpl/ppl/lines/depth = " + "%d/%d/%d/%d/%d/%d\n", v->format, v->last_frame, v->bytes_per_line, + v->pixels_per_line, v->lines, v->depth); +} + +static void +flush (Wire * w) +{ + DBG (3, "flush: wire %d\n", w->io.fd); + if (w->direction == WIRE_ENCODE) + sanei_w_space (w, w->buffer.size + 1); + else if (w->direction == WIRE_DECODE) + w->buffer.curr = w->buffer.end = w->buffer.start; + if (w->status != 0) + DBG (2, "flush: error status %d\n", w->status); + DBG (4, "flush: wire flushed\n"); +} + +void +sanei_w_set_dir (Wire * w, WireDirection dir) +{ + DBG (3, "sanei_w_set_dir: wire %d, old direction WIRE_%s\n", w->io.fd, + w->direction == WIRE_ENCODE ? "ENCODE" : + (w->direction == WIRE_DECODE ? "DECODE" : "FREE")); + if (w->direction == WIRE_DECODE && w->buffer.curr != w->buffer.end) + DBG (1, "sanei_w_set_dir: WARNING: will delete %lu bytes from buffer\n", + (u_long) (w->buffer.end - w->buffer.curr)); + flush (w); + w->direction = dir; + DBG (4, "sanei_w_set_dir: direction changed\n"); + flush (w); + DBG (3, "sanei_w_set_dir: wire %d, new direction WIRE_%s\n", w->io.fd, + dir == WIRE_ENCODE ? "ENCODE" : + (dir == WIRE_DECODE ? "DECODE" : "FREE")); +} + +void +sanei_w_call (Wire * w, + SANE_Word procnum, + WireCodecFunc w_arg, void *arg, + WireCodecFunc w_reply, void *reply) +{ + + DBG (3, "sanei_w_call: wire %d (old status %d)\n", w->io.fd, w->status); + w->status = 0; + sanei_w_set_dir (w, WIRE_ENCODE); + + DBG (4, "sanei_w_call: sending request (procedure number: %d)\n", procnum); + sanei_w_word (w, &procnum); + (*w_arg) (w, arg); + + if (w->status == 0) + { + DBG (4, "sanei_w_call: receiving reply\n"); + sanei_w_set_dir (w, WIRE_DECODE); + (*w_reply) (w, reply); + } + + if (w->status != 0) + DBG (2, "sanei_w_call: error status %d\n", w->status); + DBG (4, "sanei_w_call: done\n"); +} + +void +sanei_w_reply (Wire * w, WireCodecFunc w_reply, void *reply) +{ + DBG (3, "sanei_w_reply: wire %d (old status %d)\n", w->io.fd, w->status); + w->status = 0; + sanei_w_set_dir (w, WIRE_ENCODE); + (*w_reply) (w, reply); + flush (w); + if (w->status != 0) + DBG (2, "sanei_w_reply: error status %d\n", w->status); + DBG (4, "sanei_w_reply: done\n"); +} + +void +sanei_w_free (Wire * w, WireCodecFunc w_reply, void *reply) +{ + WireDirection saved_dir = w->direction; + + DBG (3, "sanei_w_free: wire %d\n", w->io.fd); + + w->direction = WIRE_FREE; + (*w_reply) (w, reply); + w->direction = saved_dir; + + if (w->status != 0) + DBG (2, "sanei_w_free: error status %d\n", w->status); + DBG (4, "sanei_w_free: done\n"); +} + +void +sanei_w_init (Wire * w, void (*codec_init_func) (Wire *)) +{ + DBG_INIT (); + + DBG (3, "sanei_w_init: initializing\n"); + w->status = 0; + w->direction = WIRE_ENCODE; + w->buffer.size = 8192; + w->buffer.start = malloc (w->buffer.size); + + if (w->buffer.start == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + DBG (1, "sanei_w_init: not enough free memory\n"); + } + + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + w->buffer.size; + if (codec_init_func != 0) + { + DBG (4, "sanei_w_init: initializing codec\n"); + (*codec_init_func) (w); + } + w->allocated_memory = 0; + DBG (4, "sanei_w_init: done\n"); +} + +void +sanei_w_exit (Wire * w) +{ + DBG (3, "sanei_w_exit: wire %d\n", w->io.fd); + if (w->buffer.start) + { + DBG (4, "sanei_w_exit: freeing buffer\n"); + free (w->buffer.start); + } + w->buffer.start = 0; + w->buffer.size = 0; + DBG (4, "sanei_w_exit: done\n"); +} |