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, "<");
2039 break;
2040 case '>':
2041 aux = strcat (aux, ">");
2042 break;
2043 case '\'':
2044 aux = strcat (aux, "'");
2045 break;
2046 case '&':
2047 aux = strcat (aux, "&");
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> </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> </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> </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> </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