summaryrefslogtreecommitdiff
path: root/sanei/sanei_load_values.c
diff options
context:
space:
mode:
Diffstat (limited to 'sanei/sanei_load_values.c')
-rw-r--r--sanei/sanei_load_values.c207
1 files changed, 207 insertions, 0 deletions
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;
+}