Replace 'tap' to 'spaces' to make gbs build succeed
[platform/upstream/hplip.git] / dat2drv.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # (c) Copyright 2008-9 Hewlett-Packard Development Company, L.P.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # Author: Don Welch
21 #
22
23 __version__ = "3.3"
24 __title__ = 'DAT to DRV.IN converter. Also creates Foomatic XML files.'
25 __doc__ = "Create DRV.IN file and Foomatic XML files from MODELS.DAT data. Processes all *.in.template files in prnt/drv directory."
26
27 import os
28 os.putenv("HPLIP_BUILD", "1")
29
30 # Std Lib
31 import os.path
32 import sys
33 import getopt
34 import re
35 from xml.dom.minidom import Document, parse, parseString
36 from types import StringType, UnicodeType
37 import string
38
39 # Local
40 from base.g import *
41 from base import utils, tui, models
42 #from prnt import printable_areas
43
44 # Globals
45 errors = 0
46 count = 0
47 enc = 'utf-8'
48
49 models_dict = {}
50 norm_models = {} # { 'norm'd model' : ( 'model', type, has_scanner ), ... }
51 norm_models_keys = {}
52 model_dat = None
53 total_models = 0
54 sorted_category_models = {}
55 unsupported_models = []
56
57 pat_prod_num = re.compile("""(\d+)""", re.I)
58 pat_template = re.compile("""^(\s*)//\s*<%(\S+)%>""", re.I)
59 pat_template2 = re.compile("""^\s*<%(\S+)%>""", re.I)
60
61
62 SHORTENING_REPLACEMENTS = {
63 'color laserjet' : 'CLJ',
64 'laserjet' : 'LJ',
65 'photosmart': 'PS',
66 'deskjet' : 'DJ',
67 'color inkjet printer' : '',
68 'officejet' : 'OJ',
69 'business inkjet' : 'BIJ',
70 'designjet' : 'DESIGNJ',
71 'printer scanner copier' : 'PSC',
72 'color lj' : 'CLJ',
73 'professional' : 'Pro',
74 }
75
76
77 USAGE = [(__doc__, "", "name", True),
78          ("Usage: dat2drv.py [OPTIONS]", "", "summary", True),
79          utils.USAGE_OPTIONS,
80          ("Verbose mode:", "-v or --verbose", "option", False),
81          ("Quiet mode:", "-q or --quiet", "option", False),
82          utils.USAGE_LOGGING1, utils.USAGE_LOGGING2,
83          utils.USAGE_HELP,
84         ]
85
86 def usage(typ='text'):
87     if typ == 'text':
88         utils.log_title(__title__, __version__)
89
90     utils.format_text(USAGE, typ, __title__, 'drv2xml.py', __version__)
91     sys.exit(0)
92
93
94
95 def _encode(v):
96     if isinstance(v, UnicodeType):
97         v = v.encode(enc)
98     return v
99
100
101
102 class XMLElement:
103     def __init__(self, doc, el):
104         self.doc = doc
105         self.el = el
106
107     def __getitem__(self, name):
108         a = self.el.getAttributeNode(name)
109         if a:
110             return _encode(a.value)
111         return None
112
113     def __setitem__(self, name, value):
114         self.el.setAttribute(name, _encode(value))
115
116     def __delitem__(self, name):
117         self.el.removeAttribute(name)
118
119     def __str__(self):
120         return _encode(self.doc.toxml())
121
122     def toString(self):
123         return _encode(self.doc.toxml())
124
125     def _inst(self, el):
126         return XMLElement(self.doc, el)
127
128     def get(self, name, default=None):
129         a = self.el.getAttributeNode(name)
130         if a:
131             return _encode(a.value)
132         return _encode(default)
133
134     def add(self, tag, **kwargs):
135         el = self.doc.createElement(tag)
136         for k, v in kwargs.items():
137             el.setAttribute(k, _encode(str(v)))
138         return self._inst(self.el.appendChild(el))
139
140     def addText(self, data):
141         return self._inst(
142             self.el.appendChild(
143                 self.doc.createTextNode(_encode(data))))
144
145     def addComment(self, data):
146         return self._inst(
147             self.el.appendChild(
148                 self.doc.createComment(data)))
149
150     def getText(self, sep=" "):
151         rc = []
152         for node in self.el.childNodes:
153             if node.nodeType == node.TEXT_NODE:
154                 rc.append(node.data)
155         return _encode(string.join(rc, sep))
156
157     def getAll(self, tag):
158         return map(self._inst, self.el.getElementsByTagName(tag))
159
160
161 class XMLDocument(XMLElement):
162
163     def __init__(self, tag=None, **kwargs):
164         self.doc  = Document()
165         XMLElement.__init__(self, self.doc, self.doc)
166         if tag:
167             self.el = self.add(tag, **kwargs).el
168
169     def parse(self, d):
170         self.doc = self.el = parse(d)
171         return self
172
173     def parseString(self, d):
174         self.doc = self.el = parseString(_encode(d))
175         return self
176
177
178
179
180 def fixFileName(model):
181     if model.startswith('hp_'):
182         model = model.replace('hp_', 'hp-')
183
184     elif model.startswith('apollo_'):
185         model = model.replace('apollo_', 'apollo-')
186
187     elif not model.startswith('hp-'):
188         model = 'hp-' + model
189
190     return model.strip('~')
191
192
193 def categorize2(m):
194     is_aio = (models_dict[m]['scan-type'] != SCAN_TYPE_NONE or
195         models_dict[m]['copy-type'] != COPY_TYPE_NONE or
196         models_dict[m]['fax-type'] != FAX_TYPE_NONE)
197
198     if "deskjet" in m or \
199         ("color" in m and "inkjet" in m) or \
200         m.startswith("dj") or \
201         m.startswith("cp"):
202
203         if is_aio:
204             i = MODEL_TYPE2_DESKJET_AIO
205         else:
206             i = MODEL_TYPE2_DESKJET
207
208     elif "photosmart" in m:
209         i = MODEL_TYPE2_PHOTOSMART
210
211     elif "officejet" in m:
212         i = MODEL_TYPE2_OFFICEJET
213
214     elif "psc" in m or \
215         "printer_scanner_copier" in m:
216
217         i = MODEL_TYPE2_PSC
218
219     elif "laserjet" in m:
220         if "color" in m:
221             i = MODEL_TYPE2_COLOR_LASERJET
222         else:
223             i = MODEL_TYPE2_LASERJET
224
225     elif "mopier" in m:
226         i = MODEL_TYPE2_LASERJET
227
228     elif "business" in m and \
229         "inkjet" in m:
230
231         i = MODEL_TYPE2_BIJ
232
233     elif "edgeline" in m:
234         i = MODEL_TYPE2_EDGELINE
235
236     elif "apollo" in m:
237         i = MODEL_TYPE2_APOLLO
238
239     elif "designjet" in m or \
240          "plotter" in m or \
241          "draft" in m or \
242          "eagle" in m or \
243          "electrostatic" in m or \
244          m.startswith('hp_2') or \
245          m.startswith('hp_7') or \
246          m.startswith('hp_9'):
247
248         i = MODEL_TYPE2_DESIGNJET
249
250     else: # Other
251         i = MODEL_TYPE2_OTHER
252
253     return (m, i, models_dict[m])
254
255
256 def sort_product(x, y):
257     try:
258         _x = int(pat_prod_num.search(x).group(1))
259     except (TypeError, AttributeError):
260         _x = 0
261
262     try:
263         _y = int(pat_prod_num.search(y).group(1))
264     except (TypeError, AttributeError):
265         _y = 0
266
267     if not _x and not _y:
268         return cmp(x, y)
269
270     return cmp(_x, _y)
271
272
273 def sort_product2(x, y): # sort key is first element of tuple
274     return sort_product(x[0], y[0])
275
276
277 def load_models(unreleased=True):
278     global models_dict
279     global norm_models
280     global norm_models_keys
281     global model_dat
282     global total_models
283     global sorted_category_models
284     global unsupported_models
285
286     models_dict = model_dat.read_all_files(unreleased)
287
288     log.debug("Raw models:")
289
290     for m in models_dict:
291         nm = models.normalizeModelUIName(m)
292         models_dict[m]['norm_model'] = nm.strip('~')
293         models_dict[m]['case_models'] = []
294
295         i, case_models = 1, []
296         while True:
297             try:
298                 cm = models.normalizeModelUIName(models_dict[m]['model%d' % i])
299             except KeyError:
300                 break
301
302             case_models.append(cm)
303             i+= 1
304
305         if not case_models:
306             case_models = [nm]
307
308         models_dict[m]['case_models'] = case_models[:]
309         cat = categorize2(m)
310         models_dict[m]['category'] = cat
311
312         for c in case_models:
313             norm_models[c] =  cat
314
315             if models_dict[m]['support-type'] == SUPPORT_TYPE_NONE:
316                 unsupported_models.append((c, m))
317
318     norm_models_keys = norm_models.keys()
319     norm_models_keys.sort(lambda x, y: sort_product(x, y))
320
321     unsupported_models.sort(lambda x, y: sort_product2(x, y))
322
323     total_models = len(norm_models)
324
325     #log.info("Loaded %d models." % total_models)
326
327
328
329
330 def main(args):
331     global errors
332     global model_dat
333     line_num = 0
334     log.set_module("dat2drv.py")
335     cur_path = os.path.realpath(os.path.normpath(os.getcwd()))
336     dat_path = os.path.join(cur_path, 'data', 'models')
337     model_dat = models.ModelData(dat_path)
338     load_models()
339
340
341
342     verbose = False
343     quiet = False
344
345     try:
346         opts, args = getopt.getopt(args, 'd:l:ho:vq',
347                                    ['logging=', 'help',
348                                     'help-rest', 'help-man',
349                                     'drv=', 'output=',
350                                     'verbose', 'quiet'])
351     except getopt.GetoptError, e:
352         log.error(e.msg)
353         usage()
354         sys.exit(0)
355
356     log_level = 'info'
357     if os.getenv("HPLIP_DEBUG"):
358         log.set_level('debug')
359
360     for o, a in opts:
361         if o in ('-h', '--help'):
362             usage()
363
364         elif o == '--help-rest':
365             usage('rest')
366
367         elif o == '--help-man':
368             usage('man')
369
370         elif o in ('-v', '--verbose'):
371             verbose = True
372
373         elif o in ('-q', '--quiet'):
374             quiet = True
375
376         elif o in ('-l', '--logging'):
377             log.set_level(a.lower().strip())
378
379
380     if not quiet:
381         utils.log_title(__title__, __version__)
382
383     drv_dir = os.path.join(cur_path, 'prnt', 'drv')
384
385     errors = []
386     warns = []
387     notes = []
388
389     for template_file in utils.walkFiles(drv_dir, recurse=False, abs_paths=True,
390         return_folders=False, pattern='*.in.template'):
391
392         basename = os.path.basename(template_file).split('.')[0]
393
394         # Output
395         drv_in_file = os.path.join(cur_path, 'prnt', 'drv', '%s.drv.in' % basename)
396
397         # XML output (per model)
398         output_path = os.path.join(cur_path, 'prnt', 'drv', 'foomatic_xml', basename)
399
400         # XML Output (master driver list)
401         driver_path = os.path.join(cur_path, 'prnt', 'drv', 'foomatic_xml', basename, '%s.xml' % basename)
402
403         log.info("Working on %s file..." % basename)
404         log.info("Input file: %s" % template_file)
405         log.info("Output file: %s" % drv_in_file)
406         log.info("Output XML directory: %s" % output_path)
407         log.info("Output driver XML file: %s" % driver_path)
408
409
410
411         # CREATE DRV.IN FILE
412
413         log.info("Processing %s.drv.in.template..." % basename)
414         tui.update_spinner()
415
416         template_classes = []
417
418         template_file_f = open(template_file, 'r')
419         drv_in_file_f = open(drv_in_file, 'w')
420
421         models_placement = {}
422         for m in models_dict:
423             models_placement[m] = 0
424
425         line = 0
426
427         for x in template_file_f:
428             if verbose:
429                 log.info(x.strip())
430
431             line += 1
432             tui.update_spinner()
433             drv_in_file_f.write(x)
434             match = pat_template.match(x)
435             if match is not None:
436                 matches = []
437                 indent = match.group(1)
438                 indent2 = ' '*(len(indent)+2)
439
440                 classes = match.group(2).split(':')
441                 tech_class = classes[0]
442
443                 if tech_class not in models.TECH_CLASSES:
444                     errors.append("(%s:line %d) Invalid tech-class (%s): %s" % (basename, line, tech_class, x.strip()))
445                     continue
446
447                 template_classes.append(tech_class)
448
449                 tech_subclass = classes[1:]
450
451                 ok = True
452                 for sc in tech_subclass:
453                     if sc not in models.TECH_SUBCLASSES:
454                         errors.append("(%s:line %d) Invalid tech-subclass (%s): %s" % (basename, line, sc, x.strip()))
455                         ok = False
456
457                 if not ok:
458                     continue
459
460                 for m in models_dict:
461                     include = False
462
463                     if tech_class in models_dict[m]['tech-class'] and \
464                         len(models_dict[m]['tech-subclass']) == len(tech_subclass):
465
466                         for msc in models_dict[m]['tech-subclass']:
467                             if msc not in tech_subclass:
468                                break
469                         else:
470                             include = True
471
472                     if include:
473                         models_placement[m] += 1
474                         matches.append(m)
475
476                 if matches:
477                     matches.sort(lambda x, y: sort_product(x, y))
478
479                     for p in matches:
480
481                         if verbose:
482                             log.info("(%s) Adding section for model: %s" % (basename, p))
483
484                         drv_in_file_f.write("%s{\n" % indent)
485
486                         if basename == 'hpcups':
487                             model_name = models_dict[p]['norm_model']
488                         else:
489                             model_name = models_dict[p]['norm_model'] + " %s" % basename
490
491                         orig_model_name = model_name
492
493                         while True:
494                             if len(model_name) > 31:
495                                 for k in SHORTENING_REPLACEMENTS:
496                                     if k in model_name.lower():
497                                         model_name = utils.ireplace(model_name, k, SHORTENING_REPLACEMENTS[k])
498                                         model_name = model_name.replace('  ', ' ')
499
500                                         if len(model_name) < 32:
501                                             warns.append('len("%s")>31, shortened to len("%s")=%d using sub-brand shortening replacements.' % (orig_model_name, model_name, len(model_name)))
502                                             break
503
504                                 if len(model_name) < 32:
505                                     break
506
507                                 if "series" in model_name.lower():
508                                     model_name = utils.ireplace(model_name, "series", "Ser.")
509                                     model_name = model_name.replace('  ', ' ')
510
511                                     if len(model_name) < 32:
512                                         warns.append('len("%s")>31, shortened to len("%s")=%d using "series" to "ser." replacement.' % (orig_model_name, model_name, len(model_name)))
513                                         break
514
515                                 if "ser." in model_name.lower():
516                                     model_name = utils.ireplace(model_name, "ser.", "")
517                                     model_name = model_name.replace('  ', ' ')
518
519                                     if len(model_name) < 32:
520                                         warns.append('len("%s")>31, shortened to len("%s")=%d using "ser." removal.' % (orig_model_name, model_name, len(model_name)))
521                                         break
522
523                                 if len(model_name) > 31:
524                                     model_name = model_name[:31]
525                                     errors.append('len("%s")>31 chars, could not shorten to <32. Truncating to 31 chars (%s).' % (orig_model_name, model_name))
526
527                             break
528
529                         drv_in_file_f.write('%sModelName "%s"\n' % (indent2, orig_model_name))
530
531                         if len(models_dict[p]['tech-class']) > 1:
532                             drv_in_file_f.write('%sAttribute "NickName" "" "%s %s, $Version' %
533                                 (indent2, orig_model_name, models.TECH_CLASS_PDLS[tech_class]))
534                         else:
535                             drv_in_file_f.write('%sAttribute "NickName" "" "%s, $Version' %
536                                 (indent2, orig_model_name))
537
538                         if models_dict[p]['plugin'] in (1, 2):
539                             if (models_dict[p]['plugin-reason'] & 15 ) in (1, 2, 3, 4, 5, 6, 8, 9, 10, 12):
540                                 drv_in_file_f.write(', requires proprietary plugin')
541
542                         drv_in_file_f.write('"\n')
543
544                         drv_in_file_f.write('%sAttribute "ShortNickName" "" "%s"\n' % (indent2, model_name))
545
546                         pp = p.replace('_', ' ')
547                         if 'apollo' in p.lower():
548                             devid = "MFG:Apollo;MDL:%s;DES:%s;" % (pp, pp)
549                         else:
550                             devid = "MFG:HP;MDL:%s;DES:%s;" % (pp, pp)
551
552                         drv_in_file_f.write('%sAttribute "1284DeviceID" "" "%s"\n' % (indent2, devid))
553
554                         if len(models_dict[p]['tech-class']) > 1:
555                             if basename == 'hpcups':
556                                 drv_in_file_f.write('%sPCFileName "%s-%s.ppd"\n' %
557                                     (indent2, fixFileName(p), models.TECH_CLASS_PDLS[tech_class]))
558                             else:
559                                 drv_in_file_f.write('%sPCFileName "%s-%s-%s.ppd"\n' %
560                                     (indent2, fixFileName(p), basename, models.TECH_CLASS_PDLS[tech_class]))
561
562                         elif tech_class != 'Postscript':
563                             if basename == 'hpcups':
564                                 drv_in_file_f.write('%sPCFileName "%s.ppd"\n' % (indent2, fixFileName(p)))
565                             else:
566                                 drv_in_file_f.write('%sPCFileName "%s-%s.ppd"\n' % (indent2, fixFileName(p), basename))
567
568                         else:
569                             drv_in_file_f.write('%sPCFileName "%s-ps.ppd"\n' % (indent2, fixFileName(p)))
570
571                         for c in models_dict[p]['case_models']:
572                             drv_in_file_f.write('%sAttribute "Product" "" "(%s)"\n' % (indent2, c))
573
574                         drv_in_file_f.write("%s}\n" % indent)
575
576                 else:
577                     errors.append("(%s:line %d) No models matched the specified classes on line: %s" % (basename, line, x.strip()))
578
579             else:
580                 match = pat_template2.match(x)
581                 if match is not None:
582                     errors.append("(%s:line %d) Malformed line: %s (missing initial //)" % (basename, line, x.strip()))
583
584
585         template_file_f.close()
586         drv_in_file_f.close()
587         tui.cleanup_spinner()
588
589         for tc in models.TECH_CLASSES:
590             if tc.lower() in ('undefined', 'postscript', 'unsupported'):
591                 continue
592
593             if tc not in template_classes:
594                 warns.append("(%s) Section <%%%s:...%%> not found." % (basename, tc))
595
596
597         # OUTPUT XML FILES
598
599         if not os.path.exists(output_path):
600             os.makedirs(output_path)
601
602         if os.path.exists(driver_path):
603             os.remove(driver_path)
604
605         files_to_delete = []
606         for f in utils.walkFiles(output_path, recurse=True, abs_paths=True, return_folders=False, pattern='*'):
607             files_to_delete.append(f)
608
609         for f in files_to_delete:
610             os.remove(f)
611
612         driver_f = file(driver_path, 'w')
613
614         driver_doc = XMLDocument("driver", id="driver/hplip")
615         name_node = driver_doc.add("name")
616         name_node.addText("hplip")
617         url_node = driver_doc.add("url")
618         url_node.addText("http://hplipopensource.com")
619         supplier_node = driver_doc.add("supplier")
620         supplier_node.addText("Hewlett-Packard")
621         mfg_node = driver_doc.add("manufacturersupplied")
622         mfg_node.addText("HP|Apollo")
623         lic_node = driver_doc.add("license")
624         lic_node.addText("BSD/GPL/MIT")
625         driver_doc.add("freesoftware")
626         support_node = driver_doc.add("supportcontact", level="voluntary", url="https://launchpad.net/hplip")
627         support_node.addText("HPLIP Support at Launchpad.net")
628         shortdesc_node = driver_doc.add("shortdescription")
629         shortdesc_en_node = shortdesc_node.add("en")
630         shortdesc_en_node.addText("HP's driver suite for printers and multi-function devices")
631         func_node = driver_doc.add("functionality")
632         maxresx_node = func_node.add("maxresx")
633         maxresx_node.addText("1200")
634         maxresy_node = func_node.add("maxresy")
635         maxresy_node.addText("1200")
636         func_node.add("color")
637         exec_node = driver_doc.add("execution")
638         exec_node.add("nopjl")
639         exec_node.add("ijs")
640         proto_node = exec_node.add("prototype")
641         #proto_node.addText("gs -q -dBATCH -dPARANOIDSAFER -dQUIET -dNOPAUSE -sDEVICE=ijs -sIjsServer=hpijs%A%B%C -dIjsUseOutputFD%Z -sOutputFile=- -")
642         comments_node = driver_doc.add("comments")
643         comments_en_node = comments_node.add("en")
644         comments_en_node.addText("")
645
646         printers_node = driver_doc.add("printers")
647
648         for m in models_dict:
649
650             if models_dict[m]['support-type'] == SUPPORT_TYPE_NONE:
651                 continue
652
653             if 'apollo' in m.lower():
654                 make = 'Apollo'
655             else:
656                 make = 'HP'
657
658             if 'apollo' in m.lower():
659                 ieee1284 = "MFG:Apollo;MDL:%s;DES:%s;" % (m, m)
660
661             else:
662                 ieee1284 = "MFG:HP;MDL:%s;DES:%s;" % (m, m)
663
664             postscriptppd = ''
665             if 'Postscript' in models_dict[m]['tech-class']:
666                 postscriptppd = "%s-ps.ppd" % fixFileName(m)
667
668             stripped_model = m
669
670             if stripped_model.startswith('hp_'):
671                 stripped_model = stripped_model.replace('hp_', '').capitalize()
672
673             elif stripped_model.startswith('apollo_'):
674                 stripped_model = stripped_model.replace('apollo_', '').capitalize()
675
676             fixed_model = stripped_model.replace('_', ' ').capitalize()
677
678             # Output to the per-model XML file
679             outputModel(m, fixed_model, stripped_model, make, postscriptppd, ieee1284, output_path, verbose)
680
681             # Output to driver master XML file
682             outputDriver(m, fixed_model, stripped_model, make, printers_node, verbose)
683
684         driver_f.write(str(driver_doc))
685         driver_f.close()
686
687         # Make sure all models ended up in drv.in file
688         log.info("Checking for errors...")
689         tui.update_spinner()
690
691         for m in models_dict:
692             tui.update_spinner()
693             tc = models_dict[m]['tech-class']
694             st = models_dict[m]['support-type']
695
696             if not tc or 'Undefined' in tc:
697                 if st:
698                     errors.append('(%s) Invalid tech-class for model %s ("Undefined" or missing)' % (basename, m))
699                 #else:
700                 #    warns.append('(%s) Invalid tech-class for unsupported model %s ("Undefined" or missing)' % (basename, m))
701
702             else:
703                 if not models_placement[m] and st and \
704                     len(tc) == 1 and 'Postscript' not in tc:
705
706                     sects = []
707                     for tc in models_dict[m]['tech-class']:
708                         for sc in models_dict[m]['tech-subclass']:
709                             sects.append(sc)
710
711                     errors.append("(%s) Model '%s' did not have a matching section. Needed section: <%%%s:%s%%>" %
712                         (basename, m, tc, ':'.join(sects)))
713
714                 if len(tc) == 1 and 'Postscript' in tc:
715                     notes.append("(%s) Postscript-only model %s was not included in DRV file." % (basename, m))
716
717         tui.cleanup_spinner()
718
719         # end for
720
721     if not quiet or verbose:
722         if notes:
723             tui.header("NOTES")
724             for n in notes:
725                 log.note(n)
726
727         if warns:
728             tui.header("WARNINGS")
729             for w in warns:
730                 log.warn(w)
731
732         if errors:
733             tui.header("ERRORS")
734             for e in errors:
735                 log.error(e)
736
737     else:
738         if warns:
739             log.warn("%d warnings" % len(warns))
740
741         if errors:
742             log.error("%d errors" % len(errors))
743
744
745 def parseDeviceID(device_id):
746     d= {}
747     x = [y.strip() for y in device_id.strip().split(';') if y]
748
749     for z in x:
750         y = z.split(':')
751         try:
752             d.setdefault(y[0].strip(), y[1])
753         except IndexError:
754             d.setdefault(y[0].strip(), None)
755
756     d.setdefault('MDL', '')
757     d.setdefault('SN',  '')
758
759     if 'MODEL' in d:
760         d['MDL'] = d['MODEL']
761         del d['MODEL']
762
763     if 'SERIAL' in d:
764         d['SN'] = d['SERIAL']
765         del d['SERIAL']
766
767     elif 'SERN' in d:
768         d['SN'] = d['SERN']
769         del d['SERN']
770
771     if d['SN'].startswith('X'):
772         d['SN'] = ''
773
774     return d
775
776
777 def outputModel(model, fixed_model, stripped_model, make, postscriptppd, ieee1284, output_path, verbose=False):
778     global errors
779     global count
780
781     count += 1
782
783 ##    fixed_model = model.replace(' ', '_')
784 ##
785 ##    if fixed_model.startswith('hp_'):
786 ##        fixed_model = fixed_model.replace('hp_', 'hp-')
787 ##
788 ##    elif fixed_model.startswith('apollo_'):
789 ##        fixed_model = fixed_model.replace('apollo_', 'apollo-')
790 ##
791 ##    else:
792 ##        fixed_model = 'hp-' + fixed_model
793 ##
794 ##    stripped_model = model
795 ##    if stripped_model.startswith('hp '):
796 ##        stripped_model = stripped_model.replace('hp ', '')
797
798
799     printerID = make + '-' + stripped_model
800
801     output_filename = os.path.join(output_path, printerID+".xml")
802
803     if verbose:
804         log.info("\n\n%s:" % output_filename)
805
806     output_f = file(output_filename, 'w')
807
808     doc = XMLDocument("printer", id="printer/%s" % printerID)
809     make_node = doc.add("make")
810     make_node.addText(make)
811     model_node = doc.add("model")
812     model_node.addText(fixed_model)
813     url_node = doc.add("url")
814     url_node.addText("http://www.hp.com")
815
816     lang_node = doc.add("lang")
817     lang_node.add("pcl", level="3")
818
819     autodetect_node = doc.add("autodetect")
820     usb_node = autodetect_node.add("usb")
821
822     driver_node = doc.add("driver")
823     driver_node.addText('hplip')
824
825     drivers_node = doc.add("drivers")
826     driver_node = drivers_node.add("driver")
827     id_node = driver_node.add("id")
828     id_node.addText("hplip")
829
830     if postscriptppd:
831         # Postscript
832         lang_node.add("postscript", level="2")
833         lang_node.add("pjl")
834         text_node = lang_node.add("text")
835         charset_node = text_node.add("charset")
836         charset_node.addText("us-ascii")
837         #ppd_node = driver_node.add("ppd")
838         #ppd_node.addText(postscriptppd)
839     #else:
840     #    id_node.addText("hpijs")
841
842     if 1:
843         #ieee1284_node = usb_node.add("ieee1284")
844         #ieee1284_node.addText(ieee1284)
845
846         device_id = parseDeviceID(ieee1284)
847
848         desc_node = usb_node.add("description")
849         #desc_node.addText(device_id['DES'])
850         desc_node.addText(make + ' ' + fixed_model)
851
852         mfg_node = usb_node.add("manufacturer")
853         #mfg_node.addText(device_id['MFG'])
854         mfg_node.addText("Hewlett-Packard")
855
856         model_node = usb_node.add("model")
857         #model_node.addText(device_id['MDL'])
858         model_node.addText(make + ' ' + fixed_model)
859
860         #cmdset_node = usb_node.add("commandset")
861         #cmdset_node.addText("???")
862
863     if verbose:
864         log.info(str(doc))
865
866     output_f.write(str(doc))
867
868     output_f.close()
869
870
871 def outputDriver(m, fixed_model, stripped_model, make, printers_node, verbose):
872
873     printerID = make + '-' + stripped_model
874
875     tech_classes = models_dict[m]['tech-class']
876     #print tech_classes
877     printer_node = printers_node.add("printer")
878     id_node = printer_node.add("id")
879     id_node.addText("printer/%s" % printerID)
880
881 ##    margins_node = printer_node.add("margins")
882 ##    general_margins_node = margins_node.add("general")
883
884 ##    unit_node = general_margins_node.add("unit")
885 ##    unit_node.addText("in")
886 ##
887 ##    for tc in tech_classes:
888 ##        if tc not in ('Undefined', 'Unsupported', 'PostScript'):
889 ##            try:
890 ##                margins_data = printable_areas.data[tc]
891 ##            except KeyError:
892 ##                continue
893 ##            else:
894 ##                print margins_data
895 ##                break
896
897 ##<printer>
898 ##   <id>printer/HP-DeskJet_350C</id><!-- HP DeskJet 350C -->
899 ##   <functionality>
900 ##    <maxresx>600</maxresx>
901 ##    <maxresy>300</maxresy>
902 ##   </functionality>
903 ##   <ppdentry>
904 ##     *DefaultResolution: 600dpi
905 ##    </ppdentry>
906 ##   <margins>
907 ##    <general>
908 ##     <unit>in</unit>
909 ##     <relative />
910 ##     <left>0.25</left>
911 ##     <right>0.25</right>
912 ##     <top>0.125</top>
913 ##     <bottom>0.67</bottom>
914 ##    </general>
915 ##    <exception PageSize="A4">
916 ##     <left>0.135</left>
917 ##     <right>0.135</right>
918 ##    </exception>
919 ##   </margins>
920 ##  </printer>
921
922
923
924 if __name__ == '__main__':
925     sys.exit(main(sys.argv[1:]))
926