2013-02-11 06:55:43 +00:00
/*
2002-07-05 19:37:08 +00:00
sane - desc . c - - generate list of supported SANE devices
2006-01-07 19:36:24 +00:00
Copyright ( C ) 2002 - 2006 Henning Meier - Geinitz < henning @ meier - geinitz . de >
2004-07-09 16:48:17 +00:00
Copyright ( C ) 2004 Jose Gato < jgato @ gsyc . escet . urjc . es > ( XML output )
2006-05-27 07:50:05 +00:00
Copyright ( C ) 2006 Mattias Ellert < mattias . ellert @ tsl . uu . se > ( plist output )
2009-01-13 21:17:16 +00:00
Copyright ( C ) 2009 Dr . Ing . Dieter Jurzitza < dieter . jurzitza @ t - online . de >
2013-08-02 20:25:10 +00:00
Copyright ( C ) 2013 Tom Gundersen < teg @ jklm . no > ( hwdb output )
2002-07-05 19:37:08 +00:00
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 .
*/
# include <../include/sane/config.h>
2009-02-06 03:10:44 +00:00
# include "lgetopt.h"
2002-07-05 19:37:08 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <stdarg.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <dirent.h>
# include <limits.h>
# include <ctype.h>
# include <time.h>
# include "../include/sane/sane.h"
2002-07-12 20:17:53 +00:00
# include "../include/sane/sanei.h"
2002-07-05 19:37:08 +00:00
# include "../include/sane/sanei_config.h"
2009-01-13 21:17:16 +00:00
# define SANE_DESC_VERSION "3.5"
2018-03-07 12:38:56 +00:00
# define MAN_PAGE_LINK "man / %s.5.html"
2009-01-13 21:17:16 +00:00
# define COLOR_MINIMAL "\"#B00000\""
# define COLOR_BASIC "\"#FF9000\""
# define COLOR_GOOD "\"#90B000\""
# define COLOR_COMPLETE "\"#007000\""
# define COLOR_UNTESTED "\"#0000B0\""
# define COLOR_UNSUPPORTED "\"#F00000\""
# define COLOR_NEW "\"#F00000\""
# define COLOR_UNKNOWN "\"#000000\""
# define DEVMODE "0664"
# define DEVOWNER "root"
2009-01-13 20:58:55 +00:00
# define DEVGROUP "scanner"
2002-07-05 19:37:08 +00:00
# ifndef PATH_MAX
# define PATH_MAX 1024
# endif
# define DBG_ERR current_debug_level = 0; debug_call
# define DBG_WARN current_debug_level = 1; debug_call
# define DBG_INFO current_debug_level = 2; debug_call
# define DBG_DBG current_debug_level = 3; debug_call
typedef enum output_mode
{
output_mode_ascii = 0 ,
2004-06-28 18:46:35 +00:00
output_mode_xml ,
2002-07-05 19:37:08 +00:00
output_mode_html_backends ,
2002-07-12 20:17:53 +00:00
output_mode_html_backends_split ,
2006-01-07 19:36:24 +00:00
output_mode_html_mfgs ,
2006-01-08 20:42:53 +00:00
output_mode_statistics ,
output_mode_usermap ,
output_mode_db ,
2006-05-27 07:50:05 +00:00
output_mode_udev ,
2011-06-02 09:05:30 +00:00
output_mode_udevacl ,
2013-07-17 23:27:33 +00:00
output_mode_udevhwdb ,
output_mode_hwdb ,
2007-03-18 09:31:10 +00:00
output_mode_plist ,
2008-03-28 20:57:59 +00:00
output_mode_hal ,
output_mode_halnew
2002-07-05 19:37:08 +00:00
}
output_mode ;
typedef enum parameter_type
{
param_none = 0 ,
2006-01-08 15:48:38 +00:00
param_string ,
2009-01-13 21:17:16 +00:00
param_two_strings ,
param_three_strings
2002-07-05 19:37:08 +00:00
}
parameter_type ;
typedef enum status_entry
{
status_unknown ,
2003-06-18 09:06:38 +00:00
status_unsupported ,
2006-01-07 23:44:09 +00:00
status_untested ,
2003-06-18 09:06:38 +00:00
status_minimal ,
status_basic ,
status_good ,
status_complete
2002-07-05 19:37:08 +00:00
}
status_entry ;
typedef enum device_type
{
type_unknown ,
type_scanner ,
type_stillcam ,
type_vidcam ,
type_meta ,
type_api
}
device_type ;
typedef enum level
{
level_backend ,
level_mfg ,
level_model ,
level_desc
}
level ;
typedef struct url_entry
{
struct url_entry * next ;
char * name ;
}
url_entry ;
typedef struct model_entry
{
struct model_entry * next ;
char * name ;
char * interface ;
struct url_entry * url ;
char * comment ;
2002-07-07 13:14:03 +00:00
enum status_entry status ;
2006-01-08 15:48:38 +00:00
char * usb_vendor_id ;
char * usb_product_id ;
2006-01-14 19:06:49 +00:00
SANE_Bool ignore_usb_id ;
2009-01-13 21:17:16 +00:00
char * scsi_vendor_id ;
char * scsi_product_id ;
SANE_Bool scsi_is_processor ;
2002-07-05 19:37:08 +00:00
}
model_entry ;
typedef struct desc_entry
{
struct desc_entry * next ;
char * desc ;
struct url_entry * url ;
char * comment ;
}
desc_entry ;
typedef struct mfg_entry
{
struct mfg_entry * next ;
char * name ;
struct url_entry * url ;
char * comment ;
struct model_entry * model ;
}
mfg_entry ;
typedef struct type_entry
{
struct type_entry * next ;
enum device_type type ;
struct desc_entry * desc ;
struct mfg_entry * mfg ;
}
type_entry ;
typedef struct backend_entry
{
struct backend_entry * next ;
char * name ;
char * version ;
char * manpage ;
struct url_entry * url ;
char * comment ;
struct type_entry * type ;
SANE_Bool new ;
}
backend_entry ;
2002-07-17 18:03:51 +00:00
typedef struct model_record_entry
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
struct model_record_entry * next ;
2002-07-07 13:14:03 +00:00
char * name ;
2002-07-17 18:03:51 +00:00
char * interface ;
2002-07-07 13:14:03 +00:00
struct url_entry * url ;
char * comment ;
2002-07-17 18:03:51 +00:00
enum status_entry status ;
2006-01-08 15:48:38 +00:00
char * usb_vendor_id ;
char * usb_product_id ;
2009-01-13 21:17:16 +00:00
char * scsi_vendor_id ;
char * scsi_product_id ;
SANE_Bool scsi_is_processor ;
2002-07-17 18:03:51 +00:00
struct backend_entry * be ;
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
model_record_entry ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
typedef struct mfg_record_entry
{
struct mfg_record_entry * next ;
char * name ;
2002-07-06 22:14:34 +00:00
char * comment ;
struct url_entry * url ;
2002-07-17 18:03:51 +00:00
struct model_record_entry * model_record ;
2002-07-05 19:37:08 +00:00
}
mfg_record_entry ;
2006-01-07 23:44:09 +00:00
typedef int statistics_type [ status_complete + 1 ] ;
2002-07-05 19:37:08 +00:00
2006-01-08 20:42:53 +00:00
typedef struct manufacturer_model_type
{
struct manufacturer_model_type * next ;
char * name ;
}
manufacturer_model_type ;
typedef struct usbid_type
{
struct usbid_type * next ;
char * usb_vendor_id ;
char * usb_product_id ;
struct manufacturer_model_type * name ;
}
usbid_type ;
2009-01-13 21:17:16 +00:00
typedef struct scsiid_type
{
struct scsiid_type * next ;
char * scsi_vendor_id ;
char * scsi_product_id ;
SANE_Bool is_processor ;
struct manufacturer_model_type * name ;
}
scsiid_type ;
2002-07-05 19:37:08 +00:00
static char * program_name ;
static int debug = 0 ;
static int current_debug_level = 0 ;
2006-01-07 19:36:24 +00:00
static char * search_dir_spec = 0 ;
2002-07-05 19:37:08 +00:00
static backend_entry * first_backend = 0 ;
static enum output_mode mode = output_mode_ascii ;
static char * title = 0 ;
static char * intro = 0 ;
2003-10-17 09:25:56 +00:00
static SANE_String desc_name = 0 ;
2013-02-11 06:55:43 +00:00
static const char * status_name [ ] =
{ " Unknown " , " Unsupported " , " Untested " , " Minimal " , " Basic " ,
2006-01-07 23:44:09 +00:00
" Good " , " Complete " } ;
2013-02-11 06:55:43 +00:00
static const char * device_type_name [ ] =
{ " Unknown " , " Scanners " , " Still cameras " , " Video Cameras " , " Meta backends " ,
2006-01-07 23:44:09 +00:00
" APIs " } ;
2013-02-11 06:55:43 +00:00
static const char * device_type_aname [ ] =
{ " UKNOWN " , " SCANNERS " , " STILL " , " VIDEO " , " META " ,
2006-01-07 23:44:09 +00:00
" API " } ;
static const char * status_color [ ] =
2013-02-11 06:55:43 +00:00
{ COLOR_UNKNOWN , COLOR_UNSUPPORTED , COLOR_UNTESTED , COLOR_MINIMAL ,
2006-01-07 23:44:09 +00:00
COLOR_BASIC , COLOR_GOOD , COLOR_COMPLETE } ;
2002-07-05 19:37:08 +00:00
2009-01-13 21:17:16 +00:00
2002-07-05 19:37:08 +00:00
static void
debug_call ( const char * fmt , . . . )
{
va_list ap ;
char * level_txt ;
va_start ( ap , fmt ) ;
if ( debug > = current_debug_level )
{
/* print to stderr */
switch ( current_debug_level )
{
case 0 :
level_txt = " ERROR: " ;
break ;
case 1 :
level_txt = " Warning: " ;
break ;
case 2 :
level_txt = " Info: " ;
break ;
default :
level_txt = " " ;
break ;
}
2003-10-17 09:25:56 +00:00
if ( desc_name )
fprintf ( stderr , " %s: %8s " , desc_name , level_txt ) ;
else
fprintf ( stderr , " [%s] %8s " , program_name , level_txt ) ;
2002-07-05 19:37:08 +00:00
vfprintf ( stderr , fmt , ap ) ;
}
va_end ( ap ) ;
}
static void
print_usage ( char * program_name )
{
2002-07-06 11:08:01 +00:00
printf ( " Usage: %s [-s dir] [-m mode] [-d level] [-h] [-V] \n " ,
program_name ) ;
2006-01-07 21:42:07 +00:00
printf ( " -s|--search-dir dir "
2017-05-30 13:39:30 +00:00
" Specify the directory that contains .desc files \n "
2006-01-07 21:42:07 +00:00
" "
" (multiple directories can be concatenated by \" : \" ) \n " ) ;
printf ( " -m|--mode mode "
2006-05-27 07:50:05 +00:00
" Output mode (ascii, html-backends-split, html-mfgs, \n "
2013-07-17 23:27:33 +00:00
" xml, statistics, usermap, db, udev, udev+acl, udev+hwdb, hwdb, plist, hal, hal-new) \n " ) ;
2002-07-05 19:37:08 +00:00
printf ( " -t|--title \" title \" The title used for HTML pages \n " ) ;
printf ( " -i|--intro \" intro \" A short description of the "
" contents of the page \n " ) ;
printf ( " -d|--debug-level level Specify debug level (0-3) \n " ) ;
printf ( " -h|--help Print help message \n " ) ;
printf ( " -V|--version Print version information \n " ) ;
printf ( " Report bugs to <henning@meier-geinitz.de> \n " ) ;
}
static void
print_version ( void )
{
2002-11-29 18:19:58 +00:00
printf ( " sane-desc %s (%s) \n " , SANE_DESC_VERSION , PACKAGE_STRING ) ;
2006-01-07 19:36:24 +00:00
printf ( " Copyright (C) 2002-2006 Henning Meier-Geinitz "
2002-07-05 19:37:08 +00:00
" <henning@meier-geinitz.de> \n "
" sane-desc comes with NO WARRANTY, to the extent permitted by "
" law. \n "
" You may redistribute copies of sane-desc under the terms of the "
" GNU General \n "
" Public License. \n "
2004-06-28 18:46:35 +00:00
" For more information about these matters, see the file named "
2002-07-05 19:37:08 +00:00
" COPYING. \n " ) ;
}
static SANE_Bool
get_options ( int argc , char * * argv )
{
int longindex ;
int opt ;
static struct option desc_options [ ] = {
{ " search-dir " , required_argument , NULL , ' s ' } ,
{ " mode " , required_argument , NULL , ' m ' } ,
{ " title " , required_argument , NULL , ' t ' } ,
{ " intro " , required_argument , NULL , ' i ' } ,
{ " debug-level " , required_argument , NULL , ' d ' } ,
{ " help " , 0 , NULL , ' h ' } ,
{ " version " , 0 , NULL , ' V ' } ,
{ 0 , 0 , 0 , 0 }
} ;
while ( ( opt = getopt_long ( argc , argv , " s:m:t:i:d:hV " , desc_options ,
& longindex ) ) ! = - 1 )
{
switch ( opt )
{
case ' h ' :
print_usage ( argv [ 0 ] ) ;
exit ( 0 ) ;
case ' V ' :
print_version ( ) ;
exit ( 0 ) ;
case ' s ' :
2006-01-07 19:36:24 +00:00
search_dir_spec = strdup ( optarg ) ;
DBG_INFO ( " setting search directory to `%s' \n " , search_dir_spec ) ;
2002-07-05 19:37:08 +00:00
break ;
case ' m ' :
if ( strcmp ( optarg , " ascii " ) = = 0 )
{
2006-01-07 19:36:24 +00:00
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
2002-07-05 19:37:08 +00:00
mode = output_mode_ascii ;
}
2004-07-09 16:48:17 +00:00
else if ( strcmp ( optarg , " xml " ) = = 0 )
2004-06-28 18:46:35 +00:00
{
2006-01-07 19:36:24 +00:00
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
2004-06-28 18:46:35 +00:00
mode = output_mode_xml ;
}
2002-07-12 20:17:53 +00:00
else if ( strcmp ( optarg , " html-backends-split " ) = = 0 )
{
2006-01-07 19:36:24 +00:00
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
2002-07-12 20:17:53 +00:00
mode = output_mode_html_backends_split ;
}
2002-07-05 19:37:08 +00:00
else if ( strcmp ( optarg , " html-mfgs " ) = = 0 )
{
2006-01-07 19:36:24 +00:00
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
2002-07-05 19:37:08 +00:00
mode = output_mode_html_mfgs ;
}
2006-01-07 19:36:24 +00:00
else if ( strcmp ( optarg , " statistics " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_statistics ;
}
2006-01-08 20:42:53 +00:00
else if ( strcmp ( optarg , " usermap " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_usermap ;
}
else if ( strcmp ( optarg , " db " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_db ;
}
else if ( strcmp ( optarg , " udev " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_udev ;
}
2011-06-02 09:05:30 +00:00
else if ( strcmp ( optarg , " udev+acl " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_udevacl ;
}
2013-07-17 23:27:33 +00:00
else if ( strcmp ( optarg , " udev+hwdb " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_udevhwdb ;
}
else if ( strcmp ( optarg , " hwdb " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_hwdb ;
}
2006-05-27 07:50:05 +00:00
else if ( strcmp ( optarg , " plist " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_plist ;
}
2007-03-18 09:31:10 +00:00
else if ( strcmp ( optarg , " hal " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_hal ;
}
2008-03-28 20:57:59 +00:00
else if ( strcmp ( optarg , " hal-new " ) = = 0 )
{
DBG_INFO ( " Output mode: %s \n " , optarg ) ;
mode = output_mode_halnew ;
}
2002-07-05 19:37:08 +00:00
else
{
DBG_ERR ( " Unknown output mode: %s \n " , optarg ) ;
exit ( 1 ) ;
}
break ;
case ' t ' :
title = optarg ;
DBG_INFO ( " setting title to `%s' \n " , optarg ) ;
break ;
case ' i ' :
intro = optarg ;
DBG_INFO ( " setting intro to `%s' \n " , optarg ) ;
break ;
case ' d ' :
debug = atoi ( optarg ) ;
DBG_INFO ( " setting debug level to %d \n " , debug ) ;
break ;
case ' ? ' :
DBG_ERR ( " unknown option (use -h for help) \n " ) ;
return SANE_FALSE ;
case ' : ' :
DBG_ERR ( " missing parameter (use -h for help) \n " ) ;
return SANE_FALSE ;
default :
DBG_ERR ( " missing option (use -h for help) \n " ) ;
return SANE_FALSE ;
}
}
2006-01-07 19:36:24 +00:00
if ( ! search_dir_spec )
search_dir_spec = " . " ;
2002-07-05 19:37:08 +00:00
return SANE_TRUE ;
}
2002-07-17 18:03:51 +00:00
static int
char_compare ( char char1 , char char2 )
{
char1 = toupper ( char1 ) ;
char2 = toupper ( char2 ) ;
if ( char1 < char2 )
return - 1 ;
else if ( char1 > char2 )
return 1 ;
else
return 0 ;
}
static int
num_compare ( char * num_string1 , char * num_string2 )
{
int num1 = atoi ( num_string1 ) ;
int num2 = atoi ( num_string2 ) ;
if ( num1 < num2 )
return - 1 ;
else if ( num1 > num2 )
return 1 ;
else
return 0 ;
}
/* Compare two strings, try to sort numbers correctly (600 < 1200) */
static int
string_compare ( char * string1 , char * string2 )
{
int count = 0 ;
int compare = 0 ;
2006-01-14 19:06:49 +00:00
if ( ! string1 )
{
if ( ! string2 )
return 0 ;
else
return 1 ;
}
else if ( ! string2 )
return - 1 ;
2002-07-17 18:03:51 +00:00
while ( string1 [ count ] & & string2 [ count ] )
{
if ( isdigit ( string1 [ count ] ) & & isdigit ( string2 [ count ] ) )
compare = num_compare ( & string1 [ count ] , & string2 [ count ] ) ;
else
compare = char_compare ( string1 [ count ] , string2 [ count ] ) ;
if ( compare ! = 0 )
return compare ;
count + + ;
}
return char_compare ( string1 [ count ] , string2 [ count ] ) ;
}
/* Add URLs to the end of the list if they are unique */
static url_entry *
update_url_list ( url_entry * first_url , char * new_url )
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
url_entry * url = first_url ;
SANE_Bool found = SANE_FALSE ;
while ( url & & url - > name )
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
if ( string_compare ( url - > name , new_url ) = = 0 )
found = SANE_TRUE ;
url = url - > next ;
}
if ( found )
return first_url ;
url = first_url ;
if ( url )
{
while ( url - > next )
url = url - > next ;
url - > next = calloc ( 1 , sizeof ( url_entry ) ) ;
url = url - > next ;
2002-07-05 19:37:08 +00:00
}
else
{
2002-07-17 18:03:51 +00:00
first_url = calloc ( 1 , sizeof ( url_entry ) ) ;
url = first_url ;
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
if ( ! url )
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
DBG_ERR ( " update_url_list: couldn't calloc url_entry \n " ) ;
2002-07-05 19:37:08 +00:00
exit ( 1 ) ;
}
2002-07-17 18:03:51 +00:00
url - > name = new_url ;
return first_url ;
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
/* Get the next token, ignoring escaped quotation marks */
2002-07-05 19:37:08 +00:00
static const char *
2002-07-17 18:03:51 +00:00
get_token ( const char * str , char * * string_const )
2002-07-05 19:37:08 +00:00
{
const char * start ;
size_t len ;
str = sanei_config_skip_whitespace ( str ) ;
if ( * str = = ' " ' )
{
start = + + str ;
while ( * str & & ( * str ! = ' " ' | | * ( str - 1 ) = = ' \\ ' ) )
+ + str ;
len = str - start ;
if ( * str = = ' " ' )
+ + str ;
else
start = 0 ; /* final double quote is missing */
}
else
{
start = str ;
while ( * str & & ! isspace ( * str ) )
+ + str ;
len = str - start ;
}
if ( start )
* string_const = strndup ( start , len ) ;
else
2003-09-21 08:56:35 +00:00
* string_const = NULL ;
2002-07-05 19:37:08 +00:00
return str ;
}
2002-07-17 18:03:51 +00:00
/* Checks a line for a keyword token and determines keyword/string argument */
2002-07-05 19:37:08 +00:00
static SANE_Status
read_keyword ( SANE_String line , SANE_String keyword_token ,
parameter_type p_type , void * argument )
{
SANE_String_Const cp ;
SANE_Char * word ;
word = 0 ;
2002-07-17 18:03:51 +00:00
cp = get_token ( line , & word ) ;
2002-07-05 19:37:08 +00:00
2003-09-21 08:56:35 +00:00
if ( ! word )
{
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
2002-07-05 19:37:08 +00:00
if ( strcmp ( word , keyword_token ) ! = 0 )
2013-02-11 06:55:43 +00:00
{
free ( word ) ;
return SANE_STATUS_INVAL ;
}
2002-07-05 19:37:08 +00:00
free ( word ) ;
word = 0 ;
switch ( p_type )
{
case param_none :
return SANE_STATUS_GOOD ;
case param_string :
{
2002-07-06 11:08:01 +00:00
char * pos ;
2002-07-17 18:03:51 +00:00
cp = get_token ( cp , & word ) ;
2003-09-21 08:56:35 +00:00
if ( ! word )
{
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
2002-07-05 19:37:08 +00:00
/* remove escaped quotations */
while ( ( pos = strstr ( word , " \\ \" " ) ) ! = 0 )
2002-07-06 11:08:01 +00:00
* pos = ' ' ;
2002-07-05 19:37:08 +00:00
DBG_DBG ( " read_keyword: set entry `%s' to `%s' \n " , keyword_token ,
word ) ;
* ( SANE_String * ) argument = strdup ( word ) ;
break ;
}
2006-01-08 15:48:38 +00:00
case param_two_strings :
{
char * pos ;
char * * strings = malloc ( 2 * sizeof ( SANE_String ) ) ;
cp = get_token ( cp , & word ) ;
if ( ! word )
{
2013-02-11 06:55:43 +00:00
free ( strings ) ;
2006-01-08 15:48:38 +00:00
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
/* remove escaped quotations */
while ( ( pos = strstr ( word , " \\ \" " ) ) ! = 0 )
* pos = ' ' ;
DBG_INFO ( " read_keyword: set first entry of `%s' to `%s' \n " , keyword_token ,
word ) ;
strings [ 0 ] = strdup ( word ) ;
if ( word )
free ( word ) ;
cp = get_token ( cp , & word ) ;
if ( ! word )
{
2013-02-11 06:55:43 +00:00
free ( strings ) ;
2006-01-08 15:48:38 +00:00
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
/* remove escaped quotations */
while ( ( pos = strstr ( word , " \\ \" " ) ) ! = 0 )
* pos = ' ' ;
DBG_INFO ( " read_keyword: set second entry of `%s' to `%s' \n " , keyword_token ,
word ) ;
strings [ 1 ] = strdup ( word ) ;
* ( SANE_String * * ) argument = strings ;
break ;
}
2009-01-13 21:17:16 +00:00
case param_three_strings :
{
char * pos ;
char * * strings = malloc ( 3 * sizeof ( SANE_String ) ) ;
cp = get_token ( cp , & word ) ;
if ( ! word )
{
2013-02-11 06:55:43 +00:00
free ( strings ) ;
2009-01-13 21:17:16 +00:00
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
/* remove escaped quotations */
while ( ( pos = strstr ( word , " \\ \" " ) ) ! = 0 )
* pos = ' ' ;
DBG_INFO ( " read_keyword: set first entry of `%s' to `%s' \n " , keyword_token ,
word ) ;
strings [ 0 ] = strdup ( word ) ;
if ( word )
free ( word ) ;
cp = get_token ( cp , & word ) ;
if ( ! word )
{
2013-02-11 06:55:43 +00:00
free ( strings ) ;
2009-01-13 21:17:16 +00:00
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
/* remove escaped quotations */
while ( ( pos = strstr ( word , " \\ \" " ) ) ! = 0 )
* pos = ' ' ;
DBG_INFO ( " read_keyword: set second entry of `%s' to `%s' \n " , keyword_token ,
word ) ;
strings [ 1 ] = strdup ( word ) ;
if ( word )
free ( word ) ;
cp = get_token ( cp , & word ) ;
if ( ! word )
{
2013-02-11 06:55:43 +00:00
free ( strings ) ;
2009-01-13 21:17:16 +00:00
DBG_ERR ( " read_keyword: missing quotation mark: %s \n " , line ) ;
return SANE_STATUS_INVAL ;
}
/* remove escaped quotations */
while ( ( pos = strstr ( word , " \\ \" " ) ) ! = 0 )
* pos = ' ' ;
DBG_INFO ( " read_keyword: set third entry of `%s' to `%s' \n " , keyword_token ,
word ) ;
strings [ 2 ] = strdup ( word ) ;
* ( SANE_String * * ) argument = strings ;
break ;
}
2002-07-05 19:37:08 +00:00
default :
DBG_ERR ( " read_keyword: unknown param_type %d \n " , p_type ) ;
return SANE_STATUS_INVAL ;
2002-07-17 18:03:51 +00:00
}
2002-07-05 19:37:08 +00:00
if ( word )
free ( word ) ;
word = 0 ;
return SANE_STATUS_GOOD ;
}
2006-01-08 15:48:38 +00:00
/* Check for a all-lowercase 4-digit hex number (e.g. 0x1234) */
static SANE_Bool
check_hex ( SANE_String string )
{
unsigned int i ;
if ( strlen ( string ) ! = 6 )
return SANE_FALSE ;
if ( strncmp ( string , " 0x " , 2 ) ! = 0 )
return SANE_FALSE ;
for ( i = 0 ; i < strlen ( string ) ; i + + )
{
if ( isupper ( string [ i ] ) )
return SANE_FALSE ;
}
for ( i = 2 ; i < strlen ( string ) ; i + + )
{
if ( ! isxdigit ( string [ i ] ) )
return SANE_FALSE ;
}
return SANE_TRUE ;
}
2002-07-17 18:03:51 +00:00
/* Read and interprete the .desc files */
2002-07-05 19:37:08 +00:00
static SANE_Bool
read_files ( void )
{
struct stat stat_buf ;
DIR * dir ;
struct dirent * dir_entry ;
FILE * fp ;
char file_name [ PATH_MAX ] ;
2003-09-21 08:56:35 +00:00
SANE_Char line [ 4096 ] , * word ;
2002-07-05 19:37:08 +00:00
SANE_String_Const cp ;
backend_entry * current_backend = 0 ;
type_entry * current_type = 0 ;
mfg_entry * current_mfg = 0 ;
model_entry * current_model = 0 ;
enum level current_level = level_backend ;
2006-01-07 19:36:24 +00:00
char * search_dir = search_dir_spec , * end = 0 ;
2002-07-05 19:37:08 +00:00
2006-01-07 19:36:24 +00:00
DBG_INFO ( " looking for .desc files in `%s' \n " , search_dir_spec ) ;
while ( search_dir & & search_dir [ 0 ] )
{
end = strchr ( search_dir , ' : ' ) ;
if ( end )
end [ 0 ] = ' \0 ' ;
DBG_INFO ( " reading directory `%s' \n " , search_dir ) ;
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( stat ( search_dir , & stat_buf ) < 0 )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_ERR ( " cannot stat `%s' (%s) \n " , search_dir , strerror ( errno ) ) ;
return SANE_FALSE ;
}
if ( ! S_ISDIR ( stat_buf . st_mode ) )
{
DBG_ERR ( " `%s' is not a directory \n " , search_dir ) ;
return SANE_FALSE ;
}
if ( ( dir = opendir ( search_dir ) ) = = 0 )
{
DBG_ERR ( " cannot read directory `%s' (%s) \n " , search_dir ,
strerror ( errno ) ) ;
return SANE_FALSE ;
}
while ( ( dir_entry = readdir ( dir ) ) ! = NULL )
{
if ( strlen ( dir_entry - > d_name ) > 5 & &
strcmp ( dir_entry - > d_name + strlen ( dir_entry - > d_name ) - 5 ,
" .desc " ) = = 0 )
2003-10-17 09:25:56 +00:00
{
2006-01-07 21:42:07 +00:00
if ( strlen ( search_dir )
+ strlen ( dir_entry - > d_name ) + 1 + 1 > PATH_MAX )
2003-10-17 09:25:56 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_ERR ( " filename too long \n " ) ;
return SANE_FALSE ;
}
sprintf ( file_name , " %s/%s " , search_dir , dir_entry - > d_name ) ;
DBG_INFO ( " -> reading desc file: %s \n " , file_name ) ;
fp = fopen ( file_name , " r " ) ;
if ( ! fp )
{
DBG_ERR ( " can't open desc file: %s (%s) \n " , file_name ,
strerror ( errno ) ) ;
return SANE_FALSE ;
}
2013-02-11 06:55:43 +00:00
/* now we check if everything is ok with the previous backend
2009-02-06 03:10:44 +00:00
before we read the new one */
2006-01-07 21:42:07 +00:00
if ( current_backend )
{
type_entry * current_type = current_backend - > type ;
2006-01-14 19:06:49 +00:00
int no_usbids = 0 ;
2010-02-28 02:09:45 +00:00
int no_interface = 0 ;
int no_status = 0 ;
2013-02-11 06:55:43 +00:00
2006-01-07 21:42:07 +00:00
while ( current_type )
2003-10-17 09:25:56 +00:00
{
2006-01-07 21:42:07 +00:00
if ( current_type - > type = = type_scanner | |
current_type - > type = = type_stillcam | |
current_type - > type = = type_vidcam )
2003-10-17 09:25:56 +00:00
{
2006-01-07 21:42:07 +00:00
mfg_entry * current_mfg = current_type - > mfg ;
2004-07-09 16:48:17 +00:00
2006-01-07 21:42:07 +00:00
while ( current_mfg )
2003-10-17 09:25:56 +00:00
{
2006-01-07 21:42:07 +00:00
model_entry * current_model = current_mfg - > model ;
while ( current_model )
{
if ( current_model - > status = = status_unknown )
2006-01-14 19:06:49 +00:00
{
2010-02-28 02:09:45 +00:00
DBG_INFO
2006-01-14 19:06:49 +00:00
( " Backend `%s': `%s' `%s' does not have a status \n " ,
current_backend - > name ,
current_mfg - > name ,
current_model - > name ) ;
2010-02-28 02:09:45 +00:00
no_status + + ;
2006-01-14 19:06:49 +00:00
}
if ( ! current_model - > interface )
{
2010-02-28 02:09:45 +00:00
DBG_INFO
2006-01-14 19:06:49 +00:00
( " Backend `%s': `%s' `%s' does not have an interface \n " ,
current_backend - > name ,
current_mfg - > name ,
current_model - > name ) ;
2010-02-28 02:09:45 +00:00
no_interface + + ;
2006-01-14 19:06:49 +00:00
}
else if ( strstr ( current_model - > interface , " USB " ) )
{
if ( ( ! current_model - > usb_vendor_id | | ! current_model - > usb_product_id )
& & ! current_model - > ignore_usb_id )
{
DBG_INFO ( " `%s' seems to provide a USB device "
2013-02-11 06:55:43 +00:00
" without :usbid (%s %s) \n " ,
2006-01-14 19:06:49 +00:00
current_backend - > name ,
current_mfg - > name ,
current_model - > name ) ;
no_usbids + + ;
}
}
2006-01-07 21:42:07 +00:00
current_model = current_model - > next ;
}
current_mfg = current_mfg - > next ;
2003-10-17 09:25:56 +00:00
}
}
2006-01-07 21:42:07 +00:00
current_type = current_type - > next ;
2003-10-17 09:25:56 +00:00
}
2010-02-28 02:09:45 +00:00
if ( no_status )
{
2013-02-11 06:55:43 +00:00
DBG_WARN ( " Backend `%s': %d devices without :status \n " ,
2010-02-28 02:09:45 +00:00
current_backend - > name , no_status ) ;
}
if ( no_interface )
{
2013-02-11 06:55:43 +00:00
DBG_WARN ( " Backend `%s': %d devices without :interface \n " ,
2010-02-28 02:09:45 +00:00
current_backend - > name , no_interface ) ;
}
2006-01-14 19:06:49 +00:00
if ( no_usbids )
{
2013-02-11 06:55:43 +00:00
DBG_WARN ( " Backend `%s': %d USB devices without :usbid \n " ,
2006-01-14 19:06:49 +00:00
current_backend - > name , no_usbids ) ;
}
2003-10-17 09:25:56 +00:00
}
2006-01-07 21:42:07 +00:00
desc_name = dir_entry - > d_name ;
current_backend = 0 ;
current_type = 0 ;
current_mfg = 0 ;
current_model = 0 ;
while ( sanei_config_read ( line , sizeof ( line ) , fp ) )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
char * string_entry = 0 ;
2006-01-08 15:48:38 +00:00
char * * two_string_entry ;
2009-01-13 21:17:16 +00:00
char * * three_string_entry ;
2002-07-05 19:37:08 +00:00
word = 0 ;
2006-01-07 21:42:07 +00:00
cp = get_token ( line , & word ) ;
if ( ! word | | cp = = line )
{
DBG_DBG ( " ignoring empty line \n " ) ;
if ( word )
free ( word ) ;
word = 0 ;
continue ;
}
if ( word [ 0 ] = = ' ; ' )
{
DBG_DBG ( " ignoring comment line \n " ) ;
free ( word ) ;
word = 0 ;
continue ;
}
DBG_DBG ( " line: %s \n " , line ) ;
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :backend " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
{
backend_entry * be = first_backend , * prev_be =
0 , * new_be = 0 ;
DBG_INFO ( " creating backend entry `%s' \n " ,
string_entry ) ;
new_be = calloc ( 1 , sizeof ( backend_entry ) ) ;
if ( ! new_be )
{
DBG_ERR ( " calloc failed (%s) \n " , strerror ( errno ) ) ;
return SANE_FALSE ;
}
new_be - > name = string_entry ;
new_be - > new = SANE_FALSE ;
if ( ! be )
{
first_backend = new_be ;
be = new_be ;
}
else
{
while ( be )
{
int compare =
string_compare ( new_be - > name , be - > name ) ;
if ( compare < = 0 )
{
backend_entry * be_tmp = be ;
be = new_be ;
be - > next = be_tmp ;
if ( ! prev_be )
first_backend = be ;
else
prev_be - > next = be ;
break ;
}
prev_be = be ;
be = be - > next ;
}
if ( ! be ) /* last entry */
{
prev_be - > next = new_be ;
be = prev_be - > next ;
}
}
current_backend = be ;
current_type = 0 ;
current_mfg = 0 ;
current_model = 0 ;
current_level = level_backend ;
continue ;
}
if ( ! current_backend )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_ERR ( " use `:backend' keyword first \n " ) ;
2002-07-05 19:37:08 +00:00
return SANE_FALSE ;
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :version " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2002-07-17 18:03:51 +00:00
{
2006-01-07 21:42:07 +00:00
if ( current_backend - > version )
{
DBG_WARN
( " overwriting version of backend `%s' to `%s' "
" (was: `%s') \n " , current_backend - > name ,
string_entry , current_backend - > version ,
current_backend - > version ) ;
}
DBG_INFO ( " setting version of backend `%s' to `%s' \n " ,
current_backend - > name , string_entry ) ;
current_backend - > version = string_entry ;
continue ;
2002-07-17 18:03:51 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :status " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2002-07-17 18:03:51 +00:00
{
2006-01-07 21:42:07 +00:00
switch ( current_level )
2002-07-17 18:03:51 +00:00
{
2006-01-07 21:42:07 +00:00
case level_model :
if ( current_model - > status ! = status_unknown )
2002-07-17 18:03:51 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_WARN
( " overwriting status of model `%s' (backend `%s') \n " ,
current_model - > name , current_backend - > name ) ;
}
if ( strcmp ( string_entry , " :minimal " ) = = 0 )
{
DBG_INFO
( " setting status of model `%s' to `minimal' \n " ,
current_model - > name ) ;
current_model - > status = status_minimal ;
}
else if ( strcmp ( string_entry , " :basic " ) = = 0 )
{
DBG_INFO
( " setting status of model `%s' to `basic' \n " ,
current_model - > name ) ;
current_model - > status = status_basic ;
2002-07-17 18:03:51 +00:00
}
2006-01-07 21:42:07 +00:00
else if ( strcmp ( string_entry , " :good " ) = = 0 )
{
DBG_INFO
( " setting status of model `%s' to `good' \n " ,
current_model - > name ) ;
current_model - > status = status_good ;
}
else if ( strcmp ( string_entry , " :complete " ) = = 0 )
{
DBG_INFO
( " setting status of model `%s' to `complete' \n " ,
current_model - > name ) ;
current_model - > status = status_complete ;
}
else if ( strcmp ( string_entry , " :untested " ) = = 0 )
{
DBG_INFO
( " setting status of model `%s' to `untested' \n " ,
current_model - > name ) ;
current_model - > status = status_untested ;
}
else if ( strcmp ( string_entry , " :unsupported " ) = = 0 )
{
DBG_INFO
( " setting status of model `%s' to `unsupported' \n " ,
current_model - > name ) ;
current_model - > status = status_unsupported ;
}
else
{
DBG_ERR
( " unknown status of model `%s': `%s' (backend `%s') \n " ,
current_model - > name , string_entry ,
current_backend - > name ) ;
current_model - > status = status_untested ;
return SANE_FALSE ;
}
break ;
default :
DBG_ERR
( " level %d not implemented for :status (backend `%s') \n " ,
current_level , current_backend - > name ) ;
return SANE_FALSE ;
}
continue ;
}
if ( read_keyword ( line , " :new " , param_string , & string_entry )
= = SANE_STATUS_GOOD )
{
if ( strcmp ( string_entry , " :yes " ) = = 0 )
{
DBG_INFO
( " backend %s is new in this SANE release \n " ,
current_backend - > name ) ;
current_backend - > new = SANE_TRUE ;
}
else if ( strcmp ( string_entry , " :no " ) = = 0 )
{
DBG_INFO
( " backend %s is NOT new in this SANE release \n " ,
current_backend - > name ) ;
current_backend - > new = SANE_FALSE ;
2002-07-17 18:03:51 +00:00
}
2006-01-07 21:42:07 +00:00
else
2002-07-17 18:03:51 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_ERR ( " unknown :new parameter of backend `%s': "
" `%s' \n " , current_backend - > name ,
string_entry ) ;
current_backend - > new = SANE_FALSE ;
return SANE_FALSE ;
2002-07-17 18:03:51 +00:00
}
2006-01-07 21:42:07 +00:00
continue ;
2002-07-17 18:03:51 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :manpage " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2003-01-11 23:42:14 +00:00
{
2006-01-07 21:42:07 +00:00
if ( current_backend - > manpage )
{
DBG_WARN
( " overwriting manpage of backend `%s' to `%s' "
" (was: `%s') \n " , current_backend - > name ,
string_entry , current_backend - > manpage ) ;
}
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting manpage of backend `%s' to `%s' \n " ,
current_backend - > name , string_entry ) ;
current_backend - > manpage = string_entry ;
continue ;
}
if ( read_keyword
( line , " :devicetype " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
type_entry * type = 0 ;
type = current_backend - > type ;
DBG_INFO
( " adding `%s' to list of device types of backend "
" `%s' \n " , string_entry , current_backend - > name ) ;
if ( type )
2003-01-11 23:42:14 +00:00
{
2006-01-07 21:42:07 +00:00
while ( type - > next )
type = type - > next ;
type - > next = calloc ( 1 , sizeof ( type_entry ) ) ;
type = type - > next ;
2003-01-11 23:42:14 +00:00
}
2006-01-07 21:42:07 +00:00
else
2002-07-07 13:14:03 +00:00
{
2006-01-07 21:42:07 +00:00
current_backend - > type =
calloc ( 1 , sizeof ( type_entry ) ) ;
type = current_backend - > type ;
2003-06-18 09:06:38 +00:00
}
2006-01-07 21:42:07 +00:00
type - > type = type_unknown ;
if ( strcmp ( string_entry , " :scanner " ) = = 0 )
2003-06-18 09:06:38 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting device type of backend `%s' to "
" scanner \n " , current_backend - > name ) ;
type - > type = type_scanner ;
2003-06-18 09:06:38 +00:00
}
2006-01-07 21:42:07 +00:00
else if ( strcmp ( string_entry , " :stillcam " ) = = 0 )
2003-06-18 09:06:38 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting device type of backend `%s' to "
" still camera \n " , current_backend - > name ) ;
type - > type = type_stillcam ;
2003-06-18 09:06:38 +00:00
}
2006-01-07 21:42:07 +00:00
else if ( strcmp ( string_entry , " :vidcam " ) = = 0 )
2003-06-18 09:06:38 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting device type of backend `%s' to "
" video camera \n " , current_backend - > name ) ;
type - > type = type_vidcam ;
2002-07-07 13:14:03 +00:00
}
2006-01-07 21:42:07 +00:00
else if ( strcmp ( string_entry , " :api " ) = = 0 )
2002-07-07 13:14:03 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting device type of backend `%s' to "
" API \n " , current_backend - > name ) ;
type - > type = type_api ;
2002-07-07 13:14:03 +00:00
}
2006-01-07 21:42:07 +00:00
else if ( strcmp ( string_entry , " :meta " ) = = 0 )
2002-07-08 20:24:53 +00:00
{
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting device type of backend `%s' to "
" meta \n " , current_backend - > name ) ;
type - > type = type_meta ;
2002-07-08 20:24:53 +00:00
}
2002-07-07 13:14:03 +00:00
else
{
2004-07-09 16:48:17 +00:00
DBG_ERR
2006-01-07 21:42:07 +00:00
( " unknown device type of backend `%s': `%s' \n " ,
current_backend - > name , string_entry ) ;
type - > type = type_unknown ;
2002-07-07 13:14:03 +00:00
return SANE_FALSE ;
}
2006-01-07 21:42:07 +00:00
current_type = type ;
current_mfg = 0 ;
current_model = 0 ;
continue ;
2002-07-05 19:37:08 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :desc " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
{
if ( ! current_type )
{
DBG_ERR
( " use `:devicetype' keyword first (backend `%s') \n " ,
current_backend - > name ) ;
return SANE_FALSE ;
}
if ( current_type - > type < type_meta )
{
DBG_ERR
( " use `:desc' for `:api' and `:meta' only (backend `%s') \n " ,
current_backend - > name ) ;
return SANE_FALSE ;
}
2002-07-07 13:14:03 +00:00
2006-01-07 21:42:07 +00:00
if ( current_type - > desc )
{
DBG_WARN
( " overwriting description of device type of "
" backend `%s' to `%s' (was: `%s') \n " ,
current_backend - > name , string_entry ,
current_type - > desc ) ;
}
2002-07-07 13:14:03 +00:00
2002-07-06 11:08:01 +00:00
DBG_INFO
2006-01-07 21:42:07 +00:00
( " setting description of backend `%s' to `%s' \n " ,
current_backend - > name , string_entry ) ;
current_type - > desc = calloc ( 1 , sizeof ( desc_entry ) ) ;
if ( ! current_type - > desc )
{
DBG_ERR ( " calloc failed (%s) \n " , strerror ( errno ) ) ;
return SANE_FALSE ;
}
current_type - > desc - > desc = string_entry ;
current_level = level_desc ;
current_mfg = 0 ;
current_model = 0 ;
continue ;
2002-07-05 19:37:08 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword ( line , " :mfg " , param_string , & string_entry )
= = SANE_STATUS_GOOD )
2003-01-11 23:42:14 +00:00
{
2006-01-07 21:42:07 +00:00
mfg_entry * mfg = 0 ;
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( ! current_type )
{
DBG_ERR
( " use `:devicetype' keyword first (backend `%s') \n " ,
current_backend - > name ) ;
return SANE_FALSE ;
}
if ( current_type - > type > = type_meta )
{
DBG_ERR
( " use `:mfg' for hardware devices only (backend `%s') \n " ,
current_backend - > name ) ;
return SANE_FALSE ;
}
2002-07-06 11:08:01 +00:00
2006-01-07 21:42:07 +00:00
mfg = current_type - > mfg ;
if ( mfg )
{
while ( mfg - > next )
mfg = mfg - > next ;
mfg - > next = calloc ( 1 , sizeof ( mfg_entry ) ) ;
mfg = mfg - > next ;
}
else
{
current_type - > mfg = calloc ( 1 , sizeof ( mfg_entry ) ) ;
mfg = current_type - > mfg ;
}
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( ! mfg )
{
DBG_ERR ( " calloc failed (%s) \n " , strerror ( errno ) ) ;
return SANE_FALSE ;
}
mfg - > name = string_entry ;
DBG_INFO ( " adding mfg entry %s to backend `%s' \n " ,
string_entry , current_backend - > name ) ;
current_mfg = mfg ;
current_model = 0 ;
current_level = level_mfg ;
continue ;
2003-01-11 23:42:14 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :model " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
model_entry * model = 0 ;
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( ! current_type )
{
DBG_ERR
( " use `:devicetype' keyword first (backend `%s') \n " ,
current_backend - > name ) ;
return SANE_FALSE ;
}
if ( current_level ! = level_mfg
& & current_level ! = level_model )
{
DBG_ERR
( " use `:mfg' keyword first (backend `%s') \n " ,
current_backend - > name ) ;
return SANE_FALSE ;
}
model = current_mfg - > model ;
if ( model )
{
while ( model - > next )
model = model - > next ;
model - > next = calloc ( 1 , sizeof ( model_entry ) ) ;
model = model - > next ;
}
else
{
current_mfg - > model =
calloc ( 1 , sizeof ( model_entry ) ) ;
model = current_mfg - > model ;
}
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( ! model )
{
DBG_ERR ( " calloc failed (%s) \n " , strerror ( errno ) ) ;
return SANE_FALSE ;
}
model - > name = string_entry ;
model - > status = status_unknown ;
DBG_INFO
( " adding model entry %s to manufacturer `%s' \n " ,
string_entry , current_mfg - > name ) ;
current_model = model ;
current_level = level_model ;
continue ;
2002-07-05 19:37:08 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :interface " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
if ( ! current_model )
{
DBG_WARN
( " ignored `%s' :interface, only allowed for "
" hardware devices \n " , current_backend - > name ) ;
continue ;
}
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
if ( current_model - > interface )
{
DBG_WARN ( " overwriting `%s's interface of model "
" `%s' to `%s' (was: `%s') \n " ,
current_backend - > name ,
current_model - > name , string_entry ,
current_model - > interface ) ;
}
2002-07-05 19:37:08 +00:00
2006-01-07 21:42:07 +00:00
DBG_INFO ( " setting interface of model `%s' to `%s' \n " ,
current_model - > name , string_entry ) ;
current_model - > interface = string_entry ;
2002-07-05 19:37:08 +00:00
continue ;
}
2009-01-13 21:17:16 +00:00
if ( read_keyword
( line , " :scsi " , param_three_strings ,
& three_string_entry ) = = SANE_STATUS_GOOD )
{
if ( ! current_model )
{
DBG_WARN
( " ignored `%s' :scsi, only allowed for "
" hardware devices \n " , current_backend - > name ) ;
continue ;
}
DBG_INFO ( " setting scsi vendor and product ids of model `%s' to `%s/%s' \n " ,
current_model - > name , three_string_entry [ 0 ] , three_string_entry [ 1 ] ) ;
if ( strcasecmp ( three_string_entry [ 0 ] , " ignore " ) = = 0 )
{
DBG_INFO ( " Ignoring `%s's scsi-entries of `%s' \n " ,
current_backend - > name ,
current_model - > name ) ;
continue ;
}
if ( strcasecmp ( three_string_entry [ 2 ] , " processor " ) = = 0 ) {
current_model - > scsi_is_processor = SANE_TRUE ;
current_model - > scsi_vendor_id = three_string_entry [ 0 ] ;
current_model - > scsi_product_id = three_string_entry [ 1 ] ;
}
else
{
DBG_INFO ( " scsi-format info in %s is invalid -> break \n " , current_backend - > name ) ;
continue ;
}
continue ;
}
2006-01-08 15:48:38 +00:00
if ( read_keyword
( line , " :usbid " , param_two_strings ,
& two_string_entry ) = = SANE_STATUS_GOOD )
{
if ( ! current_model )
{
DBG_WARN
( " ignored `%s' :usbid, only allowed for "
" hardware devices \n " , current_backend - > name ) ;
continue ;
}
2006-01-14 19:06:49 +00:00
if ( strcasecmp ( two_string_entry [ 0 ] , " ignore " ) = = 0 )
{
DBG_INFO ( " Ignoring `%s's USB ids of `%s' \n " ,
current_backend - > name ,
current_model - > name ) ;
current_model - > ignore_usb_id = SANE_TRUE ;
continue ;
}
2006-01-08 15:48:38 +00:00
if ( ! check_hex ( two_string_entry [ 0 ] ) )
{
DBG_WARN ( " `%s's USB vendor id of `%s' is "
" not a lowercase 4-digit hex number: "
" `%s' \n " , current_backend - > name ,
current_model - > name , two_string_entry [ 0 ] ) ;
continue ;
}
if ( ! check_hex ( two_string_entry [ 1 ] ) )
{
DBG_WARN ( " `%s's USB product id of `%s' is "
" not a lowercase 4-digit hex number: "
" `%s' \n " , current_backend - > name ,
current_model - > name , two_string_entry [ 1 ] ) ;
continue ;
}
if ( current_model - > usb_vendor_id | | current_model - > usb_product_id )
{
DBG_WARN ( " overwriting `%s's USB ids of model "
" `%s' to `%s/%s' (was: `%s/%s') \n " ,
current_backend - > name ,
current_model - > name , two_string_entry [ 0 ] ,
2013-02-11 06:55:43 +00:00
two_string_entry [ 1 ] ,
2006-01-08 15:48:38 +00:00
current_model - > usb_vendor_id ,
current_model - > usb_product_id ) ;
}
DBG_INFO ( " setting USB vendor and product ids of model `%s' to `%s/%s' \n " ,
current_model - > name , two_string_entry [ 0 ] , two_string_entry [ 1 ] ) ;
current_model - > usb_vendor_id = two_string_entry [ 0 ] ;
current_model - > usb_product_id = two_string_entry [ 1 ] ;
continue ;
}
2006-01-07 21:42:07 +00:00
if ( read_keyword ( line , " :url " , param_string , & string_entry )
= = SANE_STATUS_GOOD )
2003-01-11 23:42:14 +00:00
{
2006-01-07 21:42:07 +00:00
switch ( current_level )
{
case level_backend :
current_backend - > url =
update_url_list ( current_backend - > url ,
string_entry ) ;
DBG_INFO ( " adding `%s' to list of urls of backend "
" `%s' \n " , string_entry ,
current_backend - > name ) ;
break ;
case level_mfg :
current_mfg - > url =
update_url_list ( current_mfg - > url , string_entry ) ;
DBG_INFO ( " adding `%s' to list of urls of mfg "
" `%s' \n " , string_entry ,
current_mfg - > name ) ;
break ;
case level_desc :
current_type - > desc - > url =
update_url_list ( current_type - > desc - > url ,
string_entry ) ;
DBG_INFO
( " adding `%s' to list of urls of description "
" for backend `%s' \n " , string_entry ,
current_backend - > name ) ;
break ;
case level_model :
current_model - > url =
update_url_list ( current_model - > url ,
string_entry ) ;
DBG_INFO ( " adding `%s' to list of urls of model "
" `%s' \n " , string_entry ,
current_model - > name ) ;
break ;
default :
DBG_ERR
( " level %d not implemented for :url (backend `%s') \n " ,
current_level , current_backend - > name ) ;
return SANE_FALSE ;
}
continue ;
2002-07-05 19:37:08 +00:00
}
2006-01-07 21:42:07 +00:00
if ( read_keyword
( line , " :comment " , param_string ,
& string_entry ) = = SANE_STATUS_GOOD )
2002-07-05 19:37:08 +00:00
{
2006-01-07 21:42:07 +00:00
switch ( current_level )
{
case level_backend :
current_backend - > comment = string_entry ;
DBG_INFO ( " setting comment of backend %s to `%s' \n " ,
current_backend - > name , string_entry ) ;
break ;
case level_mfg :
current_mfg - > comment = string_entry ;
DBG_INFO
( " setting comment of manufacturer %s to `%s' \n " ,
current_mfg - > name , string_entry ) ;
break ;
case level_desc :
current_type - > desc - > comment = string_entry ;
DBG_INFO ( " setting comment of description for "
" backend %s to `%s' \n " ,
current_backend - > name , string_entry ) ;
break ;
case level_model :
current_model - > comment = string_entry ;
DBG_INFO ( " setting comment of model %s to `%s' \n " ,
current_model - > name , string_entry ) ;
break ;
default :
DBG_ERR
( " level %d not implemented for `:comment' (backend `%s') \n " ,
current_level , current_backend - > name ) ;
return SANE_FALSE ;
}
continue ;
2002-07-05 19:37:08 +00:00
}
2006-01-07 21:42:07 +00:00
DBG_ERR
( " unknown keyword token in line `%s' of file `%s' \n " ,
line , file_name ) ;
return SANE_FALSE ;
} /* while (sanei_config_readline) */
fclose ( fp ) ;
} /* if (strlen) */
} /* while (direntry) */
2009-08-13 18:15:57 +00:00
if ( closedir ( dir ) ! = 0 )
{
DBG_ERR ( " cannot close directory `%s' (%s) \n " , search_dir ,
strerror ( errno ) ) ;
return SANE_FALSE ;
}
2006-01-07 19:36:24 +00:00
if ( end )
2006-01-07 21:42:07 +00:00
search_dir = end + 1 ;
2006-01-07 19:36:24 +00:00
else
2006-01-07 21:42:07 +00:00
search_dir = ( search_dir + strlen ( search_dir ) ) ;
2006-01-07 19:36:24 +00:00
}
2003-10-17 09:25:56 +00:00
desc_name = 0 ;
2002-07-05 19:37:08 +00:00
if ( ! first_backend )
{
DBG_ERR ( " Couldn't find any .desc file \n " ) ;
return SANE_FALSE ;
}
return SANE_TRUE ;
}
2002-07-17 18:03:51 +00:00
/* Create a model_record_entry based on a model_entry */
static model_record_entry *
create_model_record ( model_entry * model )
{
model_record_entry * model_record ;
model_record = calloc ( 1 , sizeof ( model_record_entry ) ) ;
if ( ! model_record )
{
DBG_ERR ( " create_model_record: couldn't calloc model_record_entry \n " ) ;
exit ( 1 ) ;
}
model_record - > name = model - > name ;
model_record - > status = model - > status ;
model_record - > interface = model - > interface ;
model_record - > url = model - > url ;
model_record - > comment = model - > comment ;
2006-01-08 15:48:38 +00:00
model_record - > usb_vendor_id = model - > usb_vendor_id ;
model_record - > usb_product_id = model - > usb_product_id ;
2009-01-13 21:17:16 +00:00
model_record - > scsi_vendor_id = model - > scsi_vendor_id ;
model_record - > scsi_product_id = model - > scsi_product_id ;
model_record - > scsi_is_processor = model - > scsi_is_processor ;
2002-07-17 18:03:51 +00:00
return model_record ;
}
/* Calculate the priority of statuses: */
2003-06-18 09:06:38 +00:00
/* minimal, basic, good, complete -> 2, untested -> 1, unsupported -> 0 */
2002-07-17 18:03:51 +00:00
static int
calc_priority ( status_entry status )
{
switch ( status )
{
case status_untested :
return 1 ;
case status_unsupported :
return 0 ;
default :
return 2 ;
}
}
/* Insert model into list at the alphabetically correct position */
static model_record_entry *
update_model_record_list ( model_record_entry * first_model_record ,
model_entry * model , backend_entry * be )
2002-07-07 13:14:03 +00:00
{
2002-07-17 18:03:51 +00:00
model_record_entry * model_record = first_model_record ;
2002-07-07 13:14:03 +00:00
2002-07-17 18:03:51 +00:00
if ( ! first_model_record )
2002-07-07 13:14:03 +00:00
{
2002-07-17 18:03:51 +00:00
/* First model for this manufacturer */
first_model_record = create_model_record ( model ) ;
model_record = first_model_record ;
}
else
{
model_record_entry * prev_model_record = 0 ;
while ( model_record )
2002-07-07 13:14:03 +00:00
{
2002-07-17 18:03:51 +00:00
int compare = string_compare ( model - > name , model_record - > name ) ;
if ( compare < = 0 )
2002-07-07 13:14:03 +00:00
{
2002-07-17 18:03:51 +00:00
model_record_entry * tmp_model_record = model_record ;
2006-01-14 19:06:49 +00:00
if ( ( compare = = 0 ) & &
( string_compare ( model - > interface , model_record - > interface ) = = 0 ) & &
( string_compare ( model - > usb_vendor_id , model_record - > usb_vendor_id ) = = 0 ) & &
( string_compare ( model - > usb_product_id , model_record - > usb_product_id ) = = 0 ) )
2002-07-17 18:03:51 +00:00
{
2003-01-11 23:42:14 +00:00
/* Two entries for the same model */
2002-07-17 18:03:51 +00:00
int new_priority = calc_priority ( model - > status ) ;
int old_priority = calc_priority ( model_record - > status ) ;
if ( new_priority < old_priority )
2003-01-11 23:42:14 +00:00
{
2004-07-09 16:48:17 +00:00
DBG_DBG
( " update_model_record_list: model %s ignored, backend %s has "
" higher priority \n " , model - > name ,
model_record - > be - > name ) ;
return first_model_record ;
2003-01-11 23:42:14 +00:00
}
2002-07-17 18:03:51 +00:00
if ( new_priority > old_priority )
2003-01-11 23:42:14 +00:00
{
2004-07-09 16:48:17 +00:00
DBG_DBG
( " update_model_record_list: model %s overrides the one from backend %s \n " ,
model - > name , model_record - > be - > name ) ;
2003-01-11 23:42:14 +00:00
tmp_model_record = model_record - > next ;
}
2002-07-17 18:03:51 +00:00
}
/* correct position */
model_record = create_model_record ( model ) ;
model_record - > next = tmp_model_record ;
if ( ! prev_model_record )
first_model_record = model_record ;
2002-07-07 13:14:03 +00:00
else
2002-07-17 18:03:51 +00:00
prev_model_record - > next = model_record ;
break ;
}
prev_model_record = model_record ;
model_record = model_record - > next ;
}
if ( ! model_record ) /* last entry */
{
prev_model_record - > next = create_model_record ( model ) ;
model_record = prev_model_record - > next ;
}
} /* if (first_model_record) */
model_record - > be = be ;
DBG_DBG ( " update_model_record_list: added model %s \n " , model - > name ) ;
return first_model_record ;
}
/* Insert manufacturer into list at the alphabetically correct position, */
/* create new record if neccessary */
static mfg_record_entry *
update_mfg_record_list ( mfg_record_entry * first_mfg_record , mfg_entry * mfg ,
backend_entry * be )
{
model_entry * model = mfg - > model ;
mfg_record_entry * mfg_record = first_mfg_record ;
while ( mfg_record )
{
if ( string_compare ( mfg_record - > name , mfg - > name ) = = 0 )
{
/* Manufacturer already exists */
url_entry * mfg_url = mfg - > url ;
/* Manufacturer comments and (additional) URLs? */
if ( ! mfg_record - > comment )
mfg_record - > comment = mfg - > comment ;
while ( mfg_url & & mfg_url - > name )
{
mfg_record - > url = update_url_list ( mfg_record - > url ,
mfg_url - > name ) ;
mfg_url = mfg_url - > next ;
2002-07-07 13:14:03 +00:00
}
2002-07-17 18:03:51 +00:00
break ;
2002-07-07 13:14:03 +00:00
}
2002-07-17 18:03:51 +00:00
mfg_record = mfg_record - > next ;
2002-07-07 13:14:03 +00:00
}
2002-07-17 18:03:51 +00:00
if ( ! mfg_record )
{
/* Manufacturer doesn't exist yet */
url_entry * url = mfg - > url ;
mfg_record = calloc ( 1 , sizeof ( mfg_record_entry ) ) ;
if ( ! mfg_record )
{
DBG_ERR ( " update_mfg_record_list: couldn't calloc "
" mfg_record_entry \n " ) ;
exit ( 1 ) ;
}
mfg_record - > name = mfg - > name ;
mfg_record - > comment = mfg - > comment ;
while ( url )
{
mfg_record - > url = update_url_list ( mfg_record - > url , url - > name ) ;
url = url - > next ;
}
if ( first_mfg_record ! = 0 )
{
/* We already have one manufacturer in the list */
mfg_record_entry * new_mfg_record = mfg_record ;
mfg_record_entry * prev_mfg_record = 0 ;
mfg_record = first_mfg_record ;
while ( mfg_record )
{
int compare =
string_compare ( new_mfg_record - > name , mfg_record - > name ) ;
if ( compare < = 0 )
{
mfg_record_entry * tmp_mfg_record = mfg_record ;
mfg_record = new_mfg_record ;
mfg_record - > next = tmp_mfg_record ;
if ( ! prev_mfg_record )
first_mfg_record = mfg_record ;
else
prev_mfg_record - > next = mfg_record ;
break ;
}
prev_mfg_record = mfg_record ;
mfg_record = mfg_record - > next ;
}
if ( ! mfg_record ) /* last entry */
{
prev_mfg_record - > next = new_mfg_record ;
mfg_record = prev_mfg_record - > next ;
}
}
else
first_mfg_record = mfg_record ;
DBG_DBG ( " update_mfg_record_list: created mfg %s \n " , mfg_record - > name ) ;
} /* if (!mfg_record) */
/* create model entries */
while ( model )
{
mfg_record - > model_record =
update_model_record_list ( mfg_record - > model_record , model , be ) ;
model = model - > next ;
}
return first_mfg_record ;
2002-07-07 13:14:03 +00:00
}
2002-07-17 18:03:51 +00:00
/* Create a sorted list of manufacturers based on the backends list */
2002-07-05 19:37:08 +00:00
static mfg_record_entry *
2002-07-17 18:03:51 +00:00
create_mfg_list ( device_type dev_type )
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
mfg_record_entry * first_mfg_record = 0 ;
2002-07-05 19:37:08 +00:00
backend_entry * be = first_backend ;
2002-07-17 18:03:51 +00:00
DBG_DBG ( " create_mfg_list: start \n " ) ;
2002-07-05 19:37:08 +00:00
while ( be )
{
type_entry * type = be - > type ;
while ( type )
{
if ( type - > type = = dev_type )
{
mfg_entry * mfg = type - > mfg ;
while ( mfg )
{
2002-07-17 18:03:51 +00:00
first_mfg_record =
update_mfg_record_list ( first_mfg_record , mfg , be ) ;
2002-07-05 19:37:08 +00:00
mfg = mfg - > next ;
2002-07-17 18:03:51 +00:00
}
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
type = type - > next ;
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
be = be - > next ;
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
DBG_DBG ( " create_mfg_list: exit \n " ) ;
2002-07-05 19:37:08 +00:00
return first_mfg_record ;
}
2002-07-17 18:03:51 +00:00
/* Print an ASCII list with all the information we have */
2002-07-05 19:37:08 +00:00
static void
ascii_print_backends ( void )
{
backend_entry * be ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
be = first_backend ;
while ( be )
{
url_entry * url = be - > url ;
type_entry * type = be - > type ;
if ( be - > name )
printf ( " backend `%s' \n " , be - > name ) ;
else
printf ( " backend *none* \n " ) ;
if ( be - > version )
printf ( " version `%s' \n " , be - > version ) ;
else
printf ( " version *none* \n " ) ;
if ( be - > new )
printf ( " NEW! \n " ) ;
if ( be - > manpage )
printf ( " manpage `%s' \n " , be - > manpage ) ;
else
printf ( " manpage *none* \n " ) ;
if ( url )
while ( url )
{
printf ( " url `%s' \n " , url - > name ) ;
url = url - > next ;
}
else
printf ( " url *none* \n " ) ;
if ( be - > comment )
printf ( " comment `%s' \n " , be - > comment ) ;
else
printf ( " comment *none* \n " ) ;
if ( type )
while ( type )
{
switch ( type - > type )
{
case type_scanner :
printf ( " type scanner \n " ) ;
break ;
case type_stillcam :
printf ( " type stillcam \n " ) ;
break ;
case type_vidcam :
printf ( " type vidcam \n " ) ;
break ;
case type_meta :
printf ( " type meta \n " ) ;
break ;
case type_api :
printf ( " type api \n " ) ;
break ;
default :
printf ( " type *unknown* \n " ) ;
break ;
}
if ( type - > desc )
{
url_entry * url = type - > desc - > url ;
printf ( " desc `%s' \n " , type - > desc - > desc ) ;
if ( url )
while ( url )
{
printf ( " url `%s' \n " , url - > name ) ;
url = url - > next ;
}
else
printf ( " url *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
if ( type - > desc - > comment )
printf ( " comment `%s' \n " , type - > desc - > comment ) ;
else
printf ( " comment *none* \n " ) ;
}
else if ( type - > type > = type_meta )
printf ( " desc *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
if ( type - > mfg )
{
mfg_entry * mfg = type - > mfg ;
while ( mfg )
{
model_entry * model = mfg - > model ;
url_entry * url = mfg - > url ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
printf ( " mfg `%s' \n " , mfg - > name ) ;
if ( url )
while ( url )
{
printf ( " url `%s' \n " , url - > name ) ;
url = url - > next ;
}
else
printf ( " url *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
if ( mfg - > comment )
printf ( " comment `%s' \n " , mfg - > comment ) ;
else
printf ( " comment *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
if ( model )
while ( model )
{
url_entry * url = model - > url ;
printf ( " model `%s' \n " , model - > name ) ;
if ( model - > interface )
2002-07-06 11:08:01 +00:00
printf ( " interface `%s' \n " , model - > interface ) ;
2002-07-05 19:37:08 +00:00
else
printf ( " interface *none* \n " ) ;
2006-01-08 15:48:38 +00:00
if ( model - > usb_vendor_id )
printf ( " usb-vendor-id `%s' \n " , model - > usb_vendor_id ) ;
else
printf ( " usb-vendor-id *none* \n " ) ;
if ( model - > usb_product_id )
printf ( " usb-product-id `%s' \n " , model - > usb_product_id ) ;
else
printf ( " usb-product-id *none* \n " ) ;
2002-07-07 13:14:03 +00:00
switch ( model - > status )
{
2003-06-18 09:06:38 +00:00
case status_minimal :
printf ( " status minimal \n " ) ;
break ;
case status_basic :
printf ( " status basic \n " ) ;
2002-07-07 13:14:03 +00:00
break ;
2003-06-18 09:06:38 +00:00
case status_good :
printf ( " status good \n " ) ;
2002-07-07 13:14:03 +00:00
break ;
2003-06-18 09:06:38 +00:00
case status_complete :
printf ( " status complete \n " ) ;
2002-07-07 13:14:03 +00:00
break ;
case status_untested :
printf ( " status untested \n " ) ;
break ;
2002-07-08 20:24:53 +00:00
case status_unsupported :
printf ( " status unsupported \n " ) ;
break ;
2002-07-07 13:14:03 +00:00
default :
printf ( " status *unknown* \n " ) ;
break ;
}
2002-07-05 19:37:08 +00:00
if ( url )
while ( url )
{
printf ( " url `%s' \n " , url - > name ) ;
url = url - > next ;
}
else
printf ( " url *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
if ( model - > comment )
printf ( " comment `%s' \n " , model - > comment ) ;
else
printf ( " comment *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
model = model - > next ;
}
else
printf ( " model *none* \n " ) ;
2002-07-06 11:08:01 +00:00
2002-07-05 19:37:08 +00:00
mfg = mfg - > next ;
2002-07-06 11:08:01 +00:00
} /* while (mfg) */
2002-07-05 19:37:08 +00:00
}
else if ( type - > type < type_meta )
printf ( " mfg *none* \n " ) ;
type = type - > next ;
2002-07-06 11:08:01 +00:00
} /* while (type) */
2002-07-05 19:37:08 +00:00
else
printf ( " type *none* \n " ) ;
be = be - > next ;
2002-07-06 11:08:01 +00:00
} /* while (be) */
2002-07-05 19:37:08 +00:00
}
2004-07-09 16:48:17 +00:00
static char *
clean_string ( char * c )
{
/* not avoided characters */
char * aux ;
aux = malloc ( strlen ( c ) * sizeof ( char ) * 6 ) ;
* aux = ' \0 ' ;
while ( * c ! = ' \0 ' )
{
2009-03-13 13:48:44 +00:00
/*limit to printable ASCII only*/
if ( * c < 0x20 | | * c > 0x7e ) {
c + + ;
continue ;
}
2004-07-09 16:48:17 +00:00
switch ( * c )
{
case ' < ' :
aux = strcat ( aux , " < " ) ;
break ;
case ' > ' :
aux = strcat ( aux , " > " ) ;
break ;
case ' \' ' :
aux = strcat ( aux , " ' " ) ;
break ;
case ' & ' :
aux = strcat ( aux , " & " ) ;
break ;
default :
aux = strncat ( aux , c , 1 ) ;
}
c = c + 1 ;
}
return aux ;
}
2004-06-28 18:46:35 +00:00
/* Print an XML list with all the information we have */
2004-07-09 16:48:17 +00:00
static void
2004-06-28 18:46:35 +00:00
xml_print_backends ( void )
{
backend_entry * be ;
be = first_backend ;
2004-07-09 16:48:17 +00:00
printf ( " <backends> \n " ) ;
while ( be )
2004-06-28 18:46:35 +00:00
{
url_entry * url = be - > url ;
type_entry * type = be - > type ;
if ( be - > name )
2004-07-09 16:48:17 +00:00
printf ( " <backend name= \" %s \" > \n " , clean_string ( be - > name ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <backend name= \" *none \" > \n " ) ;
if ( be - > version )
2017-05-30 13:39:30 +00:00
printf ( " <version>%s</version> \n " , clean_string ( be - > version ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <version>*none*</version> \n " ) ;
if ( be - > new )
2004-07-09 16:48:17 +00:00
printf ( " <new state= \" yes \" /> \n " ) ;
else
printf ( " <new state= \" no \" /> \n " ) ;
2004-06-28 18:46:35 +00:00
if ( be - > manpage )
2004-07-09 16:48:17 +00:00
printf ( " <manpage>%s</manpage> \n " , clean_string ( be - > manpage ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <manpage>*none*</manpage> \n " ) ;
if ( url )
while ( url )
{
2004-07-09 16:48:17 +00:00
printf ( " <url>%s</url> \n " , clean_string ( url - > name ) ) ;
2004-06-28 18:46:35 +00:00
url = url - > next ;
}
else
printf ( " <url>*none*</url> \n " ) ;
if ( be - > comment )
2004-07-09 16:48:17 +00:00
printf ( " <comment>%s</comment> \n " , clean_string ( be - > comment ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <comment>*none*</comment> \n " ) ;
if ( type )
while ( type )
{
2004-07-09 16:48:17 +00:00
2004-06-28 18:46:35 +00:00
switch ( type - > type )
{
case type_scanner :
2004-07-09 16:48:17 +00:00
printf ( " <type def= \" scanner \" > \n " ) ;
2004-06-28 18:46:35 +00:00
break ;
case type_stillcam :
2004-07-09 16:48:17 +00:00
printf ( " <type def= \" stillcam \" > \n " ) ;
2004-06-28 18:46:35 +00:00
break ;
case type_vidcam :
2004-07-09 16:48:17 +00:00
printf ( " <type def= \" vidcam \" > \n " ) ;
2004-06-28 18:46:35 +00:00
break ;
case type_meta :
2004-07-09 16:48:17 +00:00
printf ( " <type def= \" meta \" > \n " ) ;
2004-06-28 18:46:35 +00:00
break ;
case type_api :
2004-07-09 16:48:17 +00:00
printf ( " <type def= \" api \" > \n " ) ;
2004-06-28 18:46:35 +00:00
break ;
default :
2004-07-09 16:48:17 +00:00
printf ( " <type def= \" *unknown* \" > \n " ) ;
2004-06-28 18:46:35 +00:00
break ;
}
if ( type - > desc )
{
url_entry * url = type - > desc - > url ;
2004-07-09 16:48:17 +00:00
printf ( " <desc>%s</desc> \n " ,
clean_string ( type - > desc - > desc ) ) ;
2004-06-28 18:46:35 +00:00
if ( url )
while ( url )
{
2004-07-09 16:48:17 +00:00
printf ( " <url>%s</url> \n " , clean_string ( url - > name ) ) ;
2004-06-28 18:46:35 +00:00
url = url - > next ;
}
else
printf ( " <url>*none*</url> \n " ) ;
if ( type - > desc - > comment )
2004-07-09 16:48:17 +00:00
printf ( " <comment>%s</comment> \n " ,
clean_string ( type - > desc - > comment ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <comment>*none*</comment> \n " ) ;
}
else if ( type - > type > = type_meta )
printf ( " <desc>*none*</desc> \n " ) ;
if ( type - > mfg )
{
mfg_entry * mfg = type - > mfg ;
while ( mfg )
{
model_entry * model = mfg - > model ;
url_entry * url = mfg - > url ;
2004-07-09 16:48:17 +00:00
printf ( " <mfg name= \" %s \" > \n " , clean_string ( mfg - > name ) ) ;
2004-06-28 18:46:35 +00:00
if ( url )
while ( url )
{
2004-07-09 16:48:17 +00:00
printf ( " <url>`%s'</url> \n " ,
clean_string ( url - > name ) ) ;
2004-06-28 18:46:35 +00:00
url = url - > next ;
}
else
printf ( " <url>*none*</url> \n " ) ;
if ( mfg - > comment )
2004-07-09 16:48:17 +00:00
printf ( " <comment>%s</comment> \n " ,
clean_string ( mfg - > comment ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <comment>*none*</comment> \n " ) ;
if ( model )
while ( model )
{
url_entry * url = model - > url ;
2004-07-09 16:48:17 +00:00
printf ( " <model name= \" %s \" > \n " ,
clean_string ( model - > name ) ) ;
2004-06-28 18:46:35 +00:00
if ( model - > interface )
2004-07-09 16:48:17 +00:00
printf ( " <interface>%s</interface> \n " ,
clean_string ( model - > interface ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <interface>*none*</interface> \n " ) ;
2006-01-08 15:48:38 +00:00
if ( model - > usb_vendor_id )
printf ( " <usbvendorid>%s</usbvendorid> \n " ,
clean_string ( model - > usb_vendor_id ) ) ;
else
printf ( " <usbvendorid>*none*</usbvendorid> \n " ) ;
if ( model - > usb_product_id )
printf ( " <usbproductid>%s</usbproductid> \n " ,
clean_string ( model - > usb_product_id ) ) ;
else
printf ( " <usbproductid>*none*</usbproductid> \n " ) ;
2004-06-28 18:46:35 +00:00
switch ( model - > status )
{
case status_minimal :
printf ( " <status>minimal</status> \n " ) ;
break ;
case status_basic :
printf ( " <status>basic</status> \n " ) ;
break ;
case status_good :
printf ( " <status>good</status> \n " ) ;
break ;
case status_complete :
printf ( " <status>complete</status> \n " ) ;
break ;
case status_untested :
printf ( " <status>untested</status> \n " ) ;
break ;
case status_unsupported :
printf ( " <status>unsupported</status> \n " ) ;
break ;
default :
printf ( " <status>*unknown*</status> \n " ) ;
break ;
}
if ( url )
while ( url )
{
2004-07-09 16:48:17 +00:00
printf ( " <url>%s</url> \n " ,
clean_string ( url - > name ) ) ;
2004-06-28 18:46:35 +00:00
url = url - > next ;
}
else
printf ( " <url>*none*</url> \n " ) ;
if ( model - > comment )
2004-07-09 16:48:17 +00:00
printf ( " <comment>%s</comment> \n " ,
clean_string ( model - > comment ) ) ;
2004-06-28 18:46:35 +00:00
else
printf ( " <comment>*none*</comment> \n " ) ;
model = model - > next ;
2004-07-09 16:48:17 +00:00
printf ( " </model> \n " ) ;
} /* while (model) */
2004-06-28 18:46:35 +00:00
else
printf ( " <model name= \" *none* \" /> \n " ) ;
2004-07-09 16:48:17 +00:00
printf ( " </mfg> \n " ) ;
2004-06-28 18:46:35 +00:00
mfg = mfg - > next ;
} /* while (mfg) */
}
else if ( type - > type < type_meta )
printf ( " <mfg>*none*</mfg> \n " ) ;
type = type - > next ;
2004-07-09 16:48:17 +00:00
printf ( " </type> \n " ) ;
2004-06-28 18:46:35 +00:00
} /* while (type) */
else
printf ( " <type>*none*</type> \n " ) ;
2004-07-09 16:48:17 +00:00
printf ( " </backend> \n " ) ;
2004-06-28 18:46:35 +00:00
be = be - > next ;
} /* while (be) */
2004-07-09 16:48:17 +00:00
printf ( " </backends> \n " ) ;
2004-06-28 18:46:35 +00:00
}
2006-01-07 23:44:09 +00:00
/* calculate statistics about supported devices per device type*/
static void
calculate_statistics_per_type ( device_type dev_type , statistics_type num )
{
backend_entry * be = first_backend ;
while ( be )
{
type_entry * type = be - > type ;
while ( type )
{
if ( type - > type = = dev_type )
{
mfg_entry * mfg = type - > mfg ;
model_entry * model ;
if ( type - > desc )
{
num [ status_complete ] + + ;
type = type - > next ;
continue ;
}
if ( ! mfg )
{
type = type - > next ;
continue ;
}
mfg = type - > mfg ;
while ( mfg )
{
model = mfg - > model ;
if ( model )
{
while ( model )
{
enum status_entry status = model - > status ;
num [ status ] + + ;
model = model - > next ;
} /* while (model) */
} /* if (num_models) */
mfg = mfg - > next ;
} /* while (mfg) */
} /* if (type->type) */
type = type - > next ;
} /* while (type) */
be = be - > next ;
} /* while (be) */
}
static void
html_print_statistics_cell ( const char * color , int number )
{
2013-02-11 06:55:43 +00:00
printf ( " <td align=center><font color=%s>%d</font></td> \n " ,
2006-01-07 23:44:09 +00:00
color , number ) ;
}
static void
html_print_statistics_per_type ( device_type dev_type )
{
statistics_type num = { 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
status_entry status ;
calculate_statistics_per_type ( dev_type , num ) ;
printf ( " <tr> \n " ) ;
2013-02-11 06:55:43 +00:00
printf ( " <td align=center><a href= \" #%s \" >%s</a></td> \n " ,
2006-01-07 23:44:09 +00:00
device_type_aname [ dev_type ] , device_type_name [ dev_type ] ) ;
2013-02-11 06:55:43 +00:00
html_print_statistics_cell
( COLOR_UNKNOWN ,
2006-01-07 23:44:09 +00:00
num [ status_minimal ] + num [ status_basic ] + num [ status_good ] +
2009-04-14 03:54:01 +00:00
num [ status_complete ] + num [ status_untested ] + num [ status_unsupported ] ) ;
2006-01-07 23:44:09 +00:00
if ( dev_type = = type_scanner | | dev_type = = type_stillcam
| | dev_type = = type_vidcam )
{
2013-02-11 06:55:43 +00:00
html_print_statistics_cell
( COLOR_UNKNOWN ,
2006-01-07 23:44:09 +00:00
num [ status_minimal ] + num [ status_basic ] + num [ status_good ] +
num [ status_complete ] ) ;
for ( status = status_complete ; status > = status_unsupported ; status - - )
html_print_statistics_cell ( status_color [ status ] , num [ status ] ) ;
}
else
{
printf ( " <td align=center colspan=7>n/a</td> \n " ) ;
}
printf ( " </tr> \n " ) ;
}
/* print html statistcis */
static void
html_print_summary ( void )
{
device_type dev_type ;
status_entry status ;
printf ( " <h2>Summary</h2> \n " ) ;
printf ( " <table border=1> \n " ) ;
printf ( " <tr bgcolor=E0E0FF> \n " ) ;
printf ( " <th align=center rowspan=3>Device type</th> \n " ) ;
printf ( " <th align=center colspan=8>Number of devices</th> \n " ) ;
printf ( " </tr> \n " ) ;
printf ( " <tr bgcolor=E0E0FF> \n " ) ;
printf ( " <th align=center rowspan=2>Total</th> \n " ) ;
printf ( " <th align=center colspan=5>Supported</th> \n " ) ;
2013-02-11 06:55:43 +00:00
printf ( " <th align=center rowspan=2><font color= " COLOR_UNTESTED
2006-01-07 23:44:09 +00:00
" >%s</font></th> \n " , status_name [ status_untested ] ) ;
printf ( " <th align=center rowspan=2><font color= " COLOR_UNSUPPORTED
" >%s</font></th> \n " , status_name [ status_unsupported ] ) ;
printf ( " </tr> \n " ) ;
printf ( " <tr bgcolor=E0E0FF> \n " ) ;
printf ( " <th align=center>Sum</th> \n " ) ;
for ( status = status_complete ; status > = status_minimal ; status - - )
printf ( " <th align=center><font color=%s>%s</font></th> \n " ,
status_color [ status ] , status_name [ status ] ) ;
printf ( " </tr> \n " ) ;
for ( dev_type = type_scanner ; dev_type < = type_api ; dev_type + + )
html_print_statistics_per_type ( dev_type ) ;
printf ( " </table> \n " ) ;
}
2004-06-28 18:46:35 +00:00
2002-07-17 18:03:51 +00:00
/* Generate a name used for <a name=...> HTML tags */
2002-07-07 13:14:03 +00:00
static char *
2004-01-11 18:05:47 +00:00
html_generate_anchor_name ( device_type dev_type , char * manufacturer_name )
2002-07-07 13:14:03 +00:00
{
2004-01-11 18:05:47 +00:00
char * name = malloc ( strlen ( manufacturer_name ) + 1 + 2 ) ;
2002-07-07 13:14:03 +00:00
char * pointer = name ;
2004-01-11 18:05:47 +00:00
char type_char ;
2002-07-07 13:14:03 +00:00
if ( ! name )
{
2004-01-11 18:05:47 +00:00
DBG_ERR ( " html_generate_anchor_name: couldn't malloc \n " ) ;
return 0 ;
}
switch ( dev_type )
{
2004-07-09 16:48:17 +00:00
case type_scanner :
type_char = ' S ' ;
break ;
case type_stillcam :
type_char = ' C ' ;
break ;
case type_vidcam :
type_char = ' V ' ;
break ;
case type_meta :
type_char = ' M ' ;
break ;
case type_api :
type_char = ' A ' ;
break ;
default :
type_char = ' Z ' ;
break ;
2002-07-07 13:14:03 +00:00
}
2004-01-11 18:05:47 +00:00
2004-07-09 16:48:17 +00:00
snprintf ( name , strlen ( manufacturer_name ) + 1 + 2 , " %c-%s " ,
2004-01-11 18:05:47 +00:00
type_char , manufacturer_name ) ;
2002-07-07 13:14:03 +00:00
while ( * pointer )
{
if ( ! isalnum ( * pointer ) )
* pointer = ' - ' ;
else
* pointer = toupper ( * pointer ) ;
pointer + + ;
}
return name ;
}
2002-07-05 19:37:08 +00:00
2002-07-17 18:03:51 +00:00
/* Generate one table per backend of all backends providing models */
/* of type dev_type */
2002-07-12 20:17:53 +00:00
static void
html_backends_split_table ( device_type dev_type )
{
backend_entry * be = first_backend ;
SANE_Bool first = SANE_TRUE ;
2017-05-30 13:39:30 +00:00
printf ( " <p><b>Backends</b>: \n " ) ;
2002-07-12 20:17:53 +00:00
while ( be ) /* print link list */
{
type_entry * type = be - > type ;
SANE_Bool found = SANE_FALSE ;
while ( type )
{
if ( type - > type = = dev_type )
found = SANE_TRUE ;
type = type - > next ;
}
if ( found )
{
if ( ! first )
2017-05-30 13:39:30 +00:00
printf ( " , \n " ) ;
2002-07-12 20:17:53 +00:00
first = SANE_FALSE ;
printf ( " <a href= \" #%s \" >%s</a> " ,
2004-01-11 18:52:00 +00:00
html_generate_anchor_name ( dev_type , be - > name ) , be - > name ) ;
2002-07-12 20:17:53 +00:00
}
be = be - > next ;
}
be = first_backend ;
if ( first )
printf ( " (none) \n " ) ;
printf ( " </p> \n " ) ;
while ( be )
{
type_entry * type = be - > type ;
while ( type )
{
if ( type - > type = = dev_type )
{
mfg_entry * mfg = type - > mfg ;
2003-04-30 23:11:50 +00:00
model_entry * model ;
2002-07-12 20:17:53 +00:00
printf ( " <h3><a name= \" %s \" >Backend: %s \n " ,
2004-07-09 16:48:17 +00:00
html_generate_anchor_name ( type - > type , be - > name ) ,
be - > name ) ;
2002-07-12 20:17:53 +00:00
if ( be - > version | | be - > new )
{
printf ( " ( " ) ;
if ( be - > version )
{
2003-06-18 09:06:38 +00:00
printf ( " %s " , be - > version ) ;
2002-07-12 20:17:53 +00:00
if ( be - > new )
printf ( " , <font color= " COLOR_NEW " >NEW!</font> " ) ;
}
else
printf ( " <font color= " COLOR_NEW " >NEW!</font> " ) ;
printf ( " ) \n " ) ;
}
printf ( " </a></h3> \n " ) ;
printf ( " <p> \n " ) ;
if ( be - > url & & be - > url - > name )
{
url_entry * url = be - > url ;
2017-05-30 13:39:30 +00:00
printf ( " <b>Link(s):</b> \n " ) ;
2002-07-12 20:17:53 +00:00
while ( url )
{
if ( url ! = be - > url )
printf ( " , " ) ;
printf ( " <a href= \" %s \" >%s</a> " , url - > name , url - > name ) ;
url = url - > next ;
}
printf ( " <br> \n " ) ;
}
if ( be - > manpage )
printf ( " <b>Manual page:</b> <a href= \" " MAN_PAGE_LINK
" \" >%s</a><br> \n " , be - > manpage , be - > manpage ) ;
if ( be - > comment )
printf ( " <b>Comment:</b> %s<br> \n " , be - > comment ) ;
2003-06-18 09:06:38 +00:00
2002-07-12 20:17:53 +00:00
if ( type - > desc )
{
if ( type - > desc - > desc )
{
if ( type - > desc - > url & & type - > desc - > url - > name )
printf ( " <b>Description:</b> "
" <a href= \" %s \" >%s</a><br> \n " ,
type - > desc - > url - > name , type - > desc - > desc ) ;
else
printf ( " <b>Description:</b> %s<br> \n " ,
type - > desc - > desc ) ;
}
if ( type - > desc - > comment )
printf ( " <b>Comment:</b> %s<br> \n " , type - > desc - > comment ) ;
printf ( " </p> \n " ) ;
type = type - > next ;
continue ;
}
printf ( " </p> \n " ) ;
if ( ! mfg )
{
type = type - > next ;
continue ;
}
printf ( " <table border=1> \n " ) ;
printf ( " <tr bgcolor=E0E0FF> \n " ) ;
printf ( " <th align=center>Manufacturer</th> \n " ) ;
printf ( " <th align=center>Model</th> \n " ) ;
printf ( " <th align=center>Interface</th> \n " ) ;
2006-01-08 15:48:38 +00:00
printf ( " <th align=center>USB id</th> \n " ) ;
2002-07-12 20:17:53 +00:00
printf ( " <th align=center>Status</th> \n " ) ;
printf ( " <th align=center>Comment</th> \n " ) ;
printf ( " </tr> \n " ) ;
mfg = type - > mfg ;
while ( mfg )
{
model = mfg - > model ;
if ( model )
{
int num_models = 0 ;
while ( model ) /* count models for rowspan */
{
model = model - > next ;
num_models + + ;
}
model = mfg - > model ;
printf ( " <tr> \n " ) ;
printf ( " <td align=center rowspan=%d> \n " , num_models ) ;
if ( mfg - > url & & mfg - > url - > name )
printf ( " <a href= \" %s \" >%s</a> \n " , mfg - > url - > name ,
mfg - > name ) ;
else
printf ( " %s \n " , mfg - > name ) ;
while ( model )
{
enum status_entry status = model - > status ;
if ( model ! = mfg - > model )
printf ( " <tr> \n " ) ;
if ( model - > url & & model - > url - > name )
printf
( " <td align=center><a href= \" %s \" >%s</a></td> \n " ,
model - > url - > name , model - > name ) ;
else
printf ( " <td align=center>%s</td> \n " ,
model - > name ) ;
if ( model - > interface )
printf ( " <td align=center>%s</td> \n " ,
model - > interface ) ;
else
printf ( " <td align=center>?</td> \n " ) ;
2006-01-08 15:48:38 +00:00
if ( model - > usb_vendor_id & & model - > usb_product_id )
2013-02-11 06:55:43 +00:00
printf ( " <td align=center>%s/%s</td> \n " ,
2006-01-08 15:48:38 +00:00
model - > usb_vendor_id , model - > usb_product_id ) ;
else
printf ( " <td align=center> </td> \n " ) ;
2013-02-11 06:55:43 +00:00
printf ( " <td align=center><font color=%s>%s</font></td> \n " ,
2006-01-07 23:44:09 +00:00
status_color [ status ] , status_name [ status ] ) ;
2002-07-12 20:17:53 +00:00
if ( model - > comment & & model - > comment [ 0 ] ! = 0 )
printf ( " <td>%s</td> \n " , model - > comment ) ;
else
printf ( " <td> </td> \n " ) ;
model = model - > next ;
printf ( " </tr> \n " ) ;
} /* while (model) */
} /* if (num_models) */
mfg = mfg - > next ;
} /* while (mfg) */
2003-04-14 19:52:57 +00:00
printf ( " </table> \n " ) ;
2002-07-12 20:17:53 +00:00
} /* if (type->type) */
type = type - > next ;
} /* while (type) */
be = be - > next ;
} /* while (be) */
2004-07-09 16:48:17 +00:00
/* printf ("</table>\n"); */
2002-07-12 20:17:53 +00:00
}
2002-07-17 18:03:51 +00:00
/* Generate one table per manufacturer constructed of all backends */
/* providing models of type dev_type */
2002-07-05 19:37:08 +00:00
static void
html_mfgs_table ( device_type dev_type )
{
mfg_record_entry * mfg_record = 0 , * first_mfg_record = 0 ;
2002-07-17 18:03:51 +00:00
first_mfg_record = create_mfg_list ( dev_type ) ;
2002-07-05 19:37:08 +00:00
mfg_record = first_mfg_record ;
2017-05-30 13:39:30 +00:00
printf ( " <p><b>Manufacturers</b>: \n " ) ;
2002-07-07 13:14:03 +00:00
while ( mfg_record )
{
if ( mfg_record ! = first_mfg_record )
2017-05-30 13:39:30 +00:00
printf ( " , \n " ) ;
2002-07-07 13:14:03 +00:00
printf ( " <a href= \" #%s \" >%s</a> " ,
2004-07-09 16:48:17 +00:00
html_generate_anchor_name ( type_unknown , mfg_record - > name ) ,
mfg_record - > name ) ;
2002-07-07 13:14:03 +00:00
mfg_record = mfg_record - > next ;
}
mfg_record = first_mfg_record ;
2002-07-12 20:17:53 +00:00
if ( ! mfg_record )
printf ( " (none) \n " ) ;
printf ( " </p> \n " ) ;
2002-07-06 22:14:34 +00:00
while ( mfg_record )
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
model_record_entry * model_record = mfg_record - > model_record ;
2002-07-06 22:14:34 +00:00
2002-07-07 13:14:03 +00:00
printf ( " <h3><a name= \" %s \" >Manufacturer: %s</a></h3> \n " ,
2004-07-09 16:48:17 +00:00
html_generate_anchor_name ( type_unknown , mfg_record - > name ) ,
mfg_record - > name ) ;
2002-07-12 20:17:53 +00:00
printf ( " <p> \n " ) ;
2002-07-06 22:14:34 +00:00
if ( mfg_record - > url & & mfg_record - > url - > name )
{
url_entry * url = mfg_record - > url ;
2017-05-30 13:39:30 +00:00
printf ( " <b>Link(s):</b> \n " ) ;
2002-07-06 22:14:34 +00:00
while ( url )
{
if ( url ! = mfg_record - > url )
printf ( " , " ) ;
printf ( " <a href= \" %s \" >%s</a> " , url - > name , url - > name ) ;
url = url - > next ;
}
2002-07-12 20:17:53 +00:00
printf ( " <br> \n " ) ;
}
if ( mfg_record - > comment )
printf ( " <b>Comment:</b> %s<br> \n " , mfg_record - > comment ) ;
printf ( " </p> \n " ) ;
2002-07-17 18:03:51 +00:00
if ( ! model_record )
2002-07-12 20:17:53 +00:00
{
mfg_record = mfg_record - > next ;
continue ;
2002-07-06 22:14:34 +00:00
}
printf ( " <table border=1> \n " ) ;
printf ( " <tr bgcolor=E0E0FF> \n " ) ;
2002-07-05 19:37:08 +00:00
printf ( " <th align=center>Model</th> \n " ) ;
printf ( " <th align=center>Interface</th> \n " ) ;
2006-01-08 15:48:38 +00:00
printf ( " <th align=center>USB id</th> \n " ) ;
2002-07-07 13:14:03 +00:00
printf ( " <th align=center>Status</th> \n " ) ;
2002-07-05 19:37:08 +00:00
printf ( " <th align=center>Comment</th> \n " ) ;
printf ( " <th align=center>Backend</th> \n " ) ;
printf ( " <th align=center>Manpage</th> \n " ) ;
2002-07-06 22:14:34 +00:00
printf ( " </tr> \n " ) ;
2002-07-05 19:37:08 +00:00
2002-07-17 18:03:51 +00:00
while ( model_record )
2002-07-05 19:37:08 +00:00
{
2002-07-17 18:03:51 +00:00
enum status_entry status = model_record - > status ;
2002-07-07 13:14:03 +00:00
2002-07-17 18:03:51 +00:00
if ( model_record - > url & & model_record - > url - > name )
printf ( " <tr><td align=center><a "
" href= \" %s \" >%s</a></td> \n " ,
model_record - > url - > name , model_record - > name ) ;
else
2003-04-14 19:52:57 +00:00
printf ( " <tr><td align=center>%s</td> \n " , model_record - > name ) ;
2002-07-07 13:14:03 +00:00
2002-07-17 18:03:51 +00:00
if ( model_record - > interface )
printf ( " <td align=center>%s</td> \n " , model_record - > interface ) ;
else
printf ( " <td align=center>?</td> \n " ) ;
2006-01-08 15:48:38 +00:00
if ( model_record - > usb_vendor_id & & model_record - > usb_product_id )
2013-02-11 06:55:43 +00:00
printf ( " <td align=center>%s/%s</td> \n " ,
2006-01-08 15:48:38 +00:00
model_record - > usb_vendor_id , model_record - > usb_product_id ) ;
else
printf ( " <td align=center> </td> \n " ) ;
2013-02-11 06:55:43 +00:00
printf ( " <td align=center><font color=%s>%s</font></td> \n " ,
2006-01-07 23:44:09 +00:00
status_color [ status ] , status_name [ status ] ) ;
2002-07-06 11:08:01 +00:00
2002-07-17 18:03:51 +00:00
if ( model_record - > comment & & model_record - > comment [ 0 ] ! = 0 )
printf ( " <td>%s</td> \n " , model_record - > comment ) ;
else
printf ( " <td> </td> \n " ) ;
2002-07-07 13:14:03 +00:00
2002-07-17 18:03:51 +00:00
printf ( " <td align=center> \n " ) ;
if ( model_record - > be - > url & & model_record - > be - > url - > name )
printf ( " <a href= \" %s \" >%s</a> \n " ,
model_record - > be - > url - > name , model_record - > be - > name ) ;
else
printf ( " %s " , model_record - > be - > name ) ;
2002-07-07 21:43:28 +00:00
2002-07-17 18:03:51 +00:00
if ( model_record - > be - > version | | model_record - > be - > new )
{
printf ( " <br>( " ) ;
if ( model_record - > be - > version )
2002-07-07 21:43:28 +00:00
{
2003-06-18 09:06:38 +00:00
printf ( " %s " , model_record - > be - > version ) ;
2002-07-17 18:03:51 +00:00
if ( model_record - > be - > new )
printf ( " , <font color= " COLOR_NEW " >NEW!</font> " ) ;
2002-07-07 21:43:28 +00:00
}
else
2002-07-17 18:03:51 +00:00
printf ( " <font color= " COLOR_NEW " >NEW!</font> " ) ;
printf ( " ) \n " ) ;
}
2002-07-07 13:14:03 +00:00
2002-07-17 18:03:51 +00:00
printf ( " </td> \n " ) ;
if ( model_record - > be - > manpage )
printf ( " <td align=center><a href= \" "
MAN_PAGE_LINK " \" >%s</a></td> \n " ,
model_record - > be - > manpage , model_record - > be - > manpage ) ;
else
printf ( " <td align=center>?</td> \n " ) ;
printf ( " </tr> \n " ) ;
model_record = model_record - > next ;
} /* while model_record */
2002-07-06 22:14:34 +00:00
printf ( " </table> \n " ) ;
2002-07-05 19:37:08 +00:00
mfg_record = mfg_record - > next ;
2002-07-06 11:08:01 +00:00
} /* while mfg_record */
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
/* Print the HTML headers and an introduction */
2002-07-06 11:08:01 +00:00
static void
html_print_header ( void )
{
printf
( " <!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML 4.0 Transitional//EN \" > \n "
" <html> <head> \n "
" <meta http-equiv= \" Content-Type \" content= \" text/html; "
" charset=iso-8859-1 \" > \n " ) ;
printf ( " <title>%s</title> \n " , title ) ;
printf
( " </head> \n "
" <body bgcolor=FFFFFF> \n "
" <div align=center> \n "
2018-03-07 12:38:56 +00:00
" <img src= \" images/sane.png \" alt= \" SANE \" > \n " ) ;
2002-07-06 11:08:01 +00:00
printf ( " <h1>%s</h1> \n " , title ) ;
printf ( " </div> \n " " <hr> \n " ) ;
printf ( " %s \n " , intro ) ;
printf
( " <p>This is only a summary! \n "
" Please consult the manpages and the author-supplied webpages \n "
" for more detailed (and usually important) information \n "
2003-09-24 15:56:34 +00:00
" concerning each backend.</p> \n " ) ;
2002-07-17 18:03:51 +00:00
printf
2003-09-24 15:56:34 +00:00
( " <p>If you have new information or corrections, please file a \n "
2018-03-07 12:38:56 +00:00
" <a href= \" bugs.html \" >bug report</a> \n "
2017-05-30 13:39:30 +00:00
" with as many details as possible. Also please tell us if your scanner \n "
2003-06-18 09:06:38 +00:00
" isn't mentioned in this list at all.</p> \n "
2002-07-07 21:43:28 +00:00
" <p>For an explanation of the tables, see the \n "
2002-07-17 18:03:51 +00:00
" <a href= \" #legend \" >legend</a>. \n " ) ;
2002-07-06 11:08:01 +00:00
}
2002-07-17 18:03:51 +00:00
/* Print the HTML footers and contact information */
2002-07-06 11:08:01 +00:00
static void
html_print_footer ( void )
{
time_t current_time = time ( 0 ) ;
printf
( " <hr> \n "
2018-03-07 12:38:56 +00:00
" <a href= \" ./ \" >SANE homepage</a> \n "
2002-07-06 11:08:01 +00:00
" <address> \n "
2018-03-07 12:38:56 +00:00
" <a href= \" imprint.html \" \n "
2004-07-09 16:48:17 +00:00
" >Contact</a> \n " " </address> \n " " <font size=-1> \n " ) ;
2006-01-08 20:42:53 +00:00
printf ( " This page was last updated on %s by sane-desc %s from %s \n " ,
asctime ( localtime ( & current_time ) ) , SANE_DESC_VERSION , PACKAGE_STRING ) ;
2002-07-06 11:08:01 +00:00
printf ( " </font> \n " ) ;
printf ( " </body> </html> \n " ) ;
}
2003-06-18 09:06:38 +00:00
/* print parts of the legend */
2002-07-05 19:37:08 +00:00
static void
2003-06-18 09:06:38 +00:00
html_print_legend_backend ( void )
2002-07-05 19:37:08 +00:00
{
2003-06-18 09:06:38 +00:00
printf
( " <dt><b>Backend:</b></dt> \n "
" <dd>Name of the backend, in parentheses if available: \n "
" Version of backend/driver; newer versions may be \n "
" available from their home sites.<br> "
" <font color= " COLOR_NEW " >NEW!</font> means brand-new to the \n "
" current release of SANE.<br> \n "
2017-05-30 13:39:30 +00:00
" UNMAINTAINED means that nobody maintains that backend. Expect no \n "
" new features or newly supported devices. You are welcome to take over \n "
2004-07-09 16:48:17 +00:00
" maintainership. \n " " </dd> \n " ) ;
2003-06-18 09:06:38 +00:00
}
2002-07-05 19:37:08 +00:00
2003-06-18 09:06:38 +00:00
static void
html_print_legend_link ( void )
{
printf
( " <dt><b>Link(s):</b></dt> \n "
" <dd>Link(s) to more extensive and \n "
" detailed information, if it exists, or the email address \n "
" of the author or maintainer. \n " ) ;
}
2002-07-05 19:37:08 +00:00
2003-06-18 09:06:38 +00:00
static void
html_print_legend_manual ( void )
{
printf
( " <dt><b>Manual Page:</b></dt> \n "
" <dd>A link to the man-page online, if it exists.</dd> \n " ) ;
}
2002-07-05 19:37:08 +00:00
2003-06-18 09:06:38 +00:00
static void
html_print_legend_comment ( void )
{
printf
( " <dt><b>Comment:</b></dt> \n "
" <dd>More information about the backend or model, e.g. the level of "
" support and possible problems.</dd> \n " ) ;
}
2002-07-05 19:37:08 +00:00
2003-06-18 09:06:38 +00:00
static void
html_print_legend_manufacturer ( void )
{
printf
( " <dt><b>Manufacturer:</b></dt> \n "
" <dd>Manufacturer, vendor or brand name of the device.</dd> \n " ) ;
}
2002-07-05 19:37:08 +00:00
2003-06-18 09:06:38 +00:00
static void
html_print_legend_model ( void )
{
2002-07-06 11:08:01 +00:00
printf
2015-07-11 06:32:09 +00:00
( " <dt><b>Model:</b></dt> \n " " <dd>Name of the device.</dd> \n " ) ;
2003-06-18 09:06:38 +00:00
}
static void
html_print_legend_interface ( void )
{
2002-07-17 18:03:51 +00:00
printf
2004-07-09 16:48:17 +00:00
( " <dt><b>Interface:</b></dt> \n "
" <dd>How the device is connected to the computer.</dd> \n " ) ;
2003-06-18 09:06:38 +00:00
}
2006-01-08 15:48:38 +00:00
static void
html_print_legend_usbid ( void )
{
printf
( " <dt><b>USB id:</b></dt> \n "
" <dd>The USB vendor and product ids as printed by sane-find-scanner -q (only applicable for USB devices).</dd> \n " ) ;
}
2003-06-18 09:06:38 +00:00
static void
html_print_legend_status ( void )
{
2002-07-17 18:03:51 +00:00
printf
( " <dt><b>Status</b>:</dt> \n "
2017-05-30 13:39:30 +00:00
" <dd>Indicates how many of the features the device provides \n "
2003-06-18 09:06:38 +00:00
" are supported by SANE. \n "
2002-07-08 20:24:53 +00:00
" <ul><li><font color= " COLOR_UNSUPPORTED " >unsupported</font> "
" means the device is not supported at least by this backend. "
2003-06-18 09:06:38 +00:00
" It may be supported by other backends, however. \n " ) ;
2002-07-17 18:03:51 +00:00
printf
2003-06-18 09:06:38 +00:00
( " <li><font color= " COLOR_UNTESTED " >untested</font> means the "
" device may be supported but couldn't be tested. Be very "
" careful and report success/failure. \n "
" <li><font color= " COLOR_MINIMAL " >minimal</font> means that the \n "
2017-05-30 13:39:30 +00:00
" device is detected and scans at least in one mode. But the quality \n "
2003-06-18 09:06:38 +00:00
" is bad or important features won't work. \n " ) ;
2002-07-17 18:03:51 +00:00
printf
2017-05-30 13:39:30 +00:00
( " <li><font color= " COLOR_BASIC " >basic</font> means it works at \n "
2003-06-18 09:06:38 +00:00
" least in the most important modes but quality is not perfect. \n "
2004-07-09 16:48:17 +00:00
" <li><font color= " COLOR_GOOD
2017-05-30 13:39:30 +00:00
" >good</font> means the device is usable \n "
2003-06-18 09:06:38 +00:00
" for day-to-day work. Some rather exotic features may be missing. \n "
2004-07-09 16:48:17 +00:00
" <li><font color= " COLOR_COMPLETE
2017-05-30 13:39:30 +00:00
" >complete</font> means the backends \n "
2004-07-09 16:48:17 +00:00
" supports everything the device can do. \n " " </ul></dd> \n " ) ;
2003-06-18 09:06:38 +00:00
}
2002-07-06 11:08:01 +00:00
2003-06-18 09:06:38 +00:00
static void
html_print_legend_description ( void )
{
printf
( " <dt><b>Description</b>:</dt> \n "
" <dd>The scope of application of the backend. \n " ) ;
2002-07-05 19:37:08 +00:00
}
2002-07-17 18:03:51 +00:00
/* Print the HTML page with one table of models per backend */
2002-07-12 20:17:53 +00:00
static void
html_print_backends_split ( void )
{
if ( ! title )
title = " SANE: Backends (Drivers) " ;
if ( ! intro )
intro = " <p> The following table summarizes the backends/drivers "
" distributed with the latest version of sane-backends, and the hardware "
" or software they support. </p> " ;
html_print_header ( ) ;
2006-01-07 23:44:09 +00:00
html_print_summary ( ) ;
2002-07-12 20:17:53 +00:00
printf ( " <h2><a name= \" SCANNERS \" >Scanners</a></h2> \n " ) ;
html_backends_split_table ( type_scanner ) ;
printf ( " <h2><a name= \" STILL \" >Still Cameras</a></h2> \n " ) ;
html_backends_split_table ( type_stillcam ) ;
printf ( " <h2><a name= \" VIDEO \" >Video Cameras</a></h2> \n " ) ;
html_backends_split_table ( type_vidcam ) ;
printf ( " <h2><a name= \" API \" >APIs</a></h2> \n " ) ;
html_backends_split_table ( type_api ) ;
printf ( " <h2><a name= \" META \" >Meta Backends</a></h2> \n " ) ;
html_backends_split_table ( type_meta ) ;
2004-07-09 16:48:17 +00:00
printf ( " <h3><a name= \" legend \" >Legend:</a></h3> \n " " <blockquote><dl> \n " ) ;
2003-06-18 09:06:38 +00:00
html_print_legend_backend ( ) ;
html_print_legend_link ( ) ;
html_print_legend_manual ( ) ;
html_print_legend_comment ( ) ;
html_print_legend_manufacturer ( ) ;
html_print_legend_model ( ) ;
html_print_legend_interface ( ) ;
2006-01-08 15:48:38 +00:00
html_print_legend_usbid ( ) ;
2003-06-18 09:06:38 +00:00
html_print_legend_status ( ) ;
html_print_legend_description ( ) ;
printf ( " </dl></blockquote> \n " ) ;
2002-07-12 20:17:53 +00:00
html_print_footer ( ) ;
}
2002-07-17 18:03:51 +00:00
/* Print the HTML page with one table of models per manufacturer */
2002-07-05 19:37:08 +00:00
static void
html_print_mfgs ( void )
{
if ( ! title )
title = " SANE: Supported Devices " ;
if ( ! intro )
intro = " <p> The following table summarizes the devices supported "
" by the latest version of sane-backends. </p> " ;
2002-07-07 13:14:03 +00:00
html_print_header ( ) ;
2002-07-05 19:37:08 +00:00
2006-01-07 23:44:09 +00:00
html_print_summary ( ) ;
2002-07-05 19:37:08 +00:00
printf ( " <h2><a name= \" SCANNERS \" >Scanners</a></h2> \n " ) ;
html_mfgs_table ( type_scanner ) ;
printf ( " <h2><a name= \" STILL \" >Still Cameras</a></h2> \n " ) ;
html_mfgs_table ( type_stillcam ) ;
printf ( " <h2><a name= \" VIDEO \" >Video Cameras</a></h2> \n " ) ;
html_mfgs_table ( type_vidcam ) ;
printf ( " <h2><a name= \" API \" >APIs</a></h2> \n " ) ;
2002-07-12 20:17:53 +00:00
html_backends_split_table ( type_api ) ;
2002-07-05 19:37:08 +00:00
printf ( " <h2><a name= \" META \" >Meta Backends</a></h2> \n " ) ;
2002-07-12 20:17:53 +00:00
html_backends_split_table ( type_meta ) ;
2002-07-05 19:37:08 +00:00
2002-07-06 11:08:01 +00:00
printf
2004-07-09 16:48:17 +00:00
( " <h3><a name= \" legend \" >Legend:</a></h3> \n " " <blockquote> \n " " <dl> \n " ) ;
2003-06-18 09:06:38 +00:00
html_print_legend_model ( ) ;
html_print_legend_interface ( ) ;
2006-01-08 15:48:38 +00:00
html_print_legend_usbid ( ) ;
2003-06-18 09:06:38 +00:00
html_print_legend_status ( ) ;
html_print_legend_comment ( ) ;
html_print_legend_backend ( ) ;
html_print_legend_manual ( ) ;
html_print_legend_manufacturer ( ) ;
html_print_legend_description ( ) ;
2004-07-09 16:48:17 +00:00
printf ( " </dl> \n " " </blockquote> \n " ) ;
2002-07-06 11:08:01 +00:00
html_print_footer ( ) ;
2002-07-05 19:37:08 +00:00
}
2006-01-07 23:44:09 +00:00
2006-01-07 19:36:24 +00:00
/* print statistics about supported devices */
static void
print_statistics_per_type ( device_type dev_type )
{
2006-01-07 23:44:09 +00:00
statistics_type num = { 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2006-01-07 19:36:24 +00:00
2006-01-07 23:44:09 +00:00
calculate_statistics_per_type ( dev_type , num ) ;
2006-01-07 19:36:24 +00:00
2006-01-07 21:42:07 +00:00
printf ( " Total: %4d \n " ,
num [ status_minimal ] + num [ status_basic ] + num [ status_good ] +
num [ status_complete ] + num [ status_untested ] + num [ status_untested ] +
num [ status_unsupported ] ) ;
if ( dev_type = = type_scanner | | dev_type = = type_stillcam
| | dev_type = = type_vidcam )
2006-01-07 19:36:24 +00:00
{
2006-01-07 23:44:09 +00:00
printf ( " Supported: %4d (complete: %d, good: %d, basic: %d, "
2013-02-11 06:55:43 +00:00
" minimal: %d) \n " ,
2006-01-07 23:44:09 +00:00
num [ status_minimal ] + num [ status_basic ] + num [ status_good ] +
num [ status_complete ] , num [ status_complete ] , num [ status_good ] ,
num [ status_basic ] , num [ status_minimal ] ) ;
2006-01-07 19:36:24 +00:00
printf ( " Untested: %4d \n " , num [ status_untested ] ) ;
printf ( " Unsupported: %4d \n " , num [ status_unsupported ] ) ;
}
}
2006-01-07 23:44:09 +00:00
2006-01-07 19:36:24 +00:00
static void
print_statistics ( void )
{
printf ( " Number of known devices: \n " ) ;
printf ( " Scanners: \n " ) ;
print_statistics_per_type ( type_scanner ) ;
printf ( " Still cameras: \n " ) ;
print_statistics_per_type ( type_stillcam ) ;
printf ( " Video cameras: \n " ) ;
print_statistics_per_type ( type_vidcam ) ;
printf ( " Meta backends: \n " ) ;
print_statistics_per_type ( type_meta ) ;
printf ( " API backends: \n " ) ;
print_statistics_per_type ( type_api ) ;
}
2002-07-05 19:37:08 +00:00
2006-01-08 20:42:53 +00:00
static usbid_type *
2013-02-11 06:55:43 +00:00
create_usbid ( char * manufacturer , char * model ,
2006-01-08 20:42:53 +00:00
char * usb_vendor_id , char * usb_product_id )
{
usbid_type * usbid = calloc ( 1 , sizeof ( usbid_type ) ) ;
usbid - > usb_vendor_id = strdup ( usb_vendor_id ) ;
usbid - > usb_product_id = strdup ( usb_product_id ) ;
usbid - > name = calloc ( 1 , sizeof ( manufacturer_model_type ) ) ;
usbid - > name - > name = calloc ( 1 , strlen ( manufacturer ) + strlen ( model ) + 3 ) ;
sprintf ( usbid - > name - > name , " %s %s " , manufacturer , model ) ;
usbid - > name - > next = 0 ;
usbid - > next = 0 ;
DBG_DBG ( " New USB ids: %s/%s (%s %s) \n " , usb_vendor_id , usb_product_id ,
manufacturer , model ) ;
return usbid ;
}
2009-01-13 21:17:16 +00:00
static scsiid_type *
2013-02-11 06:55:43 +00:00
create_scsiid ( char * manufacturer , char * model ,
2009-01-13 21:17:16 +00:00
char * scsi_vendor_id , char * scsi_product_id , SANE_Bool is_processor )
{
scsiid_type * scsiid = calloc ( 1 , sizeof ( scsiid_type ) ) ;
scsiid - > scsi_vendor_id = strdup ( scsi_vendor_id ) ;
scsiid - > scsi_product_id = strdup ( scsi_product_id ) ;
scsiid - > is_processor = is_processor ;
scsiid - > name = calloc ( 1 , sizeof ( manufacturer_model_type ) ) ;
scsiid - > name - > name = calloc ( 1 , strlen ( manufacturer ) + strlen ( model ) + 3 ) ;
sprintf ( scsiid - > name - > name , " %s %s " , manufacturer , model ) ;
scsiid - > name - > next = 0 ;
scsiid - > next = 0 ;
DBG_DBG ( " New SCSI ids: %s/%s (%s %s) \n " , scsi_vendor_id , scsi_product_id ,
manufacturer , model ) ;
return scsiid ;
}
2006-01-08 20:42:53 +00:00
static usbid_type *
2013-02-11 06:55:43 +00:00
add_usbid ( usbid_type * first_usbid , char * manufacturer , char * model ,
2006-01-08 20:42:53 +00:00
char * usb_vendor_id , char * usb_product_id )
{
usbid_type * usbid = first_usbid ;
usbid_type * prev_usbid = 0 , * tmp_usbid = 0 ;
if ( ! first_usbid )
first_usbid = create_usbid ( manufacturer , model , usb_vendor_id , usb_product_id ) ;
else
{
while ( usbid )
{
if ( strcmp ( usb_vendor_id , usbid - > usb_vendor_id ) = = 0 & &
strcmp ( usb_product_id , usbid - > usb_product_id ) = = 0 )
{
manufacturer_model_type * man_mod = usbid - > name ;
while ( man_mod - > next )
man_mod = man_mod - > next ;
man_mod - > next = malloc ( sizeof ( manufacturer_model_type ) ) ;
man_mod - > next - > name = malloc ( strlen ( manufacturer ) + strlen ( model ) + 3 ) ;
sprintf ( man_mod - > next - > name , " %s %s " , manufacturer , model ) ;
man_mod - > next - > next = 0 ;
DBG_DBG ( " Added manufacturer/model %s %s to USB ids %s/%s \n " , manufacturer , model ,
usb_vendor_id , usb_product_id ) ;
break ;
}
2013-02-11 06:55:43 +00:00
if ( strcmp ( usb_vendor_id , usbid - > usb_vendor_id ) < 0 | |
2006-01-08 20:42:53 +00:00
( strcmp ( usb_vendor_id , usbid - > usb_vendor_id ) = = 0 & &
strcmp ( usb_product_id , usbid - > usb_product_id ) < 0 ) )
{
2013-02-11 06:55:43 +00:00
2006-01-08 20:42:53 +00:00
tmp_usbid = create_usbid ( manufacturer , model , usb_vendor_id , usb_product_id ) ;
tmp_usbid - > next = usbid ;
if ( prev_usbid )
prev_usbid - > next = tmp_usbid ;
else
first_usbid = tmp_usbid ;
break ;
}
prev_usbid = usbid ;
usbid = usbid - > next ;
}
if ( ! usbid )
{
prev_usbid - > next = create_usbid ( manufacturer , model , usb_vendor_id , usb_product_id ) ;
usbid = prev_usbid - > next ;
}
}
return first_usbid ;
}
2009-01-13 21:17:16 +00:00
static scsiid_type *
2013-02-11 06:55:43 +00:00
add_scsiid ( scsiid_type * first_scsiid , char * manufacturer , char * model ,
2009-01-13 21:17:16 +00:00
char * scsi_vendor_id , char * scsi_product_id , SANE_Bool is_processor )
{
scsiid_type * scsiid = first_scsiid ;
scsiid_type * prev_scsiid = 0 , * tmp_scsiid = 0 ;
if ( ! first_scsiid )
first_scsiid = create_scsiid ( manufacturer , model , scsi_vendor_id , scsi_product_id , is_processor ) ;
else
{
while ( scsiid )
{
if ( strcmp ( scsi_vendor_id , scsiid - > scsi_vendor_id ) = = 0 & &
strcmp ( scsi_product_id , scsiid - > scsi_product_id ) = = 0 )
{
manufacturer_model_type * man_mod = scsiid - > name ;
while ( man_mod - > next )
man_mod = man_mod - > next ;
man_mod - > next = malloc ( sizeof ( manufacturer_model_type ) ) ;
man_mod - > next - > name = malloc ( strlen ( manufacturer ) + strlen ( model ) + 3 ) ;
sprintf ( man_mod - > next - > name , " %s %s " , manufacturer , model ) ;
man_mod - > next - > next = 0 ;
DBG_DBG ( " Added manufacturer/model %s %s to SCSI ids %s/%s \n " , manufacturer , model ,
scsi_vendor_id , scsi_product_id ) ;
break ;
}
2013-02-11 06:55:43 +00:00
if ( strcmp ( scsi_vendor_id , scsiid - > scsi_vendor_id ) < 0 | |
2009-01-13 21:17:16 +00:00
( strcmp ( scsi_vendor_id , scsiid - > scsi_vendor_id ) = = 0 & &
strcmp ( scsi_product_id , scsiid - > scsi_product_id ) < 0 ) )
{
2013-02-11 06:55:43 +00:00
2009-01-13 21:17:16 +00:00
tmp_scsiid = create_scsiid ( manufacturer , model , scsi_vendor_id , scsi_product_id , is_processor ) ;
tmp_scsiid - > next = scsiid ;
if ( prev_scsiid )
prev_scsiid - > next = tmp_scsiid ;
else
first_scsiid = tmp_scsiid ;
break ;
}
prev_scsiid = scsiid ;
scsiid = scsiid - > next ;
}
if ( ! scsiid )
{
prev_scsiid - > next = create_scsiid ( manufacturer , model , scsi_vendor_id , scsi_product_id , is_processor ) ;
scsiid = prev_scsiid - > next ;
}
}
return first_scsiid ;
}
2006-01-08 20:42:53 +00:00
static usbid_type *
create_usbids_table ( void )
{
2009-02-03 11:08:31 +00:00
backend_entry * be ;
usbid_type * first_usbid = NULL ;
2006-01-08 20:42:53 +00:00
2009-02-03 11:08:31 +00:00
if ( ! first_backend )
return NULL ;
for ( be = first_backend ; be ; be = be - > next )
2006-01-08 20:42:53 +00:00
{
2009-02-03 11:08:31 +00:00
type_entry * type ;
2006-01-08 20:42:53 +00:00
2009-02-03 11:08:31 +00:00
if ( ! be - > type )
continue ;
for ( type = be - > type ; type ; type = type - > next )
2006-01-08 20:42:53 +00:00
{
2009-02-03 11:08:31 +00:00
mfg_entry * mfg ;
2006-01-08 20:42:53 +00:00
2009-02-03 11:08:31 +00:00
if ( ! type - > mfg )
2006-01-08 20:42:53 +00:00
continue ;
2009-02-03 11:08:31 +00:00
for ( mfg = type - > mfg ; mfg ; mfg = mfg - > next )
2006-01-08 20:42:53 +00:00
{
2009-02-03 11:08:31 +00:00
model_entry * model ;
if ( ! mfg - > model )
continue ;
for ( model = mfg - > model ; model ; model = model - > next )
2006-01-08 20:42:53 +00:00
{
2009-02-03 11:08:31 +00:00
if ( ( model - > status = = status_unsupported )
| | ( model - > status = = status_unknown ) )
continue ;
if ( model - > usb_vendor_id & & model - > usb_product_id )
{
2013-02-11 06:55:43 +00:00
first_usbid = add_usbid ( first_usbid , mfg - > name ,
2009-02-03 11:08:31 +00:00
model - > name ,
model - > usb_vendor_id ,
model - > usb_product_id ) ;
}
} /* for (model) */
} /* for (mfg) */
} /* for (type) */
} /* for (be) */
2006-01-08 20:42:53 +00:00
return first_usbid ;
}
2009-01-13 21:17:16 +00:00
static scsiid_type *
create_scsiids_table ( void )
{
2009-02-03 11:08:31 +00:00
backend_entry * be ;
scsiid_type * first_scsiid = NULL ;
2009-01-13 21:17:16 +00:00
2009-02-03 11:08:31 +00:00
if ( ! first_backend )
return NULL ;
for ( be = first_backend ; be ; be = be - > next )
2009-01-13 21:17:16 +00:00
{
2009-02-03 11:08:31 +00:00
type_entry * type ;
2009-01-13 21:17:16 +00:00
2009-02-03 11:08:31 +00:00
if ( ! be - > type )
continue ;
for ( type = be - > type ; type ; type = type - > next )
2009-01-13 21:17:16 +00:00
{
2009-02-03 11:08:31 +00:00
mfg_entry * mfg ;
2009-01-13 21:17:16 +00:00
2009-02-03 11:08:31 +00:00
if ( ! type - > mfg )
continue ;
2009-01-13 21:17:16 +00:00
2009-02-03 11:08:31 +00:00
for ( mfg = type - > mfg ; mfg ; mfg = mfg - > next )
2009-01-13 21:17:16 +00:00
{
2009-02-03 11:08:31 +00:00
model_entry * model ;
if ( ! mfg - > model )
continue ;
for ( model = mfg - > model ; model ; model = model - > next )
2009-01-13 21:17:16 +00:00
{
2009-02-03 11:08:31 +00:00
if ( ( model - > status = = status_unsupported )
| | ( model - > status = = status_unknown ) )
continue ;
if ( model - > scsi_vendor_id & & model - > scsi_product_id )
2009-01-13 21:17:16 +00:00
{
2013-02-11 06:55:43 +00:00
first_scsiid = add_scsiid ( first_scsiid , mfg - > name ,
2009-02-03 11:08:31 +00:00
model - > name ,
model - > scsi_vendor_id ,
model - > scsi_product_id ,
model - > scsi_is_processor ) ;
}
} /* for (model) */
} /* for (mfg) */
} /* for (type) */
} /* for (be) */
2009-01-13 21:17:16 +00:00
return first_scsiid ;
}
2006-01-08 20:42:53 +00:00
/* print USB usermap file to be used by the hotplug tools */
static void
print_usermap_header ( void )
{
time_t current_time = time ( 0 ) ;
printf
2010-04-19 00:37:15 +00:00
( " # This file was automatically created based on description files (*.desc) \n "
" # by sane-desc %s from %s on %s "
" # \n "
,
SANE_DESC_VERSION , PACKAGE_STRING , asctime ( localtime ( & current_time ) ) ) ;
printf
( " # The entries below are used to detect a USB device and change owner \n "
" # and permissions on the \" device node \" used by libusb. \n "
2006-01-08 20:42:53 +00:00
" # \n "
" # The 0x0003 match flag means the device is matched by its vendor and \n "
" # product IDs. \n "
" # \n "
" # Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID \n "
2010-04-19 00:37:15 +00:00
" # respectively): \n "
" # \n "
) ;
2006-01-08 20:42:53 +00:00
printf
( " # libusbscanner 0x0003 0xVVVV 0xPPPP 0x0000 0x0000 0x00 0x00 0x00 0x00 "
" 0x00 0x00 0x00000000 \n "
" # usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi "
" bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass "
" bInterfaceSubClass bInterfaceProtocol driver_info \n "
" # \n "
2010-04-19 00:37:15 +00:00
) ;
printf
( " # If your scanner isn't listed below, you can add it as explained above. \n "
" # \n "
" # If your scanner is supported by some external backend (brother, epkowa, \n "
" # hpaio, etc) please ask the author of the backend to provide proper \n "
" # device detection support for your OS \n "
" # \n "
" # If the scanner is supported by sane-backends, please mail the entry to \n "
2018-04-18 12:36:00 +00:00
" # the sane-devel mailing list (sane-devel@alioth-lists.debian.net). \n "
2010-04-19 00:37:15 +00:00
" # \n "
) ;
2006-01-08 20:42:53 +00:00
}
static void
print_usermap ( void )
{
usbid_type * usbid = create_usbids_table ( ) ;
print_usermap_header ( ) ;
while ( usbid )
{
manufacturer_model_type * name = usbid - > name ;
printf ( " # " ) ;
while ( name )
{
if ( name ! = usbid - > name )
printf ( " | " ) ;
printf ( " %s " , name - > name ) ;
name = name - > next ;
}
printf ( " \n " ) ;
printf ( " libusbscanner 0x0003 %s %s " , usbid - > usb_vendor_id ,
usbid - > usb_product_id ) ;
printf ( " 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 \n " ) ;
usbid = usbid - > next ;
}
}
/* print libsane.db file for hotplug-ng */
static void
print_db_header ( void )
{
time_t current_time = time ( 0 ) ;
printf ( " # This file was automatically created based on description files (*.desc) \n "
" # by sane-desc %s from %s on %s " ,
SANE_DESC_VERSION , PACKAGE_STRING , asctime ( localtime ( & current_time ) ) ) ;
printf
( " # \n "
" # The entries below are used to detect a USB device when it's plugged in \n "
" # and then run a script to change the ownership and \n "
" # permissions on the \" device node \" used by libusb. \n "
" # Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID \n "
" # respectively): \n " ) ;
2013-02-11 06:55:43 +00:00
printf
2006-01-08 20:42:53 +00:00
( " # \n "
2009-01-13 20:58:55 +00:00
" # 0xVVVV<tab>0xPPPP<tab>%s:%s<tab>%s<tab>[/usr/local/bin/foo.sh] \n "
2006-01-08 20:42:53 +00:00
" # Fields: \n "
" # vendor ID \n "
" # product ID \n "
" # ownership (user:group) \n "
" # permissions \n "
2010-04-19 00:37:15 +00:00
" # path of an optional script to run (it can be omitted) \n "
" # \n "
, DEVOWNER , DEVGROUP , DEVMODE ) ;
2006-01-08 20:42:53 +00:00
printf
2010-04-19 00:37:15 +00:00
( " # If your scanner isn't listed below, you can add it as explained above. \n "
" # \n "
" # If your scanner is supported by some external backend (brother, epkowa, \n "
" # hpaio, etc) please ask the author of the backend to provide proper \n "
" # device detection support for your OS \n "
" # \n "
" # If the scanner is supported by sane-backends, please mail the entry to \n "
2018-04-18 12:36:00 +00:00
" # the sane-devel mailing list (sane-devel@alioth-lists.debian.net). \n "
2010-04-19 00:37:15 +00:00
" # \n "
) ;
2006-01-08 20:42:53 +00:00
}
static void
print_db ( void )
{
usbid_type * usbid = create_usbids_table ( ) ;
print_db_header ( ) ;
while ( usbid )
{
manufacturer_model_type * name = usbid - > name ;
printf ( " # " ) ;
while ( name )
{
if ( name ! = usbid - > name )
printf ( " | " ) ;
printf ( " %s " , name - > name ) ;
name = name - > next ;
}
printf ( " \n " ) ;
2017-05-30 13:39:30 +00:00
printf ( " %s \t %s \t %s:%s \t %s \n " , usbid - > usb_vendor_id ,
2009-01-13 20:58:55 +00:00
usbid - > usb_product_id , DEVOWNER , DEVGROUP , DEVMODE ) ;
2006-01-08 20:42:53 +00:00
usbid = usbid - > next ;
}
}
/* print libsane.rules for Linux udev */
static void
print_udev_header ( void )
{
time_t current_time = time ( 0 ) ;
printf ( " # This file was automatically created based on description files (*.desc) \n "
" # by sane-desc %s from %s on %s " ,
SANE_DESC_VERSION , PACKAGE_STRING , asctime ( localtime ( & current_time ) ) ) ;
2013-02-11 06:55:43 +00:00
printf
2006-01-08 20:42:53 +00:00
( " # \n "
2009-01-13 21:17:16 +00:00
" # udev rules file for supported USB and SCSI devices \n "
2006-01-08 20:42:53 +00:00
" # \n "
2009-01-13 21:17:16 +00:00
" # The SCSI device support is very basic and includes only \n "
" # scanners that mark themselves as type \" scanner \" or \n "
" # SCSI-scanners from HP and other vendors that are entitled \" processor \" \n "
" # but are treated accordingly. \n "
" # \n " ) ;
printf
( " # To add a USB device, add a rule to the list below between the \n "
" # LABEL= \" libsane_usb_rules_begin \" and LABEL= \" libsane_usb_rules_end \" lines. \n "
2006-01-08 20:42:53 +00:00
" # \n "
2006-07-03 17:51:32 +00:00
" # To run a script when your device is plugged in, add RUN+= \" /path/to/script \" \n "
2010-04-19 00:37:15 +00:00
" # to the appropriate rule. \n "
" # \n "
) ;
2006-01-08 20:42:53 +00:00
printf
2010-04-19 00:37:15 +00:00
( " # If your scanner isn't listed below, you can add it as explained above. \n "
" # \n "
" # If your scanner is supported by some external backend (brother, epkowa, \n "
" # hpaio, etc) please ask the author of the backend to provide proper \n "
" # device detection support for your OS \n "
" # \n "
" # If the scanner is supported by sane-backends, please mail the entry to \n "
2018-04-18 12:36:00 +00:00
" # the sane-devel mailing list (sane-devel@alioth-lists.debian.net). \n "
2010-04-19 00:37:15 +00:00
" # \n "
) ;
2006-01-08 20:42:53 +00:00
}
static void
print_udev ( void )
{
usbid_type * usbid = create_usbids_table ( ) ;
2009-01-13 21:17:16 +00:00
scsiid_type * scsiid = create_scsiids_table ( ) ;
2006-07-16 11:05:15 +00:00
int i ;
2006-01-08 20:42:53 +00:00
print_udev_header ( ) ;
2007-07-25 09:21:18 +00:00
printf ( " ACTION!= \" add \" , GOTO= \" libsane_rules_end \" \n "
2007-07-26 21:23:27 +00:00
" ENV{DEVTYPE}== \" usb_device \" , GOTO= \" libsane_create_usb_dev \" \n "
2009-01-13 21:17:16 +00:00
" SUBSYSTEMS== \" scsi \" , GOTO= \" libsane_scsi_rules_begin \" \n "
" SUBSYSTEM== \" usb_device \" , GOTO= \" libsane_usb_rules_begin \" \n "
" SUBSYSTEM!= \" usb_device \" , GOTO= \" libsane_usb_rules_end \" \n "
2007-07-26 21:23:27 +00:00
" \n " ) ;
printf ( " # Kernel >= 2.6.22 jumps here \n "
" LABEL= \" libsane_create_usb_dev \" \n "
" \n " ) ;
printf ( " # For Linux >= 2.6.22 without CONFIG_USB_DEVICE_CLASS=y \n "
2007-07-29 17:37:49 +00:00
" # If the following rule does not exist on your system yet, uncomment it \n "
2010-02-10 19:27:27 +00:00
" # ENV{DEVTYPE}== \" usb_device \" , "
2007-07-26 21:23:27 +00:00
" MODE= \" 0664 \" , OWNER= \" root \" , GROUP= \" root \" \n "
" \n " ) ;
printf ( " # Kernel < 2.6.22 jumps here \n "
2009-01-13 21:17:16 +00:00
" LABEL= \" libsane_usb_rules_begin \" \n "
2007-07-25 09:21:18 +00:00
" \n " ) ;
2006-01-08 20:42:53 +00:00
while ( usbid )
{
manufacturer_model_type * name = usbid - > name ;
2006-07-16 11:05:15 +00:00
i = 0 ;
2006-01-08 20:42:53 +00:00
printf ( " # " ) ;
while ( name )
{
2006-07-16 11:05:15 +00:00
if ( ( name ! = usbid - > name ) & & ( i > 0 ) )
2006-01-08 20:42:53 +00:00
printf ( " | " ) ;
printf ( " %s " , name - > name ) ;
name = name - > next ;
2006-07-16 11:05:15 +00:00
i + + ;
/*
* Limit the number of model names on the same line to 3 ,
* as udev cannot handle very long lines and prints a warning
* message while loading the rules files .
*/
if ( ( i = = 3 ) & & ( name ! = NULL ) )
{
printf ( " \n # " ) ;
i = 0 ;
}
2006-01-08 20:42:53 +00:00
}
printf ( " \n " ) ;
2011-06-02 09:05:30 +00:00
if ( mode = = output_mode_udevacl )
printf ( " ATTRS{idVendor}== \" %s \" , ATTRS{idProduct}== \" %s \" , ENV{libsane_matched}= \" yes \" \n " ,
usbid - > usb_vendor_id + 2 , usbid - > usb_product_id + 2 ) ;
else
printf ( " ATTRS{idVendor}== \" %s \" , ATTRS{idProduct}== \" %s \" , MODE= \" %s \" , GROUP= \" %s \" , ENV{libsane_matched}= \" yes \" \n " ,
usbid - > usb_vendor_id + 2 , usbid - > usb_product_id + 2 , DEVMODE , DEVGROUP ) ;
2006-01-08 20:42:53 +00:00
usbid = usbid - > next ;
}
2007-07-29 18:39:54 +00:00
printf ( " \n # The following rule will disable USB autosuspend for the device \n " ) ;
2011-03-19 16:51:10 +00:00
printf ( " ENV{libsane_matched}== \" yes \" , RUN+= \" /bin/sh -c 'if test -e /sys/$env{DEVPATH}/power/control; then echo on > /sys/$env{DEVPATH}/power/control; elif test -e /sys/$env{DEVPATH}/power/level; then echo on > /sys/$env{DEVPATH}/power/level; fi' \" \n " ) ;
2007-07-29 18:39:54 +00:00
2009-01-13 21:17:16 +00:00
printf ( " \n LABEL= \" libsane_usb_rules_end \" \n \n " ) ;
2013-11-20 20:45:23 +00:00
printf ( " SUBSYSTEMS== \" scsi \" , GOTO= \" libsane_scsi_rules_begin \" \n " ) ;
printf ( " GOTO= \" libsane_scsi_rules_end \" \n \n " ) ;
2009-01-13 21:17:16 +00:00
printf ( " LABEL= \" libsane_scsi_rules_begin \" \n " ) ;
printf ( " # Generic: SCSI device type 6 indicates a scanner \n " ) ;
2011-06-02 09:05:30 +00:00
if ( mode = = output_mode_udevacl )
printf ( " KERNEL== \" sg[0-9]* \" , ATTRS{type}== \" 6 \" , ENV{libsane_matched}= \" yes \" \n " ) ;
else
printf ( " KERNEL== \" sg[0-9]* \" , ATTRS{type}== \" 6 \" , MODE= \" %s \" , GROUP= \" %s \" , ENV{libsane_matched}= \" yes \" \n " , DEVMODE , DEVGROUP ) ;
2009-01-13 21:17:16 +00:00
printf ( " # Some scanners advertise themselves as SCSI device type 3 \n " ) ;
2011-06-24 20:08:52 +00:00
printf ( " # Wildcard: for some Epson SCSI scanners \n " ) ;
if ( mode = = output_mode_udevacl )
printf ( " KERNEL== \" sg[0-9]* \" , ATTRS{type}== \" 3 \" , ATTRS{vendor}== \" EPSON \" , ATTRS{model}== \" SCANNER* \" , ENV{libsane_matched}= \" yes \" \n " ) ;
else
printf ( " KERNEL== \" sg[0-9]* \" , ATTRS{type}== \" 3 \" , ATTRS{vendor}== \" EPSON \" , ATTRS{model}== \" SCANNER* \" , MODE= \" %s \" , GROUP= \" %s \" , ENV{libsane_matched}= \" yes \" \n " ,
DEVMODE , DEVGROUP ) ;
2009-01-13 21:17:16 +00:00
while ( scsiid )
{
manufacturer_model_type * name = scsiid - > name ;
if ( ! scsiid - > is_processor )
2011-06-24 20:09:43 +00:00
{
scsiid = scsiid - > next ;
continue ;
}
2009-01-13 21:17:16 +00:00
2011-06-24 20:08:52 +00:00
/* Wildcard for Epson scanners: vendor = EPSON, product = SCANNER* */
if ( ( strcmp ( scsiid - > scsi_vendor_id , " EPSON " ) = = 0 )
& & ( strncmp ( scsiid - > scsi_product_id , " SCANNER " , 7 ) = = 0 ) )
{
scsiid = scsiid - > next ;
continue ;
}
2009-01-13 21:17:16 +00:00
i = 0 ;
printf ( " # " ) ;
while ( name )
{
if ( ( name ! = scsiid - > name ) & & ( i > 0 ) )
printf ( " | " ) ;
printf ( " %s " , name - > name ) ;
name = name - > next ;
i + + ;
/*
* Limit the number of model names on the same line to 3 ,
* as udev cannot handle very long lines and prints a warning
* message while loading the rules files .
*/
if ( ( i = = 3 ) & & ( name ! = NULL ) )
{
printf ( " \n # " ) ;
i = 0 ;
}
}
printf ( " \n " ) ;
2011-06-02 09:05:30 +00:00
if ( mode = = output_mode_udevacl )
printf ( " KERNEL== \" sg[0-9]* \" , ATTRS{type}== \" 3 \" , ATTRS{vendor}== \" %s \" , ATTRS{model}== \" %s \" , ENV{libsane_matched}= \" yes \" \n " ,
scsiid - > scsi_vendor_id , scsiid - > scsi_product_id ) ;
else
printf ( " KERNEL== \" sg[0-9]* \" , ATTRS{type}== \" 3 \" , ATTRS{vendor}== \" %s \" , ATTRS{model}== \" %s \" , MODE= \" %s \" , GROUP= \" %s \" , ENV{libsane_matched}= \" yes \" \n " ,
2009-01-13 21:17:16 +00:00
scsiid - > scsi_vendor_id , scsiid - > scsi_product_id , DEVMODE , DEVGROUP ) ;
2011-06-24 20:09:43 +00:00
2009-01-13 21:17:16 +00:00
scsiid = scsiid - > next ;
}
2011-06-02 09:05:30 +00:00
printf ( " LABEL= \" libsane_scsi_rules_end \" \n " ) ;
if ( mode = = output_mode_udevacl )
printf ( " \n ENV{libsane_matched}== \" yes \" , RUN+= \" /bin/setfacl -m g:%s:rw $env{DEVNAME} \" \n " , DEVGROUP ) ;
2012-04-20 19:38:47 +00:00
else
printf ( " \n ENV{libsane_matched}== \" yes \" , MODE= \" 664 \" , GROUP= \" scanner \" \n " ) ;
2009-01-13 21:17:16 +00:00
2011-06-02 09:05:30 +00:00
printf ( " \n LABEL= \" libsane_rules_end \" \n " ) ;
2006-01-08 20:42:53 +00:00
}
2013-07-17 23:27:33 +00:00
/* print libsane.rules for Linux udev */
static void
print_udevhwdb_header ( void )
{
time_t current_time = time ( 0 ) ;
printf ( " # This file was automatically created based on description files (*.desc) \n "
" # by sane-desc %s from %s on %s " ,
SANE_DESC_VERSION , PACKAGE_STRING , asctime ( localtime ( & current_time ) ) ) ;
printf
( " # \n "
" # udev rules file for supported USB and SCSI devices \n "
" # \n "
" # For the list of supported USB devices see /usr/lib/udev/hwdb.d/20-sane.hwdb \n "
2013-08-02 20:25:10 +00:00
" # \n "
2013-07-17 23:27:33 +00:00
" # The SCSI device support is very basic and includes only \n "
" # scanners that mark themselves as type \" scanner \" or \n "
" # SCSI-scanners from HP and other vendors that are entitled \" processor \" \n "
" # but are treated accordingly. \n "
" # \n " ) ;
printf
( " # If your SCSI scanner isn't listed below, you can add it to a new rules \n "
" # file under /etc/udev/rules.d/. \n "
" # \n "
" # If your scanner is supported by some external backend (brother, epkowa, \n "
" # hpaio, etc) please ask the author of the backend to provide proper \n "
" # device detection support for your OS \n "
" # \n "
" # If the scanner is supported by sane-backends, please mail the entry to \n "
2018-04-18 12:36:00 +00:00
" # the sane-devel mailing list (sane-devel@alioth-lists.debian.net). \n "
2013-07-17 23:27:33 +00:00
" # \n "
) ;
}
static void
print_udevhwdb ( void )
{
scsiid_type * scsiid = create_scsiids_table ( ) ;
int i ;
print_udevhwdb_header ( ) ;
printf ( " ACTION!= \" add \" , GOTO= \" libsane_rules_end \" \n \n " ) ;
printf ( " # The following rule will disable USB autosuspend for the device \n " ) ;
printf ( " ENV{DEVTYPE}== \" usb_device \" , ENV{libsane_matched}== \" yes \" , TEST== \" power/control \" , ATTR{power/control}= \" on \" \n \n " ) ;
2013-11-20 20:45:23 +00:00
printf ( " SUBSYSTEMS== \" scsi \" , GOTO= \" libsane_scsi_rules_begin \" \n " ) ;
printf ( " GOTO= \" libsane_rules_end \" \n \n " ) ;
printf ( " LABEL= \" libsane_scsi_rules_begin \" \n " ) ;
2013-07-17 23:27:33 +00:00
printf ( " KERNEL!= \" sg[0-9]* \" , GOTO= \" libsane_rules_end \" \n \n " ) ;
printf ( " # Generic: SCSI device type 6 indicates a scanner \n " ) ;
printf ( " ATTRS{type}== \" 6 \" , ENV{libsane_matched}= \" yes \" \n \n " ) ;
printf ( " # Some scanners advertise themselves as SCSI device type 3 \n \n " ) ;
printf ( " # Wildcard: for some Epson SCSI scanners \n " ) ;
printf ( " ATTRS{type}== \" 3 \" , ATTRS{vendor}== \" EPSON \" , ATTRS{model}== \" SCANNER* \" , ENV{libsane_matched}= \" yes \" \n \n " ) ;
while ( scsiid )
{
manufacturer_model_type * name = scsiid - > name ;
if ( ! scsiid - > is_processor )
{
scsiid = scsiid - > next ;
continue ;
}
/* Wildcard for Epson scanners: vendor = EPSON, product = SCANNER* */
if ( ( strcmp ( scsiid - > scsi_vendor_id , " EPSON " ) = = 0 )
& & ( strncmp ( scsiid - > scsi_product_id , " SCANNER " , 7 ) = = 0 ) )
{
scsiid = scsiid - > next ;
continue ;
}
i = 0 ;
printf ( " # " ) ;
while ( name )
{
if ( ( name ! = scsiid - > name ) & & ( i > 0 ) )
printf ( " | " ) ;
printf ( " %s " , name - > name ) ;
name = name - > next ;
i + + ;
/*
* Limit the number of model names on the same line to 3 ,
* as udev cannot handle very long lines and prints a warning
* message while loading the rules files .
*/
if ( ( i = = 3 ) & & ( name ! = NULL ) )
{
printf ( " \n # " ) ;
i = 0 ;
}
}
printf ( " \n " ) ;
printf ( " ATTRS{type}== \" 3 \" , ATTRS{vendor}== \" %s \" , ATTRS{model}== \" %s \" , ENV{libsane_matched}= \" yes \" \n \n " ,
scsiid - > scsi_vendor_id , scsiid - > scsi_product_id ) ;
scsiid = scsiid - > next ;
}
printf ( " \n LABEL= \" libsane_rules_end \" \n " ) ;
}
/* print /usr/lib/udev/hwdb.d/20-sane.conf for Linux hwdb */
static void
print_hwdb_header ( void )
{
time_t current_time = time ( 0 ) ;
printf ( " # This file was automatically created based on description files (*.desc) \n "
" # by sane-desc %s from %s on %s " ,
SANE_DESC_VERSION , PACKAGE_STRING , asctime ( localtime ( & current_time ) ) ) ;
printf
( " # \n "
" # hwdb file for supported USB devices \n "
" # \n " ) ;
printf
( " # If your scanner isn't listed below, you can add it to a new hwdb file \n "
" # under /etc/udev/hwdb.d/. \n "
" # \n "
" # If your scanner is supported by some external backend (brother, epkowa, \n "
" # hpaio, etc) please ask the author of the backend to provide proper \n "
" # device detection support for your OS \n "
" # \n "
" # If the scanner is supported by sane-backends, please mail the entry to \n "
2018-04-18 12:36:00 +00:00
" # the sane-devel mailing list (sane-devel@alioth-lists.debian.net). \n "
2017-05-30 13:39:30 +00:00
" # "
2013-07-17 23:27:33 +00:00
) ;
}
static void
print_hwdb ( void )
{
usbid_type * usbid = create_usbids_table ( ) ;
char * vendor_id ;
char * product_id ;
int i , j ;
print_hwdb_header ( ) ;
while ( usbid )
{
manufacturer_model_type * name = usbid - > name ;
i = 0 ;
2017-05-30 13:39:30 +00:00
printf ( " \n # " ) ;
2013-07-17 23:27:33 +00:00
while ( name )
{
if ( ( name ! = usbid - > name ) & & ( i > 0 ) )
printf ( " | " ) ;
printf ( " %s " , name - > name ) ;
name = name - > next ;
i + + ;
/*
* Limit the number of model names on the same line to 3 ,
* as udev cannot handle very long lines and prints a warning
* message while loading the rules files .
*/
if ( ( i = = 3 ) & & ( name ! = NULL ) )
{
printf ( " \n # " ) ;
i = 0 ;
}
}
printf ( " \n " ) ;
vendor_id = strdup ( usbid - > usb_vendor_id + 2 ) ;
product_id = strdup ( usbid - > usb_product_id + 2 ) ;
for ( j = 0 ; j < 4 ; j + + ) {
vendor_id [ j ] = toupper ( vendor_id [ j ] ) ;
2013-10-24 12:22:17 +00:00
product_id [ j ] = toupper ( product_id [ j ] ) ;
2013-07-17 23:27:33 +00:00
}
2017-05-30 13:39:30 +00:00
printf ( " usb:v%sp%s* \n libsane_matched=yes \n " ,
2013-07-17 23:27:33 +00:00
vendor_id , product_id ) ;
free ( vendor_id ) ;
free ( product_id ) ;
usbid = usbid - > next ;
}
}
2006-05-27 07:50:05 +00:00
static void
print_plist ( void )
{
usbid_type * usbid = create_usbids_table ( ) ;
printf ( " <?xml version= \" 1.0 \" encoding= \" UTF-8 \" ?> \n " ) ;
printf ( " <!DOCTYPE plist PUBLIC \" -//Apple Computer//DTD PLIST 1.0//EN \" \" http://www.apple.com/DTDs/PropertyList-1.0.dtd \" > \n " ) ;
printf ( " <plist version= \" 1.0 \" > \n " ) ;
printf ( " <dict> \n " ) ;
printf ( " \t <key>device info version</key> \n " ) ;
printf ( " \t <string>2.0</string> \n " ) ;
printf ( " \t <key>usb</key> \n " ) ;
printf ( " \t <dict> \n " ) ;
printf ( " \t \t <key>IOUSBDevice</key> \n " ) ;
printf ( " \t \t <array> \n " ) ;
while ( usbid )
{
printf ( " \t \t \t <dict> \n " ) ;
printf ( " \t \t \t \t <key>device type</key> \n " ) ;
printf ( " \t \t \t \t <string>scanner</string> \n " ) ;
printf ( " \t \t \t \t <key>product</key> \n " ) ;
printf ( " \t \t \t \t <string>%s</string> \n " , usbid - > usb_product_id ) ;
printf ( " \t \t \t \t <key>vendor</key> \n " ) ;
printf ( " \t \t \t \t <string>%s</string> \n " , usbid - > usb_vendor_id ) ;
printf ( " \t \t \t </dict> \n " ) ;
usbid = usbid - > next ;
}
printf ( " \t \t </array> \n " ) ;
printf ( " \t </dict> \n " ) ;
printf ( " </dict> \n " ) ;
2006-05-27 14:56:58 +00:00
printf ( " </plist> \n " ) ;
2006-05-27 07:50:05 +00:00
}
2007-03-18 09:31:10 +00:00
static void
2008-03-28 20:57:59 +00:00
print_hal ( int new )
2007-03-18 09:31:10 +00:00
{
int i ;
2009-01-13 21:11:28 +00:00
SANE_Bool in_match ;
char * last_vendor ;
2009-01-13 21:17:16 +00:00
scsiid_type * scsiid = create_scsiids_table ( ) ;
2007-03-18 09:31:10 +00:00
usbid_type * usbid = create_usbids_table ( ) ;
2009-01-13 21:11:28 +00:00
2007-03-18 09:31:10 +00:00
printf ( " <?xml version= \" 1.0 \" encoding= \" UTF-8 \" ?> \n " ) ;
printf ( " <deviceinfo version= \" 0.2 \" > \n " ) ;
printf ( " <device> \n " ) ;
2009-01-13 21:17:16 +00:00
printf ( " <!-- SCSI-SUBSYSTEM --> \n " ) ;
printf ( " <match key= \" info.category \" string= \" scsi_generic \" > \n " ) ;
printf ( " <!-- Some SCSI Scanners announce themselves \" processor \" --> \n " ) ;
printf ( " <match key= \" @info.parent:scsi.type \" string= \" processor \" > \n " ) ;
last_vendor = " " ;
in_match = SANE_FALSE ;
while ( scsiid )
{
manufacturer_model_type * name = scsiid - > name ;
if ( ! scsiid - > is_processor )
{
scsiid = scsiid - > next ;
continue ;
}
if ( strcmp ( last_vendor , scsiid - > scsi_vendor_id ) ! = 0 )
{
if ( in_match )
printf ( " </match> \n " ) ;
printf ( " <match key= \" @info.parent:scsi.vendor \" string= \" %s \" > \n " , scsiid - > scsi_vendor_id ) ;
last_vendor = scsiid - > scsi_vendor_id ;
in_match = SANE_TRUE ;
}
printf ( " <!-- SCSI Scanner " ) ;
while ( name )
{
if ( name ! = scsiid - > name )
printf ( " | " ) ;
printf ( " \" %s \" " , name - > name ) ;
name = name - > next ;
}
printf ( " --> \n " ) ;
printf ( " <match key= \" @info.parent:scsi.model \" string= \" %s \" > \n " , scsiid - > scsi_product_id ) ;
printf ( " <append key= \" info.capabilities \" type= \" strlist \" >scanner</append> \n " ) ;
printf ( " </match> \n " ) ;
scsiid = scsiid - > next ;
}
if ( in_match )
printf ( " </match> \n " ) ;
printf ( " </match> \n " ) ;
printf ( " </match> \n " ) ;
printf ( " <!-- USB-SUBSYSTEM --> \n " ) ;
2009-01-13 21:11:28 +00:00
2008-03-28 20:57:59 +00:00
if ( new )
printf ( " <match key= \" info.subsystem \" string= \" usb \" > \n " ) ;
else
printf ( " <match key= \" info.bus \" string= \" usb \" > \n " ) ;
2009-01-13 21:11:28 +00:00
last_vendor = " " ;
in_match = SANE_FALSE ;
2007-03-18 09:31:10 +00:00
while ( usbid )
{
manufacturer_model_type * name = usbid - > name ;
2009-01-13 21:11:28 +00:00
if ( strcmp ( last_vendor , usbid - > usb_vendor_id ) ! = 0 )
{
if ( in_match )
printf ( " </match> \n " ) ;
printf ( " <match key= \" usb.vendor_id \" int= \" %s \" > \n " , usbid - > usb_vendor_id ) ;
last_vendor = usbid - > usb_vendor_id ;
in_match = SANE_TRUE ;
}
2007-03-18 09:31:10 +00:00
i = 0 ;
2009-01-13 21:11:28 +00:00
printf ( " <!-- " ) ;
2007-03-18 09:31:10 +00:00
while ( name )
{
if ( ( name ! = usbid - > name ) & & ( i > 0 ) )
printf ( " | " ) ;
2009-01-13 21:11:28 +00:00
2007-03-18 09:31:10 +00:00
printf ( " %s " , name - > name ) ;
name = name - > next ;
i + + ;
2009-01-13 21:11:28 +00:00
if ( ( i = = 3 ) & & ( name ! = NULL ) )
{
printf ( " \n " ) ;
i = 0 ;
}
2007-03-18 09:31:10 +00:00
}
printf ( " --> \n " ) ;
printf ( " <match key= \" usb.product_id \" int= \" %s \" > \n " , usbid - > usb_product_id ) ;
printf ( " <append key= \" info.capabilities \" type= \" strlist \" >scanner</append> \n " ) ;
printf ( " <merge key= \" scanner.access_method \" type= \" string \" >proprietary</merge> \n " ) ;
printf ( " </match> \n " ) ;
2009-01-13 21:11:28 +00:00
2007-03-18 09:31:10 +00:00
usbid = usbid - > next ;
}
2009-01-13 21:11:28 +00:00
if ( in_match )
printf ( " </match> \n " ) ;
2007-03-18 09:31:10 +00:00
printf ( " </match> \n " ) ;
2009-01-13 21:11:28 +00:00
2007-03-18 09:31:10 +00:00
printf ( " </device> \n " ) ;
printf ( " </deviceinfo> \n " ) ;
}
2002-07-05 19:37:08 +00:00
int
main ( int argc , char * * argv )
{
2002-07-06 22:14:34 +00:00
program_name = strrchr ( argv [ 0 ] , ' / ' ) ;
if ( program_name )
+ + program_name ;
else
program_name = argv [ 0 ] ;
2002-07-05 19:37:08 +00:00
if ( ! get_options ( argc , argv ) )
return 1 ;
if ( ! read_files ( ) )
return 1 ;
switch ( mode )
{
2002-07-06 11:08:01 +00:00
case output_mode_ascii :
ascii_print_backends ( ) ;
break ;
2004-06-28 18:46:35 +00:00
case output_mode_xml :
2004-07-09 16:48:17 +00:00
xml_print_backends ( ) ;
2004-06-28 18:46:35 +00:00
break ;
2002-07-12 20:17:53 +00:00
case output_mode_html_backends_split :
html_print_backends_split ( ) ;
break ;
2002-07-06 11:08:01 +00:00
case output_mode_html_mfgs :
html_print_mfgs ( ) ;
break ;
2006-01-07 19:36:24 +00:00
case output_mode_statistics :
print_statistics ( ) ;
break ;
2006-01-08 20:42:53 +00:00
case output_mode_usermap :
print_usermap ( ) ;
break ;
case output_mode_db :
print_db ( ) ;
break ;
case output_mode_udev :
2011-06-02 09:05:30 +00:00
case output_mode_udevacl :
2006-01-08 20:42:53 +00:00
print_udev ( ) ;
break ;
2013-07-17 23:27:33 +00:00
case output_mode_udevhwdb :
print_udevhwdb ( ) ;
break ;
case output_mode_hwdb :
print_hwdb ( ) ;
break ;
2006-05-27 07:50:05 +00:00
case output_mode_plist :
print_plist ( ) ;
break ;
2007-03-18 09:31:10 +00:00
case output_mode_hal :
2008-03-28 20:57:59 +00:00
print_hal ( 0 ) ;
break ;
case output_mode_halnew :
print_hal ( 1 ) ;
2007-03-18 09:31:10 +00:00
break ;
2002-07-06 11:08:01 +00:00
default :
DBG_ERR ( " Unknown output mode \n " ) ;
return 1 ;
2002-07-05 19:37:08 +00:00
}
return 0 ;
}