kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			199 wiersze
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			199 wiersze
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
| /* 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 _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 "sane/sanei_wire.h"
 | |
| #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;
 | |
|   w.io.read = read;
 | |
|   w.io.write = write;
 | |
|   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;
 | |
| }
 |