- 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 framework
merge-requests/1/head
Stéphane Voltz 2008-07-10 05:40:25 +00:00
rodzic 7b73560b15
commit c74a1be430
6 zmienionych plików z 404 dodań i 39 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -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@,)

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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)

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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 =