1 /*
2    sane-desc.c -- generate list of supported SANE devices
3 
4    Copyright (C) 2002-2006 Henning Meier-Geinitz <henning@meier-geinitz.de>
5    Copyright (C) 2004 Jose Gato <jgato@gsyc.escet.urjc.es> (XML output)
6    Copyright (C) 2006 Mattias Ellert <mattias.ellert@tsl.uu.se> (plist output)
7    Copyright (C) 2009 Dr. Ing. Dieter Jurzitza <dieter.jurzitza@t-online.de>
8    Copyright (C) 2013 Tom Gundersen <teg@jklm.no> (hwdb output)
9 
10    This file is part of the SANE package.
11 
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of the
15    License, or (at your option) any later version.
16 
17    This program is distributed in the hope that it will be useful, but
18    WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    General Public License for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <https://www.gnu.org/licenses/>.
24 */
25 
26 #include <../include/sane/config.h>
27 
28 #include "lgetopt.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdarg.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 #include <limits.h>
39 #include <ctype.h>
40 #include <time.h>
41 
42 #include "../include/sane/sane.h"
43 #include "../include/sane/sanei.h"
44 #include "../include/sane/sanei_config.h"
45 
46 #define SANE_DESC_VERSION "3.6"
47 
48 #define MAN_PAGE_LINK "man/%s.5.html"
49 #define COLOR_MINIMAL      "\"#B00000\""
50 #define COLOR_BASIC        "\"#FF9000\""
51 #define COLOR_GOOD         "\"#90B000\""
52 #define COLOR_COMPLETE     "\"#007000\""
53 #define COLOR_UNTESTED     "\"#0000B0\""
54 #define COLOR_UNSUPPORTED  "\"#F00000\""
55 #define COLOR_NEW          "\"#F00000\""
56 #define COLOR_UNKNOWN      "\"#000000\""
57 
58 #define DEVMODE  "0664"
59 #define DEVOWNER "root"
60 #define DEVGROUP "scanner"
61 
62 #ifndef PATH_MAX
63 # define PATH_MAX 1024
64 #endif
65 
66 #define DBG_ERR current_debug_level = 0; debug_call
67 #define DBG_WARN current_debug_level = 1; debug_call
68 #define DBG_INFO current_debug_level = 2; debug_call
69 #define DBG_DBG current_debug_level = 3; debug_call
70 
71 typedef enum output_mode
72 {
73   output_mode_ascii = 0,
74   output_mode_xml,
75   output_mode_html_backends,
76   output_mode_html_backends_split,
77   output_mode_html_mfgs,
78   output_mode_statistics,
79   output_mode_usermap,
80   output_mode_db,
81   output_mode_udev,
82   output_mode_udevacl,
83   output_mode_udevhwdb,
84   output_mode_hwdb,
85   output_mode_plist,
86   output_mode_hal,
87   output_mode_halnew
88 }
89 output_mode;
90 
91 typedef enum parameter_type
92 {
93   param_none = 0,
94   param_string,
95   param_two_strings,
96   param_three_strings
97 }
98 parameter_type;
99 
100 typedef enum status_entry
101 {
102   status_unknown,
103   status_unsupported,
104   status_untested,
105   status_minimal,
106   status_basic,
107   status_good,
108   status_complete
109 }
110 status_entry;
111 
112 typedef enum device_type
113 {
114   type_unknown,
115   type_scanner,
116   type_stillcam,
117   type_vidcam,
118   type_meta,
119   type_api
120 }
121 device_type;
122 
123 typedef enum level
124 {
125   level_backend,
126   level_mfg,
127   level_model,
128   level_desc
129 }
130 level;
131 
132 typedef struct url_entry
133 {
134   struct url_entry *next;
135   char *name;
136 }
137 url_entry;
138 
139 typedef struct model_entry
140 {
141   struct model_entry *next;
142   char *name;
143   char *interface;
144   struct url_entry *url;
145   char *comment;
146   enum status_entry status;
147   char *usb_vendor_id;
148   char *usb_product_id;
149   SANE_Bool ignore_usb_id;
150   char *scsi_vendor_id;
151   char *scsi_product_id;
152   SANE_Bool scsi_is_processor;
153 }
154 model_entry;
155 
156 typedef struct desc_entry
157 {
158   struct desc_entry *next;
159   char *desc;
160   struct url_entry *url;
161   char *comment;
162 }
163 desc_entry;
164 
165 typedef struct mfg_entry
166 {
167   struct mfg_entry *next;
168   char *name;
169   struct url_entry *url;
170   char *comment;
171   struct model_entry *model;
172 }
173 mfg_entry;
174 
175 typedef struct type_entry
176 {
177   struct type_entry *next;
178   enum device_type type;
179   struct desc_entry *desc;
180   struct mfg_entry *mfg;
181 }
182 type_entry;
183 
184 typedef struct backend_entry
185 {
186   struct backend_entry *next;
187   char *name;
188   char *version;
189   char *manpage;
190   struct url_entry *url;
191   char *comment;
192   struct type_entry *type;
193   SANE_Bool new;
194 }
195 backend_entry;
196 
197 typedef struct model_record_entry
198 {
199   struct model_record_entry *next;
200   char *name;
201   char *interface;
202   struct url_entry *url;
203   char *comment;
204   enum status_entry status;
205   char *usb_vendor_id;
206   char *usb_product_id;
207   char *scsi_vendor_id;
208   char *scsi_product_id;
209   SANE_Bool scsi_is_processor;
210   struct backend_entry *be;
211 }
212 model_record_entry;
213 
214 typedef struct mfg_record_entry
215 {
216   struct mfg_record_entry *next;
217   char *name;
218   char *comment;
219   struct url_entry *url;
220   struct model_record_entry *model_record;
221 }
222 mfg_record_entry;
223 
224 typedef int  statistics_type [status_complete + 1];
225 
226 
227 typedef struct manufacturer_model_type
228 {
229   struct manufacturer_model_type * next;
230   char *name;
231 }
232 manufacturer_model_type;
233 
234 typedef struct usbid_type
235 {
236   struct usbid_type * next;
237   char *usb_vendor_id;
238   char *usb_product_id;
239   struct manufacturer_model_type *name;
240 }
241 usbid_type;
242 
243 typedef struct scsiid_type
244 {
245   struct scsiid_type * next;
246   char *scsi_vendor_id;
247   char *scsi_product_id;
248   SANE_Bool is_processor;
249   struct manufacturer_model_type *name;
250 }
251 scsiid_type;
252 
253 static char *program_name;
254 static int debug = 0;
255 static int current_debug_level = 0;
256 static char *search_dir_spec = 0;
257 static backend_entry *first_backend = 0;
258 static enum output_mode mode = output_mode_ascii;
259 static char *title = 0;
260 static char *intro = 0;
261 static SANE_String desc_name = 0;
262 static const char *status_name[] =
263   {"Unknown", "Unsupported", "Untested", "Minimal", "Basic",
264    "Good", "Complete"};
265 static const char *device_type_name[] =
266   {"Unknown", "Scanners", "Still cameras", "Video Cameras", "Meta backends",
267    "APIs"};
268 static const char *device_type_aname[] =
269   {"UNKNOWN", "SCANNERS", "STILL", "VIDEO", "META",
270    "API"};
271 static const char *status_color[] =
272   {COLOR_UNKNOWN, COLOR_UNSUPPORTED, COLOR_UNTESTED, COLOR_MINIMAL,
273    COLOR_BASIC, COLOR_GOOD, COLOR_COMPLETE};
274 
275 
276 static void
debug_call(const char *fmt, ...)277 debug_call (const char *fmt, ...)
278 {
279   va_list ap;
280   char *level_txt;
281 
282   va_start (ap, fmt);
283   if (debug >= current_debug_level)
284     {
285       /* print to stderr */
286       switch (current_debug_level)
287 	{
288 	case 0:
289 	  level_txt = "ERROR:";
290 	  break;
291 	case 1:
292 	  level_txt = "Warning:";
293 	  break;
294 	case 2:
295 	  level_txt = "Info:";
296 	  break;
297 	default:
298 	  level_txt = "";
299 	  break;
300 	}
301       if (desc_name)
302 	fprintf (stderr, "%s: %8s ", desc_name, level_txt);
303       else
304 	fprintf (stderr, "[%s] %8s ", program_name, level_txt);
305       vfprintf (stderr, fmt, ap);
306     }
307   va_end (ap);
308 }
309 
310 static void
print_usage(char *program_name)311 print_usage (char *program_name)
312 {
313   printf ("Usage: %s [-s dir] [-m mode] [-d level] [-h] [-V]\n",
314 	  program_name);
315   printf ("  -s|--search-dir dir    "
316 	  "Specify the directory that contains .desc files\n"
317 	  "                         "
318 	  "(multiple directories can be concatenated by \":\")\n");
319   printf ("  -m|--mode mode         "
320 	  "Output mode (ascii, html-backends-split, html-mfgs,\n"
321 	  "                         xml, statistics, usermap, db, udev, udev+acl, udev+hwdb, hwdb, plist, hal, hal-new)\n");
322   printf ("  -t|--title \"title\"     The title used for HTML pages\n");
323   printf ("  -i|--intro \"intro\"     A short description of the "
324 	  "contents of the page\n");
325   printf ("  -d|--debug-level level Specify debug level (0-3)\n");
326   printf ("  -h|--help              Print help message\n");
327   printf ("  -V|--version           Print version information\n");
328   printf ("Report bugs to <henning@meier-geinitz.de>\n");
329 }
330 
331 static void
print_version(void)332 print_version (void)
333 {
334   printf ("sane-desc %s (%s)\n", SANE_DESC_VERSION, PACKAGE_STRING);
335   printf ("Copyright (C) 2002-2006 Henning Meier-Geinitz "
336 	  "<henning@meier-geinitz.de>\n"
337 	  "sane-desc comes with NO WARRANTY, to the extent permitted by "
338 	  "law.\n"
339 	  "You may redistribute copies of sane-desc under the terms of the "
340 	  "GNU General\n"
341 	  "Public License.\n"
342 	  "For more information about these matters, see the file named "
343 	  "COPYING.\n");
344 }
345 
346 static SANE_Bool
get_options(int argc, char **argv)347 get_options (int argc, char **argv)
348 {
349   int longindex;
350   int opt;
351   static struct option desc_options[] = {
352     {"search-dir", required_argument, NULL, 's'},
353     {"mode", required_argument, NULL, 'm'},
354     {"title", required_argument, NULL, 't'},
355     {"intro", required_argument, NULL, 'i'},
356     {"debug-level", required_argument, NULL, 'd'},
357     {"help", 0, NULL, 'h'},
358     {"version", 0, NULL, 'V'},
359     {0, 0, 0, 0}
360   };
361 
362   while ((opt = getopt_long (argc, argv, "s:m:t:i:d:hV", desc_options,
363 			     &longindex)) != -1)
364     {
365       switch (opt)
366 	{
367 	case 'h':
368 	  print_usage (argv[0]);
369 	  exit (0);
370 	case 'V':
371 	  print_version ();
372 	  exit (0);
373 	case 's':
374 	  search_dir_spec = strdup (optarg);
375 	  DBG_INFO ("setting search directory to `%s'\n", search_dir_spec);
376 	  break;
377 	case 'm':
378 	  if (strcmp (optarg, "ascii") == 0)
379 	    {
380 	      DBG_INFO ("Output mode: %s\n", optarg);
381 	      mode = output_mode_ascii;
382 	    }
383 	  else if (strcmp (optarg, "xml") == 0)
384 	    {
385 	      DBG_INFO ("Output mode: %s\n", optarg);
386 	      mode = output_mode_xml;
387 	    }
388 	  else if (strcmp (optarg, "html-backends-split") == 0)
389 	    {
390 	      DBG_INFO ("Output mode: %s\n", optarg);
391 	      mode = output_mode_html_backends_split;
392 	    }
393 	  else if (strcmp (optarg, "html-mfgs") == 0)
394 	    {
395 	      DBG_INFO ("Output mode: %s\n", optarg);
396 	      mode = output_mode_html_mfgs;
397 	    }
398 	  else if (strcmp (optarg, "statistics") == 0)
399 	    {
400 	      DBG_INFO ("Output mode: %s\n", optarg);
401 	      mode = output_mode_statistics;
402 	    }
403 	  else if (strcmp (optarg, "usermap") == 0)
404 	    {
405 	      DBG_INFO ("Output mode: %s\n", optarg);
406 	      mode = output_mode_usermap;
407 	    }
408 	  else if (strcmp (optarg, "db") == 0)
409 	    {
410 	      DBG_INFO ("Output mode: %s\n", optarg);
411 	      mode = output_mode_db;
412 	    }
413 	  else if (strcmp (optarg, "udev") == 0)
414 	    {
415 	      DBG_INFO ("Output mode: %s\n", optarg);
416 	      mode = output_mode_udev;
417 	    }
418 	  else if (strcmp (optarg, "udev+acl") == 0)
419 	    {
420 	      DBG_INFO ("Output mode: %s\n", optarg);
421 	      mode = output_mode_udevacl;
422 	    }
423 	  else if (strcmp (optarg, "udev+hwdb") == 0)
424 	    {
425 	      DBG_INFO ("Output mode: %s\n", optarg);
426 	      mode = output_mode_udevhwdb;
427 	    }
428 	  else if (strcmp (optarg, "hwdb") == 0)
429 	    {
430 	      DBG_INFO ("Output mode: %s\n", optarg);
431 	      mode = output_mode_hwdb;
432 	    }
433 	  else if (strcmp (optarg, "plist") == 0)
434 	    {
435 	      DBG_INFO ("Output mode: %s\n", optarg);
436 	      mode = output_mode_plist;
437 	    }
438 	  else if (strcmp (optarg, "hal") == 0)
439 	    {
440 	      DBG_INFO ("Output mode: %s\n", optarg);
441 	      mode = output_mode_hal;
442 	    }
443 	  else if (strcmp (optarg, "hal-new") == 0)
444 	    {
445 	      DBG_INFO ("Output mode: %s\n", optarg);
446 	      mode = output_mode_halnew;
447 	    }
448 	  else
449 	    {
450 	      DBG_ERR ("Unknown output mode: %s\n", optarg);
451 	      exit (1);
452 	    }
453 	  break;
454 	case 't':
455 	  title = optarg;
456 	  DBG_INFO ("setting title to `%s'\n", optarg);
457 	  break;
458 	case 'i':
459 	  intro = optarg;
460 	  DBG_INFO ("setting intro to `%s'\n", optarg);
461 	  break;
462 	case 'd':
463 	  debug = atoi (optarg);
464 	  DBG_INFO ("setting debug level to %d\n", debug);
465 	  break;
466 	case '?':
467 	  DBG_ERR ("unknown option (use -h for help)\n");
468 	  return SANE_FALSE;
469 	case ':':
470 	  DBG_ERR ("missing parameter (use -h for help)\n");
471 	  return SANE_FALSE;
472 	default:
473 	  DBG_ERR ("missing option (use -h for help)\n");
474 	  return SANE_FALSE;
475 	}
476     }
477   if (!search_dir_spec)
478     search_dir_spec = ".";
479   return SANE_TRUE;
480 }
481 
482 static int
char_compare(char char1, char char2)483 char_compare (char char1, char char2)
484 {
485   char1 = toupper (char1);
486   char2 = toupper (char2);
487 
488   if (char1 < char2)
489     return -1;
490   else if (char1 > char2)
491     return 1;
492   else
493     return 0;
494 }
495 
496 static int
num_compare(char *num_string1, char *num_string2)497 num_compare (char *num_string1, char *num_string2)
498 {
499   int num1 = atoi (num_string1);
500   int num2 = atoi (num_string2);
501   if (num1 < num2)
502     return -1;
503   else if (num1 > num2)
504     return 1;
505   else
506     return 0;
507 }
508 
509 /* Compare two strings, try to sort numbers correctly (600 < 1200) */
510 static int
string_compare(char *string1, char *string2)511 string_compare (char *string1, char *string2)
512 {
513   int count = 0;
514   int compare = 0;
515 
516   if (!string1)
517     {
518       if (!string2)
519 	return 0;
520       else
521 	return 1;
522     }
523   else if (!string2)
524     return -1;
525 
526   while (string1[count] && string2[count])
527     {
528       if (isdigit (string1[count]) && isdigit (string2[count]))
529 	compare = num_compare (&string1[count], &string2[count]);
530       else
531 	compare = char_compare (string1[count], string2[count]);
532       if (compare != 0)
533 	return compare;
534       count++;
535     }
536   return char_compare (string1[count], string2[count]);
537 }
538 
539 /* Add URLs to the end of the list if they are unique */
540 static url_entry *
update_url_list(url_entry * first_url, char *new_url)541 update_url_list (url_entry * first_url, char *new_url)
542 {
543   url_entry *url = first_url;
544   SANE_Bool found = SANE_FALSE;
545 
546   while (url && url->name)
547     {
548       if (string_compare (url->name, new_url) == 0)
549 	found = SANE_TRUE;
550       url = url->next;
551     }
552   if (found)
553     return first_url;
554 
555   url = first_url;
556   if (url)
557     {
558       while (url->next)
559 	url = url->next;
560       url->next = calloc (1, sizeof (url_entry));
561       url = url->next;
562     }
563   else
564     {
565       first_url = calloc (1, sizeof (url_entry));
566       url = first_url;
567     }
568   if (!url)
569     {
570       DBG_ERR ("update_url_list: couldn't calloc url_entry\n");
571       exit (1);
572     }
573   url->name = new_url;
574   return first_url;
575 }
576 
577 /* Get the next token, ignoring escaped quotation marks */
578 static const char *
get_token(const char *str, char **string_const)579 get_token (const char *str, char **string_const)
580 {
581   const char *start;
582   size_t len;
583 
584   str = sanei_config_skip_whitespace (str);
585 
586   if (*str == '"')
587     {
588       start = ++str;
589       while (*str && (*str != '"' || *(str - 1) == '\\'))
590 	++str;
591       len = str - start;
592       if (*str == '"')
593 	++str;
594       else
595 	start = 0;		/* final double quote is missing */
596     }
597   else
598     {
599       start = str;
600       while (*str && !isspace (*str))
601 	++str;
602       len = str - start;
603     }
604   if (start)
605     *string_const = strndup (start, len);
606   else
607     *string_const = NULL;
608   return str;
609 }
610 
611 /* Checks a line for a keyword token and determines keyword/string argument */
612 static SANE_Status
read_keyword(SANE_String line, SANE_String keyword_token, parameter_type p_type, void *argument)613 read_keyword (SANE_String line, SANE_String keyword_token,
614 	      parameter_type p_type, void *argument)
615 {
616   SANE_String_Const cp;
617   SANE_Char *word;
618 
619   word = 0;
620 
621   cp = get_token (line, &word);
622 
623   if (!word)
624     {
625       DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
626       return SANE_STATUS_INVAL;
627     }
628 
629   if (strcmp (word, keyword_token) != 0)
630     {
631       free(word);
632       return SANE_STATUS_INVAL;
633     }
634 
635   free (word);
636   word = 0;
637 
638   switch (p_type)
639     {
640     case param_none:
641       return SANE_STATUS_GOOD;
642     case param_string:
643       {
644 	char *pos;
645 	cp = get_token (cp, &word);
646 	if (!word)
647 	  {
648 	    DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
649 	    return SANE_STATUS_INVAL;
650 	  }
651 	/* remove escaped quotations */
652 	while ((pos = strstr (word, "\\\"")) != 0)
653 	  *pos = ' ';
654 
655 	DBG_DBG ("read_keyword: set entry `%s' to `%s'\n", keyword_token,
656 		 word);
657 	*(SANE_String *) argument = strdup (word);
658 	break;
659       }
660     case param_two_strings:
661       {
662 	char *pos;
663 	char **strings = malloc (2 * sizeof (SANE_String));
664 
665 	cp = get_token (cp, &word);
666 	if (!word)
667 	  {
668 	    free(strings);
669 	    DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
670 	    return SANE_STATUS_INVAL;
671 	  }
672 	/* remove escaped quotations */
673 	while ((pos = strstr (word, "\\\"")) != 0)
674 	  *pos = ' ';
675 	DBG_INFO ("read_keyword: set first entry of `%s' to `%s'\n", keyword_token,
676 		 word);
677 	strings[0] = strdup (word);
678 	if (word)
679 	  free (word);
680 
681 	cp = get_token (cp, &word);
682 	if (!word)
683 	  {
684 	    free(strings);
685 	    DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
686 	    return SANE_STATUS_INVAL;
687 	  }
688 	/* remove escaped quotations */
689 	while ((pos = strstr (word, "\\\"")) != 0)
690 	  *pos = ' ';
691 	DBG_INFO ("read_keyword: set second entry of `%s' to `%s'\n", keyword_token,
692 		 word);
693 	strings[1] = strdup (word);
694 	* (SANE_String **) argument = strings;
695 	break;
696       }
697     case param_three_strings:
698       {
699 	char *pos;
700 	char **strings = malloc (3 * sizeof (SANE_String));
701 
702 	cp = get_token (cp, &word);
703 	if (!word)
704 	  {
705 	    free(strings);
706 	    DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
707 	    return SANE_STATUS_INVAL;
708 	  }
709 	/* remove escaped quotations */
710 	while ((pos = strstr (word, "\\\"")) != 0)
711 	  *pos = ' ';
712 	DBG_INFO ("read_keyword: set first entry of `%s' to `%s'\n", keyword_token,
713 		 word);
714 	strings[0] = strdup (word);
715 	if (word)
716 	  free (word);
717 
718 	cp = get_token (cp, &word);
719 	if (!word)
720 	  {
721 	    free(strings);
722 	    DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
723 	    return SANE_STATUS_INVAL;
724 	  }
725 	/* remove escaped quotations */
726 	while ((pos = strstr (word, "\\\"")) != 0)
727 	  *pos = ' ';
728 	DBG_INFO ("read_keyword: set second entry of `%s' to `%s'\n", keyword_token,
729 		 word);
730 	strings[1] = strdup (word);
731 	if (word)
732 	  free (word);
733 
734 	cp = get_token (cp, &word);
735 	if (!word)
736 	  {
737 	    free(strings);
738 	    DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
739 	    return SANE_STATUS_INVAL;
740 	  }
741 	/* remove escaped quotations */
742 	while ((pos = strstr (word, "\\\"")) != 0)
743 	  *pos = ' ';
744 	DBG_INFO ("read_keyword: set third entry of `%s' to `%s'\n", keyword_token,
745 		 word);
746 	strings[2] = strdup (word);
747 	* (SANE_String **) argument = strings;
748 	break;
749       }
750     default:
751       DBG_ERR ("read_keyword: unknown param_type %d\n", p_type);
752       return SANE_STATUS_INVAL;
753     }
754 
755   if (word)
756     free (word);
757   word = 0;
758   return SANE_STATUS_GOOD;
759 }
760 
761 /* Check for a all-lowercase 4-digit hex number (e.g. 0x1234) */
762 static SANE_Bool
check_hex(SANE_String string)763 check_hex (SANE_String string)
764 {
765   unsigned int i;
766 
767   if (strlen (string) != 6)
768     return SANE_FALSE;
769   if (strncmp (string, "0x", 2) != 0)
770     return SANE_FALSE;
771   for (i = 0; i < strlen (string); i++)
772     {
773       if (isupper (string[i]))
774 	return SANE_FALSE;
775     }
776   for (i = 2; i < strlen (string); i++)
777     {
778       if (!isxdigit (string[i]))
779 	return SANE_FALSE;
780     }
781   return SANE_TRUE;
782 }
783 
784 /* Read and interpret the .desc files */
785 static SANE_Bool
read_files(void)786 read_files (void)
787 {
788   struct stat stat_buf;
789   DIR *dir;
790   struct dirent *dir_entry;
791   FILE *fp;
792   char file_name[PATH_MAX];
793   SANE_Char line[4096], *word;
794   SANE_String_Const cp;
795   backend_entry *current_backend = 0;
796   type_entry *current_type = 0;
797   mfg_entry *current_mfg = 0;
798   model_entry *current_model = 0;
799   enum level current_level = level_backend;
800   char *search_dir = search_dir_spec, *end = 0;
801 
802   DBG_INFO ("looking for .desc files in `%s'\n", search_dir_spec);
803 
804   while (search_dir && search_dir[0])
805     {
806       end = strchr (search_dir, ':');
807       if (end)
808 	end[0] = '\0';
809       DBG_INFO ("reading directory `%s'\n", search_dir);
810 
811       if (stat (search_dir, &stat_buf) < 0)
812 	{
813 	  DBG_ERR ("cannot stat `%s' (%s)\n", search_dir, strerror (errno));
814 	  return SANE_FALSE;
815 	}
816       if (!S_ISDIR (stat_buf.st_mode))
817 	{
818 	  DBG_ERR ("`%s' is not a directory\n", search_dir);
819 	  return SANE_FALSE;
820 	}
821       if ((dir = opendir (search_dir)) == 0)
822 	{
823 	  DBG_ERR ("cannot read directory `%s' (%s)\n", search_dir,
824 		   strerror (errno));
825 	  return SANE_FALSE;
826 	}
827 
828       while ((dir_entry = readdir (dir)) != NULL)
829 	{
830 	  if (strlen (dir_entry->d_name) > 5 &&
831 	      strcmp (dir_entry->d_name + strlen (dir_entry->d_name) - 5,
832 		      ".desc") == 0)
833 	    {
834 	      if (strlen (search_dir)
835 		  + strlen (dir_entry->d_name) + 1 + 1 > PATH_MAX)
836 		{
837 		  DBG_ERR ("filename too long\n");
838 		  return SANE_FALSE;
839 		}
840 	      sprintf (file_name, "%s/%s", search_dir, dir_entry->d_name);
841 	      DBG_INFO ("-> reading desc file: %s\n", file_name);
842 	      fp = fopen (file_name, "r");
843 	      if (!fp)
844 		{
845 		  DBG_ERR ("can't open desc file: %s (%s)\n", file_name,
846 			   strerror (errno));
847 		  return SANE_FALSE;
848 		}
849 	      /* now we check if everything is ok with the previous backend
850 		 before we read the new one */
851 	      if (current_backend)
852 		{
853 		  type_entry *current_type = current_backend->type;
854 		  int no_usbids = 0;
855 		  int no_interface = 0;
856 		  int no_status = 0;
857 
858 		  while (current_type)
859 		    {
860 		      if (current_type->type == type_scanner ||
861 			  current_type->type == type_stillcam ||
862 			  current_type->type == type_vidcam)
863 			{
864 			  mfg_entry *current_mfg = current_type->mfg;
865 
866 			  while (current_mfg)
867 			    {
868 			      model_entry *current_model = current_mfg->model;
869 
870 			      while (current_model)
871 				{
872 				  if (current_model->status == status_unknown)
873 				    {
874 				      DBG_INFO
875 					("Backend `%s': `%s' `%s' does not have a status\n",
876 					 current_backend->name,
877 					 current_mfg->name,
878 					 current_model->name);
879 				      no_status++;
880 				    }
881 				  if (!current_model->interface)
882 				    {
883 				      DBG_INFO
884 					("Backend `%s': `%s' `%s' does not have an interface\n",
885 					 current_backend->name,
886 					 current_mfg->name,
887 					 current_model->name);
888 				      no_interface++;
889 				    }
890 				  else if (strstr (current_model->interface, "USB"))
891 				    {
892 				      if ((!current_model->usb_vendor_id || !current_model->usb_product_id)
893 					  && !current_model->ignore_usb_id)
894 					{
895 					  DBG_INFO ("`%s' seems to provide a USB device "
896 						    "without :usbid (%s %s)\n",
897 						    current_backend->name,
898 						    current_mfg->name,
899 						    current_model->name);
900 					  no_usbids++;
901 					}
902 				    }
903 				  current_model = current_model->next;
904 				}
905 			      current_mfg = current_mfg->next;
906 			    }
907 			}
908 		      current_type = current_type->next;
909 		    }
910 		  if (no_status)
911 		    {
912 		      DBG_WARN ("Backend `%s': %d devices without :status\n",
913 				current_backend->name, no_status);
914 		    }
915 		  if (no_interface)
916 		    {
917 		      DBG_WARN ("Backend `%s': %d devices without :interface\n",
918 				current_backend->name, no_interface);
919 		    }
920 		  if (no_usbids)
921 		    {
922 		      DBG_WARN ("Backend `%s': %d USB devices without :usbid\n",
923 				current_backend->name, no_usbids);
924 		    }
925 		}
926 	      desc_name = dir_entry->d_name;
927 	      current_backend = 0;
928 	      current_type = 0;
929 	      current_mfg = 0;
930 	      current_model = 0;
931 	      while (sanei_config_read (line, sizeof (line), fp))
932 		{
933 		  char *string_entry = 0;
934 		  char **two_string_entry;
935 		  char **three_string_entry;
936 		  word = 0;
937 
938 		  cp = get_token (line, &word);
939 		  if (!word || cp == line)
940 		    {
941 		      DBG_DBG ("ignoring empty line\n");
942 		      if (word)
943 			free (word);
944 		      word = 0;
945 		      continue;
946 		    }
947 		  if (word[0] == ';')
948 		    {
949 		      DBG_DBG ("ignoring comment line\n");
950 		      free (word);
951 		      word = 0;
952 		      continue;
953 		    }
954 		  DBG_DBG ("line: %s\n", line);
955 
956 		  if (read_keyword
957 		      (line, ":backend", param_string,
958 		       &string_entry) == SANE_STATUS_GOOD)
959 		    {
960 		      backend_entry *be = first_backend, *prev_be =
961 			0, *new_be = 0;
962 		      DBG_INFO ("creating backend entry `%s'\n",
963 				string_entry);
964 
965 		      new_be = calloc (1, sizeof (backend_entry));
966 		      if (!new_be)
967 			{
968 			  DBG_ERR ("calloc failed (%s)\n", strerror (errno));
969 			  return SANE_FALSE;
970 			}
971 		      new_be->name = string_entry;
972 		      new_be->new = SANE_FALSE;
973 
974 		      if (!be)
975 			{
976 			  first_backend = new_be;
977 			  be = new_be;
978 			}
979 		      else
980 			{
981 			  while (be)
982 			    {
983 			      int compare =
984 				string_compare (new_be->name, be->name);
985 			      if (compare <= 0)
986 				{
987 				  backend_entry *be_tmp = be;
988 				  be = new_be;
989 				  be->next = be_tmp;
990 				  if (!prev_be)
991 				    first_backend = be;
992 				  else
993 				    prev_be->next = be;
994 				  break;
995 				}
996 			      prev_be = be;
997 			      be = be->next;
998 			    }
999 			  if (!be)	/* last entry */
1000 			    {
1001 			      prev_be->next = new_be;
1002 			      be = prev_be->next;
1003 			    }
1004 			}
1005 		      current_backend = be;
1006 		      current_type = 0;
1007 		      current_mfg = 0;
1008 		      current_model = 0;
1009 		      current_level = level_backend;
1010 		      continue;
1011 		    }
1012 		  if (!current_backend)
1013 		    {
1014 		      DBG_ERR ("use `:backend' keyword first\n");
1015 		      return SANE_FALSE;
1016 		    }
1017 		  if (read_keyword
1018 		      (line, ":version", param_string,
1019 		       &string_entry) == SANE_STATUS_GOOD)
1020 		    {
1021 		      if (current_backend->version)
1022 			{
1023 			  DBG_WARN
1024 			    ("overwriting version of backend `%s' to `%s'"
1025 			     "(was: `%s')\n", current_backend->name,
1026 			     string_entry, current_backend->version,
1027 			     current_backend->version);
1028 			}
1029 
1030 		      DBG_INFO ("setting version of backend `%s' to `%s'\n",
1031 				current_backend->name, string_entry);
1032 		      current_backend->version = string_entry;
1033 		      continue;
1034 		    }
1035 		  if (read_keyword
1036 		      (line, ":status", param_string,
1037 		       &string_entry) == SANE_STATUS_GOOD)
1038 		    {
1039 		      switch (current_level)
1040 			{
1041 			case level_model:
1042 			  if (current_model->status != status_unknown)
1043 			    {
1044 			      DBG_WARN
1045 				("overwriting status of model `%s' (backend `%s')\n",
1046 				 current_model->name, current_backend->name);
1047 			    }
1048 			  if (strcmp (string_entry, ":minimal") == 0)
1049 			    {
1050 			      DBG_INFO
1051 				("setting status of model `%s' to `minimal'\n",
1052 				 current_model->name);
1053 			      current_model->status = status_minimal;
1054 			    }
1055 			  else if (strcmp (string_entry, ":basic") == 0)
1056 			    {
1057 			      DBG_INFO
1058 				("setting status of model `%s' to `basic'\n",
1059 				 current_model->name);
1060 			      current_model->status = status_basic;
1061 			    }
1062 			  else if (strcmp (string_entry, ":good") == 0)
1063 			    {
1064 			      DBG_INFO
1065 				("setting status of model `%s' to `good'\n",
1066 				 current_model->name);
1067 			      current_model->status = status_good;
1068 			    }
1069 			  else if (strcmp (string_entry, ":complete") == 0)
1070 			    {
1071 			      DBG_INFO
1072 				("setting status of model `%s' to `complete'\n",
1073 				 current_model->name);
1074 			      current_model->status = status_complete;
1075 			    }
1076 			  else if (strcmp (string_entry, ":untested") == 0)
1077 			    {
1078 			      DBG_INFO
1079 				("setting status of model `%s' to `untested'\n",
1080 				 current_model->name);
1081 			      current_model->status = status_untested;
1082 			    }
1083 			  else if (strcmp (string_entry, ":unsupported") == 0)
1084 			    {
1085 			      DBG_INFO
1086 				("setting status of model `%s' to `unsupported'\n",
1087 				 current_model->name);
1088 			      current_model->status = status_unsupported;
1089 			    }
1090 			  else
1091 			    {
1092 			      DBG_ERR
1093 				("unknown status of model `%s': `%s' (backend `%s')\n",
1094 				 current_model->name, string_entry,
1095 				 current_backend->name);
1096 			      current_model->status = status_untested;
1097 			      return SANE_FALSE;
1098 			    }
1099 			  break;
1100 			default:
1101 			  DBG_ERR
1102 			    ("level %d not implemented for :status (backend `%s')\n",
1103 			     current_level, current_backend->name);
1104 			  return SANE_FALSE;
1105 			}
1106 
1107 
1108 		      continue;
1109 		    }
1110 		  if (read_keyword (line, ":new", param_string, &string_entry)
1111 		      == SANE_STATUS_GOOD)
1112 		    {
1113 		      if (strcmp (string_entry, ":yes") == 0)
1114 			{
1115 			  DBG_INFO
1116 			    ("backend %s is new in this SANE release\n",
1117 			     current_backend->name);
1118 			  current_backend->new = SANE_TRUE;
1119 			}
1120 		      else if (strcmp (string_entry, ":no") == 0)
1121 			{
1122 			  DBG_INFO
1123 			    ("backend %s is NOT new in this SANE release\n",
1124 			     current_backend->name);
1125 			  current_backend->new = SANE_FALSE;
1126 			}
1127 		      else
1128 			{
1129 			  DBG_ERR ("unknown :new parameter of backend `%s': "
1130 				   "`%s'\n", current_backend->name,
1131 				   string_entry);
1132 			  current_backend->new = SANE_FALSE;
1133 			  return SANE_FALSE;
1134 			}
1135 		      continue;
1136 		    }
1137 		  if (read_keyword
1138 		      (line, ":manpage", param_string,
1139 		       &string_entry) == SANE_STATUS_GOOD)
1140 		    {
1141 		      if (current_backend->manpage)
1142 			{
1143 			  DBG_WARN
1144 			    ("overwriting manpage of backend `%s' to `%s'"
1145 			     "(was: `%s')\n", current_backend->name,
1146 			     string_entry, current_backend->manpage);
1147 			}
1148 
1149 		      DBG_INFO ("setting manpage of backend `%s' to `%s'\n",
1150 				current_backend->name, string_entry);
1151 		      current_backend->manpage = string_entry;
1152 		      continue;
1153 		    }
1154 		  if (read_keyword
1155 		      (line, ":devicetype", param_string,
1156 		       &string_entry) == SANE_STATUS_GOOD)
1157 		    {
1158 		      type_entry *type = 0;
1159 
1160 		      type = current_backend->type;
1161 
1162 		      DBG_INFO
1163 			("adding `%s' to list of device types of backend "
1164 			 "`%s'\n", string_entry, current_backend->name);
1165 
1166 		      if (type)
1167 			{
1168 			  while (type->next)
1169 			    type = type->next;
1170 			  type->next = calloc (1, sizeof (type_entry));
1171 			  type = type->next;
1172 			}
1173 		      else
1174 			{
1175 			  current_backend->type =
1176 			    calloc (1, sizeof (type_entry));
1177 			  type = current_backend->type;
1178 			}
1179 
1180 		      type->type = type_unknown;
1181 		      if (strcmp (string_entry, ":scanner") == 0)
1182 			{
1183 			  DBG_INFO ("setting device type of backend `%s' to "
1184 				    "scanner\n", current_backend->name);
1185 			  type->type = type_scanner;
1186 			}
1187 		      else if (strcmp (string_entry, ":stillcam") == 0)
1188 			{
1189 			  DBG_INFO ("setting device type of backend `%s' to "
1190 				    "still camera\n", current_backend->name);
1191 			  type->type = type_stillcam;
1192 			}
1193 		      else if (strcmp (string_entry, ":vidcam") == 0)
1194 			{
1195 			  DBG_INFO ("setting device type of backend `%s' to "
1196 				    "video camera\n", current_backend->name);
1197 			  type->type = type_vidcam;
1198 			}
1199 		      else if (strcmp (string_entry, ":api") == 0)
1200 			{
1201 			  DBG_INFO ("setting device type of backend `%s' to "
1202 				    "API\n", current_backend->name);
1203 			  type->type = type_api;
1204 			}
1205 		      else if (strcmp (string_entry, ":meta") == 0)
1206 			{
1207 			  DBG_INFO ("setting device type of backend `%s' to "
1208 				    "meta\n", current_backend->name);
1209 			  type->type = type_meta;
1210 			}
1211 		      else
1212 			{
1213 			  DBG_ERR
1214 			    ("unknown device type of backend `%s': `%s'\n",
1215 			     current_backend->name, string_entry);
1216 			  type->type = type_unknown;
1217 			  return SANE_FALSE;
1218 			}
1219 		      current_type = type;
1220 		      current_mfg = 0;
1221 		      current_model = 0;
1222 		      continue;
1223 		    }
1224 		  if (read_keyword
1225 		      (line, ":desc", param_string,
1226 		       &string_entry) == SANE_STATUS_GOOD)
1227 		    {
1228 		      if (!current_type)
1229 			{
1230 			  DBG_ERR
1231 			    ("use `:devicetype' keyword first (backend `%s')\n",
1232 			     current_backend->name);
1233 			  return SANE_FALSE;
1234 			}
1235 		      if (current_type->type < type_meta)
1236 			{
1237 			  DBG_ERR
1238 			    ("use `:desc' for `:api' and `:meta' only (backend `%s')\n",
1239 			     current_backend->name);
1240 			  return SANE_FALSE;
1241 			}
1242 
1243 		      if (current_type->desc)
1244 			{
1245 			  DBG_WARN
1246 			    ("overwriting description of  device type of "
1247 			     "backend `%s' to `%s' (was: `%s')\n",
1248 			     current_backend->name, string_entry,
1249 			     current_type->desc);
1250 			}
1251 
1252 		      DBG_INFO
1253 			("setting description of backend `%s' to `%s'\n",
1254 			 current_backend->name, string_entry);
1255 		      current_type->desc = calloc (1, sizeof (desc_entry));
1256 		      if (!current_type->desc)
1257 			{
1258 			  DBG_ERR ("calloc failed (%s)\n", strerror (errno));
1259 			  return SANE_FALSE;
1260 			}
1261 		      current_type->desc->desc = string_entry;
1262 		      current_level = level_desc;
1263 		      current_mfg = 0;
1264 		      current_model = 0;
1265 		      continue;
1266 		    }
1267 		  if (read_keyword (line, ":mfg", param_string, &string_entry)
1268 		      == SANE_STATUS_GOOD)
1269 		    {
1270 		      mfg_entry *mfg = 0;
1271 
1272 		      if (!current_type)
1273 			{
1274 			  DBG_ERR
1275 			    ("use `:devicetype' keyword first (backend `%s')\n",
1276 			     current_backend->name);
1277 			  return SANE_FALSE;
1278 			}
1279 		      if (current_type->type >= type_meta)
1280 			{
1281 			  DBG_ERR
1282 			    ("use `:mfg' for hardware devices only (backend `%s')\n",
1283 			     current_backend->name);
1284 			  return SANE_FALSE;
1285 			}
1286 
1287 		      mfg = current_type->mfg;
1288 		      if (mfg)
1289 			{
1290 			  while (mfg->next)
1291 			    mfg = mfg->next;
1292 			  mfg->next = calloc (1, sizeof (mfg_entry));
1293 			  mfg = mfg->next;
1294 			}
1295 		      else
1296 			{
1297 			  current_type->mfg = calloc (1, sizeof (mfg_entry));
1298 			  mfg = current_type->mfg;
1299 			}
1300 
1301 		      if (!mfg)
1302 			{
1303 			  DBG_ERR ("calloc failed (%s)\n", strerror (errno));
1304 			  return SANE_FALSE;
1305 			}
1306 		      mfg->name = string_entry;
1307 		      DBG_INFO ("adding mfg entry %s to backend `%s'\n",
1308 				string_entry, current_backend->name);
1309 		      current_mfg = mfg;
1310 		      current_model = 0;
1311 		      current_level = level_mfg;
1312 		      continue;
1313 		    }
1314 		  if (read_keyword
1315 		      (line, ":model", param_string,
1316 		       &string_entry) == SANE_STATUS_GOOD)
1317 		    {
1318 		      model_entry *model = 0;
1319 
1320 		      if (!current_type)
1321 			{
1322 			  DBG_ERR
1323 			    ("use `:devicetype' keyword first (backend `%s')\n",
1324 			     current_backend->name);
1325 			  return SANE_FALSE;
1326 			}
1327 		      if (current_level != level_mfg
1328 			  && current_level != level_model)
1329 			{
1330 			  DBG_ERR
1331 			    ("use `:mfg' keyword first (backend `%s')\n",
1332 			     current_backend->name);
1333 			  return SANE_FALSE;
1334 			}
1335 		      model = current_mfg->model;
1336 		      if (model)
1337 			{
1338 			  while (model->next)
1339 			    model = model->next;
1340 			  model->next = calloc (1, sizeof (model_entry));
1341 			  model = model->next;
1342 			}
1343 		      else
1344 			{
1345 			  current_mfg->model =
1346 			    calloc (1, sizeof (model_entry));
1347 			  model = current_mfg->model;
1348 			}
1349 
1350 		      if (!model)
1351 			{
1352 			  DBG_ERR ("calloc failed (%s)\n", strerror (errno));
1353 			  return SANE_FALSE;
1354 			}
1355 		      model->name = string_entry;
1356 		      model->status = status_unknown;
1357 		      DBG_INFO
1358 			("adding model entry %s to manufacturer `%s'\n",
1359 			 string_entry, current_mfg->name);
1360 		      current_model = model;
1361 		      current_level = level_model;
1362 		      continue;
1363 		    }
1364 		  if (read_keyword
1365 		      (line, ":interface", param_string,
1366 		       &string_entry) == SANE_STATUS_GOOD)
1367 		    {
1368 		      if (!current_model)
1369 			{
1370 			  DBG_WARN
1371 			    ("ignored `%s' :interface, only allowed for "
1372 			     "hardware devices\n", current_backend->name);
1373 			  continue;
1374 			}
1375 
1376 		      if (current_model->interface)
1377 			{
1378 			  DBG_WARN ("overwriting `%s's interface of model "
1379 				    "`%s' to `%s' (was: `%s')\n",
1380 				    current_backend->name,
1381 				    current_model->name, string_entry,
1382 				    current_model->interface);
1383 			}
1384 
1385 		      DBG_INFO ("setting interface of model `%s' to `%s'\n",
1386 				current_model->name, string_entry);
1387 		      current_model->interface = string_entry;
1388 		      continue;
1389 		    }
1390 		  if (read_keyword
1391 		      (line, ":scsi", param_three_strings,
1392 		       &three_string_entry) == SANE_STATUS_GOOD)
1393 		    {
1394 		      if (!current_model)
1395 			{
1396 			  DBG_WARN
1397 			    ("ignored `%s' :scsi, only allowed for "
1398 			     "hardware devices\n", current_backend->name);
1399 			  continue;
1400 			}
1401 
1402 		      DBG_INFO ("setting scsi vendor and product ids of model `%s' to `%s/%s'\n",
1403 				current_model->name, three_string_entry[0], three_string_entry[1]);
1404 		      if (strcasecmp (three_string_entry[0], "ignore") == 0)
1405 			 {
1406 				DBG_INFO ("Ignoring `%s's scsi-entries of `%s'\n",
1407 						current_backend->name,
1408 						current_model->name);
1409 				continue;
1410 			 }
1411 			 if (strcasecmp (three_string_entry[2], "processor") == 0){
1412 				current_model->scsi_is_processor = SANE_TRUE;
1413 				current_model->scsi_vendor_id = three_string_entry[0];
1414 				current_model->scsi_product_id = three_string_entry[1];
1415 			 }
1416 			 else
1417 			 {
1418 				DBG_INFO ("scsi-format info in %s is invalid -> break\n", current_backend->name);
1419 				continue;
1420 			 }
1421 		      continue;
1422 		    }
1423 		  if (read_keyword
1424 		      (line, ":usbid", param_two_strings,
1425 		       &two_string_entry) == SANE_STATUS_GOOD)
1426 		    {
1427 		      if (!current_model)
1428 			{
1429 			  DBG_WARN
1430 			    ("ignored `%s' :usbid, only allowed for "
1431 			     "hardware devices\n", current_backend->name);
1432 			  continue;
1433 			}
1434 		      if (strcasecmp (two_string_entry[0], "ignore") == 0)
1435 			{
1436 			  DBG_INFO ("Ignoring `%s's USB ids of `%s'\n",
1437 				    current_backend->name,
1438 				    current_model->name);
1439 			  current_model->ignore_usb_id = SANE_TRUE;
1440 			  continue;
1441 			}
1442 		      if (!check_hex (two_string_entry[0]))
1443 			{
1444 			  DBG_WARN ("`%s's USB vendor id of `%s' is "
1445 				    "not a lowercase 4-digit hex number: "
1446 				    "`%s'\n", current_backend->name,
1447 				    current_model->name, two_string_entry[0]);
1448 			  continue;
1449 			}
1450 		      if (!check_hex (two_string_entry[1]))
1451 			{
1452 			  DBG_WARN ("`%s's USB product id of `%s' is "
1453 				    "not a lowercase 4-digit hex number: "
1454 				    "`%s'\n", current_backend->name,
1455 				    current_model->name, two_string_entry[1]);
1456 			  continue;
1457 			}
1458 
1459 		      if (current_model->usb_vendor_id || current_model->usb_product_id)
1460 			{
1461 			  DBG_WARN ("overwriting `%s's USB ids of model "
1462 				    "`%s' to `%s/%s' (was: `%s/%s')\n",
1463 				    current_backend->name,
1464 				    current_model->name, two_string_entry[0],
1465 				    two_string_entry[1],
1466 				    current_model->usb_vendor_id,
1467 				    current_model->usb_product_id);
1468 			}
1469 
1470 		      DBG_INFO ("setting USB vendor and product ids of model `%s' to `%s/%s'\n",
1471 				current_model->name, two_string_entry[0], two_string_entry[1]);
1472 		      current_model->usb_vendor_id = two_string_entry[0];
1473 		      current_model->usb_product_id = two_string_entry[1];
1474 		      continue;
1475 		    }
1476 		  if (read_keyword (line, ":url", param_string, &string_entry)
1477 		      == SANE_STATUS_GOOD)
1478 		    {
1479 		      switch (current_level)
1480 			{
1481 			case level_backend:
1482 			  current_backend->url =
1483 			    update_url_list (current_backend->url,
1484 					     string_entry);
1485 			  DBG_INFO ("adding `%s' to list of urls of backend "
1486 				    "`%s'\n", string_entry,
1487 				    current_backend->name);
1488 			  break;
1489 			case level_mfg:
1490 			  current_mfg->url =
1491 			    update_url_list (current_mfg->url, string_entry);
1492 			  DBG_INFO ("adding `%s' to list of urls of mfg "
1493 				    "`%s'\n", string_entry,
1494 				    current_mfg->name);
1495 			  break;
1496 			case level_desc:
1497 			  current_type->desc->url =
1498 			    update_url_list (current_type->desc->url,
1499 					     string_entry);
1500 			  DBG_INFO
1501 			    ("adding `%s' to list of urls of description "
1502 			     "for backend `%s'\n", string_entry,
1503 			     current_backend->name);
1504 			  break;
1505 			case level_model:
1506 			  current_model->url =
1507 			    update_url_list (current_model->url,
1508 					     string_entry);
1509 			  DBG_INFO ("adding `%s' to list of urls of model "
1510 				    "`%s'\n", string_entry,
1511 				    current_model->name);
1512 			  break;
1513 			default:
1514 			  DBG_ERR
1515 			    ("level %d not implemented for :url (backend `%s')\n",
1516 			     current_level, current_backend->name);
1517 			  return SANE_FALSE;
1518 			}
1519 		      continue;
1520 		    }
1521 		  if (read_keyword
1522 		      (line, ":comment", param_string,
1523 		       &string_entry) == SANE_STATUS_GOOD)
1524 		    {
1525 		      switch (current_level)
1526 			{
1527 			case level_backend:
1528 			  current_backend->comment = string_entry;
1529 			  DBG_INFO ("setting comment of backend %s to `%s'\n",
1530 				    current_backend->name, string_entry);
1531 			  break;
1532 			case level_mfg:
1533 			  current_mfg->comment = string_entry;
1534 			  DBG_INFO
1535 			    ("setting comment of manufacturer %s to `%s'\n",
1536 			     current_mfg->name, string_entry);
1537 			  break;
1538 			case level_desc:
1539 			  current_type->desc->comment = string_entry;
1540 			  DBG_INFO ("setting comment of description for "
1541 				    "backend %s to `%s'\n",
1542 				    current_backend->name, string_entry);
1543 			  break;
1544 			case level_model:
1545 			  current_model->comment = string_entry;
1546 			  DBG_INFO ("setting comment of model %s to `%s'\n",
1547 				    current_model->name, string_entry);
1548 			  break;
1549 			default:
1550 			  DBG_ERR
1551 			    ("level %d not implemented for `:comment' (backend `%s')\n",
1552 			     current_level, current_backend->name);
1553 			  return SANE_FALSE;
1554 			}
1555 		      continue;
1556 		    }
1557 		  DBG_ERR
1558 		    ("unknown keyword token in line `%s' of file `%s'\n",
1559 		     line, file_name);
1560 		  return SANE_FALSE;
1561 		}		/* while (sanei_config_readline) */
1562 	      fclose (fp);
1563 	    }			/* if (strlen) */
1564 	}			/* while (direntry) */
1565       if (closedir(dir) != 0)
1566 	{
1567 	  DBG_ERR ("cannot close directory `%s' (%s)\n", search_dir,
1568 		   strerror (errno));
1569 	  return SANE_FALSE;
1570 	}
1571       if (end)
1572 	search_dir = end + 1;
1573       else
1574 	search_dir = (search_dir + strlen (search_dir));
1575     }
1576 
1577   desc_name = 0;
1578   if (!first_backend)
1579     {
1580       DBG_ERR ("Couldn't find any .desc file\n");
1581       return SANE_FALSE;
1582     }
1583   return SANE_TRUE;
1584 }
1585 
1586 /* Create a model_record_entry based on a model_entry */
1587 static model_record_entry *
create_model_record(model_entry * model)1588 create_model_record (model_entry * model)
1589 {
1590   model_record_entry *model_record;
1591 
1592   model_record = calloc (1, sizeof (model_record_entry));
1593   if (!model_record)
1594     {
1595       DBG_ERR ("create_model_record: couldn't calloc model_record_entry\n");
1596       exit (1);
1597     }
1598   model_record->name = model->name;
1599   model_record->status = model->status;
1600   model_record->interface = model->interface;
1601   model_record->url = model->url;
1602   model_record->comment = model->comment;
1603   model_record->usb_vendor_id = model->usb_vendor_id;
1604   model_record->usb_product_id = model->usb_product_id;
1605   model_record->scsi_vendor_id = model->scsi_vendor_id;
1606   model_record->scsi_product_id = model->scsi_product_id;
1607   model_record->scsi_is_processor = model->scsi_is_processor;
1608   return model_record;
1609 }
1610 
1611 /* Calculate the priority of statuses: */
1612 /* minimal, basic, good, complete -> 2, untested -> 1, unsupported -> 0 */
1613 static int
calc_priority(status_entry status)1614 calc_priority (status_entry status)
1615 {
1616   switch (status)
1617     {
1618     case status_untested:
1619       return 1;
1620     case status_unsupported:
1621       return 0;
1622     default:
1623       return 2;
1624     }
1625 }
1626 
1627 /* Insert model into list at the alphabetically correct position */
1628 static model_record_entry *
update_model_record_list(model_record_entry * first_model_record, model_entry * model, backend_entry * be)1629 update_model_record_list (model_record_entry * first_model_record,
1630 			  model_entry * model, backend_entry * be)
1631 {
1632   model_record_entry *model_record = first_model_record;
1633 
1634   if (!first_model_record)
1635     {
1636       /* First model for this manufacturer */
1637       first_model_record = create_model_record (model);
1638       model_record = first_model_record;
1639     }
1640   else
1641     {
1642       model_record_entry *prev_model_record = 0;
1643 
1644       while (model_record)
1645 	{
1646 	  int compare = string_compare (model->name, model_record->name);
1647 	  if (compare <= 0)
1648 	    {
1649 	      model_record_entry *tmp_model_record = model_record;
1650 	      if ((compare == 0) &&
1651 		  (string_compare (model->interface, model_record->interface) == 0) &&
1652 		  (string_compare (model->usb_vendor_id, model_record->usb_vendor_id) == 0) &&
1653 		  (string_compare (model->usb_product_id, model_record->usb_product_id) == 0))
1654 		{
1655 		  /* Two entries for the same model */
1656 		  int new_priority = calc_priority (model->status);
1657 		  int old_priority = calc_priority (model_record->status);
1658 		  if (new_priority < old_priority)
1659 		    {
1660 		      DBG_DBG
1661 			("update_model_record_list: model %s ignored, backend %s has "
1662 			 "higher priority\n", model->name,
1663 			 model_record->be->name);
1664 		      return first_model_record;
1665 		    }
1666 		  if (new_priority > old_priority)
1667 		    {
1668 		      DBG_DBG
1669 			("update_model_record_list: model %s overrides the one from backend %s\n",
1670 			 model->name, model_record->be->name);
1671 		      tmp_model_record = model_record->next;
1672 		    }
1673 		}
1674 	      /* correct position */
1675 	      model_record = create_model_record (model);
1676 	      model_record->next = tmp_model_record;
1677 	      if (!prev_model_record)
1678 		first_model_record = model_record;
1679 	      else
1680 		prev_model_record->next = model_record;
1681 	      break;
1682 	    }
1683 	  prev_model_record = model_record;
1684 	  model_record = model_record->next;
1685 	}
1686       if (!model_record)	/* last entry */
1687 	{
1688 	  prev_model_record->next = create_model_record (model);
1689 	  model_record = prev_model_record->next;
1690 	}
1691     }				/* if (first_model_record) */
1692   model_record->be = be;
1693   DBG_DBG ("update_model_record_list: added model %s\n", model->name);
1694   return first_model_record;
1695 }
1696 
1697 
1698 /* Insert manufacturer into list at the alphabetically correct position, */
1699 /* create new record if necessary */
1700 static mfg_record_entry *
update_mfg_record_list(mfg_record_entry * first_mfg_record, mfg_entry * mfg, backend_entry * be)1701 update_mfg_record_list (mfg_record_entry * first_mfg_record, mfg_entry * mfg,
1702 			backend_entry * be)
1703 {
1704   model_entry *model = mfg->model;
1705   mfg_record_entry *mfg_record = first_mfg_record;
1706 
1707   while (mfg_record)
1708     {
1709       if (string_compare (mfg_record->name, mfg->name) == 0)
1710 	{
1711 	  /* Manufacturer already exists */
1712 	  url_entry *mfg_url = mfg->url;
1713 
1714 	  /* Manufacturer comments and (additional) URLs? */
1715 	  if (!mfg_record->comment)
1716 	    mfg_record->comment = mfg->comment;
1717 	  while (mfg_url && mfg_url->name)
1718 	    {
1719 	      mfg_record->url = update_url_list (mfg_record->url,
1720 						 mfg_url->name);
1721 	      mfg_url = mfg_url->next;
1722 	    }
1723 	  break;
1724 	}
1725       mfg_record = mfg_record->next;
1726     }
1727 
1728   if (!mfg_record)
1729     {
1730       /* Manufacturer doesn't exist yet */
1731       url_entry *url = mfg->url;
1732 
1733       mfg_record = calloc (1, sizeof (mfg_record_entry));
1734       if (!mfg_record)
1735 	{
1736 	  DBG_ERR ("update_mfg_record_list: couldn't calloc "
1737 		   "mfg_record_entry\n");
1738 	  exit (1);
1739 	}
1740       mfg_record->name = mfg->name;
1741       mfg_record->comment = mfg->comment;
1742       while (url)
1743 	{
1744 	  mfg_record->url = update_url_list (mfg_record->url, url->name);
1745 	  url = url->next;
1746 	}
1747       if (first_mfg_record != 0)
1748 	{
1749 	  /* We already have one manufacturer in the list */
1750 	  mfg_record_entry *new_mfg_record = mfg_record;
1751 	  mfg_record_entry *prev_mfg_record = 0;
1752 
1753 	  mfg_record = first_mfg_record;
1754 
1755 	  while (mfg_record)
1756 	    {
1757 	      int compare =
1758 		string_compare (new_mfg_record->name, mfg_record->name);
1759 	      if (compare <= 0)
1760 		{
1761 		  mfg_record_entry *tmp_mfg_record = mfg_record;
1762 		  mfg_record = new_mfg_record;
1763 		  mfg_record->next = tmp_mfg_record;
1764 		  if (!prev_mfg_record)
1765 		    first_mfg_record = mfg_record;
1766 		  else
1767 		    prev_mfg_record->next = mfg_record;
1768 		  break;
1769 		}
1770 	      prev_mfg_record = mfg_record;
1771 	      mfg_record = mfg_record->next;
1772 	    }
1773 	  if (!mfg_record)	/* last entry */
1774 	    {
1775 	      prev_mfg_record->next = new_mfg_record;
1776 	      mfg_record = prev_mfg_record->next;
1777 	    }
1778 	}
1779       else
1780 	first_mfg_record = mfg_record;
1781       DBG_DBG ("update_mfg_record_list: created mfg %s\n", mfg_record->name);
1782     }				/* if (!mfg_record) */
1783 
1784   /* create model entries */
1785   while (model)
1786     {
1787       mfg_record->model_record =
1788 	update_model_record_list (mfg_record->model_record, model, be);
1789       model = model->next;
1790     }
1791   return first_mfg_record;
1792 }
1793 
1794 /* Create a sorted list of manufacturers based on the backends list */
1795 static mfg_record_entry *
create_mfg_list(device_type dev_type)1796 create_mfg_list (device_type dev_type)
1797 {
1798   mfg_record_entry *first_mfg_record = 0;
1799   backend_entry *be = first_backend;
1800 
1801   DBG_DBG ("create_mfg_list: start\n");
1802   while (be)
1803     {
1804       type_entry *type = be->type;
1805       while (type)
1806 	{
1807 	  if (type->type == dev_type)
1808 	    {
1809 	      mfg_entry *mfg = type->mfg;
1810 	      while (mfg)
1811 		{
1812 		  first_mfg_record =
1813 		    update_mfg_record_list (first_mfg_record, mfg, be);
1814 		  mfg = mfg->next;
1815 		}
1816 	    }
1817 	  type = type->next;
1818 	}
1819       be = be->next;
1820     }
1821   DBG_DBG ("create_mfg_list: exit\n");
1822   return first_mfg_record;
1823 }
1824 
1825 /* Print an ASCII list with all the information we have */
1826 static void
ascii_print_backends(void)1827 ascii_print_backends (void)
1828 {
1829   backend_entry *be;
1830 
1831   be = first_backend;
1832   while (be)
1833     {
1834       url_entry *url = be->url;
1835       type_entry *type = be->type;
1836 
1837       if (be->name)
1838 	printf ("backend `%s'\n", be->name);
1839       else
1840 	printf ("backend *none*\n");
1841 
1842       if (be->version)
1843 	printf (" version `%s'\n", be->version);
1844       else
1845 	printf (" version *none*\n");
1846 
1847       if (be->new)
1848 	printf (" NEW!\n");
1849 
1850       if (be->manpage)
1851 	printf (" manpage `%s'\n", be->manpage);
1852       else
1853 	printf (" manpage *none*\n");
1854 
1855       if (url)
1856 	while (url)
1857 	  {
1858 	    printf (" url `%s'\n", url->name);
1859 	    url = url->next;
1860 	  }
1861       else
1862 	printf (" url *none*\n");
1863 
1864       if (be->comment)
1865 	printf (" comment `%s'\n", be->comment);
1866       else
1867 	printf (" comment *none*\n");
1868 
1869       if (type)
1870 	while (type)
1871 	  {
1872 	    switch (type->type)
1873 	      {
1874 	      case type_scanner:
1875 		printf (" type scanner\n");
1876 		break;
1877 	      case type_stillcam:
1878 		printf (" type stillcam\n");
1879 		break;
1880 	      case type_vidcam:
1881 		printf (" type vidcam\n");
1882 		break;
1883 	      case type_meta:
1884 		printf (" type meta\n");
1885 		break;
1886 	      case type_api:
1887 		printf (" type api\n");
1888 		break;
1889 	      default:
1890 		printf (" type *unknown*\n");
1891 		break;
1892 	      }
1893 	    if (type->desc)
1894 	      {
1895 		url_entry *url = type->desc->url;
1896 		printf ("  desc `%s'\n", type->desc->desc);
1897 		if (url)
1898 		  while (url)
1899 		    {
1900 		      printf ("   url `%s'\n", url->name);
1901 		      url = url->next;
1902 		    }
1903 		else
1904 		  printf ("   url *none*\n");
1905 
1906 		if (type->desc->comment)
1907 		  printf ("   comment `%s'\n", type->desc->comment);
1908 		else
1909 		  printf ("   comment *none*\n");
1910 	      }
1911 	    else if (type->type >= type_meta)
1912 	      printf ("  desc *none*\n");
1913 
1914 	    if (type->mfg)
1915 	      {
1916 		mfg_entry *mfg = type->mfg;
1917 		while (mfg)
1918 		  {
1919 		    model_entry *model = mfg->model;
1920 		    url_entry *url = mfg->url;
1921 
1922 		    printf ("  mfg `%s'\n", mfg->name);
1923 		    if (url)
1924 		      while (url)
1925 			{
1926 			  printf ("   url `%s'\n", url->name);
1927 			  url = url->next;
1928 			}
1929 		    else
1930 		      printf ("   url *none*\n");
1931 
1932 		    if (mfg->comment)
1933 		      printf ("   comment `%s'\n", mfg->comment);
1934 		    else
1935 		      printf ("   comment *none*\n");
1936 
1937 		    if (model)
1938 		      while (model)
1939 			{
1940 			  url_entry *url = model->url;
1941 			  printf ("   model `%s'\n", model->name);
1942 			  if (model->interface)
1943 			    printf ("    interface `%s'\n", model->interface);
1944 			  else
1945 			    printf ("    interface *none*\n");
1946 
1947 			  if (model->usb_vendor_id)
1948 			    printf ("    usb-vendor-id `%s'\n", model->usb_vendor_id);
1949 			  else
1950 			    printf ("    usb-vendor-id *none*\n");
1951 
1952 			  if (model->usb_product_id)
1953 			    printf ("    usb-product-id `%s'\n", model->usb_product_id);
1954 			  else
1955 			    printf ("    usb-product-id *none*\n");
1956 
1957 			  switch (model->status)
1958 			    {
1959 			    case status_minimal:
1960 			      printf ("    status minimal\n");
1961 			      break;
1962 			    case status_basic:
1963 			      printf ("    status basic\n");
1964 			      break;
1965 			    case status_good:
1966 			      printf ("    status good\n");
1967 			      break;
1968 			    case status_complete:
1969 			      printf ("    status complete\n");
1970 			      break;
1971 			    case status_untested:
1972 			      printf ("    status untested\n");
1973 			      break;
1974 			    case status_unsupported:
1975 			      printf ("    status unsupported\n");
1976 			      break;
1977 			    default:
1978 			      printf ("    status *unknown*\n");
1979 			      break;
1980 			    }
1981 
1982 			  if (url)
1983 			    while (url)
1984 			      {
1985 				printf ("    url `%s'\n", url->name);
1986 				url = url->next;
1987 			      }
1988 			  else
1989 			    printf ("    url *none*\n");
1990 
1991 			  if (model->comment)
1992 			    printf ("    comment `%s'\n", model->comment);
1993 			  else
1994 			    printf ("    comment *none*\n");
1995 
1996 			  model = model->next;
1997 			}
1998 		    else
1999 		      printf ("   model *none*\n");
2000 
2001 		    mfg = mfg->next;
2002 		  }		/* while (mfg) */
2003 	      }
2004 	    else if (type->type < type_meta)
2005 	      printf ("  mfg *none*\n");
2006 	    type = type->next;
2007 	  }			/* while (type) */
2008       else
2009 	printf (" type *none*\n");
2010       be = be->next;
2011     }				/* while (be) */
2012 }
2013 
2014 
2015 static char *
clean_string(char *c)2016 clean_string (char *c)
2017 {
2018   /* not avoided characters */
2019 
2020   char *aux;
2021 
2022   aux = malloc (strlen (c) * sizeof (char) * 6);
2023 
2024   *aux = '\0';
2025 
2026   while (*c != '\0')
2027     {
2028 
2029       /*limit to printable ASCII only*/
2030       if(*c < 0x20 || *c > 0x7e){
2031         c++;
2032         continue;
2033       }
2034 
2035       switch (*c)
2036 	{
2037 	case '<':
2038 	  aux = strcat (aux, "&lt;");
2039 	  break;
2040 	case '>':
2041 	  aux = strcat (aux, "&gt;");
2042 	  break;
2043 	case '\'':
2044 	  aux = strcat (aux, "&apos;");
2045 	  break;
2046 	case '&':
2047 	  aux = strcat (aux, "&amp;");
2048 	  break;
2049 	default:
2050 	  aux = strncat (aux, c, 1);
2051 	}
2052       c = c + 1;
2053     }
2054   return aux;
2055 }
2056 
2057 /* Print an XML list with all the information we have */
2058 static void
xml_print_backends(void)2059 xml_print_backends (void)
2060 {
2061   backend_entry *be;
2062 
2063   be = first_backend;
2064   printf ("<backends>\n");
2065   while (be)
2066     {
2067       url_entry *url = be->url;
2068       type_entry *type = be->type;
2069 
2070       if (be->name)
2071 	printf ("<backend name=\"%s\">\n", clean_string (be->name));
2072       else
2073 	printf ("<backend name=\"*none\">\n");
2074 
2075       if (be->version)
2076 	printf ("<version>%s</version>\n", clean_string (be->version));
2077       else
2078 	printf ("<version>*none*</version>\n");
2079 
2080       if (be->new)
2081 	printf ("<new state=\"yes\"/>\n");
2082       else
2083 	printf ("<new state=\"no\"/>\n");
2084 
2085 
2086       if (be->manpage)
2087 	printf (" <manpage>%s</manpage>\n", clean_string (be->manpage));
2088       else
2089 	printf (" <manpage>*none*</manpage>\n");
2090 
2091       if (url)
2092 	while (url)
2093 	  {
2094 	    printf (" <url>%s</url>\n", clean_string (url->name));
2095 	    url = url->next;
2096 	  }
2097       else
2098 	printf (" <url>*none*</url>\n");
2099 
2100       if (be->comment)
2101 	printf (" <comment>%s</comment>\n", clean_string (be->comment));
2102       else
2103 	printf (" <comment>*none*</comment>\n");
2104 
2105       if (type)
2106 	while (type)
2107 	  {
2108 
2109 	    switch (type->type)
2110 	      {
2111 	      case type_scanner:
2112 		printf (" <type def=\"scanner\">\n");
2113 		break;
2114 	      case type_stillcam:
2115 		printf (" <type def=\"stillcam\">\n");
2116 		break;
2117 	      case type_vidcam:
2118 		printf (" <type def=\"vidcam\">\n");
2119 		break;
2120 	      case type_meta:
2121 		printf (" <type def=\"meta\">\n");
2122 		break;
2123 	      case type_api:
2124 		printf (" <type def=\"api\">\n");
2125 		break;
2126 	      default:
2127 		printf (" <type def=\"*unknown*\">\n");
2128 		break;
2129 	      }
2130 	    if (type->desc)
2131 	      {
2132 		url_entry *url = type->desc->url;
2133 		printf ("   <desc>%s</desc>\n",
2134 			clean_string (type->desc->desc));
2135 		if (url)
2136 		  while (url)
2137 		    {
2138 		      printf ("   <url>%s</url>\n", clean_string (url->name));
2139 		      url = url->next;
2140 		    }
2141 		else
2142 		  printf ("   <url>*none*</url>\n");
2143 
2144 		if (type->desc->comment)
2145 		  printf ("   <comment>%s</comment>\n",
2146 			  clean_string (type->desc->comment));
2147 		else
2148 		  printf ("   <comment>*none*</comment>\n");
2149 	      }
2150 	    else if (type->type >= type_meta)
2151 	      printf ("  <desc>*none*</desc>\n");
2152 
2153 	    if (type->mfg)
2154 	      {
2155 		mfg_entry *mfg = type->mfg;
2156 		while (mfg)
2157 		  {
2158 		    model_entry *model = mfg->model;
2159 		    url_entry *url = mfg->url;
2160 
2161 		    printf (" <mfg name=\"%s\">\n", clean_string (mfg->name));
2162 		    if (url)
2163 		      while (url)
2164 			{
2165 			  printf ("  <url>`%s'</url>\n",
2166 				  clean_string (url->name));
2167 			  url = url->next;
2168 			}
2169 		    else
2170 		      printf ("  <url>*none*</url>\n");
2171 
2172 		    if (mfg->comment)
2173 		      printf ("  <comment>%s</comment>\n",
2174 			      clean_string (mfg->comment));
2175 		    else
2176 		      printf ("  <comment>*none*</comment>\n");
2177 
2178 		    if (model)
2179 		      while (model)
2180 			{
2181 			  url_entry *url = model->url;
2182 			  printf ("   <model name=\"%s\">\n",
2183 				  clean_string (model->name));
2184 			  if (model->interface)
2185 			    printf ("    <interface>%s</interface>\n",
2186 				    clean_string (model->interface));
2187 			  else
2188 			    printf ("    <interface>*none*</interface>\n");
2189 
2190 			  if (model->usb_vendor_id)
2191 			    printf ("    <usbvendorid>%s</usbvendorid>\n",
2192 				    clean_string (model->usb_vendor_id));
2193 			  else
2194 			    printf ("    <usbvendorid>*none*</usbvendorid>\n");
2195 			  if (model->usb_product_id)
2196 			    printf ("    <usbproductid>%s</usbproductid>\n",
2197 				    clean_string (model->usb_product_id));
2198 			  else
2199 			    printf ("    <usbproductid>*none*</usbproductid>\n");
2200 
2201 			  switch (model->status)
2202 			    {
2203 			    case status_minimal:
2204 			      printf ("    <status>minimal</status>\n");
2205 			      break;
2206 			    case status_basic:
2207 			      printf ("    <status>basic</status>\n");
2208 			      break;
2209 			    case status_good:
2210 			      printf ("    <status>good</status>\n");
2211 			      break;
2212 			    case status_complete:
2213 			      printf ("    <status>complete</status>\n");
2214 			      break;
2215 			    case status_untested:
2216 			      printf ("    <status>untested</status>\n");
2217 			      break;
2218 			    case status_unsupported:
2219 			      printf ("    <status>unsupported</status>\n");
2220 			      break;
2221 			    default:
2222 			      printf ("    <status>*unknown*</status>\n");
2223 			      break;
2224 			    }
2225 
2226 			  if (url)
2227 			    while (url)
2228 			      {
2229 				printf ("    <url>%s</url>\n",
2230 					clean_string (url->name));
2231 				url = url->next;
2232 			      }
2233 			  else
2234 			    printf ("    <url>*none*</url>\n");
2235 
2236 			  if (model->comment)
2237 			    printf ("    <comment>%s</comment>\n",
2238 				    clean_string (model->comment));
2239 			  else
2240 			    printf ("    <comment>*none*</comment>\n");
2241 
2242 			  model = model->next;
2243 			  printf ("   </model>\n");
2244 			}	/* while (model) */
2245 		    else
2246 		      printf ("   <model name=\"*none*\" />\n");
2247 
2248 		    printf (" </mfg>\n");
2249 		    mfg = mfg->next;
2250 		  }		/* while (mfg) */
2251 	      }
2252 	    else if (type->type < type_meta)
2253 	      printf ("  <mfg>*none*</mfg>\n");
2254 	    type = type->next;
2255 	    printf (" </type>\n");
2256 	  }			/* while (type) */
2257       else
2258 	printf (" <type>*none*</type>\n");
2259       printf ("</backend>\n");
2260       be = be->next;
2261 
2262     }				/* while (be) */
2263   printf ("</backends>\n");
2264 }
2265 
2266 /* calculate statistics about supported devices per device type*/
2267 static void
calculate_statistics_per_type(device_type dev_type, statistics_type num)2268 calculate_statistics_per_type (device_type dev_type, statistics_type num)
2269 {
2270   backend_entry *be = first_backend;
2271 
2272   while (be)
2273     {
2274       type_entry *type = be->type;
2275 
2276       while (type)
2277 	{
2278 	  if (type->type == dev_type)
2279 	    {
2280 	      mfg_entry *mfg = type->mfg;
2281 	      model_entry *model;
2282 
2283 	      if (type->desc)
2284 		{
2285 		  num[status_complete]++;
2286 		  type = type->next;
2287 		  continue;
2288 		}
2289 
2290 	      if (!mfg)
2291 		{
2292 		  type = type->next;
2293 		  continue;
2294 		}
2295 
2296 	      mfg = type->mfg;
2297 	      while (mfg)
2298 		{
2299 		  model = mfg->model;
2300 		  if (model)
2301 		    {
2302 		      while (model)
2303 			{
2304 			  enum status_entry status = model->status;
2305 			  num[status]++;
2306 			  model = model->next;
2307 			}	/* while (model) */
2308 		    }		/* if (num_models) */
2309 		  mfg = mfg->next;
2310 		}		/* while (mfg) */
2311 	    }			/* if (type->type) */
2312 	  type = type->next;
2313 	}			/* while (type) */
2314       be = be->next;
2315     }				/* while (be) */
2316 }
2317 
2318 static void
html_print_statistics_cell(const char * color, int number)2319 html_print_statistics_cell (const char * color, int number)
2320 {
2321   printf ("<td align=center><font color=%s>%d</font></td>\n",
2322 	  color, number);
2323 }
2324 
2325 static void
html_print_statistics_per_type(device_type dev_type)2326 html_print_statistics_per_type (device_type dev_type)
2327 {
2328   statistics_type num = {0, 0, 0, 0, 0, 0, 0};
2329   status_entry status;
2330 
2331   calculate_statistics_per_type (dev_type, num);
2332   printf ("<tr>\n");
2333   printf("<td align=center><a href=\"#%s\">%s</a></td>\n",
2334 	 device_type_aname [dev_type], device_type_name [dev_type]);
2335 
2336   html_print_statistics_cell
2337     (COLOR_UNKNOWN,
2338      num[status_minimal] + num[status_basic] + num[status_good] +
2339      num[status_complete] + num[status_untested] + num[status_unsupported]);
2340   if (dev_type == type_scanner || dev_type == type_stillcam
2341       || dev_type == type_vidcam)
2342     {
2343       html_print_statistics_cell
2344 	(COLOR_UNKNOWN,
2345 	 num[status_minimal] + num[status_basic] + num[status_good] +
2346 	 num[status_complete]);
2347       for (status = status_complete; status >= status_unsupported; status--)
2348 	html_print_statistics_cell (status_color [status], num [status]);
2349     }
2350   else
2351     {
2352       printf ("<td align=center colspan=7>n/a</td>\n");
2353     }
2354   printf ("</tr>\n");
2355 }
2356 
2357 /* print html statistcis */
2358 static void
html_print_summary(void)2359 html_print_summary (void)
2360 {
2361   device_type dev_type;
2362   status_entry status;
2363 
2364   printf ("<h2>Summary</h2>\n");
2365   printf ("<table border=1>\n");
2366   printf ("<tr bgcolor=E0E0FF>\n");
2367   printf ("<th align=center rowspan=3>Device type</th>\n");
2368   printf ("<th align=center colspan=8>Number of devices</th>\n");
2369   printf ("</tr>\n");
2370   printf ("<tr bgcolor=E0E0FF>\n");
2371   printf ("<th align=center rowspan=2>Total</th>\n");
2372   printf ("<th align=center colspan=5>Supported</th>\n");
2373   printf ("<th align=center rowspan=2><font color=" COLOR_UNTESTED
2374 	  ">%s</font></th>\n", status_name[status_untested]);
2375   printf ("<th align=center rowspan=2><font color=" COLOR_UNSUPPORTED
2376 	  ">%s</font></th>\n", status_name[status_unsupported]);
2377   printf ("</tr>\n");
2378   printf ("<tr bgcolor=E0E0FF>\n");
2379   printf ("<th align=center>Sum</th>\n");
2380   for (status = status_complete; status >= status_minimal; status--)
2381     printf ("<th align=center><font color=%s>%s</font></th>\n",
2382 	    status_color[status], status_name[status]);
2383   printf ("</tr>\n");
2384   for (dev_type = type_scanner; dev_type <= type_api; dev_type++)
2385     html_print_statistics_per_type (dev_type);
2386   printf ("</table>\n");
2387 }
2388 
2389 
2390 /* Generate a name used for <a name=...> HTML tags */
2391 static char *
html_generate_anchor_name(device_type dev_type, char *manufacturer_name)2392 html_generate_anchor_name (device_type dev_type, char *manufacturer_name)
2393 {
2394   char *name = malloc (strlen (manufacturer_name) + 1 + 2);
2395   char *pointer = name;
2396   char type_char;
2397 
2398   if (!name)
2399     {
2400       DBG_ERR ("html_generate_anchor_name: couldn't malloc\n");
2401       return 0;
2402     }
2403 
2404   switch (dev_type)
2405     {
2406     case type_scanner:
2407       type_char = 'S';
2408       break;
2409     case type_stillcam:
2410       type_char = 'C';
2411       break;
2412     case type_vidcam:
2413       type_char = 'V';
2414       break;
2415     case type_meta:
2416       type_char = 'M';
2417       break;
2418     case type_api:
2419       type_char = 'A';
2420       break;
2421     default:
2422       type_char = 'Z';
2423       break;
2424     }
2425 
2426   snprintf (name, strlen (manufacturer_name) + 1 + 2, "%c-%s",
2427 	    type_char, manufacturer_name);
2428 
2429   while (*pointer)
2430     {
2431       if (!isalnum (*pointer))
2432 	*pointer = '-';
2433       else
2434 	*pointer = toupper (*pointer);
2435       pointer++;
2436     }
2437   return name;
2438 }
2439 
2440 
2441 /* Generate one table per backend of all backends providing models */
2442 /* of type dev_type */
2443 static void
html_backends_split_table(device_type dev_type)2444 html_backends_split_table (device_type dev_type)
2445 {
2446   backend_entry *be = first_backend;
2447   SANE_Bool first = SANE_TRUE;
2448 
2449   printf ("<p><b>Backends</b>:\n");
2450   while (be)			/* print link list */
2451     {
2452       type_entry *type = be->type;
2453       SANE_Bool found = SANE_FALSE;
2454 
2455       while (type)
2456 	{
2457 	  if (type->type == dev_type)
2458 	    found = SANE_TRUE;
2459 	  type = type->next;
2460 	}
2461       if (found)
2462 	{
2463 	  if (!first)
2464 	    printf (",\n");
2465 	  first = SANE_FALSE;
2466 	  printf ("<a href=\"#%s\">%s</a>",
2467 		  html_generate_anchor_name (dev_type, be->name), be->name);
2468 	}
2469       be = be->next;
2470     }
2471   be = first_backend;
2472   if (first)
2473     printf ("(none)\n");
2474 
2475   printf ("</p>\n");
2476 
2477 
2478   while (be)
2479     {
2480       type_entry *type = be->type;
2481 
2482       while (type)
2483 	{
2484 	  if (type->type == dev_type)
2485 	    {
2486 	      mfg_entry *mfg = type->mfg;
2487 	      model_entry *model;
2488 
2489 	      printf ("<h3><a name=\"%s\">Backend: %s\n",
2490 		      html_generate_anchor_name (type->type, be->name),
2491 		      be->name);
2492 
2493 	      if (be->version || be->new)
2494 		{
2495 		  printf ("(");
2496 		  if (be->version)
2497 		    {
2498 		      printf ("%s", be->version);
2499 		      if (be->new)
2500 			printf (", <font color=" COLOR_NEW ">NEW!</font>");
2501 		    }
2502 		  else
2503 		    printf ("<font color=" COLOR_NEW ">NEW!</font>");
2504 		  printf (")\n");
2505 		}
2506 	      printf ("</a></h3>\n");
2507 
2508 	      printf ("<p>\n");
2509 
2510 	      if (be->url && be->url->name)
2511 		{
2512 		  url_entry *url = be->url;
2513 		  printf ("<b>Link(s):</b>\n");
2514 		  while (url)
2515 		    {
2516 		      if (url != be->url)
2517 			printf (", ");
2518 		      printf ("<a href=\"%s\">%s</a>", url->name, url->name);
2519 		      url = url->next;
2520 		    }
2521 		  printf ("<br>\n");
2522 		}
2523 	      if (be->manpage)
2524 		printf ("<b>Manual page:</b> <a href=\"" MAN_PAGE_LINK
2525 			"\">%s</a><br>\n", be->manpage, be->manpage);
2526 
2527 	      if (be->comment)
2528 		printf ("<b>Comment:</b> %s<br>\n", be->comment);
2529 
2530 
2531 	      if (type->desc)
2532 		{
2533 		  if (type->desc->desc)
2534 		    {
2535 		      if (type->desc->url && type->desc->url->name)
2536 			printf ("<b>Description:</b> "
2537 				"<a href=\"%s\">%s</a><br>\n",
2538 				type->desc->url->name, type->desc->desc);
2539 		      else
2540 			printf ("<b>Description:</b> %s<br>\n",
2541 				type->desc->desc);
2542 		    }
2543 
2544 		  if (type->desc->comment)
2545 		    printf ("<b>Comment:</b> %s<br>\n", type->desc->comment);
2546 		  printf ("</p>\n");
2547 		  type = type->next;
2548 		  continue;
2549 		}
2550 	      printf ("</p>\n");
2551 
2552 	      if (!mfg)
2553 		{
2554 		  type = type->next;
2555 		  continue;
2556 		}
2557 
2558 	      printf ("<table border=1>\n");
2559 
2560 	      printf ("<tr bgcolor=E0E0FF>\n");
2561 	      printf ("<th align=center>Manufacturer</th>\n");
2562 	      printf ("<th align=center>Model</th>\n");
2563 	      printf ("<th align=center>Interface</th>\n");
2564 	      printf ("<th align=center>USB id</th>\n");
2565 	      printf ("<th align=center>Status</th>\n");
2566 	      printf ("<th align=center>Comment</th>\n");
2567 	      printf ("</tr>\n");
2568 
2569 	      mfg = type->mfg;
2570 	      while (mfg)
2571 		{
2572 		  model = mfg->model;
2573 		  if (model)
2574 		    {
2575 		      int num_models = 0;
2576 
2577 		      while (model)	/* count models for rowspan */
2578 			{
2579 			  model = model->next;
2580 			  num_models++;
2581 			}
2582 		      model = mfg->model;
2583 		      printf ("<tr>\n");
2584 		      printf ("<td align=center rowspan=%d>\n", num_models);
2585 		      if (mfg->url && mfg->url->name)
2586 			printf ("<a href=\"%s\">%s</a>\n", mfg->url->name,
2587 				mfg->name);
2588 		      else
2589 			printf ("%s\n", mfg->name);
2590 
2591 		      while (model)
2592 			{
2593 			  enum status_entry status = model->status;
2594 
2595 			  if (model != mfg->model)
2596 			    printf ("<tr>\n");
2597 
2598 			  if (model->url && model->url->name)
2599 			    printf
2600 			      ("<td align=center><a href=\"%s\">%s</a></td>\n",
2601 			       model->url->name, model->name);
2602 			  else
2603 			    printf ("<td align=center>%s</td>\n",
2604 				    model->name);
2605 
2606 			  if (model->interface)
2607 			    printf ("<td align=center>%s</td>\n",
2608 				    model->interface);
2609 			  else
2610 			    printf ("<td align=center>?</td>\n");
2611 
2612 			  if (model->usb_vendor_id && model->usb_product_id)
2613 			    printf ("<td align=center>%s/%s</td>\n",
2614 				    model->usb_vendor_id, model->usb_product_id);
2615 			  else
2616 			    printf ("<td align=center>&nbsp;</td>\n");
2617 
2618 			  printf ("<td align=center><font color=%s>%s</font></td>\n",
2619 				  status_color[status], status_name[status]);
2620 
2621 			  if (model->comment && model->comment[0] != 0)
2622 			    printf ("<td>%s</td>\n", model->comment);
2623 			  else
2624 			    printf ("<td>&nbsp;</td>\n");
2625 
2626 			  model = model->next;
2627 			  printf ("</tr>\n");
2628 			}	/* while (model) */
2629 		    }		/* if (num_models) */
2630 		  mfg = mfg->next;
2631 		}		/* while (mfg) */
2632 	      printf ("</table>\n");
2633 	    }			/* if (type->type) */
2634 	  type = type->next;
2635 	}			/* while (type) */
2636       be = be->next;
2637     }				/* while (be) */
2638   /*  printf ("</table>\n"); */
2639 }
2640 
2641 /* Generate one table per manufacturer constructed of all backends */
2642 /* providing models of type dev_type */
2643 static void
html_mfgs_table(device_type dev_type)2644 html_mfgs_table (device_type dev_type)
2645 {
2646   mfg_record_entry *mfg_record = 0, *first_mfg_record = 0;
2647 
2648   first_mfg_record = create_mfg_list (dev_type);
2649   mfg_record = first_mfg_record;
2650 
2651   printf ("<p><b>Manufacturers</b>:\n");
2652   while (mfg_record)
2653     {
2654       if (mfg_record != first_mfg_record)
2655 	printf (",\n");
2656       printf ("<a href=\"#%s\">%s</a>",
2657 	      html_generate_anchor_name (type_unknown, mfg_record->name),
2658 	      mfg_record->name);
2659       mfg_record = mfg_record->next;
2660     }
2661   mfg_record = first_mfg_record;
2662   if (!mfg_record)
2663     printf ("(none)\n");
2664   printf ("</p>\n");
2665   while (mfg_record)
2666     {
2667       model_record_entry *model_record = mfg_record->model_record;
2668 
2669       printf ("<h3><a name=\"%s\">Manufacturer: %s</a></h3>\n",
2670 	      html_generate_anchor_name (type_unknown, mfg_record->name),
2671 	      mfg_record->name);
2672       printf ("<p>\n");
2673       if (mfg_record->url && mfg_record->url->name)
2674 	{
2675 	  url_entry *url = mfg_record->url;
2676 	  printf ("<b>Link(s):</b>\n");
2677 	  while (url)
2678 	    {
2679 	      if (url != mfg_record->url)
2680 		printf (", ");
2681 	      printf ("<a href=\"%s\">%s</a>", url->name, url->name);
2682 	      url = url->next;
2683 	    }
2684 	  printf ("<br>\n");
2685 	}
2686       if (mfg_record->comment)
2687 	printf ("<b>Comment:</b> %s<br>\n", mfg_record->comment);
2688       printf ("</p>\n");
2689       if (!model_record)
2690 	{
2691 	  mfg_record = mfg_record->next;
2692 	  continue;
2693 	}
2694       printf ("<table border=1>\n");
2695       printf ("<tr bgcolor=E0E0FF>\n");
2696 
2697       printf ("<th align=center>Model</th>\n");
2698       printf ("<th align=center>Interface</th>\n");
2699       printf ("<th align=center>USB id</th>\n");
2700       printf ("<th align=center>Status</th>\n");
2701       printf ("<th align=center>Comment</th>\n");
2702       printf ("<th align=center>Backend</th>\n");
2703       printf ("<th align=center>Manpage</th>\n");
2704       printf ("</tr>\n");
2705 
2706       while (model_record)
2707 	{
2708 	  enum status_entry status = model_record->status;
2709 
2710 	  if (model_record->url && model_record->url->name)
2711 	    printf ("<tr><td align=center><a "
2712 		    "href=\"%s\">%s</a></td>\n",
2713 		    model_record->url->name, model_record->name);
2714 	  else
2715 	    printf ("<tr><td align=center>%s</td>\n", model_record->name);
2716 
2717 	  if (model_record->interface)
2718 	    printf ("<td align=center>%s</td>\n", model_record->interface);
2719 	  else
2720 	    printf ("<td align=center>?</td>\n");
2721 
2722 	  if (model_record->usb_vendor_id && model_record->usb_product_id)
2723 	    printf ("<td align=center>%s/%s</td>\n",
2724 		    model_record->usb_vendor_id, model_record->usb_product_id);
2725 	  else
2726 	    printf ("<td align=center>&nbsp;</td>\n");
2727 
2728 	  printf ("<td align=center><font color=%s>%s</font></td>\n",
2729 		  status_color[status], status_name[status]);
2730 
2731 	  if (model_record->comment && model_record->comment[0] != 0)
2732 	    printf ("<td>%s</td>\n", model_record->comment);
2733 	  else
2734 	    printf ("<td>&nbsp;</td>\n");
2735 
2736 	  printf ("<td align=center>\n");
2737 	  if (model_record->be->url && model_record->be->url->name)
2738 	    printf ("<a href=\"%s\">%s</a>\n",
2739 		    model_record->be->url->name, model_record->be->name);
2740 	  else
2741 	    printf ("%s", model_record->be->name);
2742 
2743 	  if (model_record->be->version || model_record->be->new)
2744 	    {
2745 	      printf ("<br>(");
2746 	      if (model_record->be->version)
2747 		{
2748 		  printf ("%s", model_record->be->version);
2749 		  if (model_record->be->new)
2750 		    printf (", <font color=" COLOR_NEW ">NEW!</font>");
2751 		}
2752 	      else
2753 		printf ("<font color=" COLOR_NEW ">NEW!</font>");
2754 	      printf (")\n");
2755 	    }
2756 
2757 	  printf ("</td>\n");
2758 	  if (model_record->be->manpage)
2759 	    printf ("<td align=center><a href=\""
2760 		    MAN_PAGE_LINK "\">%s</a></td>\n",
2761 		    model_record->be->manpage, model_record->be->manpage);
2762 	  else
2763 	    printf ("<td align=center>?</td>\n");
2764 
2765 	  printf ("</tr>\n");
2766 	  model_record = model_record->next;
2767 	}			/* while model_record */
2768       printf ("</table>\n");
2769       mfg_record = mfg_record->next;
2770     }				/* while mfg_record */
2771 }
2772 
2773 /* Print the HTML headers and an introduction */
2774 static void
html_print_header(void)2775 html_print_header (void)
2776 {
2777   printf
2778     ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
2779      "<html> <head>\n"
2780      "<meta http-equiv=\"Content-Type\" content=\"text/html; "
2781      "charset=iso-8859-1\">\n");
2782   printf ("<title>%s</title>\n", title);
2783   printf
2784     ("</head>\n"
2785      "<body bgcolor=FFFFFF>\n"
2786      "<div align=center>\n"
2787      "<img src=\"images/sane.png\" alt=\"SANE\">\n");
2788   printf ("<h1>%s</h1>\n", title);
2789   printf ("</div>\n" "<hr>\n");
2790   printf ("%s\n", intro);
2791   printf
2792     ("<p>This is only a summary!\n"
2793      "Please consult the manpages and the author-supplied webpages\n"
2794      "for more detailed (and usually important) information\n"
2795      "concerning each backend.</p>\n");
2796   printf
2797     ("<p>If you have new information or corrections, please file a\n"
2798      "<a href=\"bugs.html\">bug report</a>\n"
2799      "with as many details as possible. Also please tell us if your scanner\n"
2800      "isn't mentioned in this list at all.</p>\n"
2801      "<p>For an explanation of the tables, see the\n"
2802      "<a href=\"#legend\">legend</a>.\n");
2803 }
2804 
2805 /* Print the HTML footers and contact information */
2806 static void
html_print_footer(void)2807 html_print_footer (void)
2808 {
2809   printf
2810     ("<hr>\n"
2811      "<a href=\"./\">SANE homepage</a>\n"
2812      "<address>\n"
2813      "<a href=\"imprint.html\"\n"
2814      ">Contact</a>\n" "</address>\n" "<font size=-1>\n");
2815   printf ("This page was created by sane-desc %s from %s\n",
2816 	  SANE_DESC_VERSION, PACKAGE_STRING);
2817   printf ("</font>\n");
2818   printf ("</body> </html>\n");
2819 }
2820 
2821 
2822 /* print parts of the legend */
2823 static void
html_print_legend_backend(void)2824 html_print_legend_backend (void)
2825 {
2826   printf
2827     ("  <dt><b>Backend:</b></dt>\n"
2828      "  <dd>Name of the backend,  in parentheses if available:\n"
2829      "      Version of backend/driver; newer versions may be\n"
2830      "      available from their home sites.<br>"
2831      "      <font color=" COLOR_NEW ">NEW!</font> means brand-new to the\n"
2832      "      current release of SANE.<br>\n"
2833      "      UNMAINTAINED means that nobody maintains that backend. Expect no\n"
2834      "      new features or newly supported devices. You are welcome to take over\n"
2835      "      maintainership.\n" "  </dd>\n");
2836 }
2837 
2838 static void
html_print_legend_link(void)2839 html_print_legend_link (void)
2840 {
2841   printf
2842     ("  <dt><b>Link(s):</b></dt>\n"
2843      "  <dd>Link(s) to more extensive and\n"
2844      "      detailed information, if it exists, or the email address\n"
2845      "      of the author or maintainer.\n");
2846 }
2847 
2848 static void
html_print_legend_manual(void)2849 html_print_legend_manual (void)
2850 {
2851   printf
2852     ("  <dt><b>Manual Page:</b></dt>\n"
2853      "  <dd>A link to the man-page online, if it exists.</dd>\n");
2854 }
2855 
2856 static void
html_print_legend_comment(void)2857 html_print_legend_comment (void)
2858 {
2859   printf
2860     ("  <dt><b>Comment:</b></dt>\n"
2861      "  <dd>More information about the backend or model, e.g. the level of "
2862      "      support and possible problems.</dd>\n");
2863 }
2864 
2865 static void
html_print_legend_manufacturer(void)2866 html_print_legend_manufacturer (void)
2867 {
2868   printf
2869     ("  <dt><b>Manufacturer:</b></dt>\n"
2870      "  <dd>Manufacturer, vendor or brand name of the device.</dd>\n");
2871 }
2872 
2873 static void
html_print_legend_model(void)2874 html_print_legend_model (void)
2875 {
2876   printf
2877     ("  <dt><b>Model:</b></dt>\n" "  <dd>Name of the device.</dd>\n");
2878 }
2879 
2880 static void
html_print_legend_interface(void)2881 html_print_legend_interface (void)
2882 {
2883   printf
2884     ("  <dt><b>Interface:</b></dt>\n"
2885      "  <dd>How the device is connected to the computer.</dd>\n");
2886 }
2887 
2888 static void
html_print_legend_usbid(void)2889 html_print_legend_usbid (void)
2890 {
2891   printf
2892     ("  <dt><b>USB id:</b></dt>\n"
2893      "  <dd>The USB vendor and product ids as printed by sane-find-scanner -q (only applicable for USB devices).</dd>\n");
2894 }
2895 
2896 static void
html_print_legend_status(void)2897 html_print_legend_status (void)
2898 {
2899   printf
2900     ("  <dt><b>Status</b>:</dt>\n"
2901      "  <dd>Indicates how many of the features the device provides\n"
2902      "      are supported by SANE.\n"
2903      "      <ul><li><font color=" COLOR_UNSUPPORTED ">unsupported</font>"
2904      "        means the device is not supported at least by this backend. "
2905      "        It may be supported by other backends, however.\n");
2906   printf
2907     ("      <li><font color=" COLOR_UNTESTED ">untested</font> means the "
2908      "        device may be supported but couldn't be tested. Be very "
2909      "        careful and report success/failure.\n"
2910      "      <li><font color=" COLOR_MINIMAL ">minimal</font> means that the\n"
2911      "        device is detected and scans at least in one mode. But the quality\n"
2912      "        is bad or important features won't work.\n");
2913   printf
2914     ("      <li><font color=" COLOR_BASIC ">basic</font> means it works at\n"
2915      "        least in the most important modes but quality is not perfect.\n"
2916      "      <li><font color=" COLOR_GOOD
2917      ">good</font> means the device is usable\n"
2918      "        for day-to-day work. Some rather exotic features may be missing.\n"
2919      "      <li><font color=" COLOR_COMPLETE
2920      ">complete</font> means the backends\n"
2921      "        supports everything the device can do.\n" "      </ul></dd>\n");
2922 }
2923 
2924 static void
html_print_legend_description(void)2925 html_print_legend_description (void)
2926 {
2927   printf
2928     ("  <dt><b>Description</b>:</dt>\n"
2929      "  <dd>The scope of application of the backend.\n");
2930 }
2931 
2932 /* Print the HTML page with one table of models per backend */
2933 static void
html_print_backends_split(void)2934 html_print_backends_split (void)
2935 {
2936   if (!title)
2937     title = "SANE: Backends (Drivers)";
2938   if (!intro)
2939     intro = "<p> The following table summarizes the backends/drivers "
2940       "distributed with the latest version of sane-backends, and the hardware "
2941       "or software they support. </p>";
2942 
2943   html_print_header ();
2944 
2945   html_print_summary ();
2946 
2947   printf ("<h2><a name=\"SCANNERS\">Scanners</a></h2>\n");
2948   html_backends_split_table (type_scanner);
2949 
2950   printf ("<h2><a name=\"STILL\">Still Cameras</a></h2>\n");
2951   html_backends_split_table (type_stillcam);
2952 
2953   printf ("<h2><a name=\"VIDEO\">Video Cameras</a></h2>\n");
2954   html_backends_split_table (type_vidcam);
2955 
2956   printf ("<h2><a name=\"API\">APIs</a></h2>\n");
2957   html_backends_split_table (type_api);
2958 
2959   printf ("<h2><a name=\"META\">Meta Backends</a></h2>\n");
2960   html_backends_split_table (type_meta);
2961 
2962   printf ("<h3><a name=\"legend\">Legend:</a></h3>\n" "<blockquote><dl>\n");
2963 
2964   html_print_legend_backend ();
2965   html_print_legend_link ();
2966   html_print_legend_manual ();
2967   html_print_legend_comment ();
2968   html_print_legend_manufacturer ();
2969   html_print_legend_model ();
2970   html_print_legend_interface ();
2971   html_print_legend_usbid ();
2972   html_print_legend_status ();
2973   html_print_legend_description ();
2974 
2975   printf ("</dl></blockquote>\n");
2976 
2977   html_print_footer ();
2978 }
2979 
2980 /* Print the HTML page with one table of models per manufacturer */
2981 static void
html_print_mfgs(void)2982 html_print_mfgs (void)
2983 {
2984   if (!title)
2985     title = "SANE: Supported Devices";
2986 
2987   if (!intro)
2988     intro = "<p> The following table summarizes the devices supported "
2989       "by the latest version of sane-backends. </p>";
2990 
2991   html_print_header ();
2992 
2993   html_print_summary ();
2994 
2995   printf ("<h2><a name=\"SCANNERS\">Scanners</a></h2>\n");
2996   html_mfgs_table (type_scanner);
2997 
2998   printf ("<h2><a name=\"STILL\">Still Cameras</a></h2>\n");
2999   html_mfgs_table (type_stillcam);
3000 
3001   printf ("<h2><a name=\"VIDEO\">Video Cameras</a></h2>\n");
3002   html_mfgs_table (type_vidcam);
3003 
3004   printf ("<h2><a name=\"API\">APIs</a></h2>\n");
3005   html_backends_split_table (type_api);
3006 
3007   printf ("<h2><a name=\"META\">Meta Backends</a></h2>\n");
3008   html_backends_split_table (type_meta);
3009 
3010   printf
3011     ("<h3><a name=\"legend\">Legend:</a></h3>\n" "<blockquote>\n" "<dl>\n");
3012 
3013   html_print_legend_model ();
3014   html_print_legend_interface ();
3015   html_print_legend_usbid ();
3016   html_print_legend_status ();
3017   html_print_legend_comment ();
3018   html_print_legend_backend ();
3019   html_print_legend_manual ();
3020 
3021   html_print_legend_manufacturer ();
3022   html_print_legend_description ();
3023 
3024   printf ("</dl>\n" "</blockquote>\n");
3025 
3026   html_print_footer ();
3027 }
3028 
3029 
3030 /* print statistics about supported devices */
3031 static void
print_statistics_per_type(device_type dev_type)3032 print_statistics_per_type (device_type dev_type)
3033 {
3034   statistics_type num = {0, 0, 0, 0, 0, 0, 0};
3035 
3036   calculate_statistics_per_type (dev_type, num);
3037 
3038   printf (" Total:       %4d\n",
3039 	  num[status_minimal] + num[status_basic] + num[status_good] +
3040 	  num[status_complete] + num[status_untested] + num[status_untested] +
3041 	  num[status_unsupported]);
3042   if (dev_type == type_scanner || dev_type == type_stillcam
3043       || dev_type == type_vidcam)
3044     {
3045       printf (" Supported:   %4d (complete: %d, good: %d, basic: %d, "
3046 	      "minimal: %d)\n",
3047 	      num[status_minimal] + num[status_basic] + num[status_good] +
3048 	      num[status_complete], num[status_complete], num[status_good],
3049 	      num[status_basic], num[status_minimal]);
3050       printf (" Untested:    %4d\n", num[status_untested]);
3051       printf (" Unsupported: %4d\n", num[status_unsupported]);
3052     }
3053 }
3054 
3055 static void
print_statistics(void)3056 print_statistics (void)
3057 {
3058   printf ("Number of known devices:\n");
3059   printf ("Scanners:\n");
3060   print_statistics_per_type (type_scanner);
3061   printf ("Still cameras:\n");
3062   print_statistics_per_type (type_stillcam);
3063   printf ("Video cameras:\n");
3064   print_statistics_per_type (type_vidcam);
3065   printf ("Meta backends:\n");
3066   print_statistics_per_type (type_meta);
3067   printf ("API backends:\n");
3068   print_statistics_per_type (type_api);
3069 }
3070 
3071 static usbid_type *
create_usbid(char *manufacturer, char *model, char *usb_vendor_id, char *usb_product_id)3072 create_usbid (char *manufacturer, char *model,
3073 	      char *usb_vendor_id, char *usb_product_id)
3074 {
3075   usbid_type * usbid = calloc (1, sizeof (usbid_type));
3076 
3077   usbid->usb_vendor_id = strdup (usb_vendor_id);
3078   usbid->usb_product_id = strdup (usb_product_id);
3079   usbid->name = calloc (1, sizeof (manufacturer_model_type));
3080   usbid->name->name = calloc (1, strlen (manufacturer) + strlen (model) + 3);
3081   sprintf (usbid->name->name, "%s %s", manufacturer, model);
3082   usbid->name->next = 0;
3083   usbid->next = 0;
3084   DBG_DBG ("New USB ids: %s/%s (%s %s)\n", usb_vendor_id, usb_product_id,
3085 	    manufacturer, model);
3086   return usbid;
3087 }
3088 
3089 static scsiid_type *
create_scsiid(char *manufacturer, char *model, char *scsi_vendor_id, char *scsi_product_id, SANE_Bool is_processor)3090 create_scsiid (char *manufacturer, char *model,
3091 	       char *scsi_vendor_id, char *scsi_product_id, SANE_Bool is_processor)
3092 {
3093   scsiid_type * scsiid = calloc (1, sizeof (scsiid_type));
3094 
3095   scsiid->scsi_vendor_id = strdup (scsi_vendor_id);
3096   scsiid->scsi_product_id = strdup (scsi_product_id);
3097   scsiid->is_processor = is_processor;
3098   scsiid->name = calloc (1, sizeof (manufacturer_model_type));
3099   scsiid->name->name = calloc (1, strlen (manufacturer) + strlen (model) + 3);
3100   sprintf (scsiid->name->name, "%s %s", manufacturer, model);
3101   scsiid->name->next = 0;
3102   scsiid->next = 0;
3103   DBG_DBG ("New SCSI ids: %s/%s (%s %s)\n", scsi_vendor_id, scsi_product_id,
3104 	    manufacturer, model);
3105   return scsiid;
3106 }
3107 
3108 static usbid_type *
add_usbid(usbid_type *first_usbid, char *manufacturer, char *model, char *usb_vendor_id, char *usb_product_id)3109 add_usbid (usbid_type *first_usbid, char *manufacturer, char *model,
3110 	   char *usb_vendor_id, char *usb_product_id)
3111 {
3112   usbid_type *usbid = first_usbid;
3113   usbid_type *prev_usbid = 0, *tmp_usbid = 0;
3114 
3115   if (!first_usbid)
3116     first_usbid = create_usbid (manufacturer, model, usb_vendor_id, usb_product_id);
3117   else
3118     {
3119       while (usbid)
3120 	{
3121 	  if (strcmp (usb_vendor_id, usbid->usb_vendor_id) == 0 &&
3122 	      strcmp (usb_product_id, usbid->usb_product_id) == 0)
3123 	    {
3124 	      manufacturer_model_type *man_mod = usbid->name;
3125 
3126 	      while (man_mod->next)
3127 		man_mod = man_mod->next;
3128 	      man_mod->next = malloc (sizeof (manufacturer_model_type));
3129 	      man_mod->next->name = malloc (strlen (manufacturer) + strlen (model) + 3);
3130 	      sprintf (man_mod->next->name, "%s %s", manufacturer, model);
3131 	      man_mod->next->next = 0;
3132 	      DBG_DBG ("Added manufacturer/model %s %s to USB ids %s/%s\n", manufacturer, model,
3133 			usb_vendor_id, usb_product_id);
3134 	      break;
3135 	    }
3136 	  if (strcmp (usb_vendor_id, usbid->usb_vendor_id) < 0 ||
3137 	      (strcmp (usb_vendor_id, usbid->usb_vendor_id) == 0 &&
3138 	       strcmp (usb_product_id, usbid->usb_product_id) < 0))
3139 	    {
3140 
3141 	      tmp_usbid = create_usbid (manufacturer, model, usb_vendor_id, usb_product_id);
3142 	      tmp_usbid->next = usbid;
3143 	      if (prev_usbid)
3144 		prev_usbid->next = tmp_usbid;
3145 	      else
3146 		first_usbid = tmp_usbid;
3147 	      break;
3148 	    }
3149 	  prev_usbid = usbid;
3150 	  usbid = usbid->next;
3151 	}
3152       if (!usbid)
3153 	{
3154 	  prev_usbid->next = create_usbid (manufacturer, model, usb_vendor_id, usb_product_id);
3155 	  usbid = prev_usbid->next;
3156 	}
3157     }
3158   return first_usbid;
3159 }
3160 
3161 static scsiid_type *
add_scsiid(scsiid_type *first_scsiid, char *manufacturer, char *model, char *scsi_vendor_id, char *scsi_product_id, SANE_Bool is_processor)3162 add_scsiid (scsiid_type *first_scsiid, char *manufacturer, char *model,
3163 	    char *scsi_vendor_id, char *scsi_product_id, SANE_Bool is_processor)
3164 {
3165   scsiid_type *scsiid = first_scsiid;
3166   scsiid_type *prev_scsiid = 0, *tmp_scsiid = 0;
3167 
3168   if (!first_scsiid)
3169     first_scsiid = create_scsiid (manufacturer, model, scsi_vendor_id, scsi_product_id, is_processor);
3170   else
3171     {
3172       while (scsiid)
3173 	{
3174 	  if (strcmp (scsi_vendor_id, scsiid->scsi_vendor_id) == 0 &&
3175 	      strcmp (scsi_product_id, scsiid->scsi_product_id) == 0)
3176 	    {
3177 	      manufacturer_model_type *man_mod = scsiid->name;
3178 
3179 	      while (man_mod->next)
3180 		man_mod = man_mod->next;
3181 	      man_mod->next = malloc (sizeof (manufacturer_model_type));
3182 	      man_mod->next->name = malloc (strlen (manufacturer) + strlen (model) + 3);
3183 	      sprintf (man_mod->next->name, "%s %s", manufacturer, model);
3184 	      man_mod->next->next = 0;
3185 	      DBG_DBG ("Added manufacturer/model %s %s to SCSI ids %s/%s\n", manufacturer, model,
3186 			scsi_vendor_id, scsi_product_id);
3187 	      break;
3188 	    }
3189 	  if (strcmp (scsi_vendor_id, scsiid->scsi_vendor_id) < 0 ||
3190 	      (strcmp (scsi_vendor_id, scsiid->scsi_vendor_id) == 0 &&
3191 	       strcmp (scsi_product_id, scsiid->scsi_product_id) < 0))
3192 	    {
3193 
3194 	      tmp_scsiid = create_scsiid (manufacturer, model, scsi_vendor_id, scsi_product_id, is_processor);
3195 	      tmp_scsiid->next = scsiid;
3196 	      if (prev_scsiid)
3197 		prev_scsiid->next = tmp_scsiid;
3198 	      else
3199 		first_scsiid = tmp_scsiid;
3200 	      break;
3201 	    }
3202 	  prev_scsiid = scsiid;
3203 	  scsiid = scsiid->next;
3204 	}
3205       if (!scsiid)
3206 	{
3207 	  prev_scsiid->next = create_scsiid (manufacturer, model, scsi_vendor_id, scsi_product_id, is_processor);
3208 	  scsiid = prev_scsiid->next;
3209 	}
3210     }
3211   return first_scsiid;
3212 }
3213 
3214 static usbid_type *
create_usbids_table(void)3215 create_usbids_table (void)
3216 {
3217   backend_entry *be;
3218   usbid_type *first_usbid = NULL;
3219 
3220   if (!first_backend)
3221     return NULL;
3222 
3223   for (be = first_backend; be; be = be->next)
3224     {
3225       type_entry *type;
3226 
3227       if (!be->type)
3228 	continue;
3229 
3230       for (type = be->type; type; type = type->next)
3231 	{
3232 	  mfg_entry *mfg;
3233 
3234 	  if (!type->mfg)
3235 	      continue;
3236 
3237 	  for (mfg = type->mfg; mfg; mfg = mfg->next)
3238 	    {
3239 	      model_entry *model;
3240 
3241 	      if (!mfg->model)
3242 		continue;
3243 
3244 	      for (model = mfg->model; model; model = model->next)
3245 		{
3246 		  if ((model->status == status_unsupported)
3247 		      || (model->status == status_unknown))
3248 		    continue;
3249 
3250 		  if (model->usb_vendor_id && model->usb_product_id)
3251 		    {
3252 		      first_usbid = add_usbid (first_usbid, mfg->name,
3253 					       model->name,
3254 					       model->usb_vendor_id,
3255 					       model->usb_product_id);
3256 		    }
3257 		} /* for (model) */
3258 	    } /* for (mfg) */
3259 	} /* for (type) */
3260     } /* for (be) */
3261 
3262   return first_usbid;
3263 }
3264 
3265 static scsiid_type *
create_scsiids_table(void)3266 create_scsiids_table (void)
3267 {
3268   backend_entry *be;
3269   scsiid_type *first_scsiid = NULL;
3270 
3271   if (!first_backend)
3272     return NULL;
3273 
3274   for (be = first_backend; be; be = be->next)
3275     {
3276       type_entry *type;
3277 
3278       if (!be->type)
3279 	continue;
3280 
3281       for (type = be->type; type; type = type->next)
3282 	{
3283 	  mfg_entry *mfg;
3284 
3285 	  if (!type->mfg)
3286 	    continue;
3287 
3288 	  for (mfg = type->mfg; mfg; mfg = mfg->next)
3289 	    {
3290 	      model_entry *model;
3291 
3292 	      if (!mfg->model)
3293 		continue;
3294 
3295 	      for (model = mfg->model; model; model = model->next)
3296 		{
3297 		  if ((model->status == status_unsupported)
3298 		      || (model->status == status_unknown))
3299 		    continue;
3300 
3301 		  if (model->scsi_vendor_id && model->scsi_product_id)
3302 		    {
3303 		      first_scsiid = add_scsiid (first_scsiid, mfg->name,
3304 						 model->name,
3305 						 model->scsi_vendor_id,
3306 						 model->scsi_product_id,
3307 						 model->scsi_is_processor);
3308 		    }
3309 		} /* for (model) */
3310 	    } /* for (mfg) */
3311 	} /* for (type) */
3312     } /* for (be) */
3313 
3314   return first_scsiid;
3315 }
3316 
3317 static void
print_header_comment(void)3318 print_header_comment (void)
3319 {
3320   printf ("# This file was generated from description files (*.desc)\n"
3321           "# by sane-desc %s from %s\n",
3322           SANE_DESC_VERSION, PACKAGE_STRING);
3323 }
3324 
3325 /* print USB usermap file to be used by the hotplug tools */
3326 static void
print_usermap_header(void)3327 print_usermap_header (void)
3328 {
3329   print_header_comment ();
3330   printf
3331     ("#\n"
3332      "# The entries below are used to detect a USB device and change owner\n"
3333      "# and permissions on the \"device node\" used by libusb.\n"
3334      "#\n"
3335      "# The 0x0003 match flag means the device is matched by its vendor and\n"
3336      "# product IDs.\n"
3337      "#\n"
3338      "# Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID\n"
3339      "# respectively):\n"
3340      "#\n"
3341      );
3342 
3343   printf
3344     ("# libusbscanner 0x0003 0xVVVV 0xPPPP 0x0000 0x0000 0x00 0x00 0x00 0x00 "
3345      "0x00 0x00 0x00000000\n"
3346      "# usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi "
3347      "bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass "
3348      "bInterfaceSubClass bInterfaceProtocol driver_info\n"
3349      "#\n"
3350      );
3351 
3352   printf
3353      ("# If your scanner isn't listed below, you can add it as explained above.\n"
3354      "#\n"
3355      "# If your scanner is supported by some external backend (brother, epkowa,\n"
3356      "# hpaio, etc) please ask the author of the backend to provide proper\n"
3357      "# device detection support for your OS\n"
3358      "#\n"
3359      "# If the scanner is supported by sane-backends, please mail the entry to\n"
3360      "# the sane-devel mailing list (sane-devel@alioth-lists.debian.net).\n"
3361      "#\n"
3362      );
3363 
3364 }
3365 
3366 static void
print_usermap(void)3367 print_usermap (void)
3368 {
3369   usbid_type *usbid = create_usbids_table ();
3370 
3371   print_usermap_header ();
3372   while (usbid)
3373     {
3374       manufacturer_model_type * name = usbid->name;
3375 
3376       printf ("# ");
3377       while (name)
3378 	{
3379 	  if (name != usbid->name)
3380 	    printf (" | ");
3381 	  printf ("%s", name->name);
3382 	  name = name->next;
3383 	}
3384       printf ("\n");
3385       printf ("libusbscanner 0x0003 %s %s ", usbid->usb_vendor_id,
3386 	      usbid->usb_product_id);
3387       printf ("0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000\n");
3388       usbid = usbid->next;
3389     }
3390 }
3391 
3392 /* print libsane.db file for hotplug-ng */
3393 static void
print_db_header(void)3394 print_db_header (void)
3395 {
3396   print_header_comment ();
3397   printf
3398     ("#\n"
3399      "# The entries below are used to detect a USB device when it's plugged in\n"
3400      "# and then run a script to change the ownership and\n"
3401      "# permissions on the \"device node\" used by libusb.\n"
3402      "# Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID\n"
3403      "# respectively):\n");
3404   printf
3405     ("#\n"
3406      "# 0xVVVV<tab>0xPPPP<tab>%s:%s<tab>%s<tab>[/usr/local/bin/foo.sh]\n"
3407      "# Fields:\n"
3408      "#   vendor ID\n"
3409      "#   product ID\n"
3410      "#   ownership (user:group)\n"
3411      "#   permissions\n"
3412      "#   path of an optional script to run (it can be omitted)\n"
3413      "#\n"
3414      , DEVOWNER, DEVGROUP, DEVMODE);
3415 
3416   printf
3417      ("# If your scanner isn't listed below, you can add it as explained above.\n"
3418      "#\n"
3419      "# If your scanner is supported by some external backend (brother, epkowa,\n"
3420      "# hpaio, etc) please ask the author of the backend to provide proper\n"
3421      "# device detection support for your OS\n"
3422      "#\n"
3423      "# If the scanner is supported by sane-backends, please mail the entry to\n"
3424      "# the sane-devel mailing list (sane-devel@alioth-lists.debian.net).\n"
3425      "#\n"
3426      );
3427 }
3428 
3429 static void
print_db(void)3430 print_db (void)
3431 {
3432   usbid_type *usbid = create_usbids_table ();
3433 
3434   print_db_header ();
3435   while (usbid)
3436     {
3437       manufacturer_model_type * name = usbid->name;
3438 
3439       printf ("# ");
3440       while (name)
3441 	{
3442 	  if (name != usbid->name)
3443 	    printf (" | ");
3444 	  printf ("%s", name->name);
3445 	  name = name->next;
3446 	}
3447       printf ("\n");
3448       printf ("%s\t%s\t%s:%s\t%s\n", usbid->usb_vendor_id,
3449 	      usbid->usb_product_id, DEVOWNER, DEVGROUP, DEVMODE);
3450       usbid = usbid->next;
3451     }
3452 }
3453 
3454 /* print libsane.rules for Linux udev */
3455 static void
print_udev_header(void)3456 print_udev_header (void)
3457 {
3458   print_header_comment ();
3459   printf
3460     ("#\n"
3461      "# udev rules file for supported USB and SCSI devices\n"
3462      "#\n"
3463      "# The SCSI device support is very basic and includes only\n"
3464      "# scanners that mark themselves as type \"scanner\" or\n"
3465      "# SCSI-scanners from HP and other vendors that are entitled \"processor\"\n"
3466      "# but are treated accordingly.\n"
3467      "#\n");
3468   printf
3469     ("# To add a USB device, add a rule to the list below between the\n"
3470      "# LABEL=\"libsane_usb_rules_begin\" and LABEL=\"libsane_usb_rules_end\" lines.\n"
3471      "#\n"
3472      "# To run a script when your device is plugged in, add RUN+=\"/path/to/script\"\n"
3473      "# to the appropriate rule.\n"
3474      "#\n"
3475      );
3476   printf
3477      ("# If your scanner isn't listed below, you can add it as explained above.\n"
3478      "#\n"
3479      "# If your scanner is supported by some external backend (brother, epkowa,\n"
3480      "# hpaio, etc) please ask the author of the backend to provide proper\n"
3481      "# device detection support for your OS\n"
3482      "#\n"
3483      "# If the scanner is supported by sane-backends, please mail the entry to\n"
3484      "# the sane-devel mailing list (sane-devel@alioth-lists.debian.net).\n"
3485      "#\n"
3486      );
3487 }
3488 
3489 static void
print_udev(void)3490 print_udev (void)
3491 {
3492   usbid_type *usbid = create_usbids_table ();
3493   scsiid_type *scsiid = create_scsiids_table ();
3494   int i;
3495 
3496   print_udev_header ();
3497   printf("ACTION==\"remove\", GOTO=\"libsane_rules_end\"\n"
3498 	 "ENV{DEVTYPE}==\"usb_device\", GOTO=\"libsane_create_usb_dev\"\n"
3499 	 "SUBSYSTEMS==\"scsi\", GOTO=\"libsane_scsi_rules_begin\"\n"
3500 	 "SUBSYSTEM==\"usb_device\", GOTO=\"libsane_usb_rules_begin\"\n"
3501 	 "SUBSYSTEM!=\"usb_device\", GOTO=\"libsane_usb_rules_end\"\n"
3502 	 "\n");
3503 
3504   printf("# Kernel >= 2.6.22 jumps here\n"
3505 	 "LABEL=\"libsane_create_usb_dev\"\n"
3506 	 "\n");
3507 
3508   printf("# For Linux >= 2.6.22 without CONFIG_USB_DEVICE_CLASS=y\n"
3509 	 "# If the following rule does not exist on your system yet, uncomment it\n"
3510 	 "# ENV{DEVTYPE}==\"usb_device\", "
3511 	 "MODE=\"0664\", OWNER=\"root\", GROUP=\"root\"\n"
3512 	 "\n");
3513 
3514   printf("# Kernel < 2.6.22 jumps here\n"
3515 	 "LABEL=\"libsane_usb_rules_begin\"\n"
3516 	 "\n");
3517 
3518   while (usbid)
3519     {
3520       manufacturer_model_type * name = usbid->name;
3521 
3522       i = 0;
3523       printf ("# ");
3524       while (name)
3525 	{
3526 	  if ((name != usbid->name) && (i > 0))
3527 	    printf (" | ");
3528 	  printf ("%s", name->name);
3529 	  name = name->next;
3530 
3531 	  i++;
3532 
3533 	  /*
3534 	   * Limit the number of model names on the same line to 3,
3535 	   * as udev cannot handle very long lines and prints a warning
3536 	   * message while loading the rules files.
3537 	   */
3538 	  if ((i == 3) && (name != NULL))
3539 	    {
3540 	      printf("\n# ");
3541 	      i = 0;
3542 	    }
3543 	}
3544       printf ("\n");
3545 
3546       if (mode == output_mode_udevacl)
3547 	printf ("ATTR{idVendor}==\"%s\", ATTR{idProduct}==\"%s\", ENV{libsane_matched}=\"yes\"\n",
3548 		usbid->usb_vendor_id + 2,  usbid->usb_product_id + 2);
3549       else
3550 	printf ("ATTR{idVendor}==\"%s\", ATTR{idProduct}==\"%s\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n",
3551 		usbid->usb_vendor_id + 2,  usbid->usb_product_id + 2, DEVMODE, DEVGROUP);
3552 
3553       usbid = usbid->next;
3554     }
3555 
3556   printf("\n# The following rule will disable USB autosuspend for the device\n");
3557   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");
3558 
3559   printf ("\nLABEL=\"libsane_usb_rules_end\"\n\n");
3560 
3561   printf ("SUBSYSTEMS==\"scsi\", GOTO=\"libsane_scsi_rules_begin\"\n");
3562   printf ("GOTO=\"libsane_scsi_rules_end\"\n\n");
3563   printf ("LABEL=\"libsane_scsi_rules_begin\"\n");
3564   printf ("# Generic: SCSI device type 6 indicates a scanner\n");
3565 
3566   if (mode == output_mode_udevacl)
3567     printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"6\", ENV{libsane_matched}=\"yes\"\n");
3568   else
3569     printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"6\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n", DEVMODE, DEVGROUP);
3570 
3571 
3572   printf ("# Some scanners advertise themselves as SCSI device type 3\n");
3573 
3574   printf ("# Wildcard: for some Epson SCSI scanners\n");
3575   if (mode == output_mode_udevacl)
3576     printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"EPSON\", ATTRS{model}==\"SCANNER*\", ENV{libsane_matched}=\"yes\"\n");
3577   else
3578     printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"EPSON\", ATTRS{model}==\"SCANNER*\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n",
3579 	    DEVMODE, DEVGROUP);
3580 
3581   while (scsiid)
3582     {
3583       manufacturer_model_type * name = scsiid->name;
3584 
3585       if (!scsiid->is_processor)
3586 	{
3587 	  scsiid = scsiid->next;
3588 	  continue;
3589 	}
3590 
3591       /* Wildcard for Epson scanners: vendor = EPSON, product = SCANNER* */
3592       if ((strcmp(scsiid->scsi_vendor_id, "EPSON") == 0)
3593 	  && (strncmp(scsiid->scsi_product_id, "SCANNER", 7) == 0))
3594 	{
3595 	  scsiid = scsiid->next;
3596 	  continue;
3597 	}
3598 
3599       i = 0;
3600       printf ("# ");
3601       while (name)
3602         {
3603           if ((name != scsiid->name) && (i > 0))
3604             printf (" | ");
3605           printf ("%s", name->name);
3606           name = name->next;
3607 
3608 	  i++;
3609 
3610 	  /*
3611 	   * Limit the number of model names on the same line to 3,
3612 	   * as udev cannot handle very long lines and prints a warning
3613 	   * message while loading the rules files.
3614 	   */
3615 	  if ((i == 3) && (name != NULL))
3616 	    {
3617 	      printf("\n# ");
3618 	      i = 0;
3619 	    }
3620         }
3621       printf ("\n");
3622 
3623       if (mode == output_mode_udevacl)
3624 	printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"%s\", ATTRS{model}==\"%s\", ENV{libsane_matched}=\"yes\"\n",
3625 		scsiid->scsi_vendor_id, scsiid->scsi_product_id);
3626       else
3627 	printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"%s\", ATTRS{model}==\"%s\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n",
3628 	      scsiid->scsi_vendor_id, scsiid->scsi_product_id, DEVMODE, DEVGROUP);
3629 
3630       scsiid = scsiid->next;
3631     }
3632   printf ("LABEL=\"libsane_scsi_rules_end\"\n");
3633 
3634   if (mode == output_mode_udevacl)
3635     printf("\nENV{libsane_matched}==\"yes\", RUN+=\"/bin/setfacl -m g:%s:rw $env{DEVNAME}\"\n", DEVGROUP);
3636   else
3637     printf ("\nENV{libsane_matched}==\"yes\", MODE=\"664\", GROUP=\"scanner\"\n");
3638 
3639   printf ("\nLABEL=\"libsane_rules_end\"\n");
3640 }
3641 
3642 
3643 /* print libsane.rules for Linux udev */
3644 static void
print_udevhwdb_header(void)3645 print_udevhwdb_header (void)
3646 {
3647   print_header_comment ();
3648   printf
3649     ("#\n"
3650      "# udev rules file for supported USB and SCSI devices\n"
3651      "#\n"
3652      "# For the list of supported USB devices see /usr/lib/udev/hwdb.d/20-sane.hwdb\n"
3653      "#\n"
3654      "# The SCSI device support is very basic and includes only\n"
3655      "# scanners that mark themselves as type \"scanner\" or\n"
3656      "# SCSI-scanners from HP and other vendors that are entitled \"processor\"\n"
3657      "# but are treated accordingly.\n"
3658      "#\n");
3659   printf
3660      ("# If your SCSI scanner isn't listed below, you can add it to a new rules\n"
3661      "# file under /etc/udev/rules.d/.\n"
3662      "#\n"
3663      "# If your scanner is supported by some external backend (brother, epkowa,\n"
3664      "# hpaio, etc) please ask the author of the backend to provide proper\n"
3665      "# device detection support for your OS\n"
3666      "#\n"
3667      "# If the scanner is supported by sane-backends, please mail the entry to\n"
3668      "# the sane-devel mailing list (sane-devel@alioth-lists.debian.net).\n"
3669      "#\n"
3670      );
3671 }
3672 
3673 static void
print_udevhwdb(void)3674 print_udevhwdb (void)
3675 {
3676   scsiid_type *scsiid = create_scsiids_table ();
3677   int i;
3678 
3679   print_udevhwdb_header ();
3680   printf("ACTION==\"remove\", GOTO=\"libsane_rules_end\"\n\n");
3681 
3682   printf("# The following rule will disable USB autosuspend for the device\n");
3683   printf("ENV{DEVTYPE}==\"usb_device\", ENV{libsane_matched}==\"yes\", TEST==\"power/control\", ATTR{power/control}=\"on\"\n\n");
3684 
3685   printf ("SUBSYSTEMS==\"scsi\", GOTO=\"libsane_scsi_rules_begin\"\n");
3686   printf ("GOTO=\"libsane_rules_end\"\n\n");
3687   printf ("LABEL=\"libsane_scsi_rules_begin\"\n");
3688   printf ("KERNEL!=\"sg[0-9]*\", GOTO=\"libsane_rules_end\"\n\n");
3689 
3690   printf ("# Generic: SCSI device type 6 indicates a scanner\n");
3691   printf ("ATTRS{type}==\"6\", ENV{libsane_matched}=\"yes\"\n\n");
3692 
3693   printf ("# Some scanners advertise themselves as SCSI device type 3\n\n");
3694 
3695   printf ("# Wildcard: for some Epson SCSI scanners\n");
3696   printf ("ATTRS{type}==\"3\", ATTRS{vendor}==\"EPSON\", ATTRS{model}==\"SCANNER*\", ENV{libsane_matched}=\"yes\"\n\n");
3697 
3698   while (scsiid)
3699     {
3700       manufacturer_model_type * name = scsiid->name;
3701 
3702       if (!scsiid->is_processor)
3703 	{
3704 	  scsiid = scsiid->next;
3705 	  continue;
3706 	}
3707 
3708       /* Wildcard for Epson scanners: vendor = EPSON, product = SCANNER* */
3709       if ((strcmp(scsiid->scsi_vendor_id, "EPSON") == 0)
3710 	  && (strncmp(scsiid->scsi_product_id, "SCANNER", 7) == 0))
3711 	{
3712 	  scsiid = scsiid->next;
3713 	  continue;
3714 	}
3715 
3716       i = 0;
3717       printf ("# ");
3718       while (name)
3719         {
3720           if ((name != scsiid->name) && (i > 0))
3721             printf (" | ");
3722           printf ("%s", name->name);
3723           name = name->next;
3724 
3725 	  i++;
3726 
3727 	  /*
3728 	   * Limit the number of model names on the same line to 3,
3729 	   * as udev cannot handle very long lines and prints a warning
3730 	   * message while loading the rules files.
3731 	   */
3732 	  if ((i == 3) && (name != NULL))
3733 	    {
3734 	      printf("\n# ");
3735 	      i = 0;
3736 	    }
3737         }
3738       printf ("\n");
3739 
3740       printf ("ATTRS{type}==\"3\", ATTRS{vendor}==\"%s\", ATTRS{model}==\"%s\", ENV{libsane_matched}=\"yes\"\n\n",
3741 		scsiid->scsi_vendor_id, scsiid->scsi_product_id);
3742 
3743       scsiid = scsiid->next;
3744     }
3745 
3746   printf ("\nLABEL=\"libsane_rules_end\"\n");
3747 }
3748 
3749 /* print /usr/lib/udev/hwdb.d/20-sane.conf for Linux hwdb */
3750 static void
print_hwdb_header(void)3751 print_hwdb_header (void)
3752 {
3753   print_header_comment ();
3754   printf
3755     ("#\n"
3756      "# hwdb file for supported USB devices\n"
3757      "#\n");
3758   printf
3759      ("# If your scanner isn't listed below, you can add it to a new hwdb file\n"
3760      "# under /etc/udev/hwdb.d/.\n"
3761      "#\n"
3762      "# If your scanner is supported by some external backend (brother, epkowa,\n"
3763      "# hpaio, etc) please ask the author of the backend to provide proper\n"
3764      "# device detection support for your OS\n"
3765      "#\n"
3766      "# If the scanner is supported by sane-backends, please mail the entry to\n"
3767      "# the sane-devel mailing list (sane-devel@alioth-lists.debian.net).\n"
3768      "#"
3769      );
3770 }
3771 
3772 static void
print_hwdb(void)3773 print_hwdb (void)
3774 {
3775   usbid_type *usbid = create_usbids_table ();
3776   char *vendor_id;
3777   char *product_id;
3778   int i,j;
3779 
3780   print_hwdb_header ();
3781 
3782   while (usbid)
3783     {
3784       manufacturer_model_type * name = usbid->name;
3785 
3786       i = 0;
3787       printf ("\n# ");
3788       while (name)
3789 	{
3790 	  if ((name != usbid->name) && (i > 0))
3791 	    printf (" | ");
3792 	  printf ("%s", name->name);
3793 	  name = name->next;
3794 
3795 	  i++;
3796 
3797 	  /*
3798 	   * Limit the number of model names on the same line to 3,
3799 	   * as udev cannot handle very long lines and prints a warning
3800 	   * message while loading the rules files.
3801 	   */
3802 	  if ((i == 3) && (name != NULL))
3803 	    {
3804 	      printf("\n# ");
3805 	      i = 0;
3806 	    }
3807 	}
3808       printf ("\n");
3809 
3810       vendor_id = strdup(usbid->usb_vendor_id + 2);
3811       product_id = strdup(usbid->usb_product_id + 2);
3812 
3813       for(j = 0; j < 4; j++) {
3814         vendor_id[j] = toupper(vendor_id[j]);
3815         product_id[j] = toupper(product_id[j]);
3816       }
3817 
3818       printf ("usb:v%sp%s*\n libsane_matched=yes\n",
3819 		vendor_id, product_id);
3820 
3821       free(vendor_id);
3822       free(product_id);
3823 
3824       usbid = usbid->next;
3825     }
3826 }
3827 
3828 static void
print_plist(void)3829 print_plist (void)
3830 {
3831   usbid_type *usbid = create_usbids_table ();
3832 
3833   printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
3834   printf ("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
3835   printf ("<plist version=\"1.0\">\n");
3836   printf ("<dict>\n");
3837   printf ("\t<key>device info version</key>\n");
3838   printf ("\t<string>2.0</string>\n");
3839   printf ("\t<key>usb</key>\n");
3840   printf ("\t<dict>\n");
3841   printf ("\t\t<key>IOUSBDevice</key>\n");
3842   printf ("\t\t<array>\n");
3843   while (usbid)
3844     {
3845       printf ("\t\t\t<dict>\n");
3846       printf ("\t\t\t\t<key>device type</key>\n");
3847       printf ("\t\t\t\t<string>scanner</string>\n");
3848       printf ("\t\t\t\t<key>product</key>\n");
3849       printf ("\t\t\t\t<string>%s</string>\n", usbid->usb_product_id);
3850       printf ("\t\t\t\t<key>vendor</key>\n");
3851       printf ("\t\t\t\t<string>%s</string>\n", usbid->usb_vendor_id);
3852       printf ("\t\t\t</dict>\n");
3853       usbid = usbid->next;
3854     }
3855   printf ("\t\t</array>\n");
3856   printf ("\t</dict>\n");
3857   printf ("</dict>\n");
3858   printf ("</plist>\n");
3859 }
3860 
3861 
3862 static void
print_hal(int new)3863 print_hal (int new)
3864 {
3865   int i;
3866   SANE_Bool in_match;
3867   char *last_vendor;
3868   scsiid_type *scsiid = create_scsiids_table ();
3869   usbid_type *usbid = create_usbids_table ();
3870 
3871   printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
3872   printf ("<deviceinfo version=\"0.2\">\n");
3873   printf ("  <device>\n");
3874   printf ("    <!-- SCSI-SUBSYSTEM -->\n");
3875   printf ("    <match key=\"info.category\" string=\"scsi_generic\">\n");
3876   printf ("      <!-- Some SCSI Scanners announce themselves \"processor\" -->\n");
3877   printf ("      <match key=\"@info.parent:scsi.type\" string=\"processor\">\n");
3878 
3879   last_vendor = "";
3880   in_match = SANE_FALSE;
3881   while (scsiid)
3882     {
3883       manufacturer_model_type * name = scsiid->name;
3884 
3885       if (!scsiid->is_processor)
3886 	{
3887 	  scsiid = scsiid->next;
3888 	  continue;
3889 	}
3890 
3891       if (strcmp(last_vendor, scsiid->scsi_vendor_id) != 0)
3892 	{
3893 	  if (in_match)
3894 	    printf ("        </match>\n");
3895 
3896 	  printf ("        <match key=\"@info.parent:scsi.vendor\" string=\"%s\">\n", scsiid->scsi_vendor_id);
3897 	  last_vendor = scsiid->scsi_vendor_id;
3898 	  in_match = SANE_TRUE;
3899 	}
3900 
3901       printf ("          <!-- SCSI Scanner ");
3902       while (name)
3903 	{
3904 	  if (name != scsiid->name)
3905 	    printf (" | ");
3906 	  printf ("\"%s\"", name->name);
3907 	  name = name->next;
3908 	}
3909       printf (" -->\n");
3910       printf ("          <match key=\"@info.parent:scsi.model\" string=\"%s\">\n", scsiid->scsi_product_id);
3911       printf ("            <append key=\"info.capabilities\" type=\"strlist\">scanner</append>\n");
3912       printf ("          </match>\n");
3913 
3914       scsiid = scsiid->next;
3915     }
3916 
3917   if (in_match)
3918     printf ("        </match>\n");
3919 
3920   printf ("      </match>\n");
3921   printf ("    </match>\n");
3922   printf ("    <!-- USB-SUBSYSTEM -->\n");
3923 
3924   if (new)
3925     printf ("    <match key=\"info.subsystem\" string=\"usb\">\n");
3926   else
3927     printf ("    <match key=\"info.bus\" string=\"usb\">\n");
3928 
3929   last_vendor = "";
3930   in_match = SANE_FALSE;
3931   while (usbid)
3932     {
3933       manufacturer_model_type * name = usbid->name;
3934 
3935       if (strcmp(last_vendor, usbid->usb_vendor_id) != 0)
3936 	{
3937 	  if (in_match)
3938 	    printf ("      </match>\n");
3939 
3940 	  printf ("      <match key=\"usb.vendor_id\" int=\"%s\">\n", usbid->usb_vendor_id);
3941 	  last_vendor = usbid->usb_vendor_id;
3942 	  in_match = SANE_TRUE;
3943 	}
3944 
3945       i = 0;
3946       printf ("        <!-- ");
3947       while (name)
3948 	{
3949 	  if ((name != usbid->name) && (i > 0))
3950 	    printf (" | ");
3951 
3952 	  printf ("%s", name->name);
3953 	  name = name->next;
3954 	  i++;
3955 
3956 	  if ((i == 3) && (name != NULL))
3957 	    {
3958 	      printf("\n             ");
3959 	      i = 0;
3960 	    }
3961 	}
3962       printf (" -->\n");
3963       printf ("        <match key=\"usb.product_id\" int=\"%s\">\n", usbid->usb_product_id);
3964       printf ("          <append key=\"info.capabilities\" type=\"strlist\">scanner</append>\n");
3965       printf ("          <merge key=\"scanner.access_method\" type=\"string\">proprietary</merge>\n");
3966       printf ("        </match>\n");
3967 
3968       usbid = usbid->next;
3969     }
3970 
3971   if (in_match)
3972     printf ("      </match>\n");
3973 
3974   printf ("    </match>\n");
3975 
3976   printf ("  </device>\n");
3977   printf ("</deviceinfo>\n");
3978 }
3979 
3980 int
main(int argc, char **argv)3981 main (int argc, char **argv)
3982 {
3983   program_name = strrchr (argv[0], '/');
3984   if (program_name)
3985     ++program_name;
3986   else
3987     program_name = argv[0];
3988 
3989   if (!get_options (argc, argv))
3990     return 1;
3991   if (!read_files ())
3992     return 1;
3993   switch (mode)
3994     {
3995     case output_mode_ascii:
3996       ascii_print_backends ();
3997       break;
3998     case output_mode_xml:
3999       xml_print_backends ();
4000       break;
4001     case output_mode_html_backends_split:
4002       html_print_backends_split ();
4003       break;
4004     case output_mode_html_mfgs:
4005       html_print_mfgs ();
4006       break;
4007     case output_mode_statistics:
4008       print_statistics ();
4009       break;
4010     case output_mode_usermap:
4011       print_usermap ();
4012       break;
4013     case output_mode_db:
4014       print_db ();
4015       break;
4016     case output_mode_udev:
4017     case output_mode_udevacl:
4018       print_udev ();
4019       break;
4020     case output_mode_udevhwdb:
4021       print_udevhwdb ();
4022       break;
4023     case output_mode_hwdb:
4024       print_hwdb ();
4025       break;
4026     case output_mode_plist:
4027       print_plist ();
4028       break;
4029     case output_mode_hal:
4030       print_hal (0);
4031       break;
4032     case output_mode_halnew:
4033       print_hal (1);
4034       break;
4035     default:
4036       DBG_ERR ("Unknown output mode\n");
4037       return 1;
4038     }
4039 
4040   return 0;
4041 }
4042