diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-12-02 20:17:04 +0100 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-12-02 20:17:04 +0100 | 
| commit | 7d8191b83e163d76bb05e13b373638e4eeb7da95 (patch) | |
| tree | fe29c36a3cb4ef2267b2253da4dde8ce360b3cb5 /sanei | |
Initial import of sane-frontends version 1.0.14-9
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"); +}  | 
