1 /*
2  *   Foomatic Perl Data
3  *   ------------------
4  *
5  *   Compute the Foomatic Perl data structures out of the
6  *   printer/driver combo XML file or overview XML file as generated
7  *   by foomatic-combo-xml.c. Compute also a Perl data structure from
8  *   printer and driver entries of the Fommatic database.
9  *
10  *   The Foomatic Perl data structure for the printer/driver combos is
11  *   the basis for all spooler-specific config files and PPD files and
12  *   also the data structure used by the filter Perl scripts.
13  *
14  *   The other Perl data structures are used by the Foomatic Perl library
15  *   to do the database operations provided by its API.
16  *
17  *   This program is based on the libxml2 and this is a retianol way to
18  *   make a C data structure from a single XML file. This structure is then
19  *   converted to Perl
20  *
21  *   Copyright 2001 by Till Kamppeter
22  *
23  *   This program is free software; you can redistribute it and/or
24  *   modify it under the terms of the GNU General Public License as
25  *   published by the Free Software Foundation; either version 2 of the
26  *   License, or (at your option) any later version.
27  *
28  *   This program is distributed in the hope that it will be useful,
29  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
30  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  *   GNU General Public License for more details.
32  *
33  *   You should have received a copy of the GNU General Public License
34  *   along with this program; if not, write to the Free Software
35  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
36  *   02111-1307  USA
37  *
38  */
39 
40 /*
41 
42   Compilable with (depending on installed packages):
43 
44   gcc `xml2-config --cflags` -lxml2 -o foomatic-perl-data \
45       foomatic-perl-data.c
46 
47   or
48 
49   gcc `xml-config --cflags` -lxml -o foomatic-perl-data \
50       foomatic-perl-data.c
51 
52 */
53 
54 #include <stdio.h>
55 #include <string.h>
56 #include <stdlib.h>
57 
58 /*
59  * This program should compile and run indifferently with libxml-1.8.8 +
60  * and libxml2-2.1.0 +
61  * Check the COMPAT comments below
62  */
63 
64 /*
65  * COMPAT using "xml-config --cflags" to get the include path this will
66  * work with both (on distros with both xml1 and xml2 "xml2-config".
67  */
68 #include <libxml/xmlmemory.h>
69 #include <libxml/parser.h>
70 
71 #define DEBUG(x) printf(x)
72 
73 /*
74  * an xmlChar * is really an UTF8 encoded char string (0 terminated)
75  */
76 
77 /*
78  * Records for the unprintable margins data
79  */
80 
81 typedef struct marginRecord {
82   xmlChar *pagesize;
83   xmlChar *unit;
84   xmlChar *absolute;
85   xmlChar *left;
86   xmlChar *right;
87   xmlChar *top;
88   xmlChar *bottom;
89 } marginRecord, *marginRecordPtr;
90 
91 typedef struct margins {
92   int     num_marginRecords;
93   marginRecordPtr *marginRecords;
94 } margins, *marginsPtr;
95 
96 /* For driver list in printer XML, for ready-made PPDs or user-contributed
97    printer entry */
98 typedef struct printerDrvEntry {
99   xmlChar *name;
100   xmlChar const *comment;
101   xmlChar *ppd;
102   /* functionality exceptions */
103   xmlChar *excmaxresx;
104   xmlChar *excmaxresy;
105   xmlChar *exccolor;
106   xmlChar *exctext;
107   xmlChar *exclineart;
108   xmlChar *excgraphics;
109   xmlChar *excphoto;
110   xmlChar *excload;
111   xmlChar *excspeed;
112 } printerDrvEntry, *printerDrvEntryPtr;
113 
114 /*
115  * Records for the data of a printer/driver combo
116  */
117 
118 typedef struct choice {
119   xmlChar const *value;
120   xmlChar const *comment;
121   xmlChar *idx;
122   xmlChar *driverval;
123 } choice, *choicePtr;
124 
125 typedef struct arg {
126   xmlChar const *name;
127   xmlChar const *name_false;
128   xmlChar const *comment;
129   xmlChar *idx;
130   xmlChar *option_type;
131   xmlChar *style;
132   xmlChar *substyle;
133   xmlChar *spot;
134   xmlChar *order;
135   xmlChar *section;
136   xmlChar *grouppath;
137   xmlChar *proto;
138   xmlChar *required;
139   xmlChar *min_value;
140   xmlChar *max_value;
141   xmlChar *max_length;
142   xmlChar *allowed_chars;
143   xmlChar *allowed_regexp;
144   xmlChar const *default_value;
145   /* Choices for enumerated options */
146   int     num_choices;
147   choicePtr *choices;
148 } arg, *argPtr;
149 
150 typedef struct comboData {
151   /* Printer */
152   xmlChar *id;
153   xmlChar *make;
154   xmlChar *model;
155   xmlChar *pcmodel;
156   xmlChar *ppdurl;
157   /* Printer properties */
158   xmlChar *color;
159   xmlChar *ascii;
160   xmlChar *pjl;
161   xmlChar *printerppdentry;
162   marginsPtr printermargins;
163   /* Printer auto-detection */
164   xmlChar *general_ieee;
165   xmlChar *general_mfg;
166   xmlChar *general_mdl;
167   xmlChar *general_des;
168   xmlChar *general_cmd;
169   xmlChar *par_ieee;
170   xmlChar *par_mfg;
171   xmlChar *par_mdl;
172   xmlChar *par_des;
173   xmlChar *par_cmd;
174   xmlChar *usb_ieee;
175   xmlChar *usb_mfg;
176   xmlChar *usb_mdl;
177   xmlChar *usb_des;
178   xmlChar *usb_cmd;
179   xmlChar *snmp_ieee;
180   xmlChar *snmp_mfg;
181   xmlChar *snmp_mdl;
182   xmlChar *snmp_des;
183   xmlChar *snmp_cmd;
184   xmlChar *recdriver;
185   /* Driver list in printer XML file (for ready-made PPD
186      links) */
187   int     num_drivers;
188   printerDrvEntryPtr  *drivers;
189   /* Driver */
190   xmlChar *driver;
191   xmlChar *driver_group;
192   xmlChar *pcdriver;
193   xmlChar *driver_type;
194   xmlChar const *driver_comment;
195   xmlChar *url;
196   xmlChar *driver_obsolete;
197   xmlChar const *supplier;
198   xmlChar *manufacturersupplied;
199   xmlChar const *license;
200   xmlChar *licensetext;
201   xmlChar *origlicensetext;
202   xmlChar *licenselink;
203   xmlChar *origlicenselink;
204   xmlChar *free;
205   xmlChar *patents;
206   int num_supportcontacts;
207   xmlChar const **supportcontacts;
208   xmlChar **supportcontacturls;
209   xmlChar **supportcontactlevels;
210   xmlChar const *shortdescription;
211   xmlChar *locales;
212   int num_packages;
213   xmlChar **packageurls;
214   xmlChar **packagescopes;
215   xmlChar **packagefingerprints;
216   xmlChar *drvmaxresx;
217   xmlChar *drvmaxresy;
218   xmlChar *drvcolor;
219   xmlChar *text;
220   xmlChar *lineart;
221   xmlChar *graphics;
222   xmlChar *photo;
223   xmlChar *load;
224   xmlChar *speed;
225   xmlChar *excmaxresx;
226   xmlChar *excmaxresy;
227   xmlChar *exccolor;
228   xmlChar *exctext;
229   xmlChar *exclineart;
230   xmlChar *excgraphics;
231   xmlChar *excphoto;
232   xmlChar *excload;
233   xmlChar *excspeed;
234   int num_requires;
235   xmlChar **requires;
236   xmlChar **requiresversion;
237   xmlChar *cmd;
238   xmlChar *cmd_pdf;
239   xmlChar *nopjl;
240   xmlChar *nopageaccounting;
241   xmlChar *driverppdentry;
242   xmlChar *comboppdentry;
243   marginsPtr drivermargins;
244   marginsPtr combomargins;
245   /* Driver options */
246   int     num_args;
247   argPtr  *args;
248   xmlChar *maxspot;
249 } comboData, *comboDataPtr;
250 
251 /*
252  * Record for a Foomatic printer entry
253  */
254 
255 typedef struct printerLanguage {
256   xmlChar *name;
257   xmlChar *level;
258 } printerLanguage, *printerLanguagePtr;
259 
260 typedef struct printerEntry {
261   xmlChar *id;
262   xmlChar *make;
263   xmlChar *model;
264   /* Printer properties */
265   xmlChar *printer_type;
266   xmlChar *color;
267   xmlChar *maxxres;
268   xmlChar *maxyres;
269   xmlChar const *refill;
270   xmlChar *ascii;
271   xmlChar *pjl;
272   xmlChar *printerppdentry;
273   marginsPtr printermargins;
274   /* Printer auto-detection */
275   xmlChar *general_ieee;
276   xmlChar *general_mfg;
277   xmlChar *general_mdl;
278   xmlChar *general_des;
279   xmlChar *general_cmd;
280   xmlChar *par_ieee;
281   xmlChar *par_mfg;
282   xmlChar *par_mdl;
283   xmlChar *par_des;
284   xmlChar *par_cmd;
285   xmlChar *usb_ieee;
286   xmlChar *usb_mfg;
287   xmlChar *usb_mdl;
288   xmlChar *usb_des;
289   xmlChar *usb_cmd;
290   xmlChar *snmp_ieee;
291   xmlChar *snmp_mfg;
292   xmlChar *snmp_mdl;
293   xmlChar *snmp_des;
294   xmlChar *snmp_cmd;
295   /* Misc items */
296   xmlChar *functionality;
297   xmlChar *driver;
298   xmlChar *unverified;
299   xmlChar *noxmlentry;
300   xmlChar *url;
301   xmlChar *contriburl;
302   xmlChar *ppdurl;
303   xmlChar const *comment;
304   /* Page Description Languages */
305   int     num_languages;
306   printerLanguagePtr  *languages;
307   /* Drivers (for user-contributed printer entries and for ready-made PPD
308      links) */
309   int     num_drivers;
310   printerDrvEntryPtr  *drivers;
311 } printerEntry, *printerEntryPtr;
312 
313 /*
314  * Records for a Foomatic driver entry
315  */
316 
317 typedef struct drvPrnEntry {
318   xmlChar *id;
319   xmlChar const *comment;
320   /* functionality exceptions */
321   xmlChar *excmaxresx;
322   xmlChar *excmaxresy;
323   xmlChar *exccolor;
324   xmlChar *exctext;
325   xmlChar *exclineart;
326   xmlChar *excgraphics;
327   xmlChar *excphoto;
328   xmlChar *excload;
329   xmlChar *excspeed;
330 } drvPrnEntry, *drvPrnEntryPtr;
331 
332 typedef struct driverEntry {
333   xmlChar *id;
334   xmlChar *name;
335   xmlChar *group;
336   xmlChar *url;
337   xmlChar *driver_obsolete;
338   xmlChar const *supplier;
339   xmlChar *manufacturersupplied;
340   xmlChar const *license;
341   xmlChar *licensetext;
342   xmlChar *origlicensetext;
343   xmlChar *licenselink;
344   xmlChar *origlicenselink;
345   xmlChar *free;
346   xmlChar *patents;
347   int num_supportcontacts;
348   xmlChar const **supportcontacts;
349   xmlChar **supportcontacturls;
350   xmlChar **supportcontactlevels;
351   xmlChar const *shortdescription;
352   xmlChar *locales;
353   int num_packages;
354   xmlChar **packageurls;
355   xmlChar **packagescopes;
356   xmlChar **packagefingerprints;
357   xmlChar *maxresx;
358   xmlChar *maxresy;
359   xmlChar *color;
360   xmlChar *text;
361   xmlChar *lineart;
362   xmlChar *graphics;
363   xmlChar *photo;
364   xmlChar *load;
365   xmlChar *speed;
366   int num_requires;
367   xmlChar **requires;
368   xmlChar **requiresversion;
369   xmlChar *driver_type;
370   xmlChar *cmd;
371   xmlChar *cmd_pdf;
372   xmlChar *driverppdentry;
373   marginsPtr drivermargins;
374   xmlChar const *comment;
375   int     num_printers;
376   drvPrnEntryPtr *printers;
377 } driverEntry, *driverEntryPtr;
378 
379 /*
380  * Records for the data of the overview
381  */
382 
383 typedef struct ppdFile {
384   xmlChar *driver;
385   xmlChar *filename;
386 } ppdFile, *ppdFilePtr;
387 
388 typedef struct overviewPrinter {
389   /* General info */
390   xmlChar *id;
391   xmlChar *make;
392   xmlChar *model;
393   xmlChar *functionality;
394   xmlChar *unverified;
395   xmlChar *noxmlentry;
396   /* Printer auto-detection */
397   xmlChar *general_ieee;
398   xmlChar *general_mfg;
399   xmlChar *general_mdl;
400   xmlChar *general_des;
401   xmlChar *general_cmd;
402   xmlChar *par_ieee;
403   xmlChar *par_mfg;
404   xmlChar *par_mdl;
405   xmlChar *par_des;
406   xmlChar *par_cmd;
407   xmlChar *usb_ieee;
408   xmlChar *usb_mfg;
409   xmlChar *usb_mdl;
410   xmlChar *usb_des;
411   xmlChar *usb_cmd;
412   xmlChar *snmp_ieee;
413   xmlChar *snmp_mfg;
414   xmlChar *snmp_mdl;
415   xmlChar *snmp_des;
416   xmlChar *snmp_cmd;
417   /* Drivers */
418   xmlChar *driver;
419   int     num_drivers;
420   printerDrvEntryPtr *drivers;
421   /* PPD files */
422   int     num_ppdfiles;
423   ppdFilePtr *ppdfiles;
424 } overviewPrinter, *overviewPrinterPtr;
425 
426 typedef struct overview {
427   int     num_overviewDrivers;
428   driverEntryPtr *overviewDrivers;
429   int     num_overviewPrinters;
430   overviewPrinterPtr *overviewPrinters;
431 } overview, *overviewPtr;
432 
433 /*
434  * Function to quote "'" and "\" in a string
435  */
436 
437 static xmlChar* /* O - String with quoted "'" */
perlquote(xmlChar * str)438 perlquote(xmlChar *str) { /* I - Original string */
439   xmlChar *dest, *s;
440   int offset = 0;
441 
442   if (str == NULL) return NULL;
443   dest = xmlStrdup(str);
444   while ((s = (xmlChar *)xmlStrchr((const xmlChar *)(dest + offset),
445 				   (xmlChar)'\'')) ||
446 	 (s = (xmlChar *)xmlStrchr((const xmlChar *)(dest + offset),
447 				   (xmlChar)'\\'))) {
448     offset = s - dest;
449     dest = (xmlChar *)realloc((xmlChar *)dest,
450 			      sizeof(xmlChar) * (xmlStrlen(dest) + 2));
451     s = dest + offset;
452     memmove(s + 1, s, xmlStrlen(dest) + 1 - offset);
453     *s = '\\';
454     offset += 2;
455   }
456   return(dest);
457 }
458 
459 /*
460  * Functions to read out localized text, choosing the translation into the
461  * desired language. Reads also simple text without language tags, for
462  * backward compatibility for the case that a not yet localized database
463  * field gets localized. The second function is especially for license text.
464  * It returns always the English (original) version in addition and allows
465  * links to text files as alternative to the text itself, as often license text
466  * has to be in its own file.
467  */
468 
469 xmlChar const sc_locale_C [] = "C", sc_locale_POSIX [] = "POSIX";
470 
471 static void
getLocalizedText(xmlDocPtr doc,xmlNodePtr node,xmlChar const ** ret,xmlChar const language[],int debug)472 getLocalizedText(xmlDocPtr doc,   /* I - The whole data tree */
473 		 xmlNodePtr node, /* I - Node of XML tree to work on */
474 		 xmlChar const **ret,   /* O - Text which was selected by the
475 				         language */
476 		 xmlChar const language [], /* I - User language */
477 		 int debug) { /* I - Debug mode flag */
478   xmlNodePtr     cur1;  /* XML node currently worked on */
479 
480   cur1 = node->xmlChildrenNode;
481   if
482   (xmlStrcasecmp(cur1->name, sc_locale_C)
483   && xmlStrcasecmp(cur1->name, sc_locale_POSIX)) {
484     while (cur1 != NULL) {
485       /* Exact match of locale ID */
486       if ((!xmlStrcasecmp(cur1->name, language))) {
487 	*ret = xmlStrdup
488 	  (perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1)));
489 	if (debug)
490 	  fprintf
491 	    (stderr,
492 	     "    Localized text with full locale ID matched (%s):\n\n%s\n\n",
493 	     language, *ret);
494 	return;
495       }
496       cur1 = cur1->next;
497     }
498     cur1 = node->xmlChildrenNode;
499     while (cur1 != NULL) {
500       /* Fall back to match only the two-character language code */
501       if ((!xmlStrncasecmp(cur1->name, language, 2))) {
502 	*ret = xmlStrdup
503 	  (perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1)));
504 	if (debug)
505 	  fprintf
506 	    (stderr,
507 	     "    Localized text with only language ID matched (%s):\n\n%s\n\n",
508 	     language, *ret);
509 	return;
510       }
511       cur1 = cur1->next;
512     }
513     cur1 = node->xmlChildrenNode;
514   }
515   while (cur1 != NULL) {
516     /* Fall back to English */
517     if ((!xmlStrncasecmp(cur1->name, (const xmlChar *) "en", 2))) {
518       *ret = xmlStrdup
519 	(perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1)));
520       if (debug)
521 	fprintf(stderr, "    English text:\n\n%s\n\n", *ret);
522       return;
523     }
524     cur1 = cur1->next;
525   }
526   cur1 = node->xmlChildrenNode;
527   /* Fall back to non-localized text (allows backward compatibility if
528      deciding on localizing a database item later */
529   *ret = xmlStrdup(perlquote(xmlNodeListGetString(doc, cur1, 1)));
530   if (debug)
531     fprintf(stderr, "    Non-localized text:\n\n%s\n\n", *ret);
532 }
533 
534 static void
getLocalizedLicenseText(xmlDocPtr doc,xmlNodePtr node,xmlChar ** text,xmlChar ** origtext,xmlChar ** link,xmlChar ** origlink,xmlChar const language[],int debug)535 getLocalizedLicenseText(xmlDocPtr doc,   /* I - The whole data tree */
536 	 xmlNodePtr node, /* I - Node of XML tree to work on */
537 		 xmlChar **text,   /* O - Text which was selected by the
538 				         language */
539 		 xmlChar **origtext, /* O - Original text in English */
540 		 xmlChar **link,   /* O - Link which was selected by the
541 				         language */
542 		 xmlChar **origlink, /* O - Link to original text in English */
543 		 xmlChar const language [], /* I - User language */
544 		 int debug) { /* I - Debug mode flag */
545   xmlNodePtr     cur1;  /* XML node currently worked on */
546   int            localizedtextfound = 0;
547 
548   cur1 = node->xmlChildrenNode;
549   if (xmlStrcasecmp(cur1->name, sc_locale_C) && xmlStrcasecmp(cur1->name, sc_locale_POSIX)) {
550     while (cur1 != NULL) {
551       /* Exact match of locale ID */
552       if ((!xmlStrcasecmp(cur1->name, language))) {
553 	*link = xmlGetProp(cur1, (const xmlChar *) "url");
554 	if (*link == NULL) {
555 	  *text = xmlStrdup
556 	    (perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1)));
557 	  if (debug)
558 	    fprintf
559 	      (stderr,
560 	       "    Localized text with full locale ID matched (%s):\n\n%s\n\n",
561 	       language, *text);
562 	} else {
563 	  if (debug)
564 	    fprintf
565 	      (stderr,
566 	       "    Link to localized text with full locale ID matched (%s):\n\n%s\n\n",
567 	       language, *link);
568 	}
569 	localizedtextfound = 1;
570 	break;
571       }
572       cur1 = cur1->next;
573     }
574     if (localizedtextfound == 0) {
575       cur1 = node->xmlChildrenNode;
576       while (cur1 != NULL) {
577 	/* Fall back to match only the two-character language code */
578 	if ((!xmlStrncasecmp(cur1->name, language, 2))) {
579 	  *link = xmlGetProp(cur1, (const xmlChar *) "url");
580 	  if (*link == NULL) {
581 	    *text = xmlStrdup
582 	      (perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1)));
583 	    if (debug)
584 	      fprintf
585 		(stderr,
586 		 "    Localized text with only language ID matched (%s):\n\n%s\n\n",
587 		 language, *text);
588 	  } else {
589 	    if (debug)
590 	      fprintf
591 		(stderr,
592 		 "    Link to localized text with only language ID matched (%s):\n\n%s\n\n",
593 		 language, *link);
594 	  }
595 	  localizedtextfound = 1;
596 	  break;
597 	}
598 	cur1 = cur1->next;
599       }
600     }
601   }
602   cur1 = node->xmlChildrenNode;
603   while (cur1 != NULL) {
604     /* Fall back to English and/or extract original, English text/link */
605     if ((!xmlStrncasecmp(cur1->name, (const xmlChar *) "en", 2))) {
606       *origlink = xmlGetProp(cur1, (const xmlChar *) "url");
607       if (*origlink == NULL) {
608 	*origtext = xmlStrdup
609 	  (perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1)));
610 	if (debug)
611 	  fprintf(stderr, "    Original English text:\n\n%s\n\n", *origtext);
612 	if (localizedtextfound == 0) {
613 	  *text = *origtext;
614 	  if (debug)
615 	    fprintf(stderr,
616 		    "      No localization, using original English text\n");
617 	}
618       } else {
619 	if (debug)
620 	  fprintf(stderr, "    Link to original English text:\n\n%s\n\n",
621 		  *origlink);
622 	if (localizedtextfound == 0) {
623 	  *link = *origlink;
624 	  if (debug)
625 	    fprintf(stderr,
626 		    "      No localization, using original English link\n");
627 	}
628       }
629       return;
630     }
631     cur1 = cur1->next;
632   }
633   cur1 = node->xmlChildrenNode;
634   /* Fall back to non-localized text (allows backward compatibility if
635      deciding on localizing a database item later */
636   *link = xmlGetProp(cur1, (const xmlChar *) "url");
637   if (*link == NULL) {
638     *text = xmlStrdup(perlquote(xmlNodeListGetString(doc, cur1, 1)));
639     *origtext = *text;
640     if (debug)
641       fprintf(stderr, "    Non-localized text:\n\n%s\n\n", *text);
642   } else {
643     *origlink = *link;
644     if (debug)
645       fprintf(stderr, "    Link to non-localized text:\n\n%s\n\n", *link);
646   }
647 }
648 
649 /*
650  * Functions to fill in the unprintable margin data structure with the
651  * data parsed from the XML input
652  */
653 
654 static void
parseMarginEntry(xmlDocPtr doc,xmlNodePtr node,int entrytype,marginsPtr ret,xmlChar const language[],int debug)655 parseMarginEntry(xmlDocPtr doc,   /* I - The whole combo data tree */
656 		 xmlNodePtr node, /* I - Node of XML tree to work on */
657 		 int entrytype,   /* I - 0: General, 1: Page size
658 				     exzception */
659 		 marginsPtr ret,  /* O - C data structure of Foomatic
660 					  overview */
661 		 xmlChar const language [], /* I - User language */
662 		 int debug) { /* I - Debug mode flag */
663   xmlNodePtr     cur1;  /* XML node currently worked on */
664   xmlChar        *pagesize;
665   marginRecordPtr marginRec;
666 
667   /* Allocate memory for the margin record */
668   ret->num_marginRecords ++;
669   ret->marginRecords =
670     (marginRecordPtr *)realloc
671     ((marginRecordPtr *)(ret->marginRecords),
672      sizeof(marginRecordPtr) * ret->num_marginRecords);
673   marginRec = (marginRecordPtr) malloc(sizeof(marginRecord));
674   if (marginRec == NULL) {
675     fprintf(stderr,"Out of memory!\n");
676     xmlFreeDoc(doc);
677     exit(1);
678   }
679   ret->marginRecords[ret->num_marginRecords-1] = marginRec;
680   memset(marginRec, 0, sizeof(marginRecord));
681 
682   /* Initialization of entries */
683   marginRec->pagesize = NULL;
684   marginRec->unit = NULL;
685   marginRec->absolute = NULL;
686   marginRec->left = NULL;
687   marginRec->right = NULL;
688   marginRec->top = NULL;
689   marginRec->bottom = NULL;
690 
691   /* Get page size */
692   if (entrytype > 0) {
693     pagesize = xmlGetProp(node, (const xmlChar *) "PageSize");
694     if (pagesize != NULL) {
695       marginRec->pagesize = perlquote(pagesize);
696       if (debug) fprintf(stderr, "    Margins for page size %s\n",
697 			 marginRec->pagesize);
698     } else {
699       fprintf(stderr,"Page size missing!\n");
700       xmlFreeDoc(doc);
701       exit(1);
702     }
703   } else {
704     if (debug) fprintf(stderr, "    General Margins\n");
705   }
706 
707   /* Go through subnodes */
708   cur1 = node->xmlChildrenNode;
709   while (cur1 != NULL) {
710     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "unit"))) {
711       marginRec->unit =
712 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
713       if (debug) fprintf(stderr, "      Unit: %s\n", marginRec->unit);
714     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "absolute"))) {
715       marginRec->absolute = (xmlChar *)"1";
716 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
717       if (debug) fprintf(stderr, "      Absolute values\n");
718     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "relative"))) {
719       marginRec->absolute = (xmlChar *)"0";
720 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
721       if (debug) fprintf(stderr, "      Relative values\n");
722     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "left"))) {
723       marginRec->left =
724 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
725       if (debug) fprintf(stderr, "      Left margin: %s\n",
726 			 marginRec->left);
727     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "right"))) {
728       marginRec->right =
729 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
730       if (debug) fprintf(stderr, "      Right margin: %s\n",
731 			 marginRec->right);
732     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "top"))) {
733       marginRec->top =
734 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
735       if (debug) fprintf(stderr, "      Top margin: %s\n",
736 			 marginRec->top);
737     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "bottom"))) {
738       marginRec->bottom =
739 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
740       if (debug) fprintf(stderr, "      Bottom margin: %s\n",
741 			 marginRec->bottom);
742     }
743     cur1 = cur1->next;
744   }
745 }
746 
747 static void
parseMargins(xmlDocPtr doc,xmlNodePtr node,marginsPtr * ret,xmlChar const language[],int debug)748 parseMargins(xmlDocPtr doc,   /* I - The whole combo data tree */
749 	     xmlNodePtr node, /* I - Node of XML tree to work on */
750 	     marginsPtr *ret, /* O - C data structure of Foomatic
751 				 overview */
752 	     xmlChar const language [], /* I - User language */
753 	     int debug) { /* I - Debug mode flag */
754   xmlNodePtr     cur1;  /* XML node currently worked on */
755 
756   /* Allocate memory for the margins data structure */
757   *ret = (marginsPtr) malloc(sizeof(margins));
758   if (*ret == NULL) {
759     fprintf(stderr,"Out of memory!\n");
760     xmlFreeDoc(doc);
761     exit(1);
762   }
763   memset(*ret, 0, sizeof(margins));
764 
765   /* Initialization of entries */
766   (*ret)->num_marginRecords = 0;
767   (*ret)->marginRecords = NULL;
768 
769   if (debug) fprintf(stderr, "  Unprintable margins\n");
770 
771   /* Go through subnodes */
772   cur1 = node->xmlChildrenNode;
773   while (cur1 != NULL) {
774     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "general"))) {
775       parseMarginEntry(doc, cur1, 0, *ret, language, debug);
776     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "exception"))) {
777       parseMarginEntry(doc, cur1, 1, *ret, language, debug);
778     }
779     cur1 = cur1->next;
780   }
781 }
782 
783 /*
784  * Function to fill in the Foomatic overview data structure with the
785  * data parsed from the XML input
786  */
787 
788 static void
parseOverviewPrinter(xmlDocPtr doc,xmlNodePtr node,overviewPtr ret,xmlChar const language[],int debug)789 parseOverviewPrinter(xmlDocPtr doc, /* I - The whole combo data tree */
790 		     xmlNodePtr node, /* I - Node of XML tree to work on */
791 		     overviewPtr ret, /* O - C data structure of Foomatic
792 					 overview */
793 		     xmlChar const language [], /* I - User language */
794 		     int debug) { /* I - Debug mode flag */
795   xmlNodePtr     cur1;  /* XML node currently worked on */
796   xmlNodePtr     cur2;  /* Another XML node pointer */
797   xmlNodePtr     cur3;  /* Another XML node pointer */
798   xmlNodePtr     cur4;  /* Another XML node pointer */
799   xmlChar        *id;  /* Full printer ID, with "printer/" */
800   xmlChar        *charset;
801   xmlChar        *drivername;
802   overviewPrinterPtr printer;
803   printerDrvEntryPtr dentry; /* An entry for a driver supporting this
804 				printer */
805   ppdFilePtr     ppd;
806   int            driverfound;
807   int            i, j;
808 
809   /* Allocate memory for the printer */
810   ret->num_overviewPrinters ++;
811   ret->overviewPrinters =
812     (overviewPrinterPtr *)realloc
813     ((overviewPrinterPtr *)(ret->overviewPrinters),
814      sizeof(overviewPrinterPtr) * ret->num_overviewPrinters);
815   printer = (overviewPrinterPtr) malloc(sizeof(overviewPrinter));
816   if (printer == NULL) {
817     fprintf(stderr,"Out of memory!\n");
818     xmlFreeDoc(doc);
819     exit(1);
820   }
821   ret->overviewPrinters[ret->num_overviewPrinters-1] = printer;
822   memset(printer, 0, sizeof(overviewPrinter));
823 
824   /* Initialization of entries */
825   printer->id = NULL;
826   printer->make = NULL;
827   printer->model = NULL;
828   printer->functionality = (xmlChar *)"X";
829   printer->unverified = NULL;
830   printer->noxmlentry = NULL;
831   printer->general_ieee = NULL;
832   printer->general_mfg = NULL;
833   printer->general_mdl = NULL;
834   printer->general_des = NULL;
835   printer->general_cmd = NULL;
836   printer->par_ieee = NULL;
837   printer->par_mfg = NULL;
838   printer->par_mdl = NULL;
839   printer->par_des = NULL;
840   printer->par_cmd = NULL;
841   printer->usb_ieee = NULL;
842   printer->usb_mfg = NULL;
843   printer->usb_mdl = NULL;
844   printer->usb_des = NULL;
845   printer->usb_cmd = NULL;
846   printer->snmp_ieee = NULL;
847   printer->snmp_mfg = NULL;
848   printer->snmp_mdl = NULL;
849   printer->snmp_des = NULL;
850   printer->snmp_cmd = NULL;
851   printer->driver = NULL;
852   printer->num_drivers = 0;
853   printer->drivers = NULL;
854   printer->num_ppdfiles = 0;
855   printer->ppdfiles = NULL;
856 
857   /* Go through subnodes */
858   cur1 = node->xmlChildrenNode;
859   while (cur1 != NULL) {
860     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "id"))) {
861       printer->id =
862 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
863       if (debug) fprintf(stderr, "  Printer ID: %s\n", printer->id);
864     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "make"))) {
865       printer->make =
866 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
867       if (debug) fprintf(stderr, "  Printer Manufacturer: %s\n",
868 			 printer->make);
869     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "model"))) {
870       printer->model =
871 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
872       if (debug) fprintf(stderr, "  Printer Model: %s\n", printer->model);
873     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "functionality"))) {
874       printer->functionality =
875 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
876       if (debug) fprintf(stderr, "  Printer Functionality: %s\n",
877 			 printer->functionality);
878     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "unverified"))) {
879       printer->unverified = (xmlChar *)"1";
880       if (debug) fprintf(stderr, "  Printer entry is unverified\n");
881     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "noxmlentry"))) {
882       printer->noxmlentry = (xmlChar *)"1";
883       if (debug) fprintf(stderr, "  Printer XML entry does not exist in the database\n");
884     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "driver"))) {
885       printer->driver =
886 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
887       if (debug) fprintf(stderr, "  Recommended driver: %s\n",
888 			 printer->driver);
889     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "drivers"))) {
890       cur2 = cur1->xmlChildrenNode;
891       while (cur2 != NULL) {
892 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "driver"))) {
893 	  drivername =
894 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
895 	  driverfound = 0;
896 	  for (i = 0; i < printer->num_drivers; i++) {
897 	    dentry = printer->drivers[i];
898 	    if ((dentry->name != NULL) &&
899 		(!xmlStrcmp(drivername, dentry->name))) {
900 	      driverfound = 1;
901 	      break;
902 	    }
903 	  }
904 	  if (!driverfound) {
905 	    printer->num_drivers ++;
906 	    printer->drivers =
907 	      (printerDrvEntryPtr *)
908 	      realloc((printerDrvEntryPtr *)printer->drivers,
909 		      sizeof(printerDrvEntryPtr) *
910 		      printer->num_drivers);
911 	    dentry = (printerDrvEntryPtr) malloc(sizeof(printerDrvEntry));
912 	    if (dentry == NULL) {
913 	      fprintf(stderr,"Out of memory!\n");
914 	      xmlFreeDoc(doc);
915 	      exit(1);
916 	    }
917 	    printer->drivers[printer->num_drivers-1] = dentry;
918 	    memset(dentry, 0, sizeof(printerDrvEntry));
919 	    dentry->name = NULL;
920 	    dentry->comment = NULL;
921 	    dentry->ppd = NULL;
922 	    dentry->excmaxresx = NULL;
923 	    dentry->excmaxresy = NULL;
924 	    dentry->exccolor = NULL;
925 	    dentry->exctext = NULL;
926 	    dentry->exclineart = NULL;
927 	    dentry->excgraphics = NULL;
928 	    dentry->excphoto = NULL;
929 	    dentry->excload = NULL;
930 	    dentry->excspeed = NULL;
931 	  }
932 	  dentry->name = drivername;
933 	  if (debug) fprintf(stderr, "  Printer works with: %s\n",
934 			     dentry->name);
935 	}
936 	cur2 = cur2->next;
937       }
938     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "driverfunctionalityexceptions"))) {
939       cur2 = cur1->xmlChildrenNode;
940       while (cur2 != NULL) {
941 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "driverfunctionalityexception"))) {
942 	  drivername = NULL;
943 	  dentry = NULL;
944 	  cur3 = cur2->xmlChildrenNode;
945 	  while (cur3 != NULL) {
946 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "driver"))) {
947 	      drivername =
948 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1));
949 	      if (debug)
950 		fprintf(stderr, "  Functionality exceptions for driver: %s\n",
951 			drivername);
952 	      if ((dentry != NULL) && (dentry->name == NULL)) {
953 		dentry->name = drivername;
954 		/* Check whether there is already an entry for this driver
955 		   and delete this old entry */
956 		for (i = 0; i < printer->num_drivers - 1; i++) {
957 		  if ((printer->drivers[i]->name != NULL) &&
958 		      (!xmlStrcmp(drivername, printer->drivers[i]->name))) {
959 		    for (j = i + 1; j < printer->num_drivers; j++)
960 		      printer->drivers[j - 1] = printer->drivers[j];
961 		    printer->num_drivers --;
962 		    printer->drivers =
963 		      (printerDrvEntryPtr *)
964 		      realloc((printerDrvEntryPtr *)printer->drivers,
965 			      sizeof(printerDrvEntryPtr) *
966 			      printer->num_drivers);
967 		    break;
968 		  }
969 		}
970 	      }
971 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "functionality"))) {
972 	      driverfound = 0;
973 	      dentry = NULL;
974 	      if (drivername != NULL) {
975 		for (i = 0; i < printer->num_drivers; i++) {
976 		  dentry = printer->drivers[i];
977 		  if ((dentry->name != NULL) &&
978 		      (!xmlStrcmp(drivername, dentry->name))) {
979 		    driverfound = 1;
980 		    break;
981 		  }
982 		}
983 	      }
984 	      if (!driverfound) {
985 		printer->num_drivers ++;
986 		printer->drivers =
987 		  (printerDrvEntryPtr *)
988 		  realloc((printerDrvEntryPtr *)printer->drivers,
989 			  sizeof(printerDrvEntryPtr) *
990 			  printer->num_drivers);
991 		dentry = (printerDrvEntryPtr) malloc(sizeof(printerDrvEntry));
992 		if (dentry == NULL) {
993 		  fprintf(stderr,"Out of memory!\n");
994 		  xmlFreeDoc(doc);
995 		  exit(1);
996 		}
997 		printer->drivers[printer->num_drivers-1] = dentry;
998 		memset(dentry, 0, sizeof(printerDrvEntry));
999 		dentry->name = NULL;
1000 		dentry->comment = NULL;
1001 		dentry->ppd = NULL;
1002 		dentry->excmaxresx = NULL;
1003 		dentry->excmaxresy = NULL;
1004 		dentry->exccolor = NULL;
1005 		dentry->exctext = NULL;
1006 		dentry->exclineart = NULL;
1007 		dentry->excgraphics = NULL;
1008 		dentry->excphoto = NULL;
1009 		dentry->excload = NULL;
1010 		dentry->excspeed = NULL;
1011 	      }
1012 	      dentry->name = drivername;
1013 	      if (drivername != NULL) {
1014 		if (debug)
1015 		  fprintf(stderr, "  Functionality exceptions for driver: %s\n",
1016 			  dentry->name);
1017 	      }
1018 	      cur4 = cur3->xmlChildrenNode;
1019 	      while (cur4 != NULL) {
1020 		if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresx"))) {
1021 		  dentry->excmaxresx =
1022 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1023 		  if (debug)
1024 		    fprintf(stderr, "    Maximum X resolution: %s\n",
1025 			    dentry->excmaxresx);
1026 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresy"))) {
1027 		  dentry->excmaxresy =
1028 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1029 		  if (debug)
1030 		    fprintf(stderr, "    Maximum Y resolution: %s\n",
1031 			    dentry->excmaxresy);
1032 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "monochrome"))) {
1033 		  dentry->exccolor = (xmlChar *)"0";
1034 		  if (debug)
1035 		    fprintf(stderr, "    Color: %s\n",
1036 			    dentry->exccolor);
1037 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "color"))) {
1038 		  dentry->exccolor = (xmlChar *)"1";
1039 		  if (debug)
1040 		    fprintf(stderr, "    Color: %s\n",
1041 			    dentry->exccolor);
1042 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "text"))) {
1043 		  dentry->exctext =
1044 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1045 		  if (debug)
1046 		    fprintf(stderr, "    Support level for text: %s\n",
1047 			    dentry->exctext);
1048 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "lineart"))) {
1049 		  dentry->exclineart =
1050 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1051 		  if (debug)
1052 		    fprintf(stderr, "    Support level for line art: %s\n",
1053 			    dentry->exclineart);
1054 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "graphics"))) {
1055 		  dentry->excgraphics =
1056 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1057 		  if (debug)
1058 		    fprintf(stderr, "    Support level for graphics: %s\n",
1059 			    dentry->excgraphics);
1060 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "photo"))) {
1061 		  dentry->excphoto =
1062 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1063 		  if (debug)
1064 		    fprintf(stderr, "    Support level for photos: %s\n",
1065 			    dentry->excphoto);
1066 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "load"))) {
1067 		  dentry->excload =
1068 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1069 		  if (debug)
1070 		    fprintf(stderr, "    Expected relative system load: %s\n",
1071 			    dentry->excload);
1072 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "speed"))) {
1073 		  dentry->excspeed =
1074 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1075 		  if (debug)
1076 		    fprintf(stderr, "    Expected relative driver speed: %s\n",
1077 			    dentry->excspeed);
1078 		}
1079 		cur4 = cur4->next;
1080 	      }
1081 	    }
1082 	    cur3 = cur3->next;
1083 	  }
1084 	}
1085 	cur2 = cur2->next;
1086       }
1087     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "ppds"))) {
1088       cur2 = cur1->xmlChildrenNode;
1089       while (cur2 != NULL) {
1090 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ppd"))) {
1091 	  printer->num_ppdfiles ++;
1092 	  printer->ppdfiles =
1093 	    (ppdFilePtr *)
1094 	    realloc((ppdFilePtr *)printer->ppdfiles,
1095 		    sizeof(ppdFilePtr) *
1096 		    printer->num_ppdfiles);
1097 	  ppd = (ppdFilePtr) malloc(sizeof(ppdFile));
1098 	  if (ppd == NULL) {
1099 	    fprintf(stderr,"Out of memory!\n");
1100 	    xmlFreeDoc(doc);
1101 	    exit(1);
1102 	  }
1103 	  printer->ppdfiles[printer->num_ppdfiles-1] = ppd;
1104 	  memset(ppd, 0, sizeof(ppdFile));
1105 	  ppd->driver = NULL;
1106 	  ppd->filename = NULL;
1107 	  if (debug) fprintf(stderr, "  Available ready-made PPD file:\n");
1108 	  cur3 = cur2->xmlChildrenNode;
1109 	  while (cur3 != NULL) {
1110 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "driver"))) {
1111 	      ppd->driver =
1112 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1));
1113 	      if (debug) fprintf(stderr, "    For driver: %s\n",
1114 				 ppd->driver);
1115 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ppdfile"))) {
1116 	      ppd->filename =
1117 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1));
1118 	      if (debug) fprintf(stderr, "    File name: %s\n",
1119 				 ppd->filename);
1120 	    }
1121 	    cur3 = cur3->next;
1122 	  }
1123 	}
1124 	cur2 = cur2->next;
1125       }
1126     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "autodetect"))) {
1127       cur2 = cur1->xmlChildrenNode;
1128       while (cur2 != NULL) {
1129 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "general"))) {
1130 	  cur3 = cur2->xmlChildrenNode;
1131 	  if (debug) fprintf(stderr, "  Printer auto-detection info (general):\n");
1132 	  while (cur3 != NULL) {
1133 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1134 	      printer->general_ieee =
1135 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1136 					       1));
1137 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1138 				 printer->general_ieee);
1139 
1140 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1141 	      printer->general_mfg =
1142 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1143 					       1));
1144 	      if (debug) fprintf(stderr, "    MFG: %s\n", printer->general_mfg);
1145 
1146 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1147 	      printer->general_mdl =
1148 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1149 					       1));
1150 	      if (debug) fprintf(stderr, "    MDL: %s\n", printer->general_mdl);
1151 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1152 	      printer->general_des =
1153 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1154 					       1));
1155 	      if (debug) fprintf(stderr, "    DES: %s\n", printer->general_des);
1156 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1157 	      printer->general_cmd =
1158 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1159 					       1));
1160 	      if (debug) fprintf(stderr, "    CMD: %s\n", printer->general_cmd);
1161 	    }
1162 	    cur3 = cur3->next;
1163 	  }
1164 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "parallel"))) {
1165 	  cur3 = cur2->xmlChildrenNode;
1166 	  if (debug) fprintf(stderr, "  Printer auto-detection info (parallel port):\n");
1167 	  while (cur3 != NULL) {
1168 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1169 	      printer->par_ieee =
1170 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1171 					       1));
1172 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1173 				 printer->par_ieee);
1174 
1175 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1176 	      printer->par_mfg =
1177 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1178 					       1));
1179 	      if (debug) fprintf(stderr, "    MFG: %s\n", printer->par_mfg);
1180 
1181 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1182 	      printer->par_mdl =
1183 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1184 					       1));
1185 	      if (debug) fprintf(stderr, "    MDL: %s\n", printer->par_mdl);
1186 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1187 	      printer->par_des =
1188 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1189 					       1));
1190 	      if (debug) fprintf(stderr, "    DES: %s\n", printer->par_des);
1191 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1192 	      printer->par_cmd =
1193 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1194 					       1));
1195 	      if (debug) fprintf(stderr, "    CMD: %s\n", printer->par_cmd);
1196 	    }
1197 	    cur3 = cur3->next;
1198 	  }
1199 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "usb"))) {
1200 	  cur3 = cur2->xmlChildrenNode;
1201 	  if (debug) fprintf(stderr, "  Printer auto-detection info (USB):\n");
1202 	  while (cur3 != NULL) {
1203 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1204 	      printer->usb_ieee =
1205 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1206 					       1));
1207 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1208 				 printer->usb_ieee);
1209 
1210 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1211 	      printer->usb_mfg =
1212 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1213 					       1));
1214 	      if (debug) fprintf(stderr, "    MFG: %s\n", printer->usb_mfg);
1215 
1216 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1217 	      printer->usb_mdl =
1218 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1219 					       1));
1220 	      if (debug) fprintf(stderr, "    MDL: %s\n", printer->usb_mdl);
1221 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1222 	      printer->usb_des =
1223 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1224 					       1));
1225 	      if (debug) fprintf(stderr, "    DES: %s\n", printer->usb_des);
1226 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1227 	      printer->usb_cmd =
1228 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1229 					       1));
1230 	      if (debug) fprintf(stderr, "    CMD: %s\n", printer->usb_cmd);
1231 	    }
1232 	    cur3 = cur3->next;
1233 	  }
1234 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "snmp"))) {
1235 	  cur3 = cur2->xmlChildrenNode;
1236 	  if (debug) fprintf(stderr, "  Printer auto-detection info (SNMP):\n");
1237 	  while (cur3 != NULL) {
1238 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1239 	      printer->snmp_ieee =
1240 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1241 					       1));
1242 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1243 				 printer->snmp_ieee);
1244 
1245 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1246 	      printer->snmp_mfg =
1247 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1248 					       1));
1249 	      if (debug) fprintf(stderr, "    MFG: %s\n", printer->snmp_mfg);
1250 
1251 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1252 	      printer->snmp_mdl =
1253 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1254 					       1));
1255 	      if (debug) fprintf(stderr, "    MDL: %s\n", printer->snmp_mdl);
1256 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1257 	      printer->snmp_des =
1258 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1259 					       1));
1260 	      if (debug) fprintf(stderr, "    DES: %s\n", printer->snmp_des);
1261 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1262 	      printer->snmp_cmd =
1263 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1264 					       1));
1265 	      if (debug) fprintf(stderr, "    CMD: %s\n", printer->snmp_cmd);
1266 	    }
1267 	    cur3 = cur3->next;
1268 	  }
1269 	}
1270 	cur2 = cur2->next;
1271       }
1272     }
1273     cur1 = cur1->next;
1274   }
1275 }
1276 
1277 /*
1278  * Functions to fill in the printer/driver combo data structure with the
1279  * data parsed from the XML input
1280  */
1281 
1282 static void
parseComboPrinter(xmlDocPtr doc,xmlNodePtr node,comboDataPtr ret,xmlChar const language[],int debug)1283 parseComboPrinter(xmlDocPtr doc, /* I - The whole combo data tree */
1284 		  xmlNodePtr node, /* I - Node of XML tree to work on */
1285 		  comboDataPtr ret, /* O - C data structure of Foomatic
1286 				       combo */
1287 		  xmlChar const language [], /* I - User language */
1288 		  int debug) { /* I - Debug mode flag */
1289   xmlNodePtr     cur1;  /* XML node currently worked on */
1290   xmlNodePtr     cur2;  /* Another XML node pointer */
1291   xmlNodePtr     cur3;  /* Another XML node pointer */
1292   xmlNodePtr     cur4;  /* Another XML node pointer */
1293   xmlChar        *id;  /* Full printer ID, with "printer/" */
1294   xmlChar        *charset;
1295   xmlChar        *dname;  /* Name of a driver supporting this printer */
1296   xmlChar        *dppd;  /* Ready-made PPD supporting this printer */
1297   printerDrvEntryPtr dentry; /* An entry for a driver supporting this
1298 				printer */
1299 
1300   /* Initialization of entries */
1301   ret->id = NULL;
1302   ret->make = NULL;
1303   ret->model = NULL;
1304   ret->pcmodel = NULL;
1305   ret->ppdurl = NULL;
1306   ret->color = (xmlChar *)"0";
1307   ret->pjl = (xmlChar *)"undef";
1308   ret->ascii = (xmlChar *)"0";
1309   ret->printerppdentry = NULL;
1310   ret->printermargins = NULL;
1311   ret->general_ieee = NULL;
1312   ret->general_mfg = NULL;
1313   ret->general_mdl = NULL;
1314   ret->general_des = NULL;
1315   ret->general_cmd = NULL;
1316   ret->par_ieee = NULL;
1317   ret->par_mfg = NULL;
1318   ret->par_mdl = NULL;
1319   ret->par_des = NULL;
1320   ret->par_cmd = NULL;
1321   ret->usb_ieee = NULL;
1322   ret->usb_mfg = NULL;
1323   ret->usb_mdl = NULL;
1324   ret->usb_des = NULL;
1325   ret->usb_cmd = NULL;
1326   ret->snmp_ieee = NULL;
1327   ret->snmp_mfg = NULL;
1328   ret->snmp_mdl = NULL;
1329   ret->snmp_des = NULL;
1330   ret->snmp_cmd = NULL;
1331   ret->recdriver = NULL;
1332   ret->num_drivers = 0;
1333   ret->drivers = NULL;
1334 
1335   /* Get printer ID */
1336   id = xmlGetProp(node, (const xmlChar *) "id");
1337   if (id == NULL) {
1338     fprintf(stderr, "No printer ID found\n");
1339     return;
1340   }
1341   ret->id = perlquote(id + 8);
1342   if (debug) fprintf(stderr, "  Printer ID: %s\n", ret->id);
1343 
1344   /* Go through subnodes */
1345   cur1 = node->xmlChildrenNode;
1346   while (cur1 != NULL) {
1347     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "make"))) {
1348       ret->make =
1349 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1350       if (debug) fprintf(stderr, "  Printer Manufacturer: %s\n", ret->make);
1351     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "model"))) {
1352       ret->model =
1353 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1354       if (debug) fprintf(stderr, "  Printer Model: %s\n", ret->model);
1355     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "driver"))) {
1356       ret->recdriver =
1357 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1358       if (debug) fprintf(stderr, "  Recommended driver: %s\n",
1359 			 ret->recdriver);
1360     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "drivers"))) {
1361       cur2 = cur1->xmlChildrenNode;
1362       while (cur2 != NULL) {
1363 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "driver"))) {
1364 	  ret->num_drivers ++;
1365 	  ret->drivers =
1366 	    (printerDrvEntryPtr *)
1367 	    realloc((printerDrvEntryPtr *)ret->drivers,
1368 		    sizeof(printerDrvEntryPtr) *
1369 		    ret->num_drivers);
1370 	  dentry = (printerDrvEntryPtr) malloc(sizeof(printerDrvEntry));
1371 	  if (dentry == NULL) {
1372 	    fprintf(stderr,"Out of memory!\n");
1373 	    xmlFreeDoc(doc);
1374 	    exit(1);
1375 	  }
1376 	  ret->drivers[ret->num_drivers-1] = dentry;
1377 	  memset(dentry, 0, sizeof(printerDrvEntry));
1378 	  dentry->name = NULL;
1379 	  dentry->comment = NULL;
1380 	  dentry->ppd = NULL;
1381           dentry->excmaxresx = NULL;
1382 	  dentry->excmaxresy = NULL;
1383 	  dentry->exccolor = NULL;
1384 	  dentry->exctext = NULL;
1385 	  dentry->exclineart = NULL;
1386 	  dentry->excgraphics = NULL;
1387 	  dentry->excphoto = NULL;
1388 	  dentry->excload = NULL;
1389 	  dentry->excspeed = NULL;
1390 	  if (debug) fprintf(stderr, "  Printer supported by drivers:\n");
1391 	  cur3 = cur2->xmlChildrenNode;
1392 	  while (cur3 != NULL) {
1393 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "id"))) {
1394 	      dname =
1395 		xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
1396 	      dentry->name = perlquote(dname);
1397 	      if (debug) fprintf(stderr, "    Name: %s\n",
1398 				 dentry->name);
1399 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ppd"))) {
1400 	      dppd =
1401 		xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
1402 	      dentry->ppd = perlquote(dppd);
1403 	      if (debug) fprintf(stderr, "    Ready-made PPD: %s\n",
1404 				 dentry->ppd);
1405 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "functionality"))) {
1406 	      cur4 = cur3->xmlChildrenNode;
1407 	      while (cur4 != NULL) {
1408 		if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresx"))) {
1409 		  dentry->excmaxresx =
1410 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1411 		  if (debug)
1412 		    fprintf(stderr, "    Maximum X resolution: %s\n",
1413 			    dentry->excmaxresx);
1414 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresy"))) {
1415 		  dentry->excmaxresy =
1416 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1417 		  if (debug)
1418 		    fprintf(stderr, "    Maximum Y resolution: %s\n",
1419 			    dentry->excmaxresy);
1420 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "monochrome"))) {
1421 		  dentry->exccolor = (xmlChar *)"0";
1422 		  if (debug)
1423 		    fprintf(stderr, "    Color: %s\n",
1424 			    dentry->exccolor);
1425 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "color"))) {
1426 		  dentry->exccolor = (xmlChar *)"1";
1427 		  if (debug)
1428 		    fprintf(stderr, "    Color: %s\n",
1429 			    dentry->exccolor);
1430 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "text"))) {
1431 		  dentry->exctext =
1432 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1433 		  if (debug)
1434 		    fprintf(stderr, "    Support level for text: %s\n",
1435 			    dentry->exctext);
1436 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "lineart"))) {
1437 		  dentry->exclineart =
1438 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1439 		  if (debug)
1440 		    fprintf(stderr, "    Support level for line art: %s\n",
1441 			    dentry->exclineart);
1442 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "graphics"))) {
1443 		  dentry->excgraphics =
1444 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1445 		  if (debug)
1446 		    fprintf(stderr, "    Support level for graphics: %s\n",
1447 			    dentry->excgraphics);
1448 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "photo"))) {
1449 		  dentry->excphoto =
1450 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1451 		  if (debug)
1452 		    fprintf(stderr, "    Support level for photos: %s\n",
1453 			    dentry->excphoto);
1454 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "load"))) {
1455 		  dentry->excload =
1456 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1457 		  if (debug)
1458 		    fprintf(stderr, "    Expected relative system load: %s\n",
1459 			    dentry->excload);
1460 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "speed"))) {
1461 		  dentry->excspeed =
1462 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
1463 		  if (debug)
1464 		    fprintf(stderr, "    Expected relative driver speed: %s\n",
1465 			    dentry->excspeed);
1466 		}
1467 		cur4 = cur4->next;
1468 	      }
1469 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "comments"))) {
1470 	      if (debug)
1471 		fprintf(stderr, "    Comments:\n");
1472 	      getLocalizedText(doc, cur3, &(dentry->comment), language, debug);
1473 	    }
1474 	    cur3 = cur3->next;
1475 	  }
1476 	}
1477 	cur2 = cur2->next;
1478       }
1479     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "ppdentry"))) {
1480       ret->printerppdentry =
1481 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1482       if (debug) fprintf(stderr, "  Extra lines for PPD file:\n%s\n",
1483 			 ret->printerppdentry);
1484     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "pcmodel"))) {
1485       ret->pcmodel =
1486 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1487       if (debug) fprintf(stderr,
1488 			 "  Model part for PC filename in PPD: %s\n",
1489 			 ret->pcmodel);
1490     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "lang"))) {
1491       cur2 = cur1->xmlChildrenNode;
1492       while (cur2 != NULL) {
1493 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "postscript"))) {
1494 	  cur3 = cur2->xmlChildrenNode;
1495 	  while (cur3 != NULL) {
1496 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ppd"))) {
1497 	      ret->ppdurl =
1498 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1499 					       1));
1500 	      if (debug) fprintf(stderr,
1501 				 "  URL for the PPD for this printer: %s\n",
1502 				 ret->ppdurl);
1503 	    }
1504 	    cur3 = cur3->next;
1505 	  }
1506 	}
1507 	cur2 = cur2->next;
1508       }
1509     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "mechanism"))) {
1510       cur2 = cur1->xmlChildrenNode;
1511       while (cur2 != NULL) {
1512 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "color"))) {
1513 	  ret->color = (xmlChar *)"1";
1514 	  if (debug) fprintf(stderr, "  Color printer\n");
1515 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "margins"))) {
1516 	  parseMargins(doc, cur2, &(ret->printermargins), language, debug);
1517 	}
1518 	cur2 = cur2->next;
1519       }
1520     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "lang"))) {
1521       cur2 = cur1->xmlChildrenNode;
1522       while (cur2 != NULL) {
1523 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "pjl"))) {
1524 	  ret->pjl = (xmlChar *)"''";
1525 	  if (debug) fprintf(stderr, "  Printer supports PJL\n");
1526 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "text"))) {
1527 	  cur3 = cur2->xmlChildrenNode;
1528 	  while (cur3 != NULL) {
1529 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "charset"))) {
1530 	      charset =
1531 		xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
1532 	      if ((!xmlStrcmp(charset, (const xmlChar *) "us-ascii")) ||
1533 		  (!xmlStrcmp(charset, (const xmlChar *) "iso-8859-1")) ||
1534 		  (!xmlStrcmp(charset, (const xmlChar *) "iso-8859-15"))) {
1535 		ret->ascii = (xmlChar *)"1";
1536 		if (debug) fprintf(stderr, "  Printer prints plain text\n");
1537 	      }
1538 	    }
1539 	    cur3 = cur3->next;
1540 	  }
1541 	}
1542 	cur2 = cur2->next;
1543       }
1544     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "autodetect"))) {
1545       cur2 = cur1->xmlChildrenNode;
1546       while (cur2 != NULL) {
1547 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "general"))) {
1548 	  cur3 = cur2->xmlChildrenNode;
1549 	  if (debug) fprintf(stderr, "  Printer auto-detection info (general):\n");
1550 	  while (cur3 != NULL) {
1551 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1552 	      ret->general_ieee =
1553 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1554 					       1));
1555 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1556 				 ret->general_ieee);
1557 
1558 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1559 	      ret->general_mfg =
1560 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1561 					       1));
1562 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->general_mfg);
1563 
1564 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1565 	      ret->general_mdl =
1566 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1567 					       1));
1568 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->general_mdl);
1569 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1570 	      ret->general_des =
1571 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1572 					       1));
1573 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->general_des);
1574 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1575 	      ret->general_cmd =
1576 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1577 					       1));
1578 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->general_cmd);
1579 	    }
1580 	    cur3 = cur3->next;
1581 	  }
1582 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "parallel"))) {
1583 	  cur3 = cur2->xmlChildrenNode;
1584 	  if (debug) fprintf(stderr, "  Printer auto-detection info (parallel port):\n");
1585 	  while (cur3 != NULL) {
1586 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1587 	      ret->par_ieee =
1588 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1589 					       1));
1590 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1591 				 ret->par_ieee);
1592 
1593 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1594 	      ret->par_mfg =
1595 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1596 					       1));
1597 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->par_mfg);
1598 
1599 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1600 	      ret->par_mdl =
1601 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1602 					       1));
1603 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->par_mdl);
1604 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1605 	      ret->par_des =
1606 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1607 					       1));
1608 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->par_des);
1609 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1610 	      ret->par_cmd =
1611 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1612 					       1));
1613 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->par_cmd);
1614 	    }
1615 	    cur3 = cur3->next;
1616 	  }
1617 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "usb"))) {
1618 	  cur3 = cur2->xmlChildrenNode;
1619 	  if (debug) fprintf(stderr, "  Printer auto-detection info (USB):\n");
1620 	  while (cur3 != NULL) {
1621 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1622 	      ret->usb_ieee =
1623 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1624 					       1));
1625 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1626 				 ret->usb_ieee);
1627 
1628 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1629 	      ret->usb_mfg =
1630 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1631 					       1));
1632 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->usb_mfg);
1633 
1634 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1635 	      ret->usb_mdl =
1636 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1637 					       1));
1638 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->usb_mdl);
1639 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1640 	      ret->usb_des =
1641 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1642 					       1));
1643 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->usb_des);
1644 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1645 	      ret->usb_cmd =
1646 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1647 					       1));
1648 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->usb_cmd);
1649 	    }
1650 	    cur3 = cur3->next;
1651 	  }
1652 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "snmp"))) {
1653 	  cur3 = cur2->xmlChildrenNode;
1654 	  if (debug) fprintf(stderr, "  Printer auto-detection info (SNMP):\n");
1655 	  while (cur3 != NULL) {
1656 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
1657 	      ret->snmp_ieee =
1658 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1659 					       1));
1660 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
1661 				 ret->snmp_ieee);
1662 
1663 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
1664 	      ret->snmp_mfg =
1665 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1666 					       1));
1667 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->snmp_mfg);
1668 
1669 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
1670 	      ret->snmp_mdl =
1671 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1672 					       1));
1673 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->snmp_mdl);
1674 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
1675 	      ret->snmp_des =
1676 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1677 					       1));
1678 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->snmp_des);
1679 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
1680 	      ret->snmp_cmd =
1681 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
1682 					       1));
1683 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->snmp_cmd);
1684 	    }
1685 	    cur3 = cur3->next;
1686 	  }
1687 	}
1688 	cur2 = cur2->next;
1689       }
1690     }
1691     cur1 = cur1->next;
1692   }
1693 }
1694 
1695 static void
parseComboDriver(xmlDocPtr doc,xmlNodePtr node,comboDataPtr ret,xmlChar const language[],int debug)1696 parseComboDriver(xmlDocPtr doc, /* I - The whole combo data tree */
1697 		 xmlNodePtr node, /* I - Node of XML tree to work on */
1698 		 comboDataPtr ret, /* O - C data structure of Foomatic
1699 				      combo */
1700 		 xmlChar const language [], /* I - User language */
1701 		 int debug) { /* I - Debug mode flag */
1702   xmlNodePtr     cur1;  /* XML node currently worked on */
1703   xmlNodePtr     cur2;  /* Another XML node pointer */
1704   xmlNodePtr     cur3;  /* Another XML node pointer */
1705   xmlNodePtr     cur4;  /* Another XML node pointer */
1706   xmlChar        *id;  /* Full driver ID, with "driver/" */
1707   xmlChar        *level, *version, *scope, *fingerprint;
1708   xmlChar        *url;
1709 
1710   /* Initialization of entries */
1711   ret->driver = NULL;
1712   ret->driver_group = NULL;
1713   ret->driver_type = NULL;
1714   ret->driver_comment = NULL;
1715   ret->url = NULL;
1716   ret->supplier = NULL;
1717   ret->driver_obsolete = NULL;
1718   ret->manufacturersupplied = NULL;
1719   ret->license = NULL;
1720   ret->licensetext = NULL;
1721   ret->origlicensetext = NULL;
1722   ret->licenselink = NULL;
1723   ret->origlicenselink = NULL;
1724   ret->free = NULL;
1725   ret->patents = NULL;
1726   ret->num_supportcontacts = 0;
1727   ret->supportcontacts = NULL;
1728   ret->supportcontacturls = NULL;
1729   ret->supportcontactlevels = NULL;
1730   ret->shortdescription = NULL;
1731   ret->locales = NULL;
1732   ret->num_packages = 0;
1733   ret->packageurls = NULL;
1734   ret->packagescopes = NULL;
1735   ret->packagefingerprints = NULL;
1736   ret->drvmaxresx = NULL;
1737   ret->drvmaxresy = NULL;
1738   ret->drvcolor = NULL;
1739   ret->text = NULL;
1740   ret->lineart = NULL;
1741   ret->graphics = NULL;
1742   ret->photo = NULL;
1743   ret->load = NULL;
1744   ret->speed = NULL;
1745   ret->excmaxresx = NULL;
1746   ret->excmaxresy = NULL;
1747   ret->exccolor = NULL;
1748   ret->exctext = NULL;
1749   ret->exclineart = NULL;
1750   ret->excgraphics = NULL;
1751   ret->excphoto = NULL;
1752   ret->excload = NULL;
1753   ret->excspeed = NULL;
1754   ret->num_requires = 0;
1755   ret->requires = NULL;
1756   ret->requiresversion = NULL;
1757   ret->cmd = NULL;
1758   ret->cmd_pdf = NULL;
1759   ret->nopjl = (xmlChar *)"0";
1760   ret->nopageaccounting = (xmlChar *)"0";
1761   ret->driverppdentry = NULL;
1762   ret->comboppdentry = NULL;
1763   ret->drivermargins = NULL;
1764   ret->combomargins = NULL;
1765 
1766   /* Get driver ID */
1767   id = xmlGetProp(node, (const xmlChar *) "id");
1768   if (id == NULL) {
1769     fprintf(stderr, "No driver ID found\n");
1770     return;
1771   }
1772   ret->driver = perlquote(id + 7);
1773   if (debug) fprintf(stderr, "  Driver ID: %s\n", ret->driver);
1774 
1775   /* Go through subnodes */
1776   cur1 = node->xmlChildrenNode;
1777   while (cur1 != NULL) {
1778     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "driver"))) {
1779       ret->driver =
1780 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1781       if (debug) fprintf(stderr, "  Driver name: %s\n", ret->driver);
1782     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "group"))) {
1783       ret->driver_group =
1784 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1785       if (debug) fprintf(stderr, "  Driver group (for localization): %s\n",
1786 			 ret->driver_group);
1787     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "pcdriver"))) {
1788       ret->pcdriver =
1789 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1790       if (debug) fprintf(stderr, "  Driver part of PC file name in PPD: %s\n",
1791 			 ret->pcdriver);
1792     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "url"))) {
1793       ret->url =
1794 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1795       if (debug) fprintf(stderr, "  Driver URL: %s\n", ret->url);
1796     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "obsolete"))) {
1797       ret->driver_obsolete = xmlGetProp(cur1, (const xmlChar *) "replace");
1798       if (ret->driver_obsolete == NULL) {
1799 	if (debug) fprintf(stderr, "    No replacement driver found!\n");
1800 	ret->driver_obsolete = (xmlChar *)"1";
1801       }
1802       if (debug) fprintf(stderr, "  Driver is obsolete: %s\n",
1803 			 ret->driver_obsolete);
1804     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "supplier"))) {
1805       if (debug)
1806 	fprintf(stderr, "  Driver supplier:\n");
1807       getLocalizedText(doc, cur1, &(ret->supplier), language, debug);
1808     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "manufacturersupplied"))) {
1809       ret->manufacturersupplied =
1810 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1811       if ((ret->manufacturersupplied == NULL) ||
1812 	  (ret->manufacturersupplied[0] == '\0'))
1813 	ret->manufacturersupplied = (xmlChar *)"1";
1814       if (debug) fprintf(stderr, "  Driver supplied by manufacturer: %s\n",
1815 			 ret->manufacturersupplied);
1816     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "thirdpartysupplied"))) {
1817       ret->manufacturersupplied = (xmlChar *)"0";
1818       if (debug) fprintf(stderr, "  Driver supplied by a third party\n");
1819     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "license"))) {
1820       if (debug)
1821 	fprintf(stderr, "  Driver license:\n");
1822       getLocalizedText(doc, cur1, &(ret->license), language, debug);
1823     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "licensetext"))) {
1824       if (debug)
1825 	fprintf(stderr, "  Driver license text:\n");
1826       getLocalizedLicenseText(doc, cur1,
1827 			      &(ret->licensetext), &(ret->origlicensetext),
1828 			      &(ret->licenselink), &(ret->origlicenselink),
1829 			      language, debug);
1830     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "freesoftware"))) {
1831       ret->free = (xmlChar *)"1";
1832       if (debug) fprintf(stderr, "  Driver is free software\n");
1833     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "nonfreesoftware"))) {
1834       ret->free = (xmlChar *)"0";
1835       if (debug) fprintf(stderr, "  Driver is not free software\n");
1836     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "patents"))) {
1837       ret->patents = (xmlChar *)"1";
1838       if (debug) fprintf(stderr, "  There are patents applying to this driver's code\n");
1839     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "nopatents"))) {
1840       ret->patents = (xmlChar *)"0";
1841       if (debug) fprintf(stderr, "  There are no patents applying to this driver's code\n");
1842     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "supportcontacts"))) {
1843       cur2 = cur1->xmlChildrenNode;
1844       if (debug) fprintf(stderr, "  Driver support contacts:\n");
1845       while (cur2 != NULL) {
1846 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "supportcontact"))) {
1847 	  ret->num_supportcontacts ++;
1848 	  ret->supportcontacts =
1849 	    (xmlChar const **)
1850 	    realloc((xmlChar **)ret->supportcontacts,
1851 		    sizeof(xmlChar *) *
1852 		    ret->num_supportcontacts);
1853 	  ret->supportcontacturls =
1854 	    (xmlChar **)
1855 	    realloc((xmlChar **)ret->supportcontacturls,
1856 		    sizeof(xmlChar *) *
1857 		    ret->num_supportcontacts);
1858 	  ret->supportcontactlevels =
1859 	    (xmlChar **)
1860 	    realloc((xmlChar **)ret->supportcontactlevels,
1861 		    sizeof(xmlChar *) *
1862 		    ret->num_supportcontacts);
1863 	  level = xmlGetProp(cur2, (const xmlChar *) "level");
1864 	  if (level == NULL) {
1865 	    level = (xmlChar *)"Unknown";
1866 	  }
1867 	  url = xmlGetProp(cur2, (const xmlChar *) "url");
1868 	  ret->supportcontactlevels[ret->num_supportcontacts - 1] = level;
1869 	  ret->supportcontacturls[ret->num_supportcontacts - 1] = url;
1870 	  getLocalizedText
1871 	    (doc, cur2,
1872 	     &(ret->supportcontacts[ret->num_supportcontacts - 1]),
1873 	     language, debug);
1874 	  if (debug)
1875 	    fprintf(stderr, "    %s (%s):\n      %s\n",
1876 		    ret->supportcontacts[ret->num_supportcontacts - 1],
1877 		    ret->supportcontactlevels[ret->num_supportcontacts - 1],
1878 		    ret->supportcontacturls[ret->num_supportcontacts - 1]);
1879 	}
1880 	cur2 = cur2->next;
1881       }
1882     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "shortdescription"))) {
1883       if (debug)
1884 	fprintf(stderr, "  Driver short description:\n");
1885       getLocalizedText(doc, cur1, &(ret->shortdescription), language, debug);
1886     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "locales"))) {
1887       ret->locales =
1888 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
1889       if (debug) fprintf(stderr, "  Driver list of locales: %s\n", ret->locales);
1890     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "packages"))) {
1891       cur2 = cur1->xmlChildrenNode;
1892       if (debug) fprintf(stderr, "  Driver downloadable packages:\n");
1893       while (cur2 != NULL) {
1894 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "package"))) {
1895 	  ret->num_packages ++;
1896 	  ret->packageurls =
1897 	    (xmlChar **)
1898 	    realloc((xmlChar **)ret->packageurls,
1899 		    sizeof(xmlChar *) *
1900 		    ret->num_packages);
1901 	  ret->packagescopes =
1902 	    (xmlChar **)
1903 	    realloc((xmlChar **)ret->packagescopes,
1904 		    sizeof(xmlChar *) *
1905 		    ret->num_packages);
1906 	  scope = xmlGetProp(cur2, (const xmlChar *) "scope");
1907 	  ret->packagefingerprints =
1908 	    (xmlChar **)
1909 	    realloc((xmlChar **)ret->packagefingerprints,
1910 		    sizeof(xmlChar *) *
1911 		    ret->num_packages);
1912 	  fingerprint = xmlGetProp(cur2, (const xmlChar *) "fingerprint");
1913 	  ret->packageurls[ret->num_packages - 1] =
1914 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1915 	  ret->packagescopes[ret->num_packages - 1] = perlquote(scope);
1916 	  ret->packagefingerprints[ret->num_packages - 1] = perlquote(fingerprint);
1917 	  if (debug)
1918 	    fprintf(stderr, "    %s (%s), key fingerprint on %s\n",
1919 		    ret->packageurls[ret->num_packages - 1],
1920 		    ret->packagescopes[ret->num_packages - 1],
1921 		    ret->packagefingerprints[ret->num_packages - 1]);
1922 	}
1923 	cur2 = cur2->next;
1924       }
1925     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "functionality"))) {
1926       cur2 = cur1->xmlChildrenNode;
1927       while (cur2 != NULL) {
1928 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "maxresx"))) {
1929 	  ret->drvmaxresx =
1930 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1931 	  if (debug)
1932 	    fprintf(stderr, "  Driver functionality: Max X resolution: %s\n",
1933 		    ret->drvmaxresx);
1934 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "maxresy"))) {
1935 	  ret->drvmaxresy =
1936 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1937 	  if (debug)
1938 	    fprintf(stderr, "  Driver functionality: Max Y resolution: %s\n",
1939 		    ret->drvmaxresy);
1940 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "color"))) {
1941 	  ret->drvcolor = (xmlChar *)"1";
1942 	  if (debug) fprintf(stderr, "  Driver functionality: Color\n");
1943 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "monochrome"))) {
1944 	  ret->drvcolor = (xmlChar *)"0";
1945 	  if (debug) fprintf(stderr, "  Driver functionality: Monochrome\n");
1946 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "text"))) {
1947 	  ret->text =
1948 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1949 	  if (debug)
1950 	    fprintf(stderr, "  Driver functionality: Text support rating: %s\n",
1951 		    ret->text);
1952 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "lineart"))) {
1953 	  ret->lineart =
1954 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1955 	  if (debug)
1956 	    fprintf(stderr, "  Driver functionality: Line art support rating: %s\n",
1957 		    ret->lineart);
1958 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "graphics"))) {
1959 	  ret->graphics =
1960 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1961 	  if (debug)
1962 	    fprintf(stderr, "  Driver functionality: Graphics support rating: %s\n",
1963 		    ret->graphics);
1964 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "photo"))) {
1965 	  ret->photo =
1966 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1967 	  if (debug)
1968 	    fprintf(stderr, "  Driver functionality: Photo support rating: %s\n",
1969 		    ret->photo);
1970 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "load"))) {
1971 	  ret->load =
1972 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1973 	  if (debug)
1974 	    fprintf(stderr, "  Driver functionality: System load rating: %s\n",
1975 		    ret->load);
1976 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "speed"))) {
1977 	  ret->speed =
1978 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
1979 	  if (debug)
1980 	    fprintf(stderr, "  Driver functionality: Speed rating: %s\n",
1981 		    ret->speed);
1982      	}
1983 	cur2 = cur2->next;
1984       }
1985     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "execution"))) {
1986       cur2 = cur1->xmlChildrenNode;
1987       while (cur2 != NULL) {
1988 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "requires"))) {
1989 	  ret->num_requires ++;
1990 	  ret->requires =
1991 	    (xmlChar **)
1992 	    realloc((xmlChar **)ret->requires,
1993 		    sizeof(xmlChar *) *
1994 		    ret->num_requires);
1995 	  ret->requiresversion =
1996 	    (xmlChar **)
1997 	    realloc((xmlChar **)ret->requiresversion,
1998 		    sizeof(xmlChar *) *
1999 		    ret->num_requires);
2000 	  version = xmlGetProp(cur2, (const xmlChar *) "version");
2001 	  ret->requires[ret->num_requires - 1] =
2002 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2003 	  ret->requiresversion[ret->num_requires - 1] = perlquote(version);
2004 	  if (debug) /* an explicit brace for GCC thought police */ {
2005 	    if (!version)
2006 	      fprintf(stderr, "  Driver requires driver: %s\n",
2007 		      ret->requires[ret->num_requires - 1]);
2008 	    else
2009 	      fprintf(stderr, "  Driver requires driver: %s (%s)\n",
2010 		      ret->requires[ret->num_requires - 1],
2011 		      ret->requiresversion[ret->num_requires - 1]); }
2012 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "cups"))) {
2013 	  ret->driver_type = (xmlChar *)"C";
2014 	  if (debug) fprintf(stderr, "  Driver type: CUPS Raster\n");
2015 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ijs"))) {
2016 	  ret->driver_type = (xmlChar *)"I";
2017 	  if (debug) fprintf(stderr, "  Driver type: IJS\n");
2018 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "opvp"))) {
2019 	  ret->driver_type = (xmlChar *)"V";
2020 	  if (debug) fprintf(stderr, "  Driver type: OpenPrinting Vector\n");
2021 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ghostscript"))) {
2022 	  ret->driver_type = (xmlChar *)"G";
2023 	  if (debug) fprintf(stderr, "  Driver type: Ghostscript built-in\n");
2024 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "filter"))) {
2025 	  ret->driver_type = (xmlChar *)"F";
2026 	  if (debug) fprintf(stderr, "  Driver type: Filter\n");
2027 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "uniprint"))) {
2028 	  ret->driver_type = (xmlChar *)"U";
2029 	  if (debug) fprintf(stderr, "  Driver type: Ghostscript Uniprint\n");
2030 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "postscript"))) {
2031 	  ret->driver_type = (xmlChar *)"P";
2032 	  if (debug) fprintf(stderr, "  Driver type: PostScript\n");
2033 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "nopjl"))) {
2034 	  ret->nopjl = (xmlChar *)"1";
2035 	  if (debug) fprintf(stderr, "  Driver suppresses PJL options\n");
2036 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "nopageaccounting"))) {
2037 	  ret->nopageaccounting = (xmlChar *)"1";
2038 	  if (debug) fprintf(stderr, "  Driver suppresses CUPS page accounting\n");
2039 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "prototype"))) {
2040 	  ret->cmd =
2041 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2042 	  if (debug) fprintf(stderr, "  Driver command line:\n\n    %s\n\n",
2043 			     ret->cmd);
2044 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "prototype_pdf"))) {
2045 	  ret->cmd_pdf =
2046 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2047 	  if (debug) fprintf(stderr, "  Driver PDF command line:\n\n    %s\n\n",
2048 			     ret->cmd_pdf);
2049 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ppdentry"))) {
2050 	  ret->driverppdentry =
2051 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2052 	  if (debug) fprintf(stderr, "  Extra lines for PPD file:\n%s\n",
2053 			     ret->driverppdentry);
2054 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "margins"))) {
2055 	  parseMargins(doc, cur2, &(ret->drivermargins), language, debug);
2056      	}
2057 	cur2 = cur2->next;
2058       }
2059     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "comments"))) {
2060       if (debug)
2061 	fprintf(stderr, "  Driver Comment:\n");
2062       getLocalizedText(doc, cur1, &(ret->driver_comment), language, debug);
2063     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "printers"))) {
2064       cur2 = cur1->xmlChildrenNode;
2065       while (cur2 != NULL) {
2066 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "printer"))) {
2067 	  cur3 = cur2->xmlChildrenNode;
2068 	  while (cur3 != NULL) {
2069 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ppdentry"))) {
2070 	      ret->comboppdentry =
2071 		perlquote(xmlNodeListGetString(doc,
2072 					       cur3->xmlChildrenNode, 1));
2073 	      if (debug)
2074 		fprintf(stderr, "  Extra lines for PPD file:\n%s\n",
2075 			ret->comboppdentry);
2076 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "margins"))) {
2077 	      parseMargins(doc, cur3, &(ret->combomargins),
2078 			   language, debug);
2079 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "functionality"))) {
2080 	      cur4 = cur3->xmlChildrenNode;
2081 	      while (cur4 != NULL) {
2082 		if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresx"))) {
2083 		  ret->excmaxresx =
2084 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2085 		  if (debug)
2086 		    fprintf(stderr, "  Combo exception: Maximum X resolution: %s\n",
2087 			    ret->excmaxresx);
2088 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresy"))) {
2089 		  ret->excmaxresy =
2090 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2091 		  if (debug)
2092 		    fprintf(stderr, "  Combo exception: Maximum Y resolution: %s\n",
2093 			    ret->excmaxresy);
2094 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "monochrome"))) {
2095 		  ret->exccolor = (xmlChar *)"0";
2096 		  if (debug)
2097 		    fprintf(stderr, "  Combo exception: Color: %s\n",
2098 			    ret->exccolor);
2099 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "color"))) {
2100 		  ret->exccolor = (xmlChar *)"1";
2101 		  if (debug)
2102 		    fprintf(stderr, "  Combo exception: Color: %s\n",
2103 			    ret->exccolor);
2104 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "text"))) {
2105 		  ret->exctext =
2106 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2107 		  if (debug)
2108 		    fprintf(stderr, "  Combo exception: Support level for text: %s\n",
2109 			    ret->exctext);
2110 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "lineart"))) {
2111 		  ret->exclineart =
2112 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2113 		  if (debug)
2114 		    fprintf(stderr, "  Combo exception: Support level for line art: %s\n",
2115 			    ret->exclineart);
2116 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "graphics"))) {
2117 		  ret->excgraphics =
2118 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2119 		  if (debug)
2120 		    fprintf(stderr, "  Combo exception: Support level for graphics: %s\n",
2121 			    ret->excgraphics);
2122 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "photo"))) {
2123 		  ret->excphoto =
2124 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2125 		  if (debug)
2126 		    fprintf(stderr, "  Combo exception: Support level for photos: %s\n",
2127 			    ret->excphoto);
2128 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "load"))) {
2129 		  ret->excload =
2130 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2131 		  if (debug)
2132 		    fprintf(stderr, "  Combo exception: Expected relative system load: %s\n",
2133 			    ret->excload);
2134 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "speed"))) {
2135 		  ret->excspeed =
2136 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
2137 		  if (debug)
2138 		    fprintf(stderr, "  Combo exception: Expected relative driver speed: %s\n",
2139 			    ret->excspeed);
2140 		}
2141 		cur4 = cur4->next;
2142 	      }
2143 	    }
2144 	    cur3 = cur3->next;
2145 	  }
2146 	}
2147 	cur2 = cur2->next;
2148       }
2149     }
2150     cur1 = cur1->next;
2151   }
2152 }
2153 
2154 static void
parseChoices(xmlDocPtr doc,xmlNodePtr node,argPtr option,xmlChar const language[],int debug)2155 parseChoices(xmlDocPtr doc, /* I - The whole combo data tree */
2156 	     xmlNodePtr node, /* I - Node of XML tree to work on */
2157 	     argPtr option, /* O - C data structure of Foomatic option */
2158 	     xmlChar const language [], /* I - User language */
2159   	     int debug) { /* I - Debug mode flag */
2160   xmlNodePtr     cur1;  /* XML node currently worked on */
2161   xmlNodePtr     cur2;  /* Another XML node pointer */
2162   xmlNodePtr     cur3;  /* Another XML node pointer */
2163   xmlChar        *id;   /* Full choice ID, with "ev/" */
2164   choicePtr      enum_val; /* Data structure for the choice currently
2165 			      parsed */
2166 
2167   /* Initialization of entries */
2168   option->num_choices = 0;
2169   option->choices = NULL;
2170 
2171   /* Go through the choice nodes */
2172   cur1 = node->xmlChildrenNode;
2173   while (cur1 != NULL) {
2174     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "enum_val"))) {
2175 
2176       /* Allocate memory for the option */
2177       option->num_choices ++;
2178       option->choices =
2179 	(choicePtr *)realloc((choicePtr *)(option->choices),
2180 			     sizeof(choicePtr) * option->num_choices);
2181       enum_val = (choicePtr) malloc(sizeof(arg));
2182       if (enum_val == NULL) {
2183 	fprintf(stderr,"Out of memory!\n");
2184 	xmlFreeDoc(doc);
2185 	exit(1);
2186       }
2187       option->choices[option->num_choices-1] = enum_val;
2188       memset(enum_val, 0, sizeof(choice));
2189 
2190       /* Initialization of entries */
2191       enum_val->value = NULL;
2192       enum_val->comment = NULL;
2193       enum_val->idx = NULL;
2194       enum_val->driverval = NULL;
2195 
2196       /* Get option ID */
2197       id = xmlGetProp(cur1, (const xmlChar *) "id");
2198       if (id == NULL) {
2199 	fprintf(stderr, "No choice ID found\n");
2200 	return;
2201       }
2202       enum_val->idx = perlquote(id);
2203       if (debug) fprintf(stderr, "    Choice ID: %s\n", enum_val->idx);
2204 
2205       /* Go through subnodes */
2206       cur2 = cur1->xmlChildrenNode;
2207       while (cur2 != NULL) {
2208 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ev_shortname"))) {
2209 	  if (debug)
2210 	    fprintf(stderr, "      Choice short name (do not translate):\n");
2211 	  getLocalizedText (doc, cur2, &(enum_val->value), sc_locale_C, debug);
2212 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ev_longname"))) {
2213 	  if (debug)
2214 	    fprintf(stderr, "      Choice long name:\n");
2215 	  getLocalizedText(doc, cur2, &(enum_val->comment), language, debug);
2216 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ev_driverval"))) {
2217 	  enum_val->driverval =
2218 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2219 	  if (debug) fprintf(stderr, "      String to insert at %%s: %s\n",
2220 			     enum_val->driverval);
2221 	}
2222 	cur2 = cur2->next;
2223       }
2224     }
2225     cur1 = cur1->next;
2226   }
2227 }
2228 
2229 static void
parseOptions(xmlDocPtr doc,xmlNodePtr node,comboDataPtr ret,xmlChar const language[],int debug)2230 parseOptions(xmlDocPtr doc, /* I - The whole combo data tree */
2231 	     xmlNodePtr node, /* I - Node of XML tree to work on */
2232 	     comboDataPtr ret, /* O - C data structure of Foomatic combo */
2233 	     xmlChar const language [], /* I - User language */
2234 	     int debug) { /* I - Debug mode flag */
2235   xmlNodePtr     cur1;  /* XML node currently worked on */
2236   xmlNodePtr     cur2;  /* Another XML node pointer */
2237   xmlNodePtr     cur3;  /* Another XML node pointer */
2238   xmlChar        *id,  /* Full option ID, with "opt/" */
2239                  *option_type; /* Option type */
2240   argPtr         option;/* Data structure for the option currently parsed */
2241 
2242   /* Initialization of entries */
2243   ret->num_args = 0;
2244   ret->args = NULL;
2245   ret->maxspot = (xmlChar *)"A";
2246 
2247   /* Go through the option nodes */
2248   cur1 = node->xmlChildrenNode;
2249   while (cur1 != NULL) {
2250     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "option"))) {
2251 
2252       /* Allocate memory for the option */
2253       ret->num_args ++;
2254       ret->args =
2255 	(argPtr *)realloc((argPtr *)(ret->args),
2256 			  sizeof(argPtr) * ret->num_args);
2257       option = (argPtr) malloc(sizeof(arg));
2258       if (option == NULL) {
2259 	fprintf(stderr,"Out of memory!\n");
2260 	xmlFreeDoc(doc);
2261 	exit(1);
2262       }
2263       ret->args[ret->num_args-1] = option;
2264       memset(option, 0, sizeof(arg));
2265 
2266       /* Initialization of entries */
2267       option->name = NULL;
2268       option->name_false = NULL;
2269       option->comment = NULL;
2270       option->idx = NULL;
2271       option->option_type = NULL;
2272       option->style = NULL;
2273       option->substyle= NULL;
2274       option->spot = NULL;
2275       option->order = NULL;
2276       option->section = NULL;
2277       option->grouppath = NULL;
2278       option->proto = NULL;
2279       option->required = NULL;
2280       option->min_value = NULL;
2281       option->max_value = NULL;
2282       option->max_length = NULL;
2283       option->allowed_chars = NULL;
2284       option->allowed_regexp = NULL;
2285       option->default_value = NULL;
2286       option->num_choices = 0;
2287       option->choices = NULL;
2288 
2289       /* Get option ID */
2290       id = xmlGetProp(cur1, (const xmlChar *) "id");
2291       if (id == NULL) {
2292 	fprintf(stderr, "No option ID found\n");
2293 	return;
2294       }
2295       option->idx = perlquote(id);
2296       if (debug) fprintf(stderr, "  Option ID: %s\n", option->idx);
2297 
2298       /* Get option type */
2299       option_type = xmlGetProp(cur1, (const xmlChar *) "type");
2300       if (option_type == NULL) {
2301 	fprintf(stderr, "No option type found\n");
2302 	return;
2303       }
2304       option->option_type = perlquote(option_type);
2305       if (debug) fprintf(stderr, "    Option type: %s\n",
2306 			 option->option_type);
2307 
2308       /* Go through subnodes */
2309       cur2 = cur1->xmlChildrenNode;
2310       while (cur2 != NULL) {
2311 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_shortname"))) {
2312 	  if (debug)
2313 	    fprintf(stderr, "    Option short name (do not translate):\n");
2314 	  getLocalizedText(doc, cur2, &(option->name), sc_locale_C, debug);
2315 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_shortname_false"))) {
2316 	  if (debug)
2317 	    fprintf(stderr,
2318 		    "    Option short name if false (do not translate):\n");
2319 	  getLocalizedText(doc, cur2, &(option->name_false), sc_locale_C, debug);
2320 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_longname"))) {
2321 	  if (debug)
2322 	    fprintf(stderr, "    Option long name:\n");
2323 	  getLocalizedText(doc, cur2, &(option->comment), language, debug);
2324 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_execution"))) {
2325 	  cur3 = cur2->xmlChildrenNode;
2326 	  while (cur3 != NULL) {
2327 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_substitution"))) {
2328 	      option->style = (xmlChar *)"C";
2329 	      option->substyle = NULL;
2330 	      if (debug)
2331 		fprintf(stderr,
2332 			"    Option style: Command line Substitution\n");
2333 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_postscript"))) {
2334 	      option->style = (xmlChar *)"G";
2335 	      option->substyle = NULL;
2336 	      if (debug)
2337 		fprintf(stderr,
2338 			"    Option style: PostScript code\n");
2339 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_pjl"))) {
2340 	      option->style = (xmlChar *)"J";
2341 	      option->substyle = NULL;
2342 	      if (debug)
2343 		fprintf(stderr,
2344 			"    Option style: PJL command\n");
2345 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_composite"))) {
2346 	      option->style = (xmlChar *)"X";
2347 	      option->substyle = NULL;
2348 	      if (debug)
2349 		fprintf(stderr,
2350 			"    Option style: Composite option\n");
2351 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_forced_composite"))) {
2352 	      option->style = (xmlChar *)"X";
2353 	      option->substyle = (xmlChar *)"F";
2354 	      if (debug)
2355 		fprintf(stderr,
2356 			"    Option style: Forced composite option\n");
2357 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_spot"))) {
2358 	      option->spot =
2359 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2360 					       1));
2361 	      if (debug) fprintf(stderr,
2362 				 "    Command line insertion spot: %%%s\n",
2363 				 option->spot);
2364 	      if ((xmlStrcmp(option->spot, ret->maxspot) > 0)) {
2365 		ret->maxspot = option->spot;
2366 	      }
2367 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_order"))) {
2368 	      option->order =
2369 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2370 					       1));
2371 	      if (debug) fprintf(stderr,
2372 				 "    Command line insertion order: %s\n",
2373 				 option->order);
2374 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_section"))) {
2375 	      option->section =
2376 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2377 					       1));
2378 	      if (debug) fprintf(stderr,
2379 				 "    Section in PostScript file: %s\n",
2380 				 option->section);
2381 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_group"))) {
2382 	      option->grouppath =
2383 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2384 					       1));
2385 	      if (debug) fprintf(stderr,
2386 				 "    Option Group: %s\n",
2387 				 option->grouppath);
2388 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_proto"))) {
2389 	      option->proto =
2390 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2391 					       1));
2392 	      if (debug) fprintf(stderr,
2393 				 "    Code to insert: %s\n",
2394 				 option->proto);
2395 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "arg_required"))) {
2396 	      option->required = (xmlChar *)"1";
2397 	      if (debug) fprintf(stderr,
2398 				 "    This option is required\n");
2399 	    }
2400 	    cur3 = cur3->next;
2401 	  }
2402 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_min"))) {
2403 	  option->min_value =
2404 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2405 	  if (debug) fprintf(stderr,
2406 			     "    Minimum value: %s\n",
2407 			     option->min_value);
2408 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_max"))) {
2409 	  option->max_value =
2410 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2411 	  if (debug) fprintf(stderr,
2412 			     "    Maximum value: %s\n",
2413 			     option->max_value);
2414 	} else if ((!xmlStrcmp(cur2->name,
2415 			       (const xmlChar *) "arg_maxlength"))) {
2416 	  option->max_length =
2417 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2418 	  if (debug) fprintf(stderr,
2419 			     "    Maximum string length: %s\n",
2420 			     option->max_length);
2421 	} else if ((!xmlStrcmp(cur2->name,
2422 			       (const xmlChar *) "arg_allowedchars"))) {
2423 	  option->allowed_chars =
2424 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2425 	  if (debug) fprintf(stderr,
2426 			     "    Allowed characters in string: %s\n",
2427 			     option->allowed_chars);
2428 	} else if ((!xmlStrcmp(cur2->name,
2429 			       (const xmlChar *) "arg_allowedregexp"))) {
2430 	  option->allowed_regexp =
2431 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2432 	  if (debug) fprintf(stderr,
2433 			     "    String must match Perl regexp: %s\n",
2434 			     option->allowed_regexp);
2435 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "arg_defval"))) {
2436 	  option->default_value =
2437 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
2438 	  if (debug) fprintf(stderr,
2439 			     "    Default: %s\n",
2440 			     option->default_value);
2441 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "enum_vals"))) {
2442 	  if (debug) fprintf(stderr, "  --> Parsing choice data\n");
2443 	  parseChoices(doc, cur2, option, language, debug);
2444 	}
2445 	cur2 = cur2->next;
2446       }
2447     }
2448     cur1 = cur1->next;
2449   }
2450   if (debug) fprintf(stderr,
2451 		     "  Last command line insertion spot: %%%s\n",
2452 		     ret->maxspot);
2453 }
2454 
2455 /*
2456  * Functions to fill in the printer and driver data structures with the
2457  * data parsed from the XML input
2458  */
2459 
2460 static void
parsePrinterEntry(xmlDocPtr doc,xmlNodePtr node,printerEntryPtr ret,xmlChar const language[],int debug)2461 parsePrinterEntry(xmlDocPtr doc, /* I - The whole printer data tree */
2462 		  xmlNodePtr node, /* I - Node of XML tree to work on */
2463 		  printerEntryPtr ret, /* O - C data structure of Foomatic
2464 					  printer entry */
2465 		  xmlChar const language [], /* I - User language */
2466 		  int debug) { /* I - Debug mode flag */
2467   xmlNodePtr     cur1;  /* XML node currently worked on */
2468   xmlNodePtr     cur2;  /* Another XML node pointer */
2469   xmlNodePtr     cur3;  /* Another XML node pointer */
2470   xmlNodePtr     cur4;  /* Another XML node pointer */
2471   xmlChar        *id;  /* Full printer ID, with "printer/" */
2472   xmlChar        *dname;  /* Name of a driver supporting this printer */
2473   xmlChar        *dppd;  /* Ready-made PPD supporting this printer */
2474   printerLanguagePtr lentry; /* An entry for a language used by this
2475 				printer */
2476   printerDrvEntryPtr dentry; /* An entry for a driver supporting this
2477 				printer */
2478 
2479   /* Initialization of entries */
2480   ret->id = NULL;
2481   ret->make = NULL;
2482   ret->model = NULL;
2483   ret->printer_type = NULL;
2484   ret->color = (xmlChar *)"0";
2485   ret->maxxres = NULL;
2486   ret->maxyres = NULL;
2487   ret->printerppdentry = NULL;
2488   ret->printermargins = NULL;
2489   ret->refill = NULL;
2490   ret->ascii = NULL;
2491   ret->pjl = (xmlChar *)"0";
2492   ret->general_ieee = NULL;
2493   ret->general_mfg = NULL;
2494   ret->general_mdl = NULL;
2495   ret->general_des = NULL;
2496   ret->general_cmd = NULL;
2497   ret->par_ieee = NULL;
2498   ret->par_mfg = NULL;
2499   ret->par_mdl = NULL;
2500   ret->par_des = NULL;
2501   ret->par_cmd = NULL;
2502   ret->usb_ieee = NULL;
2503   ret->usb_mfg = NULL;
2504   ret->usb_mdl = NULL;
2505   ret->usb_des = NULL;
2506   ret->usb_cmd = NULL;
2507   ret->snmp_ieee = NULL;
2508   ret->snmp_mfg = NULL;
2509   ret->snmp_mdl = NULL;
2510   ret->snmp_des = NULL;
2511   ret->snmp_cmd = NULL;
2512   ret->functionality = (xmlChar *)"X";
2513   ret->driver = NULL;
2514   ret->unverified = (xmlChar *)"0";
2515   ret->noxmlentry = (xmlChar *)"0";
2516   ret->url = NULL;
2517   ret->contriburl = NULL;
2518   ret->comment = NULL;
2519   ret->ppdurl = NULL;
2520   ret->num_languages = 0;
2521   ret->languages = NULL;
2522   ret->num_drivers = 0;
2523   ret->drivers = NULL;
2524 
2525   /* Get printer ID */
2526   id = xmlGetProp(node, (const xmlChar *) "id");
2527   if (id == NULL) {
2528     fprintf(stderr, "No printer ID found\n");
2529     return;
2530   }
2531   ret->id = perlquote(id + 8);
2532   if (debug) fprintf(stderr, "  Printer ID: %s\n", ret->id);
2533 
2534   /* Go through subnodes */
2535   cur1 = node->xmlChildrenNode;
2536   while (cur1 != NULL) {
2537     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "make"))) {
2538       ret->make =
2539 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2540       if (debug) fprintf(stderr, "  Printer Manufacturer: %s\n", ret->make);
2541     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "model"))) {
2542       ret->model =
2543 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2544       if (debug) fprintf(stderr, "  Printer Model: %s\n", ret->model);
2545     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "mechanism"))) {
2546       cur2 = cur1->xmlChildrenNode;
2547       while (cur2 != NULL) {
2548  	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "inkjet"))) {
2549 	  ret->printer_type = (xmlChar *)"inkjet";
2550 	  if (debug) fprintf(stderr, "  Inkjet printer\n");
2551 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "laser"))) {
2552 	  ret->printer_type = (xmlChar *)"laser";
2553 	  if (debug) fprintf(stderr, "  Laser printer\n");
2554  	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "impact"))) {
2555 	  ret->printer_type = (xmlChar *)"impact";
2556 	  if (debug) fprintf(stderr, "  Impact printer\n");
2557  	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "dotmatrix"))) {
2558 	  ret->printer_type = (xmlChar *)"dotmatrix";
2559 	  if (debug) fprintf(stderr, "  Dot matrix printer\n");
2560  	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "led"))) {
2561 	  ret->printer_type = (xmlChar *)"led";
2562 	  if (debug) fprintf(stderr, "  LED printer\n");
2563  	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "sublimation"))) {
2564 	  ret->printer_type = (xmlChar *)"sublimation";
2565 	  if (debug) fprintf(stderr, "  Dye sublimation printer\n");
2566  	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "transfer"))) {
2567 	  ret->printer_type = (xmlChar *)"transfer";
2568 	  if (debug) fprintf(stderr, "  Thermal transfer printer\n");
2569 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "color"))) {
2570 	  ret->color = (xmlChar *)"1";
2571 	  if (debug) fprintf(stderr, "  Color printer\n");
2572 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "monochrome"))) {
2573 	  ret->color = (xmlChar *)"0";
2574 	  if (debug) fprintf(stderr, "  Monochrome printer\n");
2575 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "resolution"))) {
2576 	  cur3 = cur2->xmlChildrenNode;
2577 	  while (cur3 != NULL) {
2578 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "dpi"))) {
2579 	      cur4 = cur3->xmlChildrenNode;
2580 	      while (cur4 != NULL) {
2581 		if ((!xmlStrcmp(cur4->name, (const xmlChar *) "x"))) {
2582 		  ret->maxxres =
2583 		    perlquote(xmlNodeListGetString(doc,
2584 						   cur4->xmlChildrenNode,
2585 						   1));
2586 		  if (debug) fprintf(stderr,
2587 				     "  Maximum X resolution: %s\n",
2588 				     ret->maxxres);
2589 
2590 		} else if ((!xmlStrcmp(cur4->name,(const xmlChar *) "y"))) {
2591 		  ret->maxyres =
2592 		    perlquote(xmlNodeListGetString(doc,
2593 						   cur4->xmlChildrenNode,
2594 						   1));
2595 		  if (debug) fprintf(stderr,
2596 				     "  Maximum Y resolution: %s\n",
2597 				     ret->maxyres);
2598 
2599 		}
2600 		cur4 = cur4->next;
2601 	      }
2602 	    }
2603 	    cur3 = cur3->next;
2604 	  }
2605 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "margins"))) {
2606 	  parseMargins(doc, cur2, &(ret->printermargins), language, debug);
2607 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "consumables"))) {
2608 	  cur3 = cur2->xmlChildrenNode;
2609 	  while (cur3 != NULL) {
2610 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "comments"))) {
2611 	      if (debug)
2612 		fprintf(stderr, "  Consumables:\n");
2613 	      getLocalizedText(doc, cur3, &(ret->refill), language, debug);
2614 	    }
2615 	    cur3 = cur3->next;
2616 	  }
2617 	}
2618 	cur2 = cur2->next;
2619       }
2620     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "lang"))) {
2621       cur2 = cur1->xmlChildrenNode;
2622       while (cur2 != NULL) {
2623 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "pjl"))) {
2624 	  ret->pjl = (xmlChar *)"1";
2625 	  if (debug) fprintf(stderr, "  Printer supports PJL\n");
2626 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "text"))) {
2627 	  cur3 = cur2->xmlChildrenNode;
2628 	  while (cur3 != NULL) {
2629 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "charset"))) {
2630 	      ret->ascii =
2631 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2632 					       1));
2633 	      if (debug) fprintf(stderr,
2634 				 "  Printer prints plain text: %s\n",
2635 				 ret->ascii);
2636 	    }
2637 	    cur3 = cur3->next;
2638 	  }
2639 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "postscript"))) {
2640 	  cur3 = cur2->xmlChildrenNode;
2641 	  while (cur3 != NULL) {
2642 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ppd"))) {
2643 	      ret->ppdurl =
2644 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2645 					       1));
2646 	      if (debug) fprintf(stderr,
2647 				 "  URL for the PPD for this printer: %s\n",
2648 				 ret->ppdurl);
2649 	    }
2650 	    cur3 = cur3->next;
2651 	  }
2652 	}
2653 	if ((xmlStrcmp(cur2->name, (const xmlChar *) "pjl")) &&
2654 	    (xmlStrcmp(cur2->name, (const xmlChar *) "text")) &&
2655 	    (xmlStrcmp(cur2->name, (const xmlChar *) "comment"))) {
2656 	  ret->num_languages ++;
2657 	  ret->languages =
2658 	    (printerLanguagePtr *)
2659 	    realloc((printerLanguagePtr *)ret->languages,
2660 		    sizeof(printerLanguagePtr) *
2661 		    ret->num_languages);
2662 	  lentry = (printerLanguagePtr) malloc(sizeof(printerLanguage));
2663 	  if (lentry == NULL) {
2664 	    fprintf(stderr,"Out of memory!\n");
2665 	    xmlFreeDoc(doc);
2666 	    exit(1);
2667 	  }
2668 	  ret->languages[ret->num_languages-1] = lentry;
2669 	  memset(lentry, 0, sizeof(printerLanguage));
2670 	  lentry->name = perlquote((xmlChar *)(cur2->name));
2671 	  lentry->level =
2672 	    perlquote(xmlGetProp(cur2, (const xmlChar *) "level"));
2673 	  if (lentry->level == NULL) lentry->level = (xmlChar *) "";
2674 	  if (debug)
2675 	    fprintf(stderr, "  Printer understands PDL: %s Level %s\n",
2676 		    lentry->name, lentry->level);
2677 	}
2678 	cur2 = cur2->next;
2679       }
2680     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "autodetect"))) {
2681       cur2 = cur1->xmlChildrenNode;
2682       while (cur2 != NULL) {
2683 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "general"))) {
2684 	  cur3 = cur2->xmlChildrenNode;
2685 	  if (debug) fprintf(stderr, "  Printer auto-detection info (general):\n");
2686 	  while (cur3 != NULL) {
2687 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
2688 	      ret->general_ieee =
2689 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2690 					       1));
2691 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
2692 				 ret->general_ieee);
2693 
2694 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
2695 	      ret->general_mfg =
2696 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2697 					       1));
2698 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->general_mfg);
2699 
2700 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
2701 	      ret->general_mdl =
2702 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2703 					       1));
2704 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->general_mdl);
2705 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
2706 	      ret->general_des =
2707 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2708 					       1));
2709 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->general_des);
2710 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
2711 	      ret->general_cmd =
2712 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2713 					       1));
2714 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->general_cmd);
2715 	    }
2716 	    cur3 = cur3->next;
2717 	  }
2718 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "parallel"))) {
2719 	  cur3 = cur2->xmlChildrenNode;
2720 	  if (debug) fprintf(stderr, "  Printer auto-detection info (parallel port):\n");
2721 	  while (cur3 != NULL) {
2722 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
2723 	      ret->par_ieee =
2724 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2725 					       1));
2726 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
2727 				 ret->par_ieee);
2728 
2729 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
2730 	      ret->par_mfg =
2731 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2732 					       1));
2733 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->par_mfg);
2734 
2735 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
2736 	      ret->par_mdl =
2737 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2738 					       1));
2739 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->par_mdl);
2740 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
2741 	      ret->par_des =
2742 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2743 					       1));
2744 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->par_des);
2745 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
2746 	      ret->par_cmd =
2747 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2748 					       1));
2749 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->par_cmd);
2750 	    }
2751 	    cur3 = cur3->next;
2752 	  }
2753 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "usb"))) {
2754 	  cur3 = cur2->xmlChildrenNode;
2755 	  if (debug) fprintf(stderr, "  Printer auto-detection info (USB):\n");
2756 	  while (cur3 != NULL) {
2757 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
2758 	      ret->usb_ieee =
2759 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2760 					       1));
2761 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
2762 				 ret->usb_ieee);
2763 
2764 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
2765 	      ret->usb_mfg =
2766 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2767 					       1));
2768 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->usb_mfg);
2769 
2770 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
2771 	      ret->usb_mdl =
2772 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2773 					       1));
2774 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->usb_mdl);
2775 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
2776 	      ret->usb_des =
2777 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2778 					       1));
2779 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->usb_des);
2780 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
2781 	      ret->usb_cmd =
2782 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2783 					       1));
2784 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->usb_cmd);
2785 	    }
2786 	    cur3 = cur3->next;
2787 	  }
2788 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "snmp"))) {
2789 	  cur3 = cur2->xmlChildrenNode;
2790 	  if (debug) fprintf(stderr, "  Printer auto-detection info (SNMP):\n");
2791 	  while (cur3 != NULL) {
2792 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ieee1284"))) {
2793 	      ret->snmp_ieee =
2794 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2795 					       1));
2796 	      if (debug) fprintf(stderr, "    IEEE1284: %s\n",
2797 				 ret->snmp_ieee);
2798 
2799 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "manufacturer"))) {
2800 	      ret->snmp_mfg =
2801 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2802 					       1));
2803 	      if (debug) fprintf(stderr, "    MFG: %s\n", ret->snmp_mfg);
2804 
2805 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "model"))) {
2806 	      ret->snmp_mdl =
2807 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2808 					       1));
2809 	      if (debug) fprintf(stderr, "    MDL: %s\n", ret->snmp_mdl);
2810 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "description"))) {
2811 	      ret->snmp_des =
2812 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2813 					       1));
2814 	      if (debug) fprintf(stderr, "    DES: %s\n", ret->snmp_des);
2815 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "commandset"))) {
2816 	      ret->snmp_cmd =
2817 		perlquote(xmlNodeListGetString(doc, cur3->xmlChildrenNode,
2818 					       1));
2819 	      if (debug) fprintf(stderr, "    CMD: %s\n", ret->snmp_cmd);
2820 	    }
2821 	    cur3 = cur3->next;
2822 	  }
2823 	}
2824 	cur2 = cur2->next;
2825       }
2826     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "functionality"))) {
2827       ret->functionality =
2828 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2829       if (debug) fprintf(stderr, "  Printer Functionality: %s\n",
2830 			 ret->functionality);
2831     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "driver"))) {
2832       ret->driver =
2833 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2834       if (debug) fprintf(stderr, "  Recommended driver: %s\n", ret->driver);
2835     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "ppdentry"))) {
2836       ret->printerppdentry =
2837 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2838       if (debug) fprintf(stderr, "  Extra lines for PPD file:\n%s\n",
2839 			 ret->printerppdentry);
2840     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "unverified"))) {
2841       ret->unverified = (xmlChar *)"1";
2842       if (debug) fprintf(stderr, "  Printer entry is unverified\n");
2843     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "noxmlentry"))) {
2844       ret->noxmlentry = (xmlChar *)"1";
2845       if (debug) fprintf(stderr, "  Printer XML entry does not exist in the database\n");
2846     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "url"))) {
2847       ret->url =
2848 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2849       if (debug) fprintf(stderr, "  Printer URL: %s\n", ret->url);
2850     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "contrib_url"))) {
2851       ret->contriburl =
2852 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2853       if (debug) fprintf(stderr, "  Contributed URL: %s\n",
2854 			 ret->contriburl);
2855     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "comments"))) {
2856       if (debug)
2857 	fprintf(stderr, "  Comment:\n");
2858       getLocalizedText(doc, cur1, &(ret->comment), language, debug);
2859     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "drivers"))) {
2860       cur2 = cur1->xmlChildrenNode;
2861       while (cur2 != NULL) {
2862 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "driver"))) {
2863 	  ret->num_drivers ++;
2864 	  ret->drivers =
2865 	    (printerDrvEntryPtr *)
2866 	    realloc((printerDrvEntryPtr *)ret->drivers,
2867 		    sizeof(printerDrvEntryPtr) *
2868 		    ret->num_drivers);
2869 	  dentry = (printerDrvEntryPtr) malloc(sizeof(printerDrvEntry));
2870 	  if (dentry == NULL) {
2871 	    fprintf(stderr,"Out of memory!\n");
2872 	    xmlFreeDoc(doc);
2873 	    exit(1);
2874 	  }
2875 	  ret->drivers[ret->num_drivers-1] = dentry;
2876 	  memset(dentry, 0, sizeof(printerDrvEntry));
2877 	  dentry->name = NULL;
2878 	  dentry->comment = NULL;
2879 	  dentry->ppd = NULL;
2880           dentry->excmaxresx = NULL;
2881 	  dentry->excmaxresy = NULL;
2882 	  dentry->exccolor = NULL;
2883 	  dentry->exctext = NULL;
2884 	  dentry->exclineart = NULL;
2885 	  dentry->excgraphics = NULL;
2886 	  dentry->excphoto = NULL;
2887 	  dentry->excload = NULL;
2888 	  dentry->excspeed = NULL;
2889 	  if (debug) fprintf(stderr, "  Printer supported by drivers:\n");
2890 	  cur3 = cur2->xmlChildrenNode;
2891 	  while (cur3 != NULL) {
2892 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "id"))) {
2893 	      dname =
2894 		xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
2895 	      dentry->name = perlquote(dname);
2896 	      if (debug) fprintf(stderr, "    Name: %s\n",
2897 				 dentry->name);
2898 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "ppd"))) {
2899 	      dppd =
2900 		xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
2901 	      dentry->ppd = perlquote(dppd);
2902 	      if (debug) fprintf(stderr, "    Ready-made PPD: %s\n",
2903 				 dentry->ppd);
2904 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "comments"))) {
2905 	      if (debug)
2906 		fprintf(stderr, "    Comment:\n");
2907 	      getLocalizedText(doc, cur3, &(dentry->comment), language, debug);
2908 	    }
2909 	    cur3 = cur3->next;
2910 	  }
2911 	}
2912 	cur2 = cur2->next;
2913       }
2914     }
2915     cur1 = cur1->next;
2916   }
2917 }
2918 
2919 static void
parseDriverEntry(xmlDocPtr doc,xmlNodePtr node,driverEntryPtr ret,xmlChar const language[],int debug)2920 parseDriverEntry(xmlDocPtr doc, /* I - The whole driver data tree */
2921 		 xmlNodePtr node, /* I - Node of XML tree to work on */
2922 		 driverEntryPtr ret, /* O - C data structure of Foomatic
2923 					driver entry */
2924 		 xmlChar const language [], /* I - User language */
2925 		 int debug) { /* I - Debug mode flag */
2926   xmlNodePtr     cur1;  /* XML node currently worked on */
2927   xmlNodePtr     cur2;  /* Another XML node pointer */
2928   xmlNodePtr     cur3;  /* Another XML node pointer */
2929   xmlNodePtr     cur4;  /* Another XML node pointer */
2930   xmlChar        *id;   /* Full driver ID, with "driver/" */
2931   drvPrnEntryPtr entry; /* An entry for a printer supported by this driver*/
2932   xmlChar        *url, *level, *version, *scope, *fingerprint;
2933 
2934   /* Initialization of entries */
2935   ret->id = NULL;
2936   ret->name = NULL;
2937   ret->group = NULL;
2938   ret->url = NULL;
2939   ret->driver_obsolete = NULL;
2940   ret->supplier = NULL;
2941   ret->manufacturersupplied = NULL;
2942   ret->license = NULL;
2943   ret->licensetext = NULL;
2944   ret->origlicensetext = NULL;
2945   ret->licenselink = NULL;
2946   ret->origlicenselink = NULL;
2947   ret->free = NULL;
2948   ret->patents = NULL;
2949   ret->num_supportcontacts = 0;
2950   ret->supportcontacts = NULL;
2951   ret->supportcontacturls = NULL;
2952   ret->supportcontactlevels = NULL;
2953   ret->shortdescription = NULL;
2954   ret->locales = NULL;
2955   ret->num_packages = 0;
2956   ret->packageurls = NULL;
2957   ret->packagescopes = NULL;
2958   ret->packagefingerprints = NULL;
2959   ret->maxresx = NULL;
2960   ret->maxresy = NULL;
2961   ret->color = NULL;
2962   ret->text = NULL;
2963   ret->lineart = NULL;
2964   ret->graphics = NULL;
2965   ret->photo = NULL;
2966   ret->load = NULL;
2967   ret->speed = NULL;
2968   ret->num_requires = 0;
2969   ret->requires = NULL;
2970   ret->requiresversion = NULL;
2971   ret->driver_type = NULL;
2972   ret->cmd = NULL;
2973   ret->cmd_pdf = NULL;
2974   ret->driverppdentry = NULL;
2975   ret->drivermargins = NULL;
2976   ret->comment = NULL;
2977   ret->num_printers = 0;
2978   ret->printers = NULL;
2979 
2980   /* Get driver ID */
2981   id = xmlGetProp(node, (const xmlChar *) "id");
2982   if (id == NULL) {
2983     fprintf(stderr, "No driver ID found\n");
2984     return;
2985   }
2986   ret->id = perlquote(id + 7);
2987   if (debug) fprintf(stderr, "  Driver ID: %s\n", ret->id);
2988 
2989   /* Go through subnodes */
2990   cur1 = node->xmlChildrenNode;
2991   while (cur1 != NULL) {
2992     if ((!xmlStrcmp(cur1->name, (const xmlChar *) "name"))) {
2993       ret->name =
2994 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2995       if (debug) fprintf(stderr, "  Driver name: %s\n", ret->name);
2996     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "group"))) {
2997       ret->group =
2998 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
2999       if (debug) fprintf(stderr, "  Driver group (for localization): %s\n",
3000 			 ret->group);
3001     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "url"))) {
3002       ret->url =
3003 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
3004       if (debug) fprintf(stderr, "  Driver URL: %s\n", ret->url);
3005     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "obsolete"))) {
3006       ret->driver_obsolete = xmlGetProp(cur1, (const xmlChar *) "replace");
3007       if (ret->driver_obsolete == NULL) {
3008 	if (debug) fprintf(stderr, "    No replacement driver found!\n");
3009 	ret->driver_obsolete = (xmlChar *)"1";
3010       }
3011       if (debug) fprintf(stderr, "  Driver is obsolete: %s\n",
3012 			 ret->driver_obsolete);
3013     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "supplier"))) {
3014       if (debug)
3015 	fprintf(stderr, "  Driver supplier:\n");
3016       getLocalizedText(doc, cur1, &(ret->supplier), language, debug);
3017     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "manufacturersupplied"))) {
3018       ret->manufacturersupplied =
3019 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
3020       if ((ret->manufacturersupplied == NULL) ||
3021 	  (ret->manufacturersupplied[0] == '\0'))
3022 	ret->manufacturersupplied = (xmlChar *)"1";
3023       if (debug) fprintf(stderr, "  Driver supplied by manufacturer: %s\n",
3024 			 ret->manufacturersupplied);
3025     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "thirdpartysupplied"))) {
3026       ret->manufacturersupplied = (xmlChar *)"0";
3027       if (debug) fprintf(stderr, "  Driver supplied by a third party\n");
3028     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "license"))) {
3029       if (debug)
3030 	fprintf(stderr, "  Driver license:\n");
3031       getLocalizedText(doc, cur1, &(ret->license), language, debug);
3032     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "licensetext"))) {
3033       if (debug)
3034 	fprintf(stderr, "  Driver license text:\n");
3035       getLocalizedLicenseText(doc, cur1,
3036 			      &(ret->licensetext), &(ret->origlicensetext),
3037 			      &(ret->licenselink), &(ret->origlicenselink),
3038 			      language, debug);
3039     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "freesoftware"))) {
3040       ret->free = (xmlChar *)"1";
3041       if (debug) fprintf(stderr, "  Driver is free software\n");
3042     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "nonfreesoftware"))) {
3043       ret->free = (xmlChar *)"0";
3044       if (debug) fprintf(stderr, "  Driver is not free software\n");
3045     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "patents"))) {
3046       ret->patents = (xmlChar *)"1";
3047       if (debug) fprintf(stderr, "  There are patents applying to this driver's code\n");
3048     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "nopatents"))) {
3049       ret->patents = (xmlChar *)"0";
3050       if (debug) fprintf(stderr, "  There are no patents applying to this driver's code\n");
3051     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "supportcontacts"))) {
3052       cur2 = cur1->xmlChildrenNode;
3053       if (debug) fprintf(stderr, "  Driver support contacts:\n");
3054       while (cur2 != NULL) {
3055 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "supportcontact"))) {
3056 	  ret->num_supportcontacts ++;
3057 	  ret->supportcontacts =
3058 	    (xmlChar const **)
3059 	    realloc((xmlChar **)ret->supportcontacts,
3060 		    sizeof(xmlChar *) *
3061 		    ret->num_supportcontacts);
3062 	  ret->supportcontacturls =
3063 	    (xmlChar **)
3064 	    realloc((xmlChar **)ret->supportcontacturls,
3065 		    sizeof(xmlChar *) *
3066 		    ret->num_supportcontacts);
3067 	  ret->supportcontactlevels =
3068 	    (xmlChar **)
3069 	    realloc((xmlChar **)ret->supportcontactlevels,
3070 		    sizeof(xmlChar *) *
3071 		    ret->num_supportcontacts);
3072 	  level = xmlGetProp(cur2, (const xmlChar *) "level");
3073 	  if (level == NULL) {
3074 	    level = (xmlChar *)"Unknown";
3075 	  }
3076 	  url = xmlGetProp(cur2, (const xmlChar *) "url");
3077 	  ret->supportcontactlevels[ret->num_supportcontacts - 1] = level;
3078 	  ret->supportcontacturls[ret->num_supportcontacts - 1] = url;
3079 	  getLocalizedText
3080 	    (doc, cur2,
3081 	     &(ret->supportcontacts[ret->num_supportcontacts - 1]),
3082 	     language, debug);
3083 	  if (debug)
3084 	    fprintf(stderr, "    %s (%s):\n      %s\n",
3085 		    ret->supportcontacts[ret->num_supportcontacts - 1],
3086 		    ret->supportcontactlevels[ret->num_supportcontacts - 1],
3087 		    ret->supportcontacturls[ret->num_supportcontacts - 1]);
3088 	}
3089 	cur2 = cur2->next;
3090       }
3091     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "shortdescription"))) {
3092       if (debug)
3093 	fprintf(stderr, "  Driver short description:\n");
3094       getLocalizedText(doc, cur1, &(ret->shortdescription), language, debug);
3095     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "locales"))) {
3096       ret->locales =
3097 	perlquote(xmlNodeListGetString(doc, cur1->xmlChildrenNode, 1));
3098       if (debug) fprintf(stderr, "  Driver list of locales: %s\n", ret->locales);
3099     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "packages"))) {
3100       cur2 = cur1->xmlChildrenNode;
3101       if (debug) fprintf(stderr, "  Driver downloadable packages:\n");
3102       while (cur2 != NULL) {
3103 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "package"))) {
3104 	  ret->num_packages ++;
3105 	  ret->packageurls =
3106 	    (xmlChar **)
3107 	    realloc((xmlChar **)ret->packageurls,
3108 		    sizeof(xmlChar *) *
3109 		    ret->num_packages);
3110 	  ret->packagescopes =
3111 	    (xmlChar **)
3112 	    realloc((xmlChar **)ret->packagescopes,
3113 		    sizeof(xmlChar *) *
3114 		    ret->num_packages);
3115 	  scope = xmlGetProp(cur2, (const xmlChar *) "scope");
3116 	  ret->packagefingerprints =
3117 	    (xmlChar **)
3118 	    realloc((xmlChar **)ret->packagefingerprints,
3119 		    sizeof(xmlChar *) *
3120 		    ret->num_packages);
3121 	  fingerprint = xmlGetProp(cur2, (const xmlChar *) "fingerprint");
3122 	  ret->packageurls[ret->num_packages - 1] =
3123 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3124 	  ret->packagescopes[ret->num_packages - 1] = perlquote(scope);
3125 	  ret->packagefingerprints[ret->num_packages - 1] = perlquote(fingerprint);
3126 	  if (debug)
3127 	    fprintf(stderr, "    %s (%s), key fingerprint on %s\n",
3128 		    ret->packageurls[ret->num_packages - 1],
3129 		    ret->packagescopes[ret->num_packages - 1],\
3130 		    ret->packagefingerprints[ret->num_packages - 1]);
3131 	}
3132 	cur2 = cur2->next;
3133       }
3134     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "functionality"))) {
3135       cur2 = cur1->xmlChildrenNode;
3136       while (cur2 != NULL) {
3137 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "maxresx"))) {
3138 	  ret->maxresx =
3139 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3140 	  if (debug)
3141 	    fprintf(stderr, "  Driver functionality: Max X resolution: %s\n",
3142 		    ret->maxresx);
3143 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "maxresy"))) {
3144 	  ret->maxresy =
3145 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3146 	  if (debug)
3147 	    fprintf(stderr, "  Driver functionality: Max Y resolution: %s\n",
3148 		    ret->maxresy);
3149 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "color"))) {
3150 	  ret->color = (xmlChar *)"1";
3151 	  if (debug) fprintf(stderr, "  Driver functionality: Color\n");
3152 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "monochrome"))) {
3153 	  ret->color = (xmlChar *)"0";
3154 	  if (debug) fprintf(stderr, "  Driver functionality: Monochrome\n");
3155 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "text"))) {
3156 	  ret->text =
3157 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3158 	  if (debug)
3159 	    fprintf(stderr, "  Driver functionality: Text support rating: %s\n",
3160 		    ret->text);
3161 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "lineart"))) {
3162 	  ret->lineart =
3163 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3164 	  if (debug)
3165 	    fprintf(stderr, "  Driver functionality: Line art support rating: %s\n",
3166 		    ret->lineart);
3167 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "graphics"))) {
3168 	  ret->graphics =
3169 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3170 	  if (debug)
3171 	    fprintf(stderr, "  Driver functionality: Graphics support rating: %s\n",
3172 		    ret->graphics);
3173 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "photo"))) {
3174 	  ret->photo =
3175 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3176 	  if (debug)
3177 	    fprintf(stderr, "  Driver functionality: Photo support rating: %s\n",
3178 		    ret->photo);
3179 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "load"))) {
3180 	  ret->load =
3181 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3182 	  if (debug)
3183 	    fprintf(stderr, "  Driver functionality: System load rating: %s\n",
3184 		    ret->load);
3185 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "speed"))) {
3186 	  ret->speed =
3187 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3188 	  if (debug)
3189 	    fprintf(stderr, "  Driver functionality: Speed rating: %s\n",
3190 		    ret->speed);
3191      	}
3192 	cur2 = cur2->next;
3193       }
3194     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "execution"))) {
3195       cur2 = cur1->xmlChildrenNode;
3196       while (cur2 != NULL) {
3197 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "requires"))) {
3198 	  ret->num_requires ++;
3199 	  ret->requires =
3200 	    (xmlChar **)
3201 	    realloc((xmlChar **)ret->requires,
3202 		    sizeof(xmlChar *) *
3203 		    ret->num_requires);
3204 	  ret->requiresversion =
3205 	    (xmlChar **)
3206 	    realloc((xmlChar **)ret->requiresversion,
3207 		    sizeof(xmlChar *) *
3208 		    ret->num_requires);
3209 	  version = xmlGetProp(cur2, (const xmlChar *) "version");
3210 	  ret->requires[ret->num_requires - 1] =
3211 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3212 	  ret->requiresversion[ret->num_requires - 1] = perlquote(version);
3213 	  if (debug) {
3214 	    if (!version)
3215 	      fprintf(stderr, "  Driver requires driver: %s\n",
3216 		      ret->requires[ret->num_requires - 1]);
3217 	    else
3218 	      fprintf(stderr, "  Driver requires driver: %s (%s)\n",
3219 		      ret->requires[ret->num_requires - 1],
3220 		      ret->requiresversion[ret->num_requires - 1]); }
3221 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "cups"))) {
3222 	  ret->driver_type = (xmlChar *)"C";
3223 	  if (debug) fprintf(stderr, "  Driver type: CUPS Raster\n");
3224 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ijs"))) {
3225 	  ret->driver_type = (xmlChar *)"I";
3226 	  if (debug) fprintf(stderr, "  Driver type: IJS\n");
3227 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "opvp"))) {
3228 	  ret->driver_type = (xmlChar *)"V";
3229 	  if (debug) fprintf(stderr, "  Driver type: OpenPrinting Vector\n");
3230 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ghostscript"))) {
3231 	  ret->driver_type = (xmlChar *)"G";
3232 	  if (debug) fprintf(stderr, "  Driver type: Ghostscript built-in\n");
3233 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "filter"))) {
3234 	  ret->driver_type = (xmlChar *)"F";
3235 	  if (debug) fprintf(stderr, "  Driver type: Filter\n");
3236 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "uniprint"))) {
3237 	  ret->driver_type = (xmlChar *)"U";
3238 	  if (debug) fprintf(stderr, "  Driver type: Ghostscript Uniprint\n");
3239 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "postscript"))) {
3240 	  ret->driver_type = (xmlChar *)"P";
3241 	  if (debug) fprintf(stderr, "  Driver type: PostScript\n");
3242 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "prototype"))) {
3243 	  ret->cmd =
3244 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3245 	  if (debug) fprintf(stderr, "  Driver command line:\n\n    %s\n\n",
3246 			     ret->cmd);
3247 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "prototype_pdf"))) {
3248 	  ret->cmd_pdf =
3249 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3250 	  if (debug) fprintf(stderr, "  Driver PDF command line:\n\n    %s\n\n",
3251 			     ret->cmd_pdf);
3252 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "ppdentry"))) {
3253 	  ret->driverppdentry =
3254 	    perlquote(xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1));
3255 	  if (debug) fprintf(stderr, "  Extra lines for PPD file:\n%s\n",
3256 			     ret->driverppdentry);
3257 	} else if ((!xmlStrcmp(cur2->name, (const xmlChar *) "margins"))) {
3258 	  parseMargins(doc, cur2, &(ret->drivermargins), language, debug);
3259      	}
3260 	cur2 = cur2->next;
3261       }
3262     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "comments"))) {
3263       if (debug)
3264 	fprintf(stderr, "  Comment:\n");
3265       getLocalizedText(doc, cur1, &(ret->comment), language, debug);
3266     } else if ((!xmlStrcmp(cur1->name, (const xmlChar *) "printers"))) {
3267       cur2 = cur1->xmlChildrenNode;
3268       while (cur2 != NULL) {
3269 	if ((!xmlStrcmp(cur2->name, (const xmlChar *) "printer"))) {
3270 	  ret->num_printers ++;
3271 	  ret->printers =
3272 	    (drvPrnEntryPtr *)realloc((drvPrnEntryPtr *)ret->printers,
3273 				      sizeof(drvPrnEntryPtr) *
3274 				      ret->num_printers);
3275 	  entry = (drvPrnEntryPtr) malloc(sizeof(drvPrnEntry));
3276 	  if (entry == NULL) {
3277 	    fprintf(stderr,"Out of memory!\n");
3278 	    xmlFreeDoc(doc);
3279 	    exit(1);
3280 	  }
3281 	  ret->printers[ret->num_printers-1] = entry;
3282 	  memset(entry, 0, sizeof(drvPrnEntry));
3283 	  entry->id = NULL;
3284 	  entry->comment = NULL;
3285           entry->excmaxresx = NULL;
3286 	  entry->excmaxresy = NULL;
3287 	  entry->exccolor = NULL;
3288 	  entry->exctext = NULL;
3289 	  entry->exclineart = NULL;
3290 	  entry->excgraphics = NULL;
3291 	  entry->excphoto = NULL;
3292 	  entry->excload = NULL;
3293 	  entry->excspeed = NULL;
3294 	  if (debug) fprintf(stderr, "  Driver supports printer:\n");
3295 	  cur3 = cur2->xmlChildrenNode;
3296 	  while (cur3 != NULL) {
3297 	    if ((!xmlStrcmp(cur3->name, (const xmlChar *) "id"))) {
3298 	      id =
3299 		xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
3300 	      entry->id = perlquote(id + 8);
3301 	      if (debug) fprintf(stderr, "    ID: %s\n",
3302 				 entry->id);
3303 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "comments"))) {
3304 	      if (debug)
3305 		fprintf(stderr, "    Comment:\n");
3306 	      getLocalizedText(doc, cur3, &(entry->comment), language, debug);
3307 	    } else if ((!xmlStrcmp(cur3->name, (const xmlChar *) "functionality"))) {
3308 	      cur4 = cur3->xmlChildrenNode;
3309 	      while (cur4 != NULL) {
3310 		if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresx"))) {
3311 		  entry->excmaxresx =
3312 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3313 		  if (debug)
3314 		    fprintf(stderr, "  Printer exception: Maximum X resolution: %s\n",
3315 			    entry->excmaxresx);
3316 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "maxresy"))) {
3317 		  entry->excmaxresy =
3318 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3319 		  if (debug)
3320 		    fprintf(stderr, "  Printer exception: Maximum Y resolution: %s\n",
3321 			    entry->excmaxresy);
3322 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "monochrome"))) {
3323 		  entry->exccolor = (xmlChar *)"0";
3324 		  if (debug)
3325 		    fprintf(stderr, "  Printer exception: Color: %s\n",
3326 			    entry->exccolor);
3327 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "color"))) {
3328 		  entry->exccolor = (xmlChar *)"1";
3329 		  if (debug)
3330 		    fprintf(stderr, "  Printer exception: Color: %s\n",
3331 			    entry->exccolor);
3332 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "text"))) {
3333 		  entry->exctext =
3334 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3335 		  if (debug)
3336 		    fprintf(stderr, "  Printer exception: Support level for text: %s\n",
3337 			    entry->exctext);
3338 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "lineart"))) {
3339 		  entry->exclineart =
3340 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3341 		  if (debug)
3342 		    fprintf(stderr, "  Printer exception: Support level for line art: %s\n",
3343 			    entry->exclineart);
3344 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "graphics"))) {
3345 		  entry->excgraphics =
3346 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3347 		  if (debug)
3348 		    fprintf(stderr, "  Printer exception: Support level for graphics: %s\n",
3349 			    entry->excgraphics);
3350 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "photo"))) {
3351 		  entry->excphoto =
3352 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3353 		  if (debug)
3354 		    fprintf(stderr, "  Printer exception: Support level for photos: %s\n",
3355 			    entry->excphoto);
3356 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "load"))) {
3357 		  entry->excload =
3358 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3359 		  if (debug)
3360 		    fprintf(stderr, "  Printer exception: Expected relative system load: %s\n",
3361 			    entry->excload);
3362 		} else if ((!xmlStrcmp(cur4->name, (const xmlChar *) "speed"))) {
3363 		  entry->excspeed =
3364 		    perlquote(xmlNodeListGetString(doc, cur4->xmlChildrenNode, 1));
3365 		  if (debug)
3366 		    fprintf(stderr, "  Printer exception: Expected relative driver speed: %s\n",
3367 			    entry->excspeed);
3368 		}
3369 		cur4 = cur4->next;
3370 	      }
3371 	    }
3372 	    cur3 = cur3->next;
3373 	  }
3374 	}
3375 	cur2 = cur2->next;
3376       }
3377     }
3378     cur1 = cur1->next;
3379   }
3380 }
3381 
3382 static xmlDocPtr /* O - Tree with data parsed from stdin */
parseXMLFromStdin()3383 parseXMLFromStdin() {
3384 
3385   FILE *f;
3386   xmlDocPtr doc = NULL;
3387 
3388   if (stdin != NULL) {
3389     int res, size = 1024;
3390     char chars[1024];
3391     xmlParserCtxtPtr ctxt;
3392 
3393     res = fread(chars, 1, 4, stdin);
3394     if (res > 0) {
3395       ctxt = xmlCreatePushParserCtxt(NULL, NULL,
3396 				     chars, res, NULL);
3397       while ((res = fread(chars, 1, size, stdin)) > 0) {
3398 	xmlParseChunk(ctxt, chars, res, 0);
3399       }
3400       xmlParseChunk(ctxt, chars, 0, 1);
3401       doc = ctxt->myDoc;
3402       xmlFreeParserCtxt(ctxt);
3403     }
3404   }
3405   return doc;
3406 }
3407 
3408 static overviewPtr     /* O - C data structure of overview */
parseOverviewFile(char * filename,xmlChar const language[],int debug)3409 parseOverviewFile(char *filename, /* I - Input file name, NULL: stdin */
3410 		  xmlChar const language [], /* I - User language */
3411 		  int debug) { /* I - Debug mode flag */
3412   xmlDocPtr      doc;  /* Output of XML parser */
3413   overviewPtr    ret;  /* C data structure of overview */
3414   xmlNodePtr     cur;  /* XML node currently worked on */
3415   driverEntryPtr driver;
3416 
3417   /*
3418    * build an XML tree from a file or stdin;
3419    */
3420 
3421   if (filename == NULL) {
3422     doc = parseXMLFromStdin();
3423   } else {
3424     doc = xmlParseFile(filename);
3425   }
3426   if (doc == NULL) return(NULL);
3427 
3428   /*
3429    * Check the document is of the right kind
3430    */
3431 
3432   cur = xmlDocGetRootElement(doc);
3433   if (cur == NULL) {
3434     fprintf(stderr,"Empty input document!\n");
3435     xmlFreeDoc(doc);
3436     return(NULL);
3437   }
3438 
3439   if (xmlStrcmp(cur->name, (const xmlChar *) "overview")) {
3440     fprintf(stderr,"Input document is not a Foomatic overview XML file (no \"<overview>\" tag)!\n");
3441     xmlFreeDoc(doc);
3442     return(NULL);
3443   }
3444 
3445   /*
3446    * Allocate the structure to be returned.
3447    */
3448   ret = (overviewPtr) malloc(sizeof(overview));
3449   if (ret == NULL) {
3450     fprintf(stderr,"Out of memory!\n");
3451     xmlFreeDoc(doc);
3452     return(NULL);
3453   }
3454   memset(ret, 0, sizeof(overview));
3455   ret->num_overviewPrinters = 0;
3456   ret->overviewPrinters = NULL;
3457 
3458   /*
3459    * Now, walk through the tree.
3460    */
3461 
3462   /* On the first level we have the printer entries */
3463 
3464   cur = cur->xmlChildrenNode;
3465   while (cur) {
3466     if (xmlIsBlankNode(cur)) {
3467       cur = cur->next;
3468       continue;
3469     }
3470     if (!xmlStrcmp(cur->name, (const xmlChar *) "driver")) {
3471       ret->num_overviewDrivers ++;
3472       ret->overviewDrivers =
3473 	(driverEntryPtr *)realloc
3474 	((driverEntryPtr *)(ret->overviewDrivers),
3475 	 sizeof(driverEntryPtr) * ret->num_overviewDrivers);
3476       driver = (driverEntryPtr) malloc(sizeof(driverEntry));
3477       if (driver == NULL) {
3478 	fprintf(stderr,"Out of memory!\n");
3479 	xmlFreeDoc(doc);
3480 	exit(1);
3481       }
3482       ret->overviewDrivers[ret->num_overviewDrivers-1] = driver;
3483       memset(driver, 0, sizeof(driverEntry));
3484       if (debug) fprintf(stderr, "--> Parsing driver data\n");
3485       parseDriverEntry(doc, cur, driver, language, debug);
3486     } else if (!xmlStrcmp(cur->name, (const xmlChar *) "printer")) {
3487       if (debug) fprintf(stderr, "--> Parsing printer data\n");
3488       parseOverviewPrinter(doc, cur, ret, language, debug);
3489     }
3490     cur = cur->next;
3491   }
3492 
3493   /* We succeeded, return the result */
3494 
3495   return(ret);
3496 }
3497 
3498 static comboDataPtr   /* O - C data structure of printer/driver combo */
parseComboFile(char * filename,xmlChar const language[],int debug)3499 parseComboFile(char *filename, /* I - Input file name, NULL: stdin */
3500 	       xmlChar const language [], /* I - User language */
3501 	       int debug) { /* I - Debug mode flag */
3502   xmlDocPtr      doc;  /* Output of XML parser */
3503   comboDataPtr   ret;  /* C data structure of printer/driver combo */
3504   xmlNodePtr     cur;  /* XML node currently worked on */
3505 
3506   /*
3507    * build an XML tree from a file or stdin;
3508    */
3509 
3510   if (filename == NULL) {
3511     doc = parseXMLFromStdin();
3512   } else {
3513     doc = xmlParseFile(filename);
3514   }
3515   if (doc == NULL) return(NULL);
3516 
3517   /*
3518    * Check the document is of the right kind
3519    */
3520 
3521   cur = xmlDocGetRootElement(doc);
3522   if (cur == NULL) {
3523     fprintf(stderr,"Empty input document!\n");
3524     xmlFreeDoc(doc);
3525     return(NULL);
3526   }
3527 
3528   if (xmlStrcmp(cur->name, (const xmlChar *) "foomatic")) {
3529     fprintf(stderr,"Input document is not a Foomatic combo XML file (no \"<foomatic>\" tag)!\n");
3530     xmlFreeDoc(doc);
3531     return(NULL);
3532   }
3533 
3534   /*
3535    * Allocate the structure to be returned.
3536    */
3537   ret = (comboDataPtr) malloc(sizeof(comboData));
3538   if (ret == NULL) {
3539     fprintf(stderr,"Out of memory!\n");
3540     xmlFreeDoc(doc);
3541     return(NULL);
3542   }
3543   memset(ret, 0, sizeof(comboData));
3544   ret->make = NULL;
3545   ret->driver = NULL;
3546   ret->num_args = 0;
3547   ret->args = NULL;
3548 
3549   /*
3550    * Now, walk through the tree.
3551    */
3552 
3553   /* On the first level we have the printer, the driver,
3554      and the options */
3555 
3556   cur = cur->xmlChildrenNode;
3557   while (cur) {
3558     if (xmlIsBlankNode(cur)) {
3559       cur = cur->next;
3560       continue;
3561     }
3562     if (!xmlStrcmp(cur->name, (const xmlChar *) "printer")) {
3563       if (debug) fprintf(stderr, "--> Parsing printer data\n");
3564       parseComboPrinter(doc, cur, ret, language, debug);
3565     } else if (!xmlStrcmp(cur->name, (const xmlChar *) "driver")) {
3566       if (debug) fprintf(stderr, "--> Parsing driver data\n");
3567       parseComboDriver(doc, cur, ret, language, debug);
3568     } else if (!xmlStrcmp(cur->name, (const xmlChar *) "options")) {
3569       if (debug) fprintf(stderr, "--> Parsing option data\n");
3570       parseOptions(doc, cur, ret, language, debug);
3571     }
3572     cur = cur->next;
3573   }
3574 
3575   /* All sections present in combo XML? */
3576 
3577   if (ret->make == NULL) {
3578     fprintf(stderr,"\"<printer>\" tag not found!\n");
3579     exit(1);
3580   }
3581 
3582   if (ret->driver == NULL) {
3583     fprintf(stderr,"\"<driver>\" tag not found!\n");
3584     exit(1);
3585   }
3586 
3587   /* We succeeded, return the result */
3588 
3589   return(ret);
3590 }
3591 
3592 static printerEntryPtr     /* O - C data structure of printer entry */
parsePrinterFile(char * filename,xmlChar const language[],int debug)3593 parsePrinterFile(char *filename, /* I - Input file name, NULL: stdin */
3594 		 xmlChar const language [], /* I - User language */
3595 		 int debug) { /* I - Debug mode flag */
3596   xmlDocPtr       doc;  /* Output of XML parser */
3597   printerEntryPtr ret;  /* C data structure of printer entry */
3598   xmlNodePtr      cur;  /* XML node currently worked on */
3599 
3600   /*
3601    * build an XML tree from a file or stdin;
3602    */
3603 
3604   if (filename == NULL) {
3605     doc = parseXMLFromStdin();
3606   } else {
3607     doc = xmlParseFile(filename);
3608   }
3609   if (doc == NULL) return(NULL);
3610 
3611   /*
3612    * Check the document is of the right kind
3613    */
3614 
3615   cur = xmlDocGetRootElement(doc);
3616   if (cur == NULL) {
3617     fprintf(stderr,"Empty input document!\n");
3618     xmlFreeDoc(doc);
3619     return(NULL);
3620   }
3621 
3622   if (xmlStrcmp(cur->name, (const xmlChar *) "printer")) {
3623     fprintf(stderr,"Input document is not a Foomatic printer XML file (no \"<printer>\" tag)!\n");
3624     xmlFreeDoc(doc);
3625     return(NULL);
3626   }
3627 
3628   /*
3629    * Allocate the structure to be returned.
3630    */
3631   ret = (printerEntryPtr) malloc(sizeof(printerEntry));
3632   if (ret == NULL) {
3633     fprintf(stderr,"Out of memory!\n");
3634     xmlFreeDoc(doc);
3635     return(NULL);
3636   }
3637   memset(ret, 0, sizeof(printerEntry));
3638 
3639   /*
3640    * Now, walk through the tree.
3641    */
3642 
3643   if (debug) fprintf(stderr, "--> Parsing printer data\n");
3644   parsePrinterEntry(doc, cur, ret, language, debug);
3645 
3646   /* We succeeded, return the result */
3647 
3648   return(ret);
3649 }
3650 
3651 static driverEntryPtr     /* O - C data structure of driver entry */
parseDriverFile(char * filename,xmlChar const language[],int debug)3652 parseDriverFile(char *filename, /* I - Input file name, NULL: stdin */
3653 		xmlChar const language [], /* I - User language */
3654 		int debug) { /* I - Debug mode flag */
3655   xmlDocPtr       doc;  /* Output of XML parser */
3656   driverEntryPtr  ret;  /* C data structure of driver entry */
3657   xmlNodePtr      cur;  /* XML node currently worked on */
3658 
3659   /*
3660    * build an XML tree from a file or stdin;
3661    */
3662 
3663   if (filename == NULL) {
3664     doc = parseXMLFromStdin();
3665   } else {
3666     doc = xmlParseFile(filename);
3667   }
3668   if (doc == NULL) return(NULL);
3669 
3670   /*
3671    * Check the document is of the right kind
3672    */
3673 
3674   cur = xmlDocGetRootElement(doc);
3675   if (cur == NULL) {
3676     fprintf(stderr,"Empty input document!\n");
3677     xmlFreeDoc(doc);
3678     return(NULL);
3679   }
3680 
3681   if (xmlStrcmp(cur->name, (const xmlChar *) "driver")) {
3682     fprintf(stderr,"Input document is not a Foomatic driver XML file (no \"<driver>\" tag)!\n");
3683     xmlFreeDoc(doc);
3684     return(NULL);
3685   }
3686 
3687   /*
3688    * Allocate the structure to be returned.
3689    */
3690   ret = (driverEntryPtr) malloc(sizeof(driverEntry));
3691   if (ret == NULL) {
3692     fprintf(stderr,"Out of memory!\n");
3693     xmlFreeDoc(doc);
3694     return(NULL);
3695   }
3696   memset(ret, 0, sizeof(driverEntry));
3697 
3698   /*
3699    * Now, walk through the tree.
3700    */
3701 
3702   if (debug) fprintf(stderr, "--> Parsing driver data\n");
3703   parseDriverEntry(doc, cur, ret, language, debug);
3704 
3705   /* We succeeded, return the result */
3706 
3707   return(ret);
3708 }
3709 
3710 void
prepareComboData(comboDataPtr combo,xmlChar ** defaultsettings,int num_defaultsettings,int debug)3711 prepareComboData(comboDataPtr combo, /* I/O - Foomatic combo data parsed
3712 					from XML input */
3713 		 xmlChar **defaultsettings, /* User-supplied default option
3714 					    settings */
3715 		 int num_defaultsettings, /* number of default option
3716 					     settings */
3717 		 int debug) { /* Debug flag */
3718 
3719   int i, j; /* loop variables */
3720   xmlChar *option, *value, *s;/* User option and value, temporary pointer */
3721 
3722   /* Insert the default values (not choice IDs) for the enumerated
3723      options */
3724 
3725   for (i = 0; i < combo->num_args; i ++) {
3726     for (j = 0; j < combo->args[i]->num_choices; j ++) {
3727       if (!xmlStrcmp(combo->args[i]->choices[j]->idx,
3728 		     combo->args[i]->default_value)) {
3729 	combo->args[i]->default_value = combo->args[i]->choices[j]->value;
3730 	if (debug)
3731 	  fprintf(stderr,
3732 		  "  Setting default value for enumerated option %s: %s\n",
3733 		  combo->args[i]->name,
3734 		  combo->args[i]->default_value);
3735       }
3736     }
3737   }
3738 
3739   /* Insert the user-supplied defaults */
3740 
3741   for (i = 0; i < num_defaultsettings; i ++) {
3742     s =
3743     xmlStrchr ((defaultsettings[i]), '=')
3744     - (defaultsettings[i]) + (defaultsettings[i]);
3745     *s = (xmlChar)'\0';
3746     s ++;
3747     option = defaultsettings[i];
3748     value = s;
3749     for (j = 0; j < combo->num_args; j ++) {
3750       if (!xmlStrcmp(combo->args[j]->name, option)) {
3751 	combo->args[j]->default_value = value;
3752 	if (debug) fprintf(stderr,
3753 			   "  Setting user default for option %s: %s\n",
3754 			   combo->args[j]->name,
3755 			   combo->args[j]->default_value);
3756       }
3757     }
3758   }
3759 
3760 }
3761 
3762 void
generateOverviewPerlData(overviewPtr overview,int debug)3763 generateOverviewPerlData(overviewPtr overview, /* I/O - Foomatic overview
3764 						  data parsed from XML
3765 						  input */
3766 			 int debug) { /* Debug flag */
3767 
3768   int i, j, k, l; /* loop variables */
3769   overviewPrinterPtr printer;
3770 
3771   printf("$VAR1 = [\n");
3772   for (i = 0; i < overview->num_overviewPrinters; i ++) {
3773     printer = overview->overviewPrinters[i];
3774     printf("          {\n");
3775     printf("            'id' => '%s',\n", printer->id);
3776     printf("            'make' => '%s',\n", printer->make);
3777     printf("            'model' => '%s',\n", printer->model);
3778     if (printer->general_ieee) {
3779       printf("            'general_ieee' => '%s',\n",
3780 	     printer->general_ieee);
3781     }
3782     if (printer->general_mfg) {
3783       printf("            'general_mfg' => '%s',\n", printer->general_mfg);
3784     }
3785     if (printer->general_mdl) {
3786       printf("            'general_mdl' => '%s',\n", printer->general_mdl);
3787     }
3788     if (printer->general_des) {
3789       printf("            'general_des' => '%s',\n", printer->general_des);
3790     }
3791     if (printer->general_cmd) {
3792       printf("            'general_cmd' => '%s',\n", printer->general_cmd);
3793     }
3794     if (printer->par_ieee) {
3795       printf("            'par_ieee' => '%s',\n", printer->par_ieee);
3796     }
3797     if (printer->par_mfg) {
3798       printf("            'par_mfg' => '%s',\n", printer->par_mfg);
3799     }
3800     if (printer->par_mdl) {
3801       printf("            'par_mdl' => '%s',\n", printer->par_mdl);
3802     }
3803     if (printer->par_des) {
3804       printf("            'par_des' => '%s',\n", printer->par_des);
3805     }
3806     if (printer->par_cmd) {
3807       printf("            'par_cmd' => '%s',\n", printer->par_cmd);
3808     }
3809     if (printer->usb_ieee) {
3810       printf("            'usb_ieee' => '%s',\n", printer->usb_ieee);
3811     }
3812     if (printer->usb_mfg) {
3813       printf("            'usb_mfg' => '%s',\n", printer->usb_mfg);
3814     }
3815     if (printer->usb_mdl) {
3816       printf("            'usb_mdl' => '%s',\n", printer->usb_mdl);
3817     }
3818     if (printer->usb_des) {
3819       printf("            'usb_des' => '%s',\n", printer->usb_des);
3820     }
3821     if (printer->usb_cmd) {
3822       printf("            'usb_cmd' => '%s',\n", printer->usb_cmd);
3823     }
3824     if (printer->snmp_ieee) {
3825       printf("            'snmp_ieee' => '%s',\n", printer->snmp_ieee);
3826     }
3827     if (printer->snmp_mfg) {
3828       printf("            'snmp_mfg' => '%s',\n", printer->snmp_mfg);
3829     }
3830     if (printer->snmp_mdl) {
3831       printf("            'snmp_mdl' => '%s',\n", printer->snmp_mdl);
3832     }
3833     if (printer->snmp_des) {
3834       printf("            'snmp_des' => '%s',\n", printer->snmp_des);
3835     }
3836     if (printer->snmp_cmd) {
3837       printf("            'snmp_cmd' => '%s',\n", printer->snmp_cmd);
3838     }
3839     printf("            'functionality' => '%s',\n",
3840 	   printer->functionality);
3841     if (printer->unverified) {
3842       printf("            'unverified' => 1,\n");
3843     } else {
3844       printf("            'unverified' => 0,\n");
3845     }
3846     if (printer->noxmlentry) {
3847       printf("            'noxmlentry' => 1,\n");
3848     } else {
3849       printf("            'noxmlentry' => 0,\n");
3850     }
3851     if (printer->driver) {
3852       printf("            'driver' => '%s',\n", printer->driver);
3853     }
3854     if (printer->num_drivers > 0) {
3855       printf("            'drivers' => [\n");
3856       for (j = 0; j < printer->num_drivers; j ++)
3857 	if (printer->drivers[j]->name != NULL)
3858 	  printf("                           '%s',\n",
3859 		 printer->drivers[j]->name);
3860       printf("                         ],\n");
3861       printf("            'driverproperties' => {\n");
3862       for (j = 0; j < printer->num_drivers; j ++) {
3863 	for (k = 0; k < overview->num_overviewDrivers; k ++) {
3864 	  if (!xmlStrcmp(overview->overviewDrivers[k]->name,
3865 			 printer->drivers[j]->name)) break;
3866 	}
3867 	if ((k < overview->num_overviewDrivers) &&
3868 	    (!xmlStrcmp(overview->overviewDrivers[k]->name,
3869 			printer->drivers[j]->name))) {
3870 	  printf("              '%s' => {\n",
3871 		 printer->drivers[j]->name);
3872 	  if (overview->overviewDrivers[k]->group != NULL) {
3873 	    printf("                'group' => '%s',\n",
3874 		   overview->overviewDrivers[k]->group);
3875 	  }
3876 	  if (overview->overviewDrivers[k]->url != NULL) {
3877 	    printf("                'url' => '%s',\n",
3878 		   overview->overviewDrivers[k]->url);
3879 	  }
3880 	  if (overview->overviewDrivers[k]->driver_obsolete != NULL) {
3881 	    printf("                'obsolete' => '%s',\n",
3882 		   overview->overviewDrivers[k]->driver_obsolete);
3883 	  }
3884 	  if (overview->overviewDrivers[k]->supplier != NULL) {
3885 	    printf("                'supplier' => '%s',\n",
3886 		   overview->overviewDrivers[k]->supplier);
3887 	  }
3888 	  if (overview->overviewDrivers[k]->manufacturersupplied != NULL) {
3889 	    printf("                'manufacturersupplied' => '%s',\n",
3890 		   overview->overviewDrivers[k]->manufacturersupplied);
3891 	  }
3892 	  if (overview->overviewDrivers[k]->license != NULL) {
3893 	    printf("                'license' => '%s',\n",
3894 		   overview->overviewDrivers[k]->license);
3895 	  }
3896 	  if (overview->overviewDrivers[k]->licensetext != NULL) {
3897 	    printf("                'licensetext' => '%s',\n",
3898 		   overview->overviewDrivers[k]->licensetext);
3899 	  }
3900 	  if (overview->overviewDrivers[k]->origlicensetext != NULL) {
3901 	    printf("                'origlicensetext' => '%s',\n",
3902 		   overview->overviewDrivers[k]->origlicensetext);
3903 	  }
3904 	  if (overview->overviewDrivers[k]->licenselink != NULL) {
3905 	    printf("                'licenselink' => '%s',\n",
3906 		   overview->overviewDrivers[k]->licenselink);
3907 	  }
3908 	  if (overview->overviewDrivers[k]->origlicenselink != NULL) {
3909 	    printf("                'origlicenselink' => '%s',\n",
3910 		   overview->overviewDrivers[k]->origlicenselink);
3911 	  }
3912 	  if (overview->overviewDrivers[k]->free != NULL) {
3913 	    printf("                'free' => '%s',\n",
3914 		   overview->overviewDrivers[k]->free);
3915 	  }
3916 	  if (overview->overviewDrivers[k]->patents != NULL) {
3917 	    printf("                'patents' => '%s',\n",
3918 		   overview->overviewDrivers[k]->patents);
3919 	  }
3920 	  if (overview->overviewDrivers[k]->num_supportcontacts != 0) {
3921 	    printf("                'supportcontacts' => [\n");
3922 	    for (l = 0;
3923 		 l < overview->overviewDrivers[k]->num_supportcontacts; l ++) {
3924 	      if (overview->overviewDrivers[k]->supportcontacturls[l] !=
3925 		  NULL) {
3926 		printf("                  {\n");
3927 		printf("                    'description' => '%s',\n",
3928 		       overview->overviewDrivers[k]->supportcontacts[l]);
3929 		if (overview->overviewDrivers[k]->supportcontacturls[l]
3930 		    != NULL)
3931 		  printf("                    'url' => '%s',\n",
3932 			 overview->overviewDrivers[k]->supportcontacturls[l]);
3933 		printf("                    'level' => '%s',\n",
3934 		       overview->overviewDrivers[k]->supportcontactlevels[l]);
3935 		printf("                  },\n");
3936 	      }
3937 	    }
3938 	    printf("                ],\n");
3939 	  }
3940 	  if (overview->overviewDrivers[k]->shortdescription != NULL) {
3941 	    printf("                'shortdescription' => '%s',\n",
3942 		   overview->overviewDrivers[k]->shortdescription);
3943 	  }
3944 	  if (overview->overviewDrivers[k]->locales != NULL) {
3945 	    printf("                'locales' => '%s',\n",
3946 		   overview->overviewDrivers[k]->locales);
3947 	  }
3948 	  if (overview->overviewDrivers[k]->num_packages != 0) {
3949 	    printf("                'packages' => [\n");
3950 	    for (l = 0;
3951 		 l < overview->overviewDrivers[k]->num_packages; l ++) {
3952 	      if (overview->overviewDrivers[k]->packageurls[l] !=
3953 		  NULL) {
3954 		printf("                  {\n");
3955 		printf("                    'url' => '%s',\n",
3956 		       overview->overviewDrivers[k]->packageurls[l]);
3957 		if (overview->overviewDrivers[k]->packagescopes[l]
3958 		    != NULL)
3959 		  printf("                    'scope' => '%s',\n",
3960 			 overview->overviewDrivers[k]->packagescopes[l]);
3961 		if (overview->overviewDrivers[k]->packagefingerprints[l]
3962 		    != NULL)
3963 		  printf("                    'fingerprint' => '%s',\n",
3964 			 overview->overviewDrivers[k]->packagefingerprints[l]);
3965 		printf("                  },\n");
3966 	      }
3967 	    }
3968 	    printf("                ],\n");
3969 	  }
3970 	  if (overview->overviewDrivers[k]->num_requires != 0) {
3971 	    printf("                'requires' => [\n");
3972 	    for (l = 0;
3973 		 l < overview->overviewDrivers[k]->num_requires; l ++) {
3974 	      if (overview->overviewDrivers[k]->requires[l] !=
3975 		  NULL) {
3976 		printf("                  {\n");
3977 		printf("                    'driver' => '%s',\n",
3978 		       overview->overviewDrivers[k]->requires[l]);
3979 		if (overview->overviewDrivers[k]->requiresversion[l]
3980 		    != NULL)
3981 		  printf("                    'version' => '%s',\n",
3982 			 overview->overviewDrivers[k]->requiresversion[l]);
3983 		printf("                  },\n");
3984 	      }
3985 	    }
3986 	    printf("                ],\n");
3987 	  }
3988 	  if (overview->overviewDrivers[k]->driver_type != NULL) {
3989 	    printf("                'type' => '%s',\n",
3990 		   overview->overviewDrivers[k]->driver_type);
3991 	  }
3992 	  if (printer->drivers[j]->excmaxresx != NULL) {
3993 	    printf("                'drvmaxresx' => '%s',\n",
3994 		   printer->drivers[j]->excmaxresx);
3995 	  } else if (overview->overviewDrivers[k]->maxresx != NULL) {
3996 	    printf("                'drvmaxresx' => '%s',\n",
3997 		   overview->overviewDrivers[k]->maxresx);
3998 	  }
3999 	  if (printer->drivers[j]->excmaxresy != NULL) {
4000 	    printf("                'drvmaxresy' => '%s',\n",
4001 		   printer->drivers[j]->excmaxresy);
4002 	  } else if (overview->overviewDrivers[k]->maxresy != NULL) {
4003 	    printf("                'drvmaxresy' => '%s',\n",
4004 		   overview->overviewDrivers[k]->maxresy);
4005 	  }
4006 	  if (printer->drivers[j]->exccolor != NULL) {
4007 	    printf("                'drvcolor' => '%s',\n",
4008 		   printer->drivers[j]->exccolor);
4009 	  } else if (overview->overviewDrivers[k]->color != NULL) {
4010 	    printf("                'drvcolor' => '%s',\n",
4011 		   overview->overviewDrivers[k]->color);
4012 	  }
4013 	  if (printer->drivers[j]->exctext != NULL) {
4014 	    printf("                'text' => '%s',\n",
4015 		   printer->drivers[j]->exctext);
4016 	  } else if (overview->overviewDrivers[k]->text != NULL) {
4017 	    printf("                'text' => '%s',\n",
4018 		   overview->overviewDrivers[k]->text);
4019 	  }
4020 	  if (printer->drivers[j]->exclineart != NULL) {
4021 	    printf("                'lineart' => '%s',\n",
4022 		   printer->drivers[j]->exclineart);
4023 	  } else if (overview->overviewDrivers[k]->lineart != NULL) {
4024 	    printf("                'lineart' => '%s',\n",
4025 		   overview->overviewDrivers[k]->lineart);
4026 	  }
4027 	  if (printer->drivers[j]->excgraphics != NULL) {
4028 	    printf("                'graphics' => '%s',\n",
4029 		   printer->drivers[j]->excgraphics);
4030 	  } else if (overview->overviewDrivers[k]->graphics != NULL) {
4031 	    printf("                'graphics' => '%s',\n",
4032 		   overview->overviewDrivers[k]->graphics);
4033 	  }
4034 	  if (printer->drivers[j]->excphoto != NULL) {
4035 	    printf("                'photo' => '%s',\n",
4036 		   printer->drivers[j]->excphoto);
4037 	  } else if (overview->overviewDrivers[k]->photo != NULL) {
4038 	    printf("                'photo' => '%s',\n",
4039 		   overview->overviewDrivers[k]->photo);
4040 	  }
4041 	  if (printer->drivers[j]->excload != NULL) {
4042 	    printf("                'load' => '%s',\n",
4043 		   printer->drivers[j]->excload);
4044 	  } else if (overview->overviewDrivers[k]->load != NULL) {
4045 	    printf("                'load' => '%s',\n",
4046 		   overview->overviewDrivers[k]->load);
4047 	  }
4048 	  if (printer->drivers[j]->excspeed != NULL) {
4049 	    printf("                'speed' => '%s',\n",
4050 		   printer->drivers[j]->excspeed);
4051 	  } else if (overview->overviewDrivers[k]->speed != NULL) {
4052 	    printf("                'speed' => '%s',\n",
4053 		   overview->overviewDrivers[k]->speed);
4054 	  }
4055 	  printf("              },\n");
4056 	}
4057       }
4058       printf("            },\n");
4059     } else {
4060       printf("            'drivers' => [],\n");
4061     }
4062     if (printer->num_ppdfiles > 0) {
4063       printf("            'ppds' => [\n");
4064       for (j = 0; j < printer->num_ppdfiles; j ++)
4065 	if ((printer->ppdfiles[j]->driver != NULL) &&
4066 	    (printer->ppdfiles[j]->filename != NULL)) {
4067 	  printf("                        {\n");
4068 	  printf("                          'driver' => '%s',\n",
4069 		 printer->ppdfiles[j]->driver);
4070 	  printf("                          'ppdfile' => '%s',\n",
4071 		 printer->ppdfiles[j]->filename);
4072 	  printf("                        },\n");
4073 	}
4074       printf("                      ],\n");
4075     }
4076     printf("          },\n");
4077   }
4078   printf("        ];\n");
4079 
4080 }
4081 
4082 void
generateMarginsPerlData(marginsPtr margins,int debug)4083 generateMarginsPerlData(marginsPtr margins, /* I/O - Foomatic margins data
4084 					       parsed from XML input */
4085 			int debug) { /* Debug flag */
4086 
4087   int i; /* loop variable */
4088 
4089   for (i = 0; i < margins->num_marginRecords; i ++) {
4090     if (margins->marginRecords[i]->pagesize) {
4091       printf("    '%s' => {\n", margins->marginRecords[i]->pagesize);
4092     } else {
4093       printf("    '_general' => {\n");
4094     }
4095     if (margins->marginRecords[i]->unit) {
4096       printf("      'unit' => '%s',\n", margins->marginRecords[i]->unit);
4097     }
4098     if (margins->marginRecords[i]->absolute) {
4099       printf("      'absolute' => '%s',\n",
4100 	     margins->marginRecords[i]->absolute);
4101     }
4102     if (margins->marginRecords[i]->left) {
4103       printf("      'left' => '%s',\n", margins->marginRecords[i]->left);
4104     }
4105     if (margins->marginRecords[i]->right) {
4106       printf("      'right' => '%s',\n", margins->marginRecords[i]->right);
4107     }
4108     if (margins->marginRecords[i]->top) {
4109       printf("      'top' => '%s',\n", margins->marginRecords[i]->top);
4110     }
4111     if (margins->marginRecords[i]->bottom) {
4112       printf("      'bottom' => '%s',\n", margins->marginRecords[i]->bottom);
4113     }
4114     printf("    },\n");
4115   }
4116 }
4117 
4118 xmlChar const sc_Postscript [] = "Postscript";
4119 
4120 void
generateComboPerlData(comboDataPtr combo,int debug)4121 generateComboPerlData(comboDataPtr combo, /* I/O - Foomatic combo data
4122 					     parsed from XML input */
4123 		      int debug) { /* Debug flag */
4124 
4125   int i, j; /* loop variables */
4126   int haspsdriver = 0; /* Is the "Postscript" driver in the printer's
4127 			  driver list? */
4128 
4129   printf("$VAR1 = {\n");
4130   printf("  'id' => '%s',\n", combo->id);
4131   printf("  'make' => '%s',\n", combo->make);
4132   printf("  'model' => '%s',\n", combo->model);
4133   if (combo->recdriver) {
4134     printf("  'recdriver' => '%s',\n", combo->recdriver);
4135   } else {
4136     printf("  'recdriver' => undef,\n");
4137   }
4138   if ((combo->num_drivers > 0) || (combo->ppdurl)) {
4139     printf("  'drivers' => [\n");
4140     for (i = 0; i < combo->num_drivers; i ++) {
4141       printf("                 {\n");
4142       if (combo->drivers[i]->name) {
4143 	if (xmlStrncmp(combo->drivers[i]->name, sc_Postscript, 10))
4144 	  haspsdriver = 1;
4145 	printf("                   'name' => '%s',\n",
4146 	       combo->drivers[i]->name);
4147 	printf("                   'id' => '%s',\n",
4148 	       combo->drivers[i]->name);
4149       }
4150       if (combo->drivers[i]->ppd) {
4151 	printf("                   'ppd' => '%s',\n",
4152 	       combo->drivers[i]->ppd);
4153       }
4154       if (combo->drivers[i]->comment) {
4155 	printf("                   'comment' => '%s',\n",
4156 	       combo->drivers[i]->comment);
4157       }
4158       printf("                 },\n");
4159     }
4160     if ((combo->ppdurl) && !haspsdriver) {
4161       printf("                 {\n");
4162       printf("                   'name' => '%s',\n",
4163 	     "Postscript");
4164       printf("                   'id' => '%s',\n",
4165 	     "Postscript");
4166       printf("                   'ppd' => '%s',\n",
4167 	     combo->ppdurl);
4168       printf("                 },\n");
4169     }
4170     printf("               ],\n");
4171   }
4172   if (combo->pcmodel) {
4173     printf("  'pcmodel' => '%s',\n", combo->pcmodel);
4174   } else {
4175     printf("  'pcmodel' => undef,\n");
4176   }
4177   if (combo->ppdurl) {
4178     printf("  'ppdurl' => '%s',\n", combo->ppdurl);
4179   }
4180   printf("  'color' => %s,\n", combo->color);
4181   printf("  'ascii' => %s,\n", combo->ascii);
4182   printf("  'pjl' => %s,\n", combo->pjl);
4183   if (combo->printerppdentry) {
4184     printf("  'printerppdentry' => '%s',\n", combo->printerppdentry);
4185   } else {
4186     printf("  'printerppdentry' => undef,\n");
4187   }
4188   if (combo->printermargins) {
4189     printf("  'printermargins' => {\n");
4190     generateMarginsPerlData(combo->printermargins, debug);
4191     printf("  },\n");
4192   }
4193   if (combo->general_ieee) {
4194     printf("  'pnp_ieee' => '%s',\n", combo->general_ieee);
4195     printf("  'general_ieee' => '%s',\n", combo->general_ieee);
4196   } else {
4197     printf("  'pnp_ieee' => undef,\n");
4198     printf("  'general_ieee' => undef,\n");
4199   }
4200   if (combo->general_mfg) {
4201     printf("  'pnp_mfg' => '%s',\n", combo->general_mfg);
4202     printf("  'general_mfg' => '%s',\n", combo->general_mfg);
4203   } else {
4204     printf("  'pnp_mfg' => undef,\n");
4205     printf("  'general_mfg' => undef,\n");
4206   }
4207   if (combo->general_mdl) {
4208     printf("  'pnp_mdl' => '%s',\n", combo->general_mdl);
4209     printf("  'general_mdl' => '%s',\n", combo->general_mdl);
4210   } else {
4211     printf("  'pnp_mdl' => undef,\n");
4212     printf("  'general_mdl' => undef,\n");
4213   }
4214   if (combo->general_des) {
4215     printf("  'pnp_des' => '%s',\n", combo->general_des);
4216     printf("  'general_des' => '%s',\n", combo->general_des);
4217   } else {
4218     printf("  'pnp_des' => undef,\n");
4219     printf("  'general_des' => undef,\n");
4220   }
4221   if (combo->general_cmd) {
4222     printf("  'pnp_cmd' => '%s',\n", combo->general_cmd);
4223     printf("  'general_cmd' => '%s',\n", combo->general_cmd);
4224   } else {
4225     printf("  'pnp_cmd' => undef,\n");
4226     printf("  'general_cmd' => undef,\n");
4227   }
4228   if (combo->par_ieee) {
4229     printf("  'par_ieee' => '%s',\n", combo->par_ieee);
4230   } else {
4231     printf("  'par_ieee' => undef,\n");
4232   }
4233   if (combo->par_mfg) {
4234     printf("  'par_mfg' => '%s',\n", combo->par_mfg);
4235   } else {
4236     printf("  'par_mfg' => undef,\n");
4237   }
4238   if (combo->par_mdl) {
4239     printf("  'par_mdl' => '%s',\n", combo->par_mdl);
4240   } else {
4241     printf("  'par_mdl' => undef,\n");
4242   }
4243   if (combo->par_des) {
4244     printf("  'par_des' => '%s',\n", combo->par_des);
4245   } else {
4246     printf("  'par_des' => undef,\n");
4247   }
4248   if (combo->par_cmd) {
4249     printf("  'par_cmd' => '%s',\n", combo->par_cmd);
4250   } else {
4251     printf("  'par_cmd' => undef,\n");
4252   }
4253   if (combo->usb_ieee) {
4254     printf("  'usb_ieee' => '%s',\n", combo->usb_ieee);
4255   } else {
4256     printf("  'usb_ieee' => undef,\n");
4257   }
4258   if (combo->usb_mfg) {
4259     printf("  'usb_mfg' => '%s',\n", combo->usb_mfg);
4260   } else {
4261     printf("  'usb_mfg' => undef,\n");
4262   }
4263   if (combo->usb_mdl) {
4264     printf("  'usb_mdl' => '%s',\n", combo->usb_mdl);
4265   } else {
4266     printf("  'usb_mdl' => undef,\n");
4267   }
4268   if (combo->usb_des) {
4269     printf("  'usb_des' => '%s',\n", combo->usb_des);
4270   } else {
4271     printf("  'usb_des' => undef,\n");
4272   }
4273   if (combo->usb_cmd) {
4274     printf("  'usb_cmd' => '%s',\n", combo->usb_cmd);
4275   } else {
4276     printf("  'usb_cmd' => undef,\n");
4277   }
4278   if (combo->snmp_ieee) {
4279     printf("  'snmp_ieee' => '%s',\n", combo->snmp_ieee);
4280   } else {
4281     printf("  'snmp_ieee' => undef,\n");
4282   }
4283   if (combo->snmp_mfg) {
4284     printf("  'snmp_mfg' => '%s',\n", combo->snmp_mfg);
4285   } else {
4286     printf("  'snmp_mfg' => undef,\n");
4287   }
4288   if (combo->snmp_mdl) {
4289     printf("  'snmp_mdl' => '%s',\n", combo->snmp_mdl);
4290   } else {
4291     printf("  'snmp_mdl' => undef,\n");
4292   }
4293   if (combo->snmp_des) {
4294     printf("  'snmp_des' => '%s',\n", combo->snmp_des);
4295   } else {
4296     printf("  'snmp_des' => undef,\n");
4297   }
4298   if (combo->snmp_cmd) {
4299     printf("  'snmp_cmd' => '%s',\n", combo->snmp_cmd);
4300   } else {
4301     printf("  'snmp_cmd' => undef,\n");
4302   }
4303   printf("  'driver' => '%s',\n", combo->driver);
4304   if (combo->driver_group) {
4305     printf("  'group' => '%s',\n", combo->driver_group);
4306   }
4307   if (combo->pcdriver) {
4308     printf("  'pcdriver' => '%s',\n", combo->pcdriver);
4309   } else {
4310     printf("  'pcdriver' => undef,\n");
4311   }
4312   printf("  'type' => '%s',\n", combo->driver_type);
4313   if (combo->driver_comment) {
4314     printf("  'comment' => '%s',\n", combo->driver_comment);
4315   } else {
4316     printf("  'comment' => undef,\n");
4317   }
4318   if (combo->url) {
4319     printf("  'url' => '%s',\n", combo->url);
4320   } else {
4321     printf("  'url' => undef,\n");
4322   }
4323   if (combo->driver_obsolete) {
4324     printf("  'obsolete' => '%s',\n", combo->driver_obsolete);
4325   }
4326   if (combo->supplier != NULL) {
4327     printf("  'supplier' => '%s',\n",
4328 	   combo->supplier);
4329   }
4330   if (combo->manufacturersupplied != NULL) {
4331     printf("  'manufacturersupplied' => '%s',\n",
4332 	   combo->manufacturersupplied);
4333   }
4334   if (combo->license != NULL) {
4335     printf("  'license' => '%s',\n",
4336 	   combo->license);
4337   }
4338   if (combo->licensetext != NULL) {
4339     printf("  'licensetext' => '%s',\n",
4340 	   combo->licensetext);
4341   }
4342   if (combo->origlicensetext != NULL) {
4343     printf("  'origlicensetext' => '%s',\n",
4344 	   combo->origlicensetext);
4345   }
4346   if (combo->licenselink != NULL) {
4347     printf("  'licenselink' => '%s',\n",
4348 	   combo->licenselink);
4349   }
4350   if (combo->origlicenselink != NULL) {
4351     printf("  'origlicenselink' => '%s',\n",
4352 	   combo->origlicenselink);
4353   }
4354   if (combo->free != NULL) {
4355     printf("  'free' => '%s',\n",
4356 	   combo->free);
4357   }
4358   if (combo->patents != NULL) {
4359     printf("  'patents' => '%s',\n",
4360 	   combo->patents);
4361   }
4362   if (combo->num_supportcontacts != 0) {
4363     printf("  'supportcontacts' => [\n");
4364     for (i = 0;
4365 	 i < combo->num_supportcontacts; i ++) {
4366       if (combo->supportcontacturls[i] !=
4367 	  NULL) {
4368 	printf("    {\n");
4369 	printf("      'description' => '%s',\n",
4370 	       combo->supportcontacts[i]);
4371 	if (combo->supportcontacturls[i]
4372 	    != NULL)
4373 	  printf("      'url' => '%s',\n",
4374 		 combo->supportcontacturls[i]);
4375 	printf("      'level' => '%s',\n",
4376 	       combo->supportcontactlevels[i]);
4377 	printf("    },\n");
4378       }
4379     }
4380     printf("  ],\n");
4381   }
4382   if (combo->shortdescription != NULL) {
4383     printf("  'shortdescription' => '%s',\n",
4384 	   combo->shortdescription);
4385   }
4386   if (combo->locales != NULL) {
4387     printf("  'locales' => '%s',\n",
4388 	   combo->locales);
4389   }
4390   if (combo->num_packages != 0) {
4391     printf("  'packages' => [\n");
4392     for (i = 0;
4393 	 i < combo->num_packages; i ++) {
4394       if (combo->packageurls[i] !=
4395 	  NULL) {
4396 	printf("    {\n");
4397 	printf("      'url' => '%s',\n",
4398 	       combo->packageurls[i]);
4399 	if (combo->packagescopes[i]
4400 	    != NULL)
4401 	  printf("      'scope' => '%s',\n",
4402 		 combo->packagescopes[i]);
4403 	if (combo->packagefingerprints[i]
4404 	    != NULL)
4405 	  printf("      'fingerprint' => '%s',\n",
4406 		 combo->packagefingerprints[i]);
4407 	printf("    },\n");
4408       }
4409     }
4410     printf("  ],\n");
4411   }
4412   if (combo->excmaxresx != NULL) {
4413     printf("  'drvmaxresx' => '%s',\n",
4414 	   combo->excmaxresx);
4415   } else if (combo->drvmaxresx != NULL) {
4416     printf("  'drvmaxresx' => '%s',\n",
4417 	   combo->drvmaxresx);
4418   }
4419   if (combo->excmaxresy != NULL) {
4420     printf("  'drvmaxresy' => '%s',\n",
4421 	   combo->excmaxresy);
4422   } else if (combo->drvmaxresy != NULL) {
4423     printf("  'drvmaxresy' => '%s',\n",
4424 	   combo->drvmaxresy);
4425   }
4426   if (combo->exccolor != NULL) {
4427     printf("  'drvcolor' => '%s',\n",
4428 	   combo->exccolor);
4429   } else if (combo->drvcolor != NULL) {
4430     printf("  'drvcolor' => '%s',\n",
4431 	   combo->drvcolor);
4432   }
4433   if (combo->exctext != NULL) {
4434     printf("  'text' => '%s',\n",
4435 	   combo->exctext);
4436   } else if (combo->text != NULL) {
4437     printf("  'text' => '%s',\n",
4438 	   combo->text);
4439   }
4440   if (combo->exclineart != NULL) {
4441     printf("  'lineart' => '%s',\n",
4442 	   combo->exclineart);
4443   } else if (combo->lineart != NULL) {
4444     printf("  'lineart' => '%s',\n",
4445 	   combo->lineart);
4446   }
4447   if (combo->excgraphics != NULL) {
4448     printf("  'graphics' => '%s',\n",
4449 	   combo->excgraphics);
4450   } else if (combo->graphics != NULL) {
4451     printf("  'graphics' => '%s',\n",
4452 	   combo->graphics);
4453   }
4454   if (combo->excphoto != NULL) {
4455     printf("  'photo' => '%s',\n",
4456 	   combo->excphoto);
4457   } else if (combo->photo != NULL) {
4458     printf("  'photo' => '%s',\n",
4459 	   combo->photo);
4460   }
4461   if (combo->excload != NULL) {
4462     printf("  'load' => '%s',\n",
4463 	   combo->excload);
4464   } else if (combo->load != NULL) {
4465     printf("  'load' => '%s',\n",
4466 	   combo->load);
4467   }
4468   if (combo->excspeed != NULL) {
4469     printf("  'speed' => '%s',\n",
4470 	   combo->excspeed);
4471   } else if (combo->speed != NULL) {
4472     printf("  'speed' => '%s',\n",
4473 	   combo->speed);
4474   }
4475   if (combo->num_requires != 0) {
4476     printf("  'requires' => [\n");
4477     for (i = 0;
4478 	 i < combo->num_requires; i ++) {
4479       if (combo->requires[i] !=
4480 	  NULL) {
4481 	printf("    {\n");
4482 	printf("      'driver' => '%s',\n",
4483 	       combo->requires[i]);
4484 	if (combo->requiresversion[i]
4485 	    != NULL)
4486 	  printf("      'version' => '%s',\n",
4487 		 combo->requiresversion[i]);
4488 	printf("    },\n");
4489       }
4490     }
4491     printf("  ],\n");
4492   }
4493   if (combo->cmd) {
4494     printf("  'cmd' => '%s',\n", combo->cmd);
4495   } else {
4496     printf("  'cmd' => undef,\n");
4497   }
4498   if (combo->cmd_pdf) {
4499     printf("  'cmd_pdf' => '%s',\n", combo->cmd_pdf);
4500   } else {
4501     printf("  'cmd_pdf' => undef,\n");
4502   }
4503   if (combo->nopjl) {
4504     printf("  'drivernopjl' => %s,\n", combo->nopjl);
4505   } else {
4506     printf("  'drivernopjl' => 0,\n");
4507   }
4508   if (combo->nopageaccounting) {
4509     printf("  'drivernopageaccounting' => %s,\n", combo->nopageaccounting);
4510   } else {
4511     printf("  'drivernopageaccounting' => 0,\n");
4512   }
4513   if (combo->driverppdentry) {
4514     printf("  'driverppdentry' => '%s',\n", combo->driverppdentry);
4515   } else {
4516     printf("  'driverppdentry' => undef,\n");
4517   }
4518   if (combo->comboppdentry) {
4519     printf("  'comboppdentry' => '%s',\n", combo->comboppdentry);
4520   } else {
4521     printf("  'comboppdentry' => undef,\n");
4522   }
4523   if (combo->drivermargins) {
4524     printf("  'drivermargins' => {\n");
4525     generateMarginsPerlData(combo->drivermargins, debug);
4526     printf("  },\n");
4527   }
4528   if (combo->combomargins) {
4529     printf("  'combomargins' => {\n");
4530     generateMarginsPerlData(combo->combomargins, debug);
4531     printf("  },\n");
4532   }
4533   if (combo->maxspot > 0) {
4534     printf("  'maxspot' => '%s',\n", combo->maxspot);
4535   } else {
4536     printf("  'maxspot' => 'A',\n");
4537   }
4538   printf("  'args_byname' => {\n");
4539   for (i = 0; i < combo->num_args; i ++) {
4540     printf("    '%s' => {},\n", combo->args[i]->name);
4541   }
4542   printf("  },\n");
4543   printf("  'args' => [\n");
4544   for (i = 0; i < combo->num_args; i ++) {
4545     printf("    {\n");
4546     printf("      'name' => '%s',\n", combo->args[i]->name);
4547     if (combo->args[i]->name_false) {
4548       printf("      'name_false' => '%s',\n", combo->args[i]->name_false);
4549     }
4550     printf("      'comment' => '%s',\n", combo->args[i]->comment);
4551     printf("      'idx' => '%s',\n", combo->args[i]->idx);
4552     printf("      'type' => '%s',\n", combo->args[i]->option_type);
4553     printf("      'style' => '%s',\n", combo->args[i]->style);
4554     if (combo->args[i]->substyle) {
4555       printf("      'substyle' => '%s',\n", combo->args[i]->substyle);
4556     }
4557     printf("      'spot' => '%s',\n", combo->args[i]->spot);
4558     printf("      'order' => '%s',\n", combo->args[i]->order);
4559     if (combo->args[i]->section) {
4560       printf("      'section' => '%s',\n", combo->args[i]->section);
4561     }
4562     if (combo->args[i]->grouppath) {
4563       printf("      'group' => '%s',\n", combo->args[i]->grouppath);
4564     }
4565     if (combo->args[i]->proto) {
4566       printf("      'proto' => '%s',\n", combo->args[i]->proto);
4567     }
4568     if (combo->args[i]->required) {
4569       printf("      'required' => 1,\n");
4570     }
4571     if (combo->args[i]->min_value) {
4572       printf("      'min' => '%s',\n", combo->args[i]->min_value);
4573     }
4574     if (combo->args[i]->max_value) {
4575       printf("      'max' => '%s',\n", combo->args[i]->max_value);
4576     }
4577     if (combo->args[i]->max_length) {
4578       printf("      'maxlength' => '%s',\n", combo->args[i]->max_length);
4579     }
4580     if (combo->args[i]->allowed_chars) {
4581       printf("      'allowedchars' => '%s',\n", combo->args[i]->allowed_chars);
4582     }
4583     if (combo->args[i]->allowed_regexp) {
4584       printf("      'allowedregexp' => '%s',\n",
4585 	     combo->args[i]->allowed_regexp);
4586     }
4587     if (combo->args[i]->default_value) {
4588       printf("      'default' => '%s',\n", combo->args[i]->default_value);
4589     } else {
4590       printf("      'default' => 'None',\n");
4591     }
4592     if (combo->args[i]->num_choices > 0) {
4593       printf("      'vals_byname' => {\n");
4594       for (j = 0; j < combo->args[i]->num_choices; j ++) {
4595 	if (combo->args[i]->choices[j]->value == NULL) {
4596 		static xmlChar sc_None [] = "None";
4597 	  combo->args[i]->choices[j]->value = sc_None;
4598 	}
4599 	printf("        '%s' => {\n", combo->args[i]->choices[j]->value);
4600 	printf("          'value' => '%s',\n",
4601 	       combo->args[i]->choices[j]->value);
4602 	if (combo->args[i]->choices[j]->comment) {
4603 	  printf("          'comment' => '%s',\n",
4604 		 combo->args[i]->choices[j]->comment);
4605 	}
4606 	printf("          'idx' => '%s',\n",
4607 	       combo->args[i]->choices[j]->idx);
4608 	if (combo->args[i]->choices[j]->driverval) {
4609 	  printf("          'driverval' => '%s'\n",
4610 		 combo->args[i]->choices[j]->driverval);
4611 	} else {
4612 	  printf("          'driverval' => ''\n");
4613 	}
4614 	printf("        },\n");
4615       }
4616       printf("      },\n");
4617       printf("      'vals' => [\n");
4618       for (j = 0; j < combo->args[i]->num_choices; j ++) {
4619 	printf("        {},\n");
4620       }
4621       printf("      ]\n");
4622     }
4623     printf("    },\n");
4624   }
4625   printf("  ]\n");
4626   printf("};\n");
4627   for (i = 0; i < combo->num_args; i ++) {
4628     for (j = 0; j < combo->args[i]->num_choices; j ++) {
4629       printf("$VAR1->{'args'}[%d]{'vals'}[%d] = $VAR1->{'args'}[%d]{'vals_byname'}{'%s'};\n",
4630 	     i, j, i, combo->args[i]->choices[j]->value);
4631     }
4632   }
4633   for (i = 0; i < combo->num_args; i ++) {
4634     printf("$VAR1->{'args_byname'}{'%s'} = $VAR1->{'args'}[%d];\n",
4635 	   combo->args[i]->name, i);
4636   }
4637 
4638 }
4639 
4640 void
generatePrinterPerlData(printerEntryPtr printer,int debug)4641 generatePrinterPerlData(printerEntryPtr printer, /* I/O - Foomatic printer
4642 						    data parsed from XML
4643 						    input */
4644 			int debug) { /* Debug flag */
4645 
4646   int i; /* loop variable */
4647   int haspsdriver = 0; /* Is the "Postscript" driver in the printer's
4648 			  driver list? */
4649 
4650   printf("$VAR1 = {\n");
4651   printf("  'id' => '%s',\n", printer->id);
4652   printf("  'make' => '%s',\n", printer->make);
4653   printf("  'model' => '%s',\n", printer->model);
4654   if (printer->printer_type) {
4655     printf("  'type' => '%s',\n", printer->printer_type);
4656   }
4657   if (printer->color) {
4658     printf("  'color' => '%s',\n", printer->color);
4659   }
4660   if (printer->maxxres) {
4661     printf("  'maxxres' => '%s',\n", printer->maxxres);
4662   }
4663   if (printer->maxyres) {
4664     printf("  'maxyres' => '%s',\n", printer->maxyres);
4665   }
4666   if (printer->printerppdentry) {
4667     printf("  'ppdentry' => '%s',\n", printer->printerppdentry);
4668   } else {
4669     printf("  'ppdentry' => undef,\n");
4670   }
4671   if (printer->printermargins) {
4672     printf("  'margins' => {\n");
4673     generateMarginsPerlData(printer->printermargins, debug);
4674     printf("  },\n");
4675   }
4676   if (printer->refill) {
4677     printf("  'refill' => '%s',\n", printer->refill);
4678   }
4679   if (printer->ascii) {
4680     printf("  'ascii' => '%s',\n", printer->ascii);
4681   }
4682   if (printer->pjl) {
4683     printf("  'pjl' => '%s',\n", printer->pjl);
4684   }
4685   if (printer->num_languages > 0) {
4686     printf("  'languages' => [\n");
4687     for (i = 0; i < printer->num_languages; i ++) {
4688       printf("                   {\n");
4689       printf("                     'name' => '%s',\n",
4690 	     printer->languages[i]->name);
4691       printf("                     'level' => '%s',\n",
4692 	     printer->languages[i]->level);
4693       printf("                   },\n");
4694     }
4695     printf("                 ],\n");
4696   }
4697   if (printer->ppdurl) {
4698     printf("  'ppdurl' => '%s',\n", printer->ppdurl);
4699   }
4700   if (printer->general_ieee) {
4701     printf("  'general_ieee' => '%s',\n", printer->general_ieee);
4702   }
4703   if (printer->general_mfg) {
4704     printf("  'general_mfg' => '%s',\n", printer->general_mfg);
4705   }
4706   if (printer->general_mdl) {
4707     printf("  'general_mdl' => '%s',\n", printer->general_mdl);
4708   }
4709   if (printer->general_des) {
4710     printf("  'general_des' => '%s',\n", printer->general_des);
4711   }
4712   if (printer->general_cmd) {
4713     printf("  'general_cmd' => '%s',\n", printer->general_cmd);
4714   }
4715   if (printer->par_ieee) {
4716     printf("  'par_ieee' => '%s',\n", printer->par_ieee);
4717   }
4718   if (printer->par_mfg) {
4719     printf("  'par_mfg' => '%s',\n", printer->par_mfg);
4720   }
4721   if (printer->par_mdl) {
4722     printf("  'par_mdl' => '%s',\n", printer->par_mdl);
4723   }
4724   if (printer->par_des) {
4725     printf("  'par_des' => '%s',\n", printer->par_des);
4726   }
4727   if (printer->par_cmd) {
4728     printf("  'par_cmd' => '%s',\n", printer->par_cmd);
4729   }
4730   if (printer->usb_ieee) {
4731     printf("  'usb_ieee' => '%s',\n", printer->usb_ieee);
4732   }
4733   if (printer->usb_mfg) {
4734     printf("  'usb_mfg' => '%s',\n", printer->usb_mfg);
4735   }
4736   if (printer->usb_mdl) {
4737     printf("  'usb_mdl' => '%s',\n", printer->usb_mdl);
4738   }
4739   if (printer->usb_des) {
4740     printf("  'usb_des' => '%s',\n", printer->usb_des);
4741   }
4742   if (printer->usb_cmd) {
4743     printf("  'usb_cmd' => '%s',\n", printer->usb_cmd);
4744   }
4745   if (printer->snmp_ieee) {
4746     printf("  'snmp_ieee' => '%s',\n", printer->snmp_ieee);
4747   }
4748   if (printer->snmp_mfg) {
4749     printf("  'snmp_mfg' => '%s',\n", printer->snmp_mfg);
4750   }
4751   if (printer->snmp_mdl) {
4752     printf("  'snmp_mdl' => '%s',\n", printer->snmp_mdl);
4753   }
4754   if (printer->snmp_des) {
4755     printf("  'snmp_des' => '%s',\n", printer->snmp_des);
4756   }
4757   if (printer->snmp_cmd) {
4758     printf("  'snmp_cmd' => '%s',\n", printer->snmp_cmd);
4759   }
4760   if (printer->functionality) {
4761     printf("  'functionality' => '%s',\n", printer->functionality);
4762   }
4763   if (printer->driver) {
4764     printf("  'driver' => '%s',\n", printer->driver);
4765   }
4766   if ((printer->num_drivers > 0) || (printer->ppdurl)) {
4767     printf("  'drivers' => [\n");
4768     for (i = 0; i < printer->num_drivers; i ++) {
4769       printf("                 {\n");
4770       if (printer->drivers[i]->name) {
4771 	if (xmlStrncmp(printer->drivers[i]->name, sc_Postscript, 10))
4772 	  haspsdriver = 1;
4773 	printf("                   'name' => '%s',\n",
4774 	       printer->drivers[i]->name);
4775 	printf("                   'id' => '%s',\n",
4776 	       printer->drivers[i]->name);
4777       }
4778       if (printer->drivers[i]->ppd) {
4779 	printf("                   'ppd' => '%s',\n",
4780 	       printer->drivers[i]->ppd);
4781       }
4782       if (printer->drivers[i]->comment) {
4783 	printf("                   'comment' => '%s',\n",
4784 	       printer->drivers[i]->comment);
4785       }
4786       printf("                 },\n");
4787     }
4788     if ((printer->ppdurl) && !haspsdriver) {
4789       printf("                 {\n");
4790       printf("                   'name' => '%s',\n",
4791 	     "Postscript");
4792       printf("                   'id' => '%s',\n",
4793 	     "Postscript");
4794       printf("                   'ppd' => '%s',\n",
4795 	     printer->ppdurl);
4796       printf("                 },\n");
4797     }
4798     printf("               ],\n");
4799   }
4800   if (printer->unverified) {
4801     printf("  'unverified' => '%s',\n", printer->unverified);
4802   }
4803   if (printer->noxmlentry) {
4804     printf("  'noxmlentry' => '%s',\n", printer->noxmlentry);
4805   }
4806   if (printer->url) {
4807     printf("  'url' => '%s',\n", printer->url);
4808   }
4809   if (printer->contriburl) {
4810     printf("  'contriburl' => '%s',\n", printer->contriburl);
4811   }
4812   if (printer->comment) {
4813     printf("  'comment' => '%s',\n", printer->comment);
4814   }
4815   printf("};\n");
4816 
4817 }
4818 
4819 void
generateDriverPerlData(driverEntryPtr driver,int debug)4820 generateDriverPerlData(driverEntryPtr driver, /* I/O - Foomatic driver
4821 						 data parsed from XML
4822 						 input */
4823 		       int debug) { /* Debug flag */
4824 
4825   int i; /* loop variable */
4826 
4827   xmlChar *id;
4828   xmlChar *name;
4829   xmlChar *url;
4830   xmlChar *driver_type;
4831   xmlChar *cmd;
4832   xmlChar *comment;
4833   int     num_printers;
4834   xmlChar **printers;
4835   printf("$VAR1 = {\n");
4836   printf("  'name' => '%s',\n", driver->name);
4837   if (driver->group) {
4838     printf("  'group' => '%s',\n", driver->group);
4839   }
4840   if (driver->url) {
4841     printf("  'url' => '%s',\n", driver->url);
4842   }
4843   if (driver->driver_obsolete) {
4844     printf("  'obsolete' => '%s',\n", driver->driver_obsolete);
4845   }
4846   if (driver->supplier != NULL) {
4847     printf("  'supplier' => '%s',\n",
4848 	   driver->supplier);
4849   }
4850   if (driver->manufacturersupplied != NULL) {
4851     printf("  'manufacturersupplied' => '%s',\n",
4852 	   driver->manufacturersupplied);
4853   }
4854   if (driver->license != NULL) {
4855     printf("  'license' => '%s',\n",
4856 	   driver->license);
4857   }
4858   if (driver->licensetext != NULL) {
4859     printf("  'licensetext' => '%s',\n",
4860 	   driver->licensetext);
4861   }
4862   if (driver->origlicensetext != NULL) {
4863     printf("  'origlicensetext' => '%s',\n",
4864 	   driver->origlicensetext);
4865   }
4866   if (driver->licenselink != NULL) {
4867     printf("  'licenselink' => '%s',\n",
4868 	   driver->licenselink);
4869   }
4870   if (driver->origlicenselink != NULL) {
4871     printf("  'origlicenselink' => '%s',\n",
4872 	   driver->origlicenselink);
4873   }
4874   if (driver->free != NULL) {
4875     printf("  'free' => '%s',\n",
4876 	   driver->free);
4877   }
4878   if (driver->patents != NULL) {
4879     printf("  'patents' => '%s',\n",
4880 	   driver->patents);
4881   }
4882   if (driver->num_supportcontacts != 0) {
4883     printf("  'supportcontacts' => [\n");
4884     for (i = 0;
4885 	 i < driver->num_supportcontacts; i ++) {
4886       if (driver->supportcontacturls[i] !=
4887 	  NULL) {
4888 	printf("    {\n");
4889 	printf("      'description' => '%s',\n",
4890 	       driver->supportcontacts[i]);
4891 	if (driver->supportcontacturls[i]
4892 	    != NULL)
4893 	  printf("      'url' => '%s',\n",
4894 		 driver->supportcontacturls[i]);
4895 	printf("      'level' => '%s',\n",
4896 	       driver->supportcontactlevels[i]);
4897 	printf("    },\n");
4898       }
4899     }
4900     printf("  ],\n");
4901   }
4902   if (driver->shortdescription != NULL) {
4903     printf("  'shortdescription' => '%s',\n",
4904 	   driver->shortdescription);
4905   }
4906   if (driver->locales != NULL) {
4907     printf("  'locales' => '%s',\n",
4908 	   driver->locales);
4909   }
4910   if (driver->num_packages != 0) {
4911     printf("  'packages' => [\n");
4912     for (i = 0;
4913 	 i < driver->num_packages; i ++) {
4914       if (driver->packageurls[i] !=
4915 	  NULL) {
4916 	printf("    {\n");
4917 	printf("      'url' => '%s',\n",
4918 	       driver->packageurls[i]);
4919 	if (driver->packagescopes[i]
4920 	    != NULL)
4921 	  printf("      'scope' => '%s',\n",
4922 		 driver->packagescopes[i]);
4923 	if (driver->packagefingerprints[i]
4924 	    != NULL)
4925 	  printf("      'fingerprint' => '%s',\n",
4926 		 driver->packagefingerprints[i]);
4927 	printf("    },\n");
4928       }
4929     }
4930     printf("  ],\n");
4931   }
4932   if (driver->maxresx != NULL) {
4933     printf("  'drvmaxresx' => '%s',\n",
4934 	   driver->maxresx);
4935   }
4936   if (driver->maxresy != NULL) {
4937     printf("  'drvmaxresy' => '%s',\n",
4938 	   driver->maxresy);
4939   }
4940   if (driver->color != NULL) {
4941     printf("  'drvcolor' => '%s',\n",
4942 	   driver->color);
4943   }
4944   if (driver->text != NULL) {
4945     printf("  'text' => '%s',\n",
4946 	   driver->text);
4947   }
4948   if (driver->lineart != NULL) {
4949     printf("  'lineart' => '%s',\n",
4950 	   driver->lineart);
4951   }
4952   if (driver->graphics != NULL) {
4953     printf("  'graphics' => '%s',\n",
4954 	   driver->graphics);
4955   }
4956   if (driver->photo != NULL) {
4957     printf("  'photo' => '%s',\n",
4958 	   driver->photo);
4959   }
4960   if (driver->load != NULL) {
4961     printf("  'load' => '%s',\n",
4962 	   driver->load);
4963   }
4964   if (driver->speed != NULL) {
4965     printf("  'speed' => '%s',\n",
4966 	   driver->speed);
4967   }
4968   if (driver->num_requires != 0) {
4969     printf("  'requires' => [\n");
4970     for (i = 0;
4971 	 i < driver->num_requires; i ++) {
4972       if (driver->requires[i] !=
4973 	  NULL) {
4974 	printf("    {\n");
4975 	printf("      'driver' => '%s',\n",
4976 	       driver->requires[i]);
4977 	if (driver->requiresversion[i]
4978 	    != NULL)
4979 	  printf("      'version' => '%s',\n",
4980 		 driver->requiresversion[i]);
4981 	printf("    },\n");
4982       }
4983     }
4984     printf("  ],\n");
4985   }
4986   if (driver->driver_type) {
4987     printf("  'type' => '%s',\n", driver->driver_type);
4988   }
4989   if (driver->cmd) {
4990     printf("  'cmd' => '%s',\n", driver->cmd);
4991   }
4992   if (driver->cmd_pdf) {
4993     printf("  'cmd_cmd' => '%s',\n", driver->cmd_pdf);
4994   }
4995   if (driver->driverppdentry) {
4996     printf("  'ppdentry' => '%s',\n", driver->driverppdentry);
4997   } else {
4998     printf("  'ppdentry' => undef,\n");
4999   }
5000   if (driver->drivermargins) {
5001     printf("  'margins' => {\n");
5002     generateMarginsPerlData(driver->drivermargins, debug);
5003     printf("  },\n");
5004   }
5005   if (driver->comment) {
5006     printf("  'comment' => '%s',\n", driver->comment);
5007   }
5008   if (driver->num_printers > 0) {
5009     printf("  'printers' => [\n");
5010     for (i = 0; i < driver->num_printers; i ++) {
5011       printf("    {\n");
5012       printf("      'id' => '%s',\n",
5013 	     driver->printers[i]->id);
5014       if (driver->printers[i]->comment) {
5015 	printf("      'comment' => '%s'\n",
5016 	       driver->printers[i]->comment);
5017       }
5018       if (driver->printers[i]->excmaxresx != NULL) {
5019 	printf("      'excmaxresx' => '%s',\n",
5020 	       driver->printers[i]->excmaxresx);
5021       }
5022       if (driver->printers[i]->excmaxresy != NULL) {
5023 	printf("      'excmaxresy' => '%s',\n",
5024 	       driver->printers[i]->excmaxresy);
5025       }
5026       if (driver->printers[i]->exccolor != NULL) {
5027 	printf("      'exccolor' => '%s',\n",
5028 	       driver->printers[i]->exccolor);
5029       }
5030       if (driver->printers[i]->exctext != NULL) {
5031 	printf("      'exctext' => '%s',\n",
5032 	       driver->printers[i]->exctext);
5033       }
5034       if (driver->printers[i]->exclineart != NULL) {
5035 	printf("      'exclineart' => '%s',\n",
5036 	       driver->printers[i]->exclineart);
5037       }
5038       if (driver->printers[i]->excgraphics != NULL) {
5039 	printf("      'excgraphics' => '%s',\n",
5040 	       driver->printers[i]->excgraphics);
5041       }
5042       if (driver->printers[i]->excphoto != NULL) {
5043 	printf("      'excphoto' => '%s',\n",
5044 	       driver->printers[i]->excphoto);
5045       }
5046       if (driver->printers[i]->excload != NULL) {
5047 	printf("      'excload' => '%s',\n",
5048 	       driver->printers[i]->excload);
5049       }
5050       if (driver->printers[i]->excspeed != NULL) {
5051 	printf("      'excspeed' => '%s',\n",
5052 	       driver->printers[i]->excspeed);
5053       }
5054       printf("    },\n");
5055     }
5056     printf("  ]\n");
5057   } else {
5058     printf("  'printers' => []\n");
5059   }
5060   printf("};\n");
5061 
5062 }
5063 
5064 int /* O - Error state */
main(int argc,char ** argv)5065 main(int argc, char **argv) { /* I - Command line arguments */
5066   int i, j; /* loop variables */
5067   int           debug = 0; /* Debug output level */
5068   xmlChar       *setting;
5069   xmlChar const      *language = sc_locale_C;
5070   xmlChar       **defaultsettings = NULL; /* User-supplied option settings*/
5071   int           num_defaultsettings = 0;
5072   char          *filename = NULL;
5073   int           datatype = 1;  /* Data type to parse: 0: Overview, 1: Combo
5074 				  2: Printer, 3: Driver */
5075   comboDataPtr  combo;  /* C data structure of printer/driver combo */
5076   overviewPtr   overview;  /* C data structure of printer/driver combo */
5077   printerEntryPtr printer;  /* C data structure of printer entry */
5078   driverEntryPtr driver;  /* C data structure of driver entry*/
5079 
5080   /* COMPAT: Do not genrate nodes for formatting spaces */
5081   LIBXML_TEST_VERSION
5082   xmlKeepBlanksDefault(0);
5083 
5084   /* Read the command line arguments */
5085   for (i = 1; i < argc; i ++) {
5086     if (argv[i][0] == '-') {
5087       switch (argv[i][1]) {
5088       case 'O' : /* Parse overview */
5089 	datatype = 0;
5090 	break;
5091       case 'C' : /* Parse combo */
5092 	datatype = 1;
5093 	break;
5094       case 'P' : /* Parse printer */
5095 	datatype = 2;
5096 	break;
5097       case 'D' : /* Parse driver */
5098 	datatype = 3;
5099 	break;
5100       case 'o' : /* option setting */
5101 	if (argv[i][2] != '\0')
5102 	  setting = (xmlChar *)(argv[i] + 2);
5103 	else {
5104 	  i ++;
5105 	  setting = (xmlChar *)(argv[i]);
5106 	}
5107 	num_defaultsettings ++;
5108 	defaultsettings =
5109 	  (xmlChar **)realloc((xmlChar **)defaultsettings,
5110 			      sizeof(xmlChar *) * num_defaultsettings);
5111 	defaultsettings[num_defaultsettings-1] = xmlStrdup (setting);
5112 	break;
5113       case 'l' : /* language */
5114 	if (argv[i][2] != '\0')
5115 	  language = (xmlChar *)(argv[i] + 2);
5116 	else {
5117 	  i ++;
5118 	  language = (xmlChar *)(argv[i]);
5119 	}
5120 	break;
5121       case 'v' : /* verbose */
5122 	debug++;
5123 	j = 2;
5124 	while (argv[i][j] != '\0') {
5125 	  if (argv[i][j] == 'v') debug++;
5126 	  j++;
5127 	}
5128 	break;
5129       case '?' :
5130       case 'h' : /* Help */
5131 	fprintf(stderr, "Usage: foomatic-perl-data [ -O ] [ -C ] [ -P ] [ -D ]\n                          [ -o option=setting ] [ -o ... ] [ -l language ]\n                          [ -v ] [ -vv ] [ filename ]\n");
5132 	fprintf(stderr, "\n");
5133 	fprintf(stderr, "   -O           Parse overview XML data\n");
5134 	fprintf(stderr, "   -C           Parse printer/driver combo XML data (default)\n");
5135 	fprintf(stderr, "   -P           Parse printer entry XML data\n");
5136 	fprintf(stderr, "   -D           Parse driver entry XML data\n");
5137 	fprintf(stderr, "   -o option=setting\n");
5138 	fprintf(stderr, "                Default option settings for the generated Perl data (combo\n");
5139 	fprintf(stderr, "                only, no range-checking)\n");
5140 	fprintf(stderr, "   -l language  Language in which the texts are returned, default is \"en\"\n");
5141 	fprintf(stderr, "                (English). If the text in the requested language is missing,\n");
5142 	fprintf(stderr, "                english text will be returned.\n");
5143 	fprintf(stderr, "   -v           Verbose (debug) mode\n");
5144 	fprintf(stderr, "   -vv          Very verbose (debug) mode\n");
5145 	fprintf(stderr, "   filename     Read input from a file and not from standard input\n");
5146 	fprintf(stderr, "\n");
5147 	exit(1);
5148        	break;
5149       default :
5150 	fprintf(stderr, "Unknown option \'-%c\'!\n", argv[i][1]);
5151 	exit(1);
5152       }
5153     } else {
5154       filename = argv[i];
5155     }
5156   }
5157 
5158   if (debug) fprintf(stderr,"Language: %s\n", language);
5159 
5160   if (datatype == 0) { /* Parse overview data */
5161 
5162     /* Parse the XML input */
5163     overview = parseOverviewFile(filename, language, debug);
5164 
5165     if (overview) {
5166 
5167       /* Generate the Perl data structure on standard output */
5168       generateOverviewPerlData(overview, debug);
5169 
5170     } else {
5171       exit(1);
5172     }
5173 
5174   } else if (datatype == 1) { /* Parse printer/driver combo data */
5175 
5176     /* Parse the XML input */
5177     combo = parseComboFile(filename, language, debug);
5178 
5179     if (combo) {
5180 
5181       /* Prepare the data for the output */
5182       prepareComboData(combo, defaultsettings, num_defaultsettings, debug);
5183 
5184       /* Generate the Perl data structure on standard output */
5185       generateComboPerlData(combo, debug);
5186 
5187     } else {
5188       exit(1);
5189     }
5190 
5191   } else if (datatype == 2) { /* Parse overview data */
5192 
5193     /* Parse the XML input */
5194     printer = parsePrinterFile(filename, language, debug);
5195 
5196     if (printer) {
5197 
5198       /* Generate the Perl data structure on standard output */
5199       generatePrinterPerlData(printer, debug);
5200 
5201     } else {
5202       exit(1);
5203     }
5204 
5205   } else if (datatype == 3) { /* Parse overview data */
5206 
5207     /* Parse the XML input */
5208     driver = parseDriverFile(filename, language, debug);
5209 
5210     if (driver) {
5211 
5212       /* Generate the Perl data structure on standard output */
5213       generateDriverPerlData(driver, debug);
5214 
5215     } else {
5216       exit(1);
5217     }
5218 
5219   }
5220 
5221   /* Clean up everything else before quitting. */
5222   xmlCleanupParser();
5223 
5224   return(0);
5225 }
5226