mirror of
https://github.com/openharmony/third_party_sane-airscan.git
synced 2026-06-30 21:17:55 -04:00
Refactoring: code split to many modules
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
SRC = airscan.c airscan-array.c airscan-xml.c sane_strstatus.c
|
||||
|
||||
CFLAGS = -O2 -g -W -Wall -fPIC
|
||||
CFLAGS += `pkg-config --cflags --libs avahi-client`
|
||||
CFLAGS += `pkg-config --cflags --libs avahi-glib`
|
||||
CFLAGS += `pkg-config --cflags --libs libjpeg`
|
||||
CFLAGS += `pkg-config --cflags --libs libsoup-2.4`
|
||||
CFLAGS += `pkg-config --cflags --libs libxml-2.0`
|
||||
CFLAGS += -Wl,--version-script=airscan.sym
|
||||
|
||||
# This magic is a workaround for libsoup bug.
|
||||
#
|
||||
@@ -22,9 +25,9 @@ CFLAGS += -Wl,-z,nodelete
|
||||
|
||||
all: libsane-airscan.so test
|
||||
|
||||
libsane-airscan.so: Makefile airscan.c
|
||||
libsane-airscan.so: Makefile $(SRC) airscan.h airscan.sym
|
||||
@ctags -R .
|
||||
gcc -o libsane-airscan.so -shared ${CFLAGS} airscan.c
|
||||
gcc -o libsane-airscan.so -shared ${CFLAGS} $(SRC)
|
||||
|
||||
test: libsane-airscan.so test.c
|
||||
#gcc -o test test.c -l sane
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/* AirScan (a.k.a. eSCL) backend for SANE
|
||||
*
|
||||
* Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
|
||||
* See LICENSE for license terms and conditions
|
||||
*/
|
||||
|
||||
#include "airscan.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/******************** Typed Arrays ********************/
|
||||
/* Initial capacity of arrays
|
||||
*/
|
||||
#define ARRAY_INITIAL_CAPACITY 4
|
||||
|
||||
/* Initialize array of SANE_Word
|
||||
*/
|
||||
void
|
||||
array_of_word_init (SANE_Word **a)
|
||||
{
|
||||
*a = g_new0(SANE_Word, ARRAY_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
/* Cleanup array of SANE_Word
|
||||
*/
|
||||
void
|
||||
array_of_word_cleanup (SANE_Word **a)
|
||||
{
|
||||
g_free(*a);
|
||||
*a = NULL;
|
||||
}
|
||||
|
||||
/* Get length of the SANE_Word array
|
||||
*/
|
||||
size_t
|
||||
array_of_word_len (SANE_Word **a)
|
||||
{
|
||||
return (size_t) (*a)[0];
|
||||
}
|
||||
|
||||
/* Append word to array
|
||||
*/
|
||||
void
|
||||
array_of_word_append(SANE_Word **a, SANE_Word w)
|
||||
{
|
||||
size_t sz = array_of_word_len(a) + 1;
|
||||
|
||||
/* If sz reached the power-of-2, reallocate the array, doubling its size */
|
||||
if (sz >= ARRAY_INITIAL_CAPACITY && (sz & (sz - 1)) == 0) {
|
||||
*a = g_renew(SANE_Word, (*a), sz + sz);
|
||||
}
|
||||
|
||||
(*a)[sz] = w;
|
||||
(*a)[0] ++;
|
||||
}
|
||||
|
||||
/* Compare function for array_of_word_sort
|
||||
*/
|
||||
int
|
||||
array_of_word_sort_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
return *(SANE_Word*) p1 - *(SANE_Word*) p2;
|
||||
}
|
||||
|
||||
/* Sort array of SANE_Word in increasing order
|
||||
*/
|
||||
void
|
||||
array_of_word_sort(SANE_Word **a)
|
||||
{
|
||||
SANE_Word len = (*a)[0];
|
||||
|
||||
if (len) {
|
||||
qsort((*a) + 1, len, sizeof(SANE_Word), array_of_word_sort_cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize array of SANE_String
|
||||
*/
|
||||
void
|
||||
array_of_string_init (SANE_String **a)
|
||||
{
|
||||
*a = g_new0(SANE_String, ARRAY_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
/* Cleanup array of SANE_String
|
||||
*/
|
||||
void
|
||||
array_of_string_cleanup (SANE_String **a)
|
||||
{
|
||||
g_free(*a);
|
||||
*a = NULL;
|
||||
}
|
||||
|
||||
/* Get length of the SANE_Word array
|
||||
*/
|
||||
size_t
|
||||
array_of_string_len (SANE_String **a)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
for (sz = 0; (*a)[sz]; sz ++)
|
||||
;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* Append string to array
|
||||
*/
|
||||
void
|
||||
array_of_string_append(SANE_String **a, SANE_String s)
|
||||
{
|
||||
size_t sz = array_of_string_len(a) + 1;
|
||||
|
||||
/* If sz reached the power-of-2, reallocate the array, doubling its size */
|
||||
if (sz >= ARRAY_INITIAL_CAPACITY && (sz & (sz - 1)) == 0) {
|
||||
*a = g_renew(SANE_String, (*a), sz + sz);
|
||||
}
|
||||
|
||||
/* Append string */
|
||||
(*a)[sz - 1] = s;
|
||||
(*a)[sz] = NULL;
|
||||
}
|
||||
|
||||
/* vim:ts=8:sw=4:et
|
||||
*/
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/* AirScan (a.k.a. eSCL) backend for SANE
|
||||
*
|
||||
* Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
|
||||
* See LICENSE for license terms and conditions
|
||||
*/
|
||||
|
||||
#include "airscan.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/******************** XML utilities ********************/
|
||||
/* Static initializer for the XML iterator
|
||||
*/
|
||||
#define XML_ITER_INIT {NULL, NULL, NULL, NULL, NULL}
|
||||
|
||||
/* Skip dummy nodes. This is internal function, don't call directly
|
||||
*/
|
||||
static void
|
||||
__xml_iter_skip_dummy (xml_iter *iter)
|
||||
{
|
||||
xmlNode *node = iter->node;
|
||||
|
||||
while (node != NULL &&
|
||||
(node->type == XML_COMMENT_NODE || xmlIsBlankNode (node))) {
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
iter->node = node;
|
||||
}
|
||||
|
||||
/* Invalidate cached data. This is internal function, don't call directly
|
||||
*/
|
||||
static void
|
||||
__xml_iter_invalidate_cache (xml_iter *iter)
|
||||
{
|
||||
g_free((void*) iter->name);
|
||||
xmlFree((xmlChar*) iter->text);
|
||||
g_free((void*) iter->err);
|
||||
iter->name = NULL;
|
||||
iter->text = NULL;
|
||||
iter->err = NULL;
|
||||
}
|
||||
|
||||
/* Initialize iterator to iterate starting from the given node
|
||||
*/
|
||||
void
|
||||
xml_iter_init (xml_iter *iter, xmlNode *node)
|
||||
{
|
||||
iter->node = node;
|
||||
__xml_iter_skip_dummy(iter);
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
iter->parent = iter->node ? iter->node->parent : NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Cleanup XML iterator
|
||||
*/
|
||||
void
|
||||
xml_iter_cleanup (xml_iter *iter)
|
||||
{
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
iter->node = NULL;
|
||||
iter->parent = NULL;
|
||||
}
|
||||
|
||||
/* Check for end-of-document condition
|
||||
*/
|
||||
SANE_Bool
|
||||
xml_iter_end (xml_iter *iter)
|
||||
{
|
||||
return iter->node == NULL;
|
||||
}
|
||||
|
||||
/* Shift to the next node
|
||||
*/
|
||||
void
|
||||
xml_iter_next (xml_iter *iter)
|
||||
{
|
||||
if (iter->node) {
|
||||
iter->node = iter->node->next;
|
||||
__xml_iter_skip_dummy(iter);
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the current node - iterate its children
|
||||
*/
|
||||
void
|
||||
xml_iter_enter (xml_iter *iter)
|
||||
{
|
||||
if (iter->node) {
|
||||
iter->parent = iter->node;
|
||||
iter->node = iter->node->children;
|
||||
__xml_iter_skip_dummy(iter);
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave the current node - return to its parent
|
||||
*/
|
||||
void
|
||||
xml_iter_leave (xml_iter *iter)
|
||||
{
|
||||
iter->node = iter->parent;
|
||||
if (iter->node) {
|
||||
iter->parent = iter->node->parent;
|
||||
}
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
}
|
||||
|
||||
/* Get name of the current node.
|
||||
*
|
||||
* The returned string remains valid, until iterator is cleaned up
|
||||
* or current node is changed (by set/next/enter/leave operations).
|
||||
* You don't need to free this string explicitly
|
||||
*/
|
||||
const char*
|
||||
xml_iter_node_name (xml_iter *iter)
|
||||
{
|
||||
const char *prefix = NULL;
|
||||
|
||||
if (iter->name == NULL && iter->node != NULL) {
|
||||
if (iter->node->ns != NULL) {
|
||||
prefix = (const char*) iter->node->ns->prefix;
|
||||
}
|
||||
|
||||
if (prefix != NULL) {
|
||||
iter->name = g_strconcat(prefix, ":", iter->node->name, NULL);
|
||||
} else {
|
||||
iter->name = g_strdup((const char*) iter->node->name);
|
||||
}
|
||||
}
|
||||
|
||||
return iter->name;
|
||||
}
|
||||
|
||||
/* Match name of the current node against the pattern
|
||||
*/
|
||||
SANE_Bool
|
||||
xml_iter_node_name_match (xml_iter *iter, const char *pattern)
|
||||
{
|
||||
return !g_strcmp0(xml_iter_node_name(iter), pattern);
|
||||
}
|
||||
|
||||
/* Get value of the current node as text
|
||||
*
|
||||
* The returned string remains valid, until iterator is cleaned up
|
||||
* or current node is changed (by set/next/enter/leave operations).
|
||||
* You don't need to free this string explicitly
|
||||
*/
|
||||
const char*
|
||||
xml_iter_node_value (xml_iter *iter)
|
||||
{
|
||||
if (iter->text == NULL && iter->node != NULL) {
|
||||
iter->text = xmlNodeGetContent(iter->node);
|
||||
g_strstrip((char*) iter->text);
|
||||
}
|
||||
|
||||
return (const char*) iter->text;
|
||||
}
|
||||
|
||||
/* Get value of the current node as unsigned integer
|
||||
* Returns error string, NULL if OK
|
||||
*/
|
||||
const char*
|
||||
xml_iter_node_value_uint (xml_iter *iter, SANE_Word *val)
|
||||
{
|
||||
const char *s = xml_iter_node_value(iter);
|
||||
char *end;
|
||||
unsigned long v;
|
||||
|
||||
g_assert(s != NULL);
|
||||
|
||||
v = strtoul(s, &end, 10);
|
||||
if (end == s || *end || v != (unsigned long) (SANE_Word) v) {
|
||||
g_free((char*) iter->err);
|
||||
iter->err = g_strdup_printf("%s: invalid numerical value",
|
||||
xml_iter_node_name(iter));
|
||||
return iter->err;
|
||||
}
|
||||
|
||||
*val = (SANE_Word) v;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* vim:ts=8:sw=4:et
|
||||
*/
|
||||
@@ -4,7 +4,7 @@
|
||||
* See LICENSE for license terms and conditions
|
||||
*/
|
||||
|
||||
#include <sane/sane.h>
|
||||
#include "airscan.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include <libsoup/soup.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/******************** Constants *********************/
|
||||
/* Service type to look for
|
||||
@@ -43,305 +42,6 @@
|
||||
/******************** Debugging ********************/
|
||||
#define DBG(level, msg, args...) printf("airscan: " msg, ##args)
|
||||
|
||||
/******************** XML utilities ********************/
|
||||
/* XML iterator
|
||||
*/
|
||||
typedef struct {
|
||||
xmlNode *node;
|
||||
xmlNode *parent;
|
||||
const char *name;
|
||||
const xmlChar *text;
|
||||
const char *err;
|
||||
} xml_iter;
|
||||
|
||||
/* Static initializer for the XML iterator
|
||||
*/
|
||||
#define XML_ITER_INIT {NULL, NULL, NULL, NULL, NULL}
|
||||
|
||||
/* Skip dummy nodes. This is internal function, don't call directly
|
||||
*/
|
||||
static void
|
||||
__xml_iter_skip_dummy (xml_iter *iter)
|
||||
{
|
||||
xmlNode *node = iter->node;
|
||||
|
||||
while (node != NULL &&
|
||||
(node->type == XML_COMMENT_NODE || xmlIsBlankNode (node))) {
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
iter->node = node;
|
||||
}
|
||||
|
||||
/* Invalidate cached data. This is internal function, don't call directly
|
||||
*/
|
||||
static void
|
||||
__xml_iter_invalidate_cache (xml_iter *iter)
|
||||
{
|
||||
g_free((void*) iter->name);
|
||||
xmlFree((xmlChar*) iter->text);
|
||||
g_free((void*) iter->err);
|
||||
iter->name = NULL;
|
||||
iter->text = NULL;
|
||||
iter->err = NULL;
|
||||
}
|
||||
|
||||
/* Set current node to iterate from
|
||||
*/
|
||||
static void
|
||||
xml_iter_set (xml_iter *iter, xmlNode *node)
|
||||
{
|
||||
iter->node = node;
|
||||
__xml_iter_skip_dummy(iter);
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
iter->parent = iter->node ? iter->node->parent : NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Cleanup XML iterator
|
||||
*/
|
||||
static void
|
||||
xml_iter_cleanup (xml_iter *iter)
|
||||
{
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
iter->node = NULL;
|
||||
iter->parent = NULL;
|
||||
}
|
||||
|
||||
/* Check for end-of-document condition
|
||||
*/
|
||||
static SANE_Bool
|
||||
xml_iter_end (xml_iter *iter)
|
||||
{
|
||||
return iter->node == NULL;
|
||||
}
|
||||
|
||||
/* Shift to the next node
|
||||
*/
|
||||
static void
|
||||
xml_iter_next (xml_iter *iter)
|
||||
{
|
||||
if (iter->node) {
|
||||
iter->node = iter->node->next;
|
||||
__xml_iter_skip_dummy(iter);
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the current node - iterate its children
|
||||
*/
|
||||
static void
|
||||
xml_iter_enter (xml_iter *iter)
|
||||
{
|
||||
if (iter->node) {
|
||||
iter->parent = iter->node;
|
||||
iter->node = iter->node->children;
|
||||
__xml_iter_skip_dummy(iter);
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave the current node - return to its parent
|
||||
*/
|
||||
static void
|
||||
xml_iter_leave (xml_iter *iter)
|
||||
{
|
||||
iter->node = iter->parent;
|
||||
if (iter->node) {
|
||||
iter->parent = iter->node->parent;
|
||||
}
|
||||
__xml_iter_invalidate_cache(iter);
|
||||
}
|
||||
|
||||
/* Get name of the current node.
|
||||
*
|
||||
* The returned string remains valid, until iterator is cleaned up
|
||||
* or current node is changed (by set/next/enter/leave operations).
|
||||
* You don't need to free this string explicitly
|
||||
*/
|
||||
static const char*
|
||||
xml_iter_node_name (xml_iter *iter)
|
||||
{
|
||||
const char *prefix = NULL;
|
||||
|
||||
if (iter->name == NULL && iter->node != NULL) {
|
||||
if (iter->node->ns != NULL) {
|
||||
prefix = (const char*) iter->node->ns->prefix;
|
||||
}
|
||||
|
||||
if (prefix != NULL) {
|
||||
iter->name = g_strconcat(prefix, ":", iter->node->name, NULL);
|
||||
} else {
|
||||
iter->name = g_strdup((const char*) iter->node->name);
|
||||
}
|
||||
}
|
||||
|
||||
return iter->name;
|
||||
}
|
||||
|
||||
/* Match name of the current node against the pattern
|
||||
*/
|
||||
static SANE_Bool
|
||||
xml_iter_node_name_match (xml_iter *iter, const char *pattern)
|
||||
{
|
||||
return !g_strcmp0(xml_iter_node_name(iter), pattern);
|
||||
}
|
||||
|
||||
/* Get value of the current node as text
|
||||
*
|
||||
* The returned string remains valid, until iterator is cleaned up
|
||||
* or current node is changed (by set/next/enter/leave operations).
|
||||
* You don't need to free this string explicitly
|
||||
*/
|
||||
static const char*
|
||||
xml_iter_node_value (xml_iter *iter)
|
||||
{
|
||||
if (iter->text == NULL && iter->node != NULL) {
|
||||
iter->text = xmlNodeGetContent(iter->node);
|
||||
g_strstrip((char*) iter->text);
|
||||
}
|
||||
|
||||
return (const char*) iter->text;
|
||||
}
|
||||
|
||||
/* Get value of the current node as unsigned integer
|
||||
* Returns error string, NULL if OK
|
||||
*/
|
||||
static const char*
|
||||
xml_iter_node_value_uint (xml_iter *iter, SANE_Word *val)
|
||||
{
|
||||
const char *s = xml_iter_node_value(iter);
|
||||
char *end;
|
||||
unsigned long v;
|
||||
|
||||
g_assert(s != NULL);
|
||||
|
||||
v = strtoul(s, &end, 10);
|
||||
if (end == s || *end || v != (unsigned long) (SANE_Word) v) {
|
||||
g_free((char*) iter->err);
|
||||
iter->err = g_strdup_printf("%s: invalid numerical value",
|
||||
xml_iter_node_name(iter));
|
||||
return iter->err;
|
||||
}
|
||||
|
||||
*val = (SANE_Word) v;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/******************** Types Arrays ********************/
|
||||
/* Initial capacity of arrays
|
||||
*/
|
||||
#define ARRAY_INITIAL_CAPACITY 4
|
||||
|
||||
/* Initialize array of SANE_Word
|
||||
*/
|
||||
static void
|
||||
array_of_word_init (SANE_Word **a)
|
||||
{
|
||||
*a = g_new0(SANE_Word, ARRAY_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
/* Cleanup array of SANE_Word
|
||||
*/
|
||||
static void
|
||||
array_of_word_cleanup (SANE_Word **a)
|
||||
{
|
||||
g_free(*a);
|
||||
*a = NULL;
|
||||
}
|
||||
|
||||
/* Get length of the SANE_Word array
|
||||
*/
|
||||
static size_t
|
||||
array_of_word_len (SANE_Word **a)
|
||||
{
|
||||
return (size_t) (*a)[0];
|
||||
}
|
||||
|
||||
/* Append word to array
|
||||
*/
|
||||
static void
|
||||
array_of_word_append(SANE_Word **a, SANE_Word w)
|
||||
{
|
||||
size_t sz = array_of_word_len(a) + 1;
|
||||
|
||||
/* If sz reached the power-of-2, reallocate the array, doubling its size */
|
||||
if (sz >= ARRAY_INITIAL_CAPACITY && (sz & (sz - 1)) == 0) {
|
||||
*a = g_renew(SANE_Word, (*a), sz + sz);
|
||||
}
|
||||
|
||||
(*a)[sz] = w;
|
||||
(*a)[0] ++;
|
||||
}
|
||||
|
||||
/* Compare function for array_of_word_sort
|
||||
*/
|
||||
static int
|
||||
array_of_word_sort_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
return *(SANE_Word*) p1 - *(SANE_Word*) p2;
|
||||
}
|
||||
|
||||
/* Sort array of SANE_Word in increasing order
|
||||
*/
|
||||
static void
|
||||
array_of_word_sort(SANE_Word **a)
|
||||
{
|
||||
SANE_Word len = (*a)[0];
|
||||
|
||||
if (len) {
|
||||
qsort((*a) + 1, len, sizeof(SANE_Word), array_of_word_sort_cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize array of SANE_String
|
||||
*/
|
||||
static void
|
||||
array_of_string_init (SANE_String **a)
|
||||
{
|
||||
*a = g_new0(SANE_String, ARRAY_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
/* Cleanup array of SANE_String
|
||||
*/
|
||||
static void
|
||||
array_of_string_cleanup (SANE_String **a)
|
||||
{
|
||||
g_free(*a);
|
||||
*a = NULL;
|
||||
}
|
||||
|
||||
/* Get length of the SANE_Word array
|
||||
*/
|
||||
static size_t
|
||||
array_of_string_len (SANE_String **a)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
for (sz = 0; (*a)[sz]; sz ++)
|
||||
;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* Append string to array
|
||||
*/
|
||||
static void
|
||||
array_of_string_append(SANE_String **a, SANE_String s)
|
||||
{
|
||||
size_t sz = array_of_string_len(a) + 1;
|
||||
|
||||
/* If sz reached the power-of-2, reallocate the array, doubling its size */
|
||||
if (sz >= ARRAY_INITIAL_CAPACITY && (sz & (sz - 1)) == 0) {
|
||||
*a = g_renew(SANE_String, (*a), sz + sz);
|
||||
}
|
||||
|
||||
/* Append string */
|
||||
(*a)[sz - 1] = s;
|
||||
(*a)[sz] = NULL;
|
||||
}
|
||||
|
||||
/******************** Device Capabilities ********************/
|
||||
/* Source flags
|
||||
*/
|
||||
@@ -664,7 +364,7 @@ devcaps_parse (devcaps *caps, xmlDoc *xml)
|
||||
xml_iter iter = XML_ITER_INIT;
|
||||
|
||||
/* Parse capabilities XML */
|
||||
xml_iter_set(&iter, xmlDocGetRootElement(xml));
|
||||
xml_iter_init(&iter, xmlDocGetRootElement(xml));
|
||||
if (!xml_iter_node_name_match(&iter, "scan:ScannerCapabilities")) {
|
||||
err = "XML: missed scan:ScannerCapabilities";
|
||||
goto DONE;
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/* AirScan (a.k.a. eSCL) backend for SANE
|
||||
*
|
||||
* Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
|
||||
* See LICENSE for license terms and conditions
|
||||
*/
|
||||
|
||||
#ifndef airscan_h
|
||||
#define airscan_h
|
||||
|
||||
#include <sane/sane.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/******************** Typed Arrays ********************/
|
||||
/* Initialize array of SANE_Word
|
||||
*/
|
||||
void
|
||||
array_of_word_init (SANE_Word **a);
|
||||
|
||||
/* Cleanup array of SANE_Word
|
||||
*/
|
||||
void
|
||||
array_of_word_cleanup (SANE_Word **a);
|
||||
|
||||
/* Get length of the SANE_Word array
|
||||
*/
|
||||
size_t
|
||||
array_of_word_len (SANE_Word **a);
|
||||
|
||||
/* Append word to array
|
||||
*/
|
||||
void
|
||||
array_of_word_append(SANE_Word **a, SANE_Word w);
|
||||
|
||||
/* Compare function for array_of_word_sort
|
||||
*/
|
||||
int
|
||||
array_of_word_sort_cmp(const void *p1, const void *p2);
|
||||
|
||||
/* Sort array of SANE_Word in increasing order
|
||||
*/
|
||||
void
|
||||
array_of_word_sort(SANE_Word **a);
|
||||
|
||||
/* Initialize array of SANE_String
|
||||
*/
|
||||
void
|
||||
array_of_string_init (SANE_String **a);
|
||||
|
||||
/* Cleanup array of SANE_String
|
||||
*/
|
||||
void
|
||||
array_of_string_cleanup (SANE_String **a);
|
||||
|
||||
/* Get length of the SANE_Word array
|
||||
*/
|
||||
size_t
|
||||
array_of_string_len (SANE_String **a);
|
||||
|
||||
/* Append string to array
|
||||
*/
|
||||
void
|
||||
array_of_string_append(SANE_String **a, SANE_String s);
|
||||
|
||||
/******************** XML utilities ********************/
|
||||
/* XML iterator
|
||||
*/
|
||||
typedef struct {
|
||||
xmlNode *node;
|
||||
xmlNode *parent;
|
||||
const char *name;
|
||||
const xmlChar *text;
|
||||
const char *err;
|
||||
} xml_iter;
|
||||
|
||||
/* Static initializer for the XML iterator
|
||||
*/
|
||||
#define XML_ITER_INIT {NULL, NULL, NULL, NULL, NULL}
|
||||
|
||||
/* Initialize iterator to iterate starting from the given node
|
||||
*/
|
||||
void
|
||||
xml_iter_init (xml_iter *iter, xmlNode *node);
|
||||
|
||||
/* Cleanup XML iterator
|
||||
*/
|
||||
void
|
||||
xml_iter_cleanup (xml_iter *iter);
|
||||
|
||||
/* Check for end-of-document condition
|
||||
*/
|
||||
SANE_Bool
|
||||
xml_iter_end (xml_iter *iter);
|
||||
|
||||
/* Shift to the next node
|
||||
*/
|
||||
void
|
||||
xml_iter_next (xml_iter *iter);
|
||||
|
||||
/* Enter the current node - iterate its children
|
||||
*/
|
||||
void
|
||||
xml_iter_enter (xml_iter *iter);
|
||||
|
||||
/* Leave the current node - return to its parent
|
||||
*/
|
||||
void
|
||||
xml_iter_leave (xml_iter *iter);
|
||||
|
||||
/* Get name of the current node.
|
||||
*
|
||||
* The returned string remains valid, until iterator is cleaned up
|
||||
* or current node is changed (by set/next/enter/leave operations).
|
||||
* You don't need to free this string explicitly
|
||||
*/
|
||||
const char*
|
||||
xml_iter_node_name (xml_iter *iter);
|
||||
|
||||
/* Match name of the current node against the pattern
|
||||
*/
|
||||
SANE_Bool
|
||||
xml_iter_node_name_match (xml_iter *iter, const char *pattern);
|
||||
|
||||
/* Get value of the current node as text
|
||||
*
|
||||
* The returned string remains valid, until iterator is cleaned up
|
||||
* or current node is changed (by set/next/enter/leave operations).
|
||||
* You don't need to free this string explicitly
|
||||
*/
|
||||
const char*
|
||||
xml_iter_node_value (xml_iter *iter);
|
||||
|
||||
/* Get value of the current node as unsigned integer
|
||||
* Returns error string, NULL if OK
|
||||
*/
|
||||
const char*
|
||||
xml_iter_node_value_uint (xml_iter *iter, SANE_Word *val);
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:ts=8:sw=4:et
|
||||
*/
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
global:
|
||||
sane_airscan_cancel;
|
||||
sane_airscan_close;
|
||||
sane_airscan_control_option;
|
||||
sane_airscan_exit;
|
||||
sane_airscan_get_devices;
|
||||
sane_airscan_get_option_descriptor;
|
||||
sane_airscan_get_parameters;
|
||||
sane_airscan_get_select_fd;
|
||||
sane_airscan_init;
|
||||
sane_airscan_open;
|
||||
sane_airscan_read;
|
||||
sane_airscan_set_io_mode;
|
||||
sane_airscan_start;
|
||||
sane_cancel;
|
||||
sane_close;
|
||||
sane_control_option;
|
||||
sane_exit;
|
||||
sane_get_devices;
|
||||
sane_get_option_descriptor;
|
||||
sane_get_parameters;
|
||||
sane_get_select_fd;
|
||||
sane_init;
|
||||
sane_open;
|
||||
sane_read;
|
||||
sane_set_io_mode;
|
||||
sane_start;
|
||||
sane_strstatus;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
/* 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.
|
||||
|
||||
This file implements the backend-independent parts of SANE. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sane/sane.h>
|
||||
|
||||
#ifndef SANE_I18N
|
||||
#define SANE_I18N(text) text
|
||||
#endif
|
||||
|
||||
SANE_String_Const
|
||||
sane_strstatus (SANE_Status status)
|
||||
{
|
||||
static char buf[80];
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case SANE_STATUS_GOOD:
|
||||
return SANE_I18N("Success");
|
||||
|
||||
case SANE_STATUS_UNSUPPORTED:
|
||||
return SANE_I18N("Operation not supported");
|
||||
|
||||
case SANE_STATUS_CANCELLED:
|
||||
return SANE_I18N("Operation was canceled");
|
||||
|
||||
case SANE_STATUS_DEVICE_BUSY:
|
||||
return SANE_I18N("Device busy");
|
||||
|
||||
case SANE_STATUS_INVAL:
|
||||
return SANE_I18N("Invalid argument");
|
||||
|
||||
case SANE_STATUS_EOF:
|
||||
return SANE_I18N("End of file reached");
|
||||
|
||||
case SANE_STATUS_JAMMED:
|
||||
return SANE_I18N("Document feeder jammed");
|
||||
|
||||
case SANE_STATUS_NO_DOCS:
|
||||
return SANE_I18N("Document feeder out of documents");
|
||||
|
||||
case SANE_STATUS_COVER_OPEN:
|
||||
return SANE_I18N("Scanner cover is open");
|
||||
|
||||
case SANE_STATUS_IO_ERROR:
|
||||
return SANE_I18N("Error during device I/O");
|
||||
|
||||
case SANE_STATUS_NO_MEM:
|
||||
return SANE_I18N("Out of memory");
|
||||
|
||||
case SANE_STATUS_ACCESS_DENIED:
|
||||
return SANE_I18N("Access to resource has been denied");
|
||||
|
||||
#ifdef SANE_STATUS_WARMING_UP
|
||||
case SANE_STATUS_WARMING_UP:
|
||||
return SANE_I18N("Lamp not ready, please retry");
|
||||
#endif
|
||||
|
||||
#ifdef SANE_STATUS_HW_LOCKED
|
||||
case SANE_STATUS_HW_LOCKED:
|
||||
return SANE_I18N("Scanner mechanism locked for transport");
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* non-reentrant, but better than nothing */
|
||||
sprintf (buf, "Unknown SANE status code %d", status);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user