kopia lustrzana https://gitlab.com/sane-project/backends
- add support for SANE_Bool in sanei_check_value
- add sanei_constrain_value.lo to libsane dependencies - add makedepend for .lo files in sanei - add configuration parsing frameworkmerge-requests/1/head
rodzic
7b73560b15
commit
c74a1be430
|
@ -1,3 +1,12 @@
|
|||
2008-07-10 Stéphane Voltz <stef.dev@free.fr>
|
||||
* backend/sanei_constrain_value.c: add support for SANE_Bool
|
||||
in sanei_check_value
|
||||
* backend/Makefile.in: add sanei_constrain_value.lo to libsane
|
||||
dependencies
|
||||
* sanei/Makefile.in: add makedepend for .lo files
|
||||
* include/sane/sanei_config.h sanei/sanei_config.c: add configuration
|
||||
parsing framework
|
||||
|
||||
2008-07-05 m. allan noah <kitno455 a t gmail d o t com>
|
||||
* backend/fujitsu.[ch]: backend v70,
|
||||
- fix bug in sane_get_parameters (failed to copy values)
|
||||
|
|
|
@ -76,7 +76,7 @@ ALL_BACKENDS = $(PRELOADABLE_BACKENDS) dll
|
|||
LIBS = $(addprefix libsane-,$(addsuffix .la,$(ALL_BACKENDS)))
|
||||
CONFIGS = $(addsuffix .conf,$(ALL_BACKENDS)) saned.conf
|
||||
|
||||
EXTRA = sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_config.lo
|
||||
EXTRA = sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo
|
||||
|
||||
# With libtool-1.0, we have to mention each library object explicitly... ;-(
|
||||
ifneq (@LIBOBJS@ @ALLOCA@,)
|
||||
|
|
|
@ -37,40 +37,129 @@
|
|||
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 provides generic configuration support. */
|
||||
/** @file sanei_config.h
|
||||
* Generic configuration support.
|
||||
*
|
||||
* Use the functions of this header file if you want to read and analyze
|
||||
* configuration files.
|
||||
*/
|
||||
|
||||
#ifndef sanei_config_h
|
||||
#define sanei_config_h 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sane/sane.h>
|
||||
|
||||
/** Search configuration file \a name along directory list and return file
|
||||
* pointer if such a file exists.
|
||||
*
|
||||
* The following directory list is used:
|
||||
* 1st: SANE_CONFIG_DIR environment variable.
|
||||
* 2nd: PATH_SANE_CONFIG_DIR set during configuration.
|
||||
* 3rd: Current directory.
|
||||
* @param name filename with extension but without path (such as "mustek.conf")
|
||||
*
|
||||
* @return file pointer, or NULL if not found
|
||||
*
|
||||
*/
|
||||
extern FILE *sanei_config_open (const char *name);
|
||||
|
||||
/** Read a line from configuration file.
|
||||
*
|
||||
* Strips all unwanted chars. Use this instead of fgets() to remove
|
||||
* line ending chars on all known platforms.
|
||||
*
|
||||
* @param str points to the buffer for the line
|
||||
* @param n size of the buffer
|
||||
* @param stream file pointer
|
||||
*
|
||||
* @return \a str on success and NULL on error
|
||||
*/
|
||||
extern char *sanei_config_read (char *str, int n, FILE *stream);
|
||||
|
||||
/** Remove all whitespace from the beginning of a string.
|
||||
*
|
||||
* @param str string
|
||||
*
|
||||
* @return string without leading whitespace
|
||||
*
|
||||
*/
|
||||
extern const char *sanei_config_skip_whitespace (const char *str);
|
||||
/* Scan a string constant from the string pointed to by STR and return
|
||||
a malloced copy of it in *STRING_CONST (it's the responsibility of
|
||||
the caller to free the returned string at an appropriate time).
|
||||
Whitespace in front of the string constant is ignored. Whitespace
|
||||
can be included in the string constant by enclosing it in
|
||||
double-quotes. A return val of NULL indicates that no string
|
||||
constant was found. */
|
||||
|
||||
|
||||
/** Scan a string constant from a line of text and return a malloced copy
|
||||
* of it.
|
||||
*
|
||||
* It's the responsibility of the caller to free the returned string constant
|
||||
* at an appropriate time. Whitespace in front of the string constant is
|
||||
* ignored. Whitespace can be included in the string constant by enclosing it
|
||||
* in double-quotes.
|
||||
*
|
||||
* @param str line of text to scan for a string constant
|
||||
* @param string_const copy of the string constant
|
||||
*
|
||||
* @return a pointer to the position in str where the scan stopped
|
||||
*/
|
||||
extern const char *sanei_config_get_string (const char *str,
|
||||
char **string_const);
|
||||
|
||||
/* A convenience function to support expanding device name patterns
|
||||
into a list of devices. Apart from a normal device name
|
||||
(such as /dev/sdb), this function currently supports SCSI
|
||||
device specifications of the form:
|
||||
|
||||
scsi VENDOR MODEL TYPE BUS CHANNEL ID LUN
|
||||
|
||||
Where VENDOR is the desired vendor name. MODEL is the desired
|
||||
MODEL name. TYPE is the desired device type. All of these can be
|
||||
set to * to match anything. To include whitespace in these
|
||||
strings, enclose them in double-quotes ("). BUS, ID, and LUN are
|
||||
the desired SCSI bus, id, and logical-unit numbers. These can be
|
||||
set to * or simply omitted to match anything. */
|
||||
/** Expand device name patterns into a list of devices.
|
||||
*
|
||||
* Apart from a normal device name (such as /dev/sdb), this function currently
|
||||
* supports SCSI device specifications of the form:
|
||||
*
|
||||
* scsi VENDOR MODEL TYPE BUS CHANNEL ID LUN
|
||||
*
|
||||
* Where VENDOR is the desired vendor name. MODEL is the desired model name.
|
||||
* TYPE is the desired device type. All of these can be set to * to match
|
||||
* anything. To include whitespace in these strings, enclose them in
|
||||
* double-quotes ("). BUS, ID, and LUN are the desired SCSI bus, id, and
|
||||
* logical-unit numbers. These can be set to * or simply omitted to match
|
||||
* anything.
|
||||
*
|
||||
* @param name device name pattern
|
||||
* @param attach attach function
|
||||
*/
|
||||
extern void sanei_config_attach_matching_devices (const char *name,
|
||||
SANE_Status (*attach)
|
||||
(const char *dev));
|
||||
(const char *dev));
|
||||
|
||||
/** this structure holds the description of configuration options. There is
|
||||
* a list for options and another for their values.
|
||||
* These lists are used when the configuration file is
|
||||
* parsed. Read values are stored in Option_Value. Helpers functions are
|
||||
* provided to access values easily */
|
||||
typedef struct
|
||||
{
|
||||
/** number of options */
|
||||
SANE_Int count;
|
||||
|
||||
/** NULL terminated list of configuration option */
|
||||
SANE_Option_Descriptor **descriptors;
|
||||
|
||||
/** values for the configuration options */
|
||||
void **values;
|
||||
|
||||
} SANEI_Config;
|
||||
|
||||
/** attach with configuration callback function type. */
|
||||
typedef SANE_Status (*config_attach)(SANEI_Config *config, const char *devname);
|
||||
|
||||
/** Parse configuration file, reading configuration options and trying to
|
||||
* attach devices found in file.
|
||||
*
|
||||
* The option are gathered in a single configuration structure. Each time
|
||||
* a line holds a value that is not an option, the attach function is called
|
||||
* with the name found and the configuration structure with it's current values.
|
||||
*
|
||||
* @param name name of the configuration file to read
|
||||
* @param attach attach function
|
||||
*
|
||||
* @return SANE_STATUS_GOOD if no errors
|
||||
* SANE_STATUS_ACCESS_DENIED if configuration file can't be opened
|
||||
*/
|
||||
extern SANE_Status sanei_configure_attach (const char *config_file,SANEI_Config *config,
|
||||
config_attach);
|
||||
#endif /* sanei_config_h */
|
||||
|
|
|
@ -104,6 +104,7 @@ test_wire.o: test_wire.c
|
|||
|
||||
depend:
|
||||
makedepend -I. -I../include *.c 2>/dev/null
|
||||
makedepend -a -o.lo $(INCLUDES) *.c 2>/dev/null
|
||||
|
||||
clean:
|
||||
rm -f *.o *.lo *.a $(OBJS) $(TESTPROGRAMS)
|
||||
|
|
|
@ -214,3 +214,219 @@ sanei_config_read (char *str, int n, FILE *stream)
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
SANE_Status
|
||||
sanei_configure_attach (const char *config_file, SANEI_Config * config,
|
||||
SANE_Status (*attach) (SANEI_Config * config,
|
||||
const char *devname))
|
||||
{
|
||||
SANE_Char line[PATH_MAX];
|
||||
SANE_Char *token, *string;
|
||||
SANE_Int len;
|
||||
const char *lp, *lp2;
|
||||
FILE *fp;
|
||||
SANE_Status status = SANE_STATUS_GOOD;
|
||||
int i, j, count;
|
||||
void *value = NULL;
|
||||
int size=0;
|
||||
SANE_Bool found;
|
||||
SANE_Word *wa;
|
||||
SANE_Bool *ba;
|
||||
|
||||
DBG (3, "sanei_configure_attach: start\n");
|
||||
|
||||
/* open configuration file */
|
||||
fp = sanei_config_open (config_file);
|
||||
if (!fp)
|
||||
{
|
||||
DBG (2, "sanei_configure_attach: couldn't access %s\n", config_file);
|
||||
DBG (3, "sanei_configure_attach: exit\n");
|
||||
return SANE_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/* loop reading the configuration file, all line beginning by "option " are
|
||||
* parsed for value to store in configuration structure, other line are
|
||||
* used are device to try to attach
|
||||
*/
|
||||
while (sanei_config_read (line, PATH_MAX, fp) && status == SANE_STATUS_GOOD)
|
||||
{
|
||||
/* skip white spaces at beginning of line */
|
||||
lp = sanei_config_skip_whitespace (line);
|
||||
|
||||
/* skip empty lines */
|
||||
if (*lp == 0)
|
||||
continue;
|
||||
|
||||
/* skip comment line */
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
len = strlen (line);
|
||||
|
||||
/* delete newline characters at end */
|
||||
if (line[len - 1] == '\n')
|
||||
line[--len] = '\0';
|
||||
|
||||
lp2 = lp;
|
||||
|
||||
/* to ensure maximum compatibility, we accept line like:
|
||||
* option "option_name" "option_value"
|
||||
* "option_name" "option_value"
|
||||
* So we parse the line 2 time to find an option */
|
||||
/* check if it is an option */
|
||||
lp = sanei_config_get_string (lp, &token);
|
||||
if (strncmp (token, "option", 6) == 0)
|
||||
{
|
||||
/* skip the "option" token */
|
||||
free (token);
|
||||
lp = sanei_config_get_string (lp, &token);
|
||||
}
|
||||
|
||||
/* search for a matching descriptor */
|
||||
i = 0;
|
||||
found = SANE_FALSE;
|
||||
while (i < config->count && !found)
|
||||
{
|
||||
if (strcmp (config->descriptors[i]->name, token) == 0)
|
||||
{
|
||||
found = SANE_TRUE;
|
||||
switch (config->descriptors[i]->type)
|
||||
{
|
||||
case SANE_TYPE_INT:
|
||||
size=config->descriptors[i]->size;
|
||||
value = malloc (size);
|
||||
wa = (SANE_Word *) value;
|
||||
count = config->descriptors[i]->size / sizeof (SANE_Word);
|
||||
for (j = 0; j < count; j++)
|
||||
{
|
||||
lp = sanei_config_get_string (lp, &string);
|
||||
if (string == NULL)
|
||||
{
|
||||
DBG (2,
|
||||
"sanei_configure_attach: couldn't find a string to parse");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
wa[j] = strtol (string, NULL, 0);
|
||||
free (string);
|
||||
}
|
||||
break;
|
||||
case SANE_TYPE_BOOL:
|
||||
size=config->descriptors[i]->size;
|
||||
value = malloc (size);
|
||||
ba = (SANE_Bool *) value;
|
||||
count = config->descriptors[i]->size / sizeof (SANE_Bool);
|
||||
for (j = 0; j < count; j++)
|
||||
{
|
||||
lp = sanei_config_get_string (lp, &string);
|
||||
if (string == NULL)
|
||||
{
|
||||
DBG (2,
|
||||
"sanei_configure_attach: couldn't find a string to parse");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
if ((strcmp (string, "1") == 0)
|
||||
|| (strcmp (string, "true") == 0))
|
||||
{
|
||||
ba[j] = SANE_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((strcmp (string, "0") == 0)
|
||||
|| (strcmp (string, "false") == 0))
|
||||
ba[j] = SANE_FALSE;
|
||||
else
|
||||
{
|
||||
DBG (2,
|
||||
"sanei_configure_attach: couldn't find a valid boolean value");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
}
|
||||
free (string);
|
||||
}
|
||||
break;
|
||||
case SANE_TYPE_FIXED:
|
||||
size=config->descriptors[i]->size;
|
||||
value = malloc (size);
|
||||
wa = (SANE_Word *) value;
|
||||
count = config->descriptors[i]->size / sizeof (SANE_Word);
|
||||
for (j = 0; j < count; j++)
|
||||
{
|
||||
lp = sanei_config_get_string (lp, &string);
|
||||
if (string == NULL)
|
||||
{
|
||||
DBG (2,
|
||||
"sanei_configure_attach: couldn't find a string to parse");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
wa[j] = SANE_FIX(strtod (string, NULL));
|
||||
free (string);
|
||||
}
|
||||
break;
|
||||
case SANE_TYPE_STRING:
|
||||
sanei_config_get_string (lp, &string);
|
||||
if (string == NULL)
|
||||
{
|
||||
DBG (2,
|
||||
"sanei_configure_attach: couldn't find a string value to parse");
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
value = string;
|
||||
size=strlen(string)+1;
|
||||
if(size>config->descriptors[i]->size)
|
||||
{
|
||||
size=config->descriptors[i]->size-1;
|
||||
string[size]=0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DBG (1,
|
||||
"sanei_configure_attach: incorrect type %d for option %s, skipping option ...\n",
|
||||
config->descriptors[i]->type,
|
||||
config->descriptors[i]->name);
|
||||
}
|
||||
|
||||
/* check decoded value */
|
||||
status = sanei_check_value (config->descriptors[i], value);
|
||||
|
||||
/* if value OK, copy it in configuration struct */
|
||||
if (status == SANE_STATUS_GOOD)
|
||||
{
|
||||
memcpy (config->values[i], value, size);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
free (value);
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (1,
|
||||
"sanei_configure_attach: failed to parse option '%s', line '%s'\n",
|
||||
token, line);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
free (token);
|
||||
|
||||
/* not detected as an option, so we call the attach function
|
||||
* with it */
|
||||
if (!found && status == SANE_STATUS_GOOD)
|
||||
{
|
||||
/* if not an option, try to attach */
|
||||
/* to avoid every backend to depend on scsi and usb functions
|
||||
* we call back the backend for attach. In turn it will call
|
||||
* sanei_usb_attach_matching_devices, sanei_config_attach_matching_devices
|
||||
* or other. This means 2 callback functions per backend using this
|
||||
* function. */
|
||||
DBG (3, "sanei_configure_attach: trying to attach with '%s'\n",
|
||||
lp2);
|
||||
attach (config, lp2);
|
||||
}
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
DBG (3, "sanei_configure_attach: exit\n");
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -55,29 +55,47 @@ sanei_check_value (const SANE_Option_Descriptor * opt, void *value)
|
|||
{
|
||||
const SANE_String_Const *string_list;
|
||||
const SANE_Word *word_list;
|
||||
int i;
|
||||
int i, count;
|
||||
const SANE_Range *range;
|
||||
SANE_Word w, v;
|
||||
SANE_Word w, v, *array;
|
||||
SANE_Bool *barray;
|
||||
size_t len;
|
||||
|
||||
switch (opt->constraint_type)
|
||||
{
|
||||
case SANE_CONSTRAINT_RANGE:
|
||||
w = *(SANE_Word *) value;
|
||||
range = opt->constraint.range;
|
||||
|
||||
if (w < range->min || w > range->max)
|
||||
return SANE_STATUS_INVAL;
|
||||
/* single values are treated as arrays of length 1 */
|
||||
array = (SANE_Word *) value;
|
||||
|
||||
w = *(SANE_Word *) value;
|
||||
|
||||
if (range->quant)
|
||||
/* compute number of elements */
|
||||
if (opt->size > 0)
|
||||
{
|
||||
v =
|
||||
(unsigned int) (w - range->min + range->quant / 2) / range->quant;
|
||||
v = v * range->quant + range->min;
|
||||
if (v != w)
|
||||
count = opt->size / sizeof (SANE_Word);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
|
||||
range = opt->constraint.range;
|
||||
/* for each element of the array, we check according to the constraint */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
/* test for min and max */
|
||||
if (array[i] < range->min || array[i] > range->max)
|
||||
return SANE_STATUS_INVAL;
|
||||
|
||||
/* check quantization */
|
||||
if (range->quant)
|
||||
{
|
||||
v =
|
||||
(unsigned int) (array[i] - range->min +
|
||||
range->quant / 2) / range->quant;
|
||||
v = v * range->quant + range->min;
|
||||
if (v != array[i])
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -99,6 +117,36 @@ sanei_check_value (const SANE_Option_Descriptor * opt, void *value)
|
|||
return SANE_STATUS_GOOD;
|
||||
return SANE_STATUS_INVAL;
|
||||
|
||||
case SANE_CONSTRAINT_NONE:
|
||||
switch (opt->type)
|
||||
{
|
||||
case SANE_TYPE_BOOL:
|
||||
/* single values are treated as arrays of length 1 */
|
||||
array = (SANE_Word *) value;
|
||||
|
||||
/* compute number of elements */
|
||||
if (opt->size > 0)
|
||||
{
|
||||
count = opt->size / sizeof (SANE_Bool);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
|
||||
barray = (SANE_Bool *) value;
|
||||
|
||||
/* test each boolean value in the array */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (barray[i] != SANE_TRUE && barray[i] != SANE_FALSE)
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -131,7 +179,7 @@ sanei_constrain_value (const SANE_Option_Descriptor * opt, void *value,
|
|||
array = (SANE_Word *) value;
|
||||
|
||||
/* compute number of elements */
|
||||
if (opt->size>0)
|
||||
if (opt->size > 0)
|
||||
{
|
||||
k = opt->size / sizeof (SANE_Word);
|
||||
}
|
||||
|
@ -140,11 +188,11 @@ sanei_constrain_value (const SANE_Option_Descriptor * opt, void *value,
|
|||
k = 1;
|
||||
}
|
||||
|
||||
range = opt->constraint.range;
|
||||
/* for each element of the array, we apply the constraint */
|
||||
for (i = 0; i < k; i++)
|
||||
{
|
||||
range = opt->constraint.range;
|
||||
|
||||
/* constrain min */
|
||||
if (array[i] < range->min)
|
||||
{
|
||||
array[i] = range->min;
|
||||
|
@ -154,6 +202,7 @@ sanei_constrain_value (const SANE_Option_Descriptor * opt, void *value,
|
|||
}
|
||||
}
|
||||
|
||||
/* constrain max */
|
||||
if (array[i] > range->max)
|
||||
{
|
||||
array[i] = range->max;
|
||||
|
@ -163,6 +212,7 @@ sanei_constrain_value (const SANE_Option_Descriptor * opt, void *value,
|
|||
}
|
||||
}
|
||||
|
||||
/* quantization */
|
||||
if (range->quant)
|
||||
{
|
||||
v =
|
||||
|
|
Ładowanie…
Reference in New Issue