home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / hplip / base / utils.pyc (.txt) < prev   
Encoding:
Python Compiled Bytecode  |  2006-08-31  |  37.0 KB  |  1,357 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. from __future__ import generators
  5. import sys
  6. import os
  7. import fnmatch
  8. import tempfile
  9. import socket
  10. import struct
  11. import select
  12. import time
  13. import fcntl
  14. import errno
  15. import stat
  16. import string
  17. import xml.parsers.expat as xml
  18. import commands
  19. from g import *
  20. from codes import *
  21.  
  22. def Translator(frm = '', to = '', delete = '', keep = None):
  23.     allchars = string.maketrans('', '')
  24.     if len(to) == 1:
  25.         to = to * len(frm)
  26.     
  27.     trans = string.maketrans(frm, to)
  28.     if keep is not None:
  29.         delete = allchars.translate(allchars, keep.translate(allchars, delete))
  30.     
  31.     
  32.     def callable(s):
  33.         return s.translate(trans, delete)
  34.  
  35.     return callable
  36.  
  37. prv_pidfile = None
  38. prv_pidfile_name = ''
  39.  
  40. def get_pidfile_lock(a_pidfile_name = ''):
  41.     ''' Call this to either lock the pidfile, or to update it after a fork()
  42.         Credit: Henrique M. Holschuh <hmh@debian.org>
  43.     '''
  44.     global prv_pidfile_name, prv_pidfile
  45.     if prv_pidfile_name == '':
  46.         
  47.         try:
  48.             prv_pidfile_name = a_pidfile_name
  49.             prv_pidfile = os.fdopen(os.open(prv_pidfile_name, os.O_RDWR | os.O_CREAT, 420), 'r+')
  50.             fcntl.fcntl(prv_pidfile.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
  51.             while None:
  52.                 
  53.                 try:
  54.                     fcntl.flock(prv_pidfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
  55.                 except (OSError, IOError):
  56.                     e = None
  57.                     if e.errno == errno.EINTR:
  58.                         continue
  59.                     elif e.errno == errno.EWOULDBLOCK:
  60.                         
  61.                         try:
  62.                             prv_pidfile.seek(0)
  63.                             otherpid = int(prv_pidfile.readline(), 10)
  64.                             sys.stderr.write("can't lock %s, running daemon's pid may be %d\n" % (prv_pidfile_name, otherpid))
  65.                         except (OSError, IOError):
  66.                             e = None
  67.                             sys.stderr.write('error reading pidfile %s: (%d) %s\n' % (prv_pidfile_name, e.errno, e.strerror))
  68.  
  69.                         sys.exit(1)
  70.                     
  71.                     sys.stderr.write("can't lock %s: (%d) %s\n" % (prv_pidfile_name, e.errno, e.strerror))
  72.                     sys.exit(1)
  73.  
  74.                 break
  75.         except (OSError, IOError):
  76.             e = None
  77.             sys.stderr.write("can't open pidfile %s: (%d) %s\n" % (prv_pidfile_name, e.errno, e.strerror))
  78.             sys.exit(1)
  79.         except:
  80.             None<EXCEPTION MATCH>(OSError, IOError)
  81.         
  82.  
  83.     None<EXCEPTION MATCH>(OSError, IOError)
  84.     
  85.     try:
  86.         prv_pidfile.seek(0)
  87.         prv_pidfile.write('%d\n' % os.getpid())
  88.         prv_pidfile.flush()
  89.         prv_pidfile.truncate()
  90.     except (OSError, IOError):
  91.         e = None
  92.         log.error("can't update pidfile %s: (%d) %s\n" % (prv_pidfile_name, e.errno, e.strerror))
  93.  
  94.  
  95.  
  96. def daemonize(stdin = '/dev/null', stdout = '/dev/null', stderr = '/dev/null'):
  97.     '''
  98.     Credit: J\xc3\xbcrgen Hermann, Andy Gimblett, and Noah Spurrier
  99.             http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012
  100.  
  101.     Proper pidfile support: Henrique M. Holschuh <hmh@debian.org>
  102.     '''
  103.     if prv_pidfile_name != '' or prv_pidfile_name != '':
  104.         get_pidfile_lock(prv_pidfile_name)
  105.     
  106.     
  107.     try:
  108.         pid = os.fork()
  109.         if pid > 0:
  110.             sys.exit(0)
  111.     except OSError:
  112.         e = None
  113.         sys.stderr.write('fork #1 failed: (%d) %s\n' % (e.errno, e.strerror))
  114.         sys.exit(1)
  115.  
  116.     os.chdir('/')
  117.     os.umask(0)
  118.     os.setsid()
  119.     
  120.     try:
  121.         pid = os.fork()
  122.         if pid > 0:
  123.             sys.exit(0)
  124.     except OSError:
  125.         e = None
  126.         sys.stderr.write('fork #2 failed: (%d) %s\n' % (e.errno, e.strerror))
  127.         sys.exit(1)
  128.  
  129.     if prv_pidfile_name != '':
  130.         get_pidfile_lock()
  131.     
  132.     si = file(stdin, 'r')
  133.     so = file(stdout, 'a+')
  134.     se = file(stderr, 'a+', 0)
  135.     os.dup2(si.fileno(), sys.stdin.fileno())
  136.     os.dup2(so.fileno(), sys.stdout.fileno())
  137.     os.dup2(se.fileno(), sys.stderr.fileno())
  138.  
  139.  
  140. def ifelse(cond, t, f):
  141.     if cond:
  142.         return t
  143.     else:
  144.         return f
  145.  
  146.  
  147. def to_bool_str(s, default = '0'):
  148.     ''' Convert an arbitrary 0/1/T/F/Y/N string to a normalized string 0/1.'''
  149.     if isinstance(s, str) and s:
  150.         if s[0].lower() in [
  151.             '1',
  152.             't',
  153.             'y']:
  154.             return '1'
  155.         elif s[0].lower() in [
  156.             '0',
  157.             'f',
  158.             'n']:
  159.             return '0'
  160.         
  161.     
  162.     return default
  163.  
  164.  
  165. def to_bool(s, default = False):
  166.     ''' Convert an arbitrary 0/1/T/F/Y/N string to a boolean True/False value.'''
  167.     if isinstance(s, str) and s:
  168.         if s[0].lower() in [
  169.             '1',
  170.             't',
  171.             'y']:
  172.             return True
  173.         elif s[0].lower() in [
  174.             '0',
  175.             'f',
  176.             'n']:
  177.             return False
  178.         
  179.     elif isinstance(s, bool):
  180.         return s
  181.     
  182.     return default
  183.  
  184.  
  185. def path_exists_safely(path):
  186.     ''' Returns True if path exists, and points to a file with permissions at least as strict as 0755.
  187.         Credit: Contributed by Henrique M. Holschuh <hmh@debian.org>'''
  188.     
  189.     try:
  190.         pathmode = os.stat(path)[stat.ST_MODE]
  191.         if pathmode & 18 != 0:
  192.             return False
  193.     except (IOError, OSError):
  194.         return False
  195.  
  196.     return True
  197.  
  198.  
  199. def walkFiles(root, recurse = True, abs_paths = False, return_folders = False, pattern = '*', path = None):
  200.     if path is None:
  201.         path = root
  202.     
  203.     
  204.     try:
  205.         names = os.listdir(root)
  206.     except os.error:
  207.         raise StopIteration
  208.  
  209.     if not pattern:
  210.         pass
  211.     pattern = '*'
  212.     pat_list = pattern.split(';')
  213.     for name in names:
  214.         fullname = os.path.normpath(os.path.join(root, name))
  215.         for pat in pat_list:
  216.             if fnmatch.fnmatch(name, pat):
  217.                 if return_folders or not os.path.isdir(fullname):
  218.                     pass
  219.                 None if abs_paths else None<EXCEPTION MATCH>ValueError
  220.                 continue
  221.         
  222.         if os.path.islink(fullname):
  223.             fullname = os.path.realpath(os.readlink(fullname))
  224.         
  225.         if recurse or os.path.isdir(fullname) or os.path.islink(fullname):
  226.             for f in walkFiles(fullname, recurse, abs_paths, return_folders, pattern, path):
  227.                 yield f
  228.             
  229.     
  230.  
  231.  
  232. def is_path_writable(path):
  233.     if os.path.exists(path):
  234.         s = os.stat(path)
  235.         mode = s[stat.ST_MODE] & 511
  236.         if mode & 2:
  237.             return True
  238.         elif s[stat.ST_GID] == os.getgid() and mode & 16:
  239.             return True
  240.         elif s[stat.ST_UID] == os.getuid() and mode & 128:
  241.             return True
  242.         
  243.     
  244.     return False
  245.  
  246.  
  247. class TextFormatter:
  248.     LEFT = 0
  249.     CENTER = 1
  250.     RIGHT = 2
  251.     
  252.     def __init__(self, colspeclist):
  253.         self.columns = []
  254.         for colspec in colspeclist:
  255.             self.columns.append(Column(**colspec))
  256.         
  257.  
  258.     
  259.     def compose(self, textlist, add_newline = False):
  260.         numlines = 0
  261.         textlist = list(textlist)
  262.         if len(textlist) != len(self.columns):
  263.             log.error('Formatter: Number of text items does not match columns')
  264.             return None
  265.         
  266.         for text, column in map(None, textlist, self.columns):
  267.             column.wrap(text)
  268.             numlines = max(numlines, len(column.lines))
  269.         
  270.         complines = [
  271.             ''] * numlines
  272.         for ln in range(numlines):
  273.             for column in self.columns:
  274.                 complines[ln] = complines[ln] + column.getline(ln)
  275.             
  276.         
  277.         if add_newline:
  278.             return '\n'.join(complines) + '\n'
  279.         else:
  280.             return '\n'.join(complines)
  281.  
  282.     
  283.     def bold(text):
  284.         return ''.join([
  285.             '\x1b[1m',
  286.             text,
  287.             '\x1b[0m'])
  288.  
  289.     bold = staticmethod(bold)
  290.  
  291.  
  292. class Column:
  293.     
  294.     def __init__(self, width = 78, alignment = TextFormatter.LEFT, margin = 0):
  295.         self.width = width
  296.         self.alignment = alignment
  297.         self.margin = margin
  298.         self.lines = []
  299.  
  300.     
  301.     def align(self, line):
  302.         if self.alignment == TextFormatter.CENTER:
  303.             return line.center(self.width)
  304.         elif self.alignment == TextFormatter.RIGHT:
  305.             return line.rjust(self.width)
  306.         else:
  307.             return line.ljust(self.width)
  308.  
  309.     
  310.     def wrap(self, text):
  311.         self.lines = []
  312.         words = []
  313.         for word in text.split():
  314.             if word <= self.width:
  315.                 words.append(word)
  316.                 continue
  317.             for i in range(0, len(word), self.width):
  318.                 words.append(word[i:i + self.width])
  319.             
  320.         
  321.         if not len(words):
  322.             return None
  323.         
  324.         current = words.pop(0)
  325.         for word in words:
  326.             increment = 1 + len(word)
  327.             if len(current) + increment > self.width:
  328.                 self.lines.append(self.align(current))
  329.                 current = word
  330.                 continue
  331.             current = current + ' ' + word
  332.         
  333.         self.lines.append(self.align(current))
  334.  
  335.     
  336.     def getline(self, index):
  337.         if index < len(self.lines):
  338.             return ' ' * self.margin + self.lines[index]
  339.         else:
  340.             return ' ' * (self.margin + self.width)
  341.  
  342.  
  343.  
  344. class Stack:
  345.     
  346.     def __init__(self):
  347.         self.stack = []
  348.  
  349.     
  350.     def pop(self):
  351.         return self.stack.pop()
  352.  
  353.     
  354.     def push(self, value):
  355.         self.stack.append(value)
  356.  
  357.     
  358.     def as_list(self):
  359.         return self.stack
  360.  
  361.     
  362.     def clear(self):
  363.         self.stack = []
  364.  
  365.  
  366.  
  367. class RingBuffer:
  368.     
  369.     def __init__(self, size_max = 50):
  370.         self.max = size_max
  371.         self.data = []
  372.  
  373.     
  374.     def append(self, x):
  375.         '''append an element at the end of the buffer'''
  376.         self.data.append(x)
  377.         if len(self.data) == self.max:
  378.             self.cur = 0
  379.             self.__class__ = RingBufferFull
  380.         
  381.  
  382.     
  383.     def get(self):
  384.         ''' return a list of elements from the oldest to the newest'''
  385.         return self.data
  386.  
  387.  
  388.  
  389. class RingBufferFull:
  390.     
  391.     def __init__(self, n):
  392.         pass
  393.  
  394.     
  395.     def append(self, x):
  396.         self.data[self.cur] = x
  397.         self.cur = (self.cur + 1) % self.max
  398.  
  399.     
  400.     def get(self):
  401.         return self.data[self.cur:] + self.data[:self.cur]
  402.  
  403.  
  404. MASK_CCITT = 4129
  405. MASK_CRC16 = 40961
  406.  
  407. def updateCRC(crc, data, mask = MASK_CRC16):
  408.     for char in data:
  409.         c = ord(char)
  410.         c = c << 0x8L
  411.         for j in xrange(8):
  412.             if (crc ^ c) & 0x8000L:
  413.                 crc = crc << 0x1L ^ mask
  414.             else:
  415.                 crc = crc << 0x1L
  416.             c = c << 0x1L
  417.         
  418.     
  419.     return crc & 0xFFFFL
  420.  
  421.  
  422. def calcCRC(data):
  423.     crc = 0
  424.     crc = updateCRC(crc, data)
  425.     if crc == 0:
  426.         crc = len(data)
  427.     
  428.     return crc
  429.  
  430.  
  431. def sort_dict_by_value(d):
  432.     ''' Returns the keys of dictionary d sorted by their values '''
  433.     items = d.items()
  434.     backitems = [ [
  435.         v[1],
  436.         v[0]] for v in items ]
  437.     backitems.sort()
  438.     return [ backitems[i][1] for i in range(0, len(backitems)) ]
  439.  
  440. codes = { }
  441. codes['reset'] = '\x1b[0m'
  442. codes['bold'] = '\x1b[01m'
  443. codes['teal'] = '\x1b[36;06m'
  444. codes['turquoise'] = '\x1b[36;01m'
  445. codes['fuscia'] = '\x1b[35;01m'
  446. codes['purple'] = '\x1b[35;06m'
  447. codes['blue'] = '\x1b[34;01m'
  448. codes['darkblue'] = '\x1b[34;06m'
  449. codes['green'] = '\x1b[32;01m'
  450. codes['darkgreen'] = '\x1b[32;06m'
  451. codes['yellow'] = '\x1b[33;01m'
  452. codes['brown'] = '\x1b[33;06m'
  453. codes['red'] = '\x1b[31;01m'
  454. codes['darkred'] = '\x1b[31;06m'
  455.  
  456. def bold(text):
  457.     return codes['bold'] + text + codes['reset']
  458.  
  459.  
  460. def white(text):
  461.     return bold(text)
  462.  
  463.  
  464. def teal(text):
  465.     return codes['teal'] + text + codes['reset']
  466.  
  467.  
  468. def turquoise(text):
  469.     return codes['turquoise'] + text + codes['reset']
  470.  
  471.  
  472. def darkteal(text):
  473.     return turquoise(text)
  474.  
  475.  
  476. def fuscia(text):
  477.     return codes['fuscia'] + text + codes['reset']
  478.  
  479.  
  480. def purple(text):
  481.     return codes['purple'] + text + codes['reset']
  482.  
  483.  
  484. def blue(text):
  485.     return codes['blue'] + text + codes['reset']
  486.  
  487.  
  488. def darkblue(text):
  489.     return codes['darkblue'] + text + codes['reset']
  490.  
  491.  
  492. def green(text):
  493.     return codes['green'] + text + codes['reset']
  494.  
  495.  
  496. def darkgreen(text):
  497.     return codes['darkgreen'] + text + codes['reset']
  498.  
  499.  
  500. def yellow(text):
  501.     return codes['yellow'] + text + codes['reset']
  502.  
  503.  
  504. def brown(text):
  505.     return codes['brown'] + text + codes['reset']
  506.  
  507.  
  508. def darkyellow(text):
  509.     return brown(text)
  510.  
  511.  
  512. def red(text):
  513.     return codes['red'] + text + codes['reset']
  514.  
  515.  
  516. def darkred(text):
  517.     return codes['darkred'] + text + codes['reset']
  518.  
  519.  
  520. def commafy(val):
  521.     if not val < 0 or '-' + commafy(abs(val)):
  522.         if not val < 1000 or str(val):
  523.             pass
  524.     return '%s,%03d' % (commafy(val / 1000), val % 1000)
  525.  
  526.  
  527. def format_bytes(s, show_bytes = False):
  528.     if s < 1024:
  529.         return ''.join([
  530.             commafy(s),
  531.             ' B'])
  532.     elif s < s:
  533.         pass
  534.     elif s < 1048576:
  535.         if show_bytes:
  536.             return ''.join([
  537.                 str(round(s / 1024.0, 1)),
  538.                 ' KB (',
  539.                 commafy(s),
  540.                 ')'])
  541.         else:
  542.             return ''.join([
  543.                 str(round(s / 1024.0, 1)),
  544.                 ' KB'])
  545.     elif show_bytes:
  546.         return ''.join([
  547.             str(round(s / 1048576.0, 1)),
  548.             ' MB (',
  549.             commafy(s),
  550.             ')'])
  551.     else:
  552.         return ''.join([
  553.             str(round(s / 1048576.0, 1)),
  554.             ' MB'])
  555.  
  556.  
  557. try:
  558.     make_temp_file = tempfile.mkstemp
  559. except AttributeError:
  560.     
  561.     def make_temp_file(suffix = '', prefix = '', dir = '', text = False):
  562.         path = tempfile.mktemp(suffix)
  563.         fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_EXCL, 448)
  564.         return (os.fdopen(fd, 'w+b'), path)
  565.  
  566.  
  567.  
  568. def log_title(program_name, version):
  569.     log.info('')
  570.     log.info(bold('HP Linux Imaging and Printing System (ver. %s)' % prop.version))
  571.     log.info(bold('%s ver. %s' % (program_name, version)))
  572.     log.info('')
  573.     log.info('Copyright (c) 2003-6 Hewlett-Packard Development Company, LP')
  574.     log.info('This software comes with ABSOLUTELY NO WARRANTY.')
  575.     log.info('This is free software, and you are welcome to distribute it')
  576.     log.info('under certain conditions. See COPYING file for more details.')
  577.     log.info('')
  578.  
  579.  
  580. def which(command):
  581.     path = os.getenv('PATH').split(':')
  582.     found_path = ''
  583.     for p in path:
  584.         
  585.         try:
  586.             files = os.listdir(p)
  587.         except:
  588.             continue
  589.             continue
  590.  
  591.         if command in files:
  592.             found_path = p
  593.             break
  594.             continue
  595.     
  596.     return found_path
  597.  
  598.  
  599. def deviceDefaultFunctions():
  600.     (cmd_print, cmd_copy, cmd_fax, cmd_pcard, cmd_scan, cmd_fab) = ('', '', '', '', '', '')
  601.     path = which('hp-print')
  602.     if len(path) > 0:
  603.         cmd_print = 'hp-print -p%PRINTER%'
  604.     else:
  605.         path = which('kprinter')
  606.         if len(path) > 0:
  607.             cmd_print = 'kprinter -P%PRINTER% --system cups'
  608.         else:
  609.             path = which('gtklp')
  610.             if len(path) > 0:
  611.                 cmd_print = 'gtklp -P%PRINTER%'
  612.             else:
  613.                 path = which('xpp')
  614.                 if len(path) > 0:
  615.                     cmd_print = 'xpp -P%PRINTER%'
  616.                 
  617.     path = which('xsane')
  618.     if len(path) > 0:
  619.         cmd_scan = 'xsane -V %SANE_URI%'
  620.     else:
  621.         path = which('kooka')
  622.         if len(path) > 0:
  623.             cmd_scan = 'kooka'
  624.         else:
  625.             path = which('xscanimage')
  626.             if len(path) > 0:
  627.                 cmd_scan = 'xscanimage'
  628.             
  629.     path = which('hp-unload')
  630.     if len(path):
  631.         cmd_pcard = 'hp-unload -d %DEVICE_URI%'
  632.     else:
  633.         cmd_pcard = 'python %HOME%/unload.py -d %DEVICE_URI%'
  634.     path = which('hp-sendfax')
  635.     if len(path):
  636.         cmd_fax = 'hp-sendfax -d %FAX_URI%'
  637.     else:
  638.         cmd_fax = 'python %HOME%/sendfax.py -d %FAX_URI%'
  639.     path = which('hp-fab')
  640.     if len(path):
  641.         cmd_fab = 'hp-fab'
  642.     else:
  643.         cmd_fab = 'python %HOME%/fab.py'
  644.     return (cmd_print, cmd_scan, cmd_pcard, cmd_copy, cmd_fax, cmd_fab)
  645.  
  646.  
  647. def checkPyQtImport():
  648.     
  649.     try:
  650.         import qt
  651.     except ImportError:
  652.         log.error('PyQt not installed. GUI not available. Exiting.')
  653.         return False
  654.  
  655.     qtMajor = int(qt.qVersion().split('.')[0])
  656.     if qtMajor < MINIMUM_QT_MAJOR_VER:
  657.         log.error('Incorrect version of Qt installed. Ver. 3.0.0 or greater required.')
  658.         return False
  659.     
  660.     
  661.     try:
  662.         pyqtVersion = qt.PYQT_VERSION_STR
  663.     except:
  664.         pyqtVersion = qt.PYQT_VERSION
  665.  
  666.     while pyqtVersion.count('.') < 2:
  667.         pyqtVersion += '.0'
  668.     (maj_ver, min_ver, pat_ver) = pyqtVersion.split('.')
  669.     if pyqtVersion.find('snapshot') >= 0:
  670.         log.warning('A non-stable snapshot version of PyQt is installed.')
  671.     else:
  672.         
  673.         try:
  674.             maj_ver = int(maj_ver)
  675.             min_ver = int(min_ver)
  676.             pat_ver = int(pat_ver)
  677.         except ValueError:
  678.             (maj_ver, min_ver, pat_ver) = (0, 0, 0)
  679.  
  680.         if (maj_ver < MINIMUM_PYQT_MAJOR_VER or maj_ver == MINIMUM_PYQT_MAJOR_VER) and min_ver < MINIMUM_PYQT_MINOR_VER:
  681.             log.error('This program may not function properly with the version of PyQt that is installed (%d.%d.%d).' % (maj_ver, min_ver, pat_ver))
  682.             log.error('Incorrect version of pyQt installed. Ver. %d.%d or greater required.' % (MINIMUM_PYQT_MAJOR_VER, MINIMUM_PYQT_MINOR_VER))
  683.             return False
  684.         
  685.     return True
  686.  
  687.  
  688. def loadTranslators(app, user_config):
  689.     import qt
  690.     loc = None
  691.     if os.path.exists(user_config):
  692.         if not path_exists_safely(user_config):
  693.             log.warning('File %s has insecure permissions! File ignored.' % user_config)
  694.         else:
  695.             config = ConfigParser.ConfigParser()
  696.             config.read(user_config)
  697.             if config.has_section('ui'):
  698.                 loc = config.get('ui', 'loc')
  699.                 if not loc:
  700.                     loc = None
  701.                 
  702.             
  703.     
  704.     if loc is not None:
  705.         if loc.lower() == 'system':
  706.             loc = str(qt.QTextCodec.locale())
  707.         
  708.         if loc.lower() != 'c':
  709.             log.debug('Trying to load .qm file for %s locale.' % loc)
  710.             dirs = [
  711.                 prop.home_dir,
  712.                 prop.data_dir,
  713.                 prop.i18n_dir]
  714.             trans = qt.QTranslator(None)
  715.             for dir in dirs:
  716.                 qm_file = 'hplip_%s' % loc
  717.                 loaded = trans.load(qm_file, dir)
  718.                 if loaded:
  719.                     app.installTranslator(trans)
  720.                     break
  721.                     continue
  722.             
  723.         else:
  724.             loc = None
  725.     
  726.     if loc is None:
  727.         log.debug("Using default 'C' locale")
  728.     else:
  729.         log.debug('Using locale: %s' % loc)
  730.     return loc
  731.  
  732.  
  733. try:
  734.     from string import Template
  735. except ImportError:
  736.     import re as _re
  737.     
  738.     class _multimap:
  739.         '''Helper class for combining multiple mappings.
  740.  
  741.         Used by .{safe_,}substitute() to combine the mapping and keyword
  742.         arguments.
  743.         '''
  744.         
  745.         def __init__(self, primary, secondary):
  746.             self._primary = primary
  747.             self._secondary = secondary
  748.  
  749.         
  750.         def __getitem__(self, key):
  751.             
  752.             try:
  753.                 return self._primary[key]
  754.             except KeyError:
  755.                 return self._secondary[key]
  756.  
  757.  
  758.  
  759.     
  760.     class _TemplateMetaclass(type):
  761.         pattern = '\n        %(delim)s(?:\n          (?P<escaped>%(delim)s) |   # Escape sequence of two delimiters\n          (?P<named>%(id)s)      |   # delimiter and a Python identifier\n          {(?P<braced>%(id)s)}   |   # delimiter and a braced identifier\n          (?P<invalid>)              # Other ill-formed delimiter exprs\n        )\n        '
  762.         
  763.         def __init__(cls, name, bases, dct):
  764.             super(_TemplateMetaclass, cls).__init__(name, bases, dct)
  765.             if 'pattern' in dct:
  766.                 pattern = cls.pattern
  767.             else:
  768.                 pattern = _TemplateMetaclass.pattern % {
  769.                     'delim': _re.escape(cls.delimiter),
  770.                     'id': cls.idpattern }
  771.             cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
  772.  
  773.  
  774.     
  775.     class Template:
  776.         '''A string class for supporting $-substitutions.'''
  777.         __metaclass__ = _TemplateMetaclass
  778.         delimiter = '$'
  779.         idpattern = '[_a-z][_a-z0-9]*'
  780.         
  781.         def __init__(self, template):
  782.             self.template = template
  783.  
  784.         
  785.         def _invalid(self, mo):
  786.             i = mo.start('invalid')
  787.             lines = self.template[:i].splitlines(True)
  788.             if not lines:
  789.                 colno = 1
  790.                 lineno = 1
  791.             else:
  792.                 colno = i - len(''.join(lines[:-1]))
  793.                 lineno = len(lines)
  794.             raise ValueError('Invalid placeholder in string: line %d, col %d' % (lineno, colno))
  795.  
  796.         
  797.         def substitute(self, *args, **kws):
  798.             if len(args) > 1:
  799.                 raise TypeError('Too many positional arguments')
  800.             
  801.             if not args:
  802.                 mapping = kws
  803.             elif kws:
  804.                 mapping = _multimap(kws, args[0])
  805.             else:
  806.                 mapping = args[0]
  807.             
  808.             def convert(mo):
  809.                 if not mo.group('named'):
  810.                     pass
  811.                 named = mo.group('braced')
  812.                 if named is not None:
  813.                     val = mapping[named]
  814.                     return '%s' % val
  815.                 
  816.                 if mo.group('escaped') is not None:
  817.                     return self.delimiter
  818.                 
  819.                 if mo.group('invalid') is not None:
  820.                     self._invalid(mo)
  821.                 
  822.                 raise ValueError('Unrecognized named group in pattern', self.pattern)
  823.  
  824.             return self.pattern.sub(convert, self.template)
  825.  
  826.         
  827.         def safe_substitute(self, *args, **kws):
  828.             if len(args) > 1:
  829.                 raise TypeError('Too many positional arguments')
  830.             
  831.             if not args:
  832.                 mapping = kws
  833.             elif kws:
  834.                 mapping = _multimap(kws, args[0])
  835.             else:
  836.                 mapping = args[0]
  837.             
  838.             def convert(mo):
  839.                 named = mo.group('named')
  840.                 if named is not None:
  841.                     
  842.                     try:
  843.                         return '%s' % mapping[named]
  844.                     except KeyError:
  845.                         return self.delimiter + named
  846.                     except:
  847.                         None<EXCEPTION MATCH>KeyError
  848.                     
  849.  
  850.                 None<EXCEPTION MATCH>KeyError
  851.                 braced = mo.group('braced')
  852.                 if braced is not None:
  853.                     
  854.                     try:
  855.                         return '%s' % mapping[braced]
  856.                     except KeyError:
  857.                         return self.delimiter + '{' + braced + '}'
  858.                     except:
  859.                         None<EXCEPTION MATCH>KeyError
  860.                     
  861.  
  862.                 None<EXCEPTION MATCH>KeyError
  863.                 if mo.group('escaped') is not None:
  864.                     return self.delimiter
  865.                 
  866.                 if mo.group('invalid') is not None:
  867.                     return self.delimiter
  868.                 
  869.                 raise ValueError('Unrecognized named group in pattern', self.pattern)
  870.  
  871.             return self.pattern.sub(convert, self.template)
  872.  
  873.  
  874.  
  875.  
  876. cat = lambda _: Template(_).substitute(sys._getframe(1).f_globals, **sys._getframe(1).f_locals)
  877.  
  878. class ModelParser:
  879.     
  880.     def __init__(self):
  881.         self.model = None
  882.         self.cur_model = None
  883.         self.stack = []
  884.         self.in_model = False
  885.         self.models = { }
  886.  
  887.     
  888.     def startElement(self, name, attrs):
  889.         if name == 'models':
  890.             return None
  891.         elif name == 'model':
  892.             self.model = { }
  893.             self.cur_model = str(attrs['name']).replace('_', ' ').strip()
  894.             self.in_model = True
  895.             self.stack = []
  896.         else:
  897.             self.stack.append(str(name).lower())
  898.             if len(attrs):
  899.                 for a in attrs:
  900.                     self.stack.append(str(a).lower())
  901.                     
  902.                     try:
  903.                         i = int(attrs[a])
  904.                     except ValueError:
  905.                         i = str(attrs[a])
  906.  
  907.                     self.model[str('-'.join(self.stack))] = i
  908.                     self.stack.pop()
  909.                 
  910.             
  911.  
  912.     
  913.     def endElement(self, name):
  914.         if name == 'model':
  915.             self.in_model = False
  916.             if self.cur_model in self.models:
  917.                 log.error('Duplicate model in XML: %s' % self.cur_model)
  918.                 raise Error(ERROR_INTERNAL)
  919.             
  920.             print self.cur_model
  921.             self.models[self.cur_model] = self.model
  922.             self.model = None
  923.         elif name == 'models':
  924.             return None
  925.         else:
  926.             self.stack.pop()
  927.  
  928.     
  929.     def charData(self, data):
  930.         data = str(data).strip()
  931.         if data and self.model is not None and self.stack:
  932.             self.model[str('-'.join(self.stack))] = str(data)
  933.         
  934.  
  935.     
  936.     def loadModels(self, filename, untested = False):
  937.         parser = xml.parsers.expat.ParserCreate()
  938.         parser.StartElementHandler = self.startElement
  939.         parser.EndElementHandler = self.endElement
  940.         parser.CharacterDataHandler = self.charData
  941.         
  942.         try:
  943.             parser.Parse(open(filename).read(), True)
  944.         except xml.parsers.expat.ExpatError:
  945.             e = None
  946.             log.error('XML file parse error: %s' % e)
  947.             raise Error(ERROR_INTERNAL)
  948.  
  949.         return self.models
  950.  
  951.  
  952. identity = string.maketrans('', '')
  953. unprintable = identity.translate(identity, string.printable)
  954.  
  955. def printable(s):
  956.     return s.translate(identity, unprintable)
  957.  
  958.  
  959. def any(S, f = (lambda x: x)):
  960.     for x in S:
  961.         if f(x):
  962.             return True
  963.             continue
  964.     
  965.     return False
  966.  
  967.  
  968. def all(S, f = (lambda x: x)):
  969.     for x in S:
  970.         if not f(x):
  971.             return False
  972.             continue
  973.     
  974.     return True
  975.  
  976.  
  977. def openURL(url):
  978.     browsers = [
  979.         'firefox',
  980.         'mozilla',
  981.         'konqueror',
  982.         'galeon',
  983.         'skipstone']
  984.     for b in browsers:
  985.         if which(b):
  986.             cmd = '%s %s &' % (b, url)
  987.             log.debug(cmd)
  988.             os.system(cmd)
  989.             break
  990.             continue
  991.     
  992.  
  993.  
  994. def uniqueList(input):
  995.     temp = []
  996.     _[1]
  997.     return temp
  998.  
  999.  
  1000. def list_move_up(l, m):
  1001.     for i in range(1, len(l)):
  1002.         if l[i] == m:
  1003.             l[i - 1] = l[i]
  1004.             l[i] = l[i - 1]
  1005.             continue
  1006.     
  1007.  
  1008.  
  1009. def list_move_down(l, m):
  1010.     for i in range(len(l) - 2, 0, -1):
  1011.         if l[i] == m:
  1012.             l[i] = l[i + 1]
  1013.             l[i + 1] = l[i]
  1014.             continue
  1015.     
  1016.  
  1017.  
  1018. def levenshtein_distance(a, b):
  1019.     '''
  1020.     Calculates the Levenshtein distance between a and b.
  1021.     Written by Magnus Lie Hetland.
  1022.     '''
  1023.     n = len(a)
  1024.     m = len(b)
  1025.     if n > m:
  1026.         a = b
  1027.         b = a
  1028.         n = m
  1029.         m = n
  1030.     
  1031.     current = range(n + 1)
  1032.     for i in range(1, m + 1):
  1033.         previous = current
  1034.         current = [
  1035.             i] + [
  1036.             0] * m
  1037.         for j in range(1, n + 1):
  1038.             add = previous[j] + 1
  1039.             delete = current[j - 1] + 1
  1040.             change = previous[j - 1]
  1041.             if a[j - 1] != b[i - 1]:
  1042.                 change = change + 1
  1043.             
  1044.             current[j] = min(add, delete, change)
  1045.         
  1046.     
  1047.     return current[n]
  1048.  
  1049.  
  1050. class XMLToDictParser:
  1051.     
  1052.     def __init__(self):
  1053.         self.stack = []
  1054.         self.data = { }
  1055.  
  1056.     
  1057.     def startElement(self, name, attrs):
  1058.         self.stack.append(str(name).lower())
  1059.         if len(attrs):
  1060.             for a in attrs:
  1061.                 self.stack.append(str(a).lower())
  1062.                 self.addData(attrs[a])
  1063.                 self.stack.pop()
  1064.             
  1065.         
  1066.  
  1067.     
  1068.     def endElement(self, name):
  1069.         self.stack.pop()
  1070.  
  1071.     
  1072.     def charData(self, data):
  1073.         data = str(data).strip()
  1074.         if data and self.stack:
  1075.             self.addData(data)
  1076.         
  1077.  
  1078.     
  1079.     def addData(self, data):
  1080.         
  1081.         try:
  1082.             data = int(data)
  1083.         except ValueError:
  1084.             data = str(data)
  1085.  
  1086.         stack_str = '-'.join(self.stack)
  1087.         stack_str_0 = '-'.join([
  1088.             stack_str,
  1089.             '0'])
  1090.         
  1091.         try:
  1092.             self.data[stack_str]
  1093.         except KeyError:
  1094.             
  1095.             try:
  1096.                 self.data[stack_str_0]
  1097.             except KeyError:
  1098.                 self.data[stack_str] = data
  1099.  
  1100.             j = 2
  1101.             while True:
  1102.                 
  1103.                 try:
  1104.                     self.data['-'.join([
  1105.                         stack_str,
  1106.                         str(j)])]
  1107.                 except KeyError:
  1108.                     self.data['-'.join([
  1109.                         stack_str,
  1110.                         str(j)])] = data
  1111.                     break
  1112.  
  1113.                 j += 1
  1114.  
  1115.         self.data[stack_str_0] = self.data[stack_str]
  1116.         self.data['-'.join([
  1117.             stack_str,
  1118.             '1'])] = data
  1119.         del self.data[stack_str]
  1120.  
  1121.     
  1122.     def parseXML(self, text):
  1123.         parser = xml.parsers.expat.ParserCreate()
  1124.         parser.StartElementHandler = self.startElement
  1125.         parser.EndElementHandler = self.endElement
  1126.         parser.CharacterDataHandler = self.charData
  1127.         parser.Parse(text, True)
  1128.         return self.data
  1129.  
  1130.  
  1131. USAGE_OPTIONS = ('[OPTIONS]', '', 'heading', False)
  1132. USAGE_LOGGING1 = ('Set the logging level:', '-l<level> or --logging=<level>', 'option', False)
  1133. USAGE_LOGGING2 = ('', '<level>: none, info*, error, warn, debug (\\*default)', 'option', False)
  1134. USAGE_LOGGING3 = ('Run in debug mode:', '-g (same as option: -ldebug)', 'option', False)
  1135. USAGE_ARGS = ('[PRINTER|DEVICE-URI] (See Notes)', '', 'heading', False)
  1136. USAGE_DEVICE = ('To specify a device-URI:', '-d<device-uri> or --device=<device-uri>', 'option', False)
  1137. USAGE_PRINTER = ('To specify a CUPS printer:', '-p<printer> or --printer=<printer>', 'option', False)
  1138. USAGE_BUS1 = ('Bus to probe (if device not specified):', '-b<bus> or --bus=<bus>', 'option', False)
  1139. USAGE_BUS2 = ('', '<bus>: cups\\*, usb*, net, bt, fw, par\\* (\\*default) (Note: bt and fw not supported in this release', 'option', False)
  1140. USAGE_HELP = ('This help information:', '-h or --help', 'option', True)
  1141. USAGE_SPACE = ('', '', 'space', False)
  1142. USAGE_EXAMPLES = ('Examples:', '', 'heading', False)
  1143. USAGE_NOTES = ('Notes:', '', 'heading', False)
  1144. USAGE_STD_NOTES1 = ('1. If device or printer is not specified, the local device bus is probed and the program enters interactive mode.', '', 'note', False)
  1145. USAGE_STD_NOTES2 = ('2. If -p\\* is specified, the default CUPS printer will be used.', '', 'note', False)
  1146. USAGE_SEEALSO = ('See Also:', '', 'heading', False)
  1147.  
  1148. def ttysize():
  1149.     ln1 = commands.getoutput('stty -a').splitlines()[0]
  1150.     vals = {
  1151.         'rows': None,
  1152.         'columns': None }
  1153.     for ph in ln1.split(';'):
  1154.         x = ph.split()
  1155.         if len(x) == 2:
  1156.             vals[x[0]] = x[1]
  1157.             vals[x[1]] = x[0]
  1158.             continue
  1159.     
  1160.     return (int(vals['rows']), int(vals['columns']))
  1161.  
  1162.  
  1163. def usage_formatter(override = 0):
  1164.     (rows, cols) = ttysize()
  1165.     if override:
  1166.         col1 = override
  1167.         col2 = cols - col1 - 8
  1168.     else:
  1169.         col1 = int(cols / 3) - 8
  1170.         col2 = cols - col1 - 8
  1171.     return TextFormatter(({
  1172.         'width': col1,
  1173.         'margin': 2 }, {
  1174.         'width': col2,
  1175.         'margin': 2 }))
  1176.  
  1177.  
  1178. def format_text(text_list, typ = 'text', title = '', crumb = '', version = ''):
  1179.     '''
  1180.     Format usage text in multiple formats:
  1181.         text: for --help in the console
  1182.         rest: for conversion with rst2web for the website
  1183.         man: for manpages
  1184.     '''
  1185.     if typ == 'text':
  1186.         formatter = usage_formatter()
  1187.         for line in text_list:
  1188.             (text1, text2, format, trailing_space) = line
  1189.             text1 = text1.replace('\\', '')
  1190.             text2 = text2.replace('\\', '')
  1191.             if format == 'summary':
  1192.                 log.info(bold(text1))
  1193.                 log.info('')
  1194.                 continue
  1195.             if format in ('para', 'name', 'seealso'):
  1196.                 log.info(text1)
  1197.                 if trailing_space:
  1198.                     log.info('')
  1199.                 
  1200.             trailing_space
  1201.             if format in ('heading', 'header'):
  1202.                 log.info(bold(text1))
  1203.                 continue
  1204.             if format in ('option', 'example'):
  1205.                 log.info(formatter.compose((text1, text2), trailing_space))
  1206.                 continue
  1207.             if format == 'note':
  1208.                 if text1.startswith(' '):
  1209.                     log.info('\t' + text1.lstrip())
  1210.                 else:
  1211.                     log.info(text1)
  1212.             text1.startswith(' ')
  1213.             if format == 'space':
  1214.                 log.info('')
  1215.                 continue
  1216.         
  1217.         log.info('')
  1218.     elif typ == 'rest':
  1219.         (colwidth1, colwidth2) = (0, 0)
  1220.         for line in text_list:
  1221.             (text1, text2, format, trailing_space) = line
  1222.             if format in ('option', 'example'):
  1223.                 colwidth1 = max(len(text1), colwidth1)
  1224.                 colwidth2 = max(len(text2), colwidth2)
  1225.                 continue
  1226.         
  1227.         colwidth1 += 3
  1228.         tablewidth = colwidth1 + colwidth2
  1229.         log.info('restindex\npage-title: %s\ncrumb: %s\nformat: rest\nfile-extension: html\nencoding: utf8\n/restindex\n' % (title, crumb))
  1230.         links = []
  1231.         for line in text_list:
  1232.             (text1, text2, format, trailing_space) = line
  1233.             if format == 'seealso':
  1234.                 links.append(text1)
  1235.                 text1 = '`%s`_' % text1
  1236.             
  1237.             len1 = len(text1)
  1238.             len2 = len(text2)
  1239.             if format == 'summary':
  1240.                 log.info(''.join([
  1241.                     '**',
  1242.                     text1,
  1243.                     '**']))
  1244.                 log.info('')
  1245.                 continue
  1246.             if format in ('para', 'name'):
  1247.                 log.info('')
  1248.                 log.info(text1)
  1249.                 log.info('')
  1250.                 continue
  1251.             if format in ('heading', 'header'):
  1252.                 log.info('')
  1253.                 log.info('**' + text1 + '**')
  1254.                 log.info('')
  1255.                 log.info('.. class:: borderless')
  1256.                 log.info('')
  1257.                 log.info(''.join([
  1258.                     '+',
  1259.                     '-' * colwidth1,
  1260.                     '+',
  1261.                     '-' * colwidth2,
  1262.                     '+']))
  1263.                 continue
  1264.             if format in ('option', 'example', 'seealso'):
  1265.                 if text1 and '`_' not in text1:
  1266.                     log.info(''.join([
  1267.                         '| *',
  1268.                         text1,
  1269.                         '*',
  1270.                         ' ' * (colwidth1 - len1 - 3),
  1271.                         '|',
  1272.                         text2,
  1273.                         ' ' * (colwidth2 - len2),
  1274.                         '|']))
  1275.                 elif text1:
  1276.                     log.info(''.join([
  1277.                         '|',
  1278.                         text1,
  1279.                         ' ' * (colwidth1 - len1),
  1280.                         '|',
  1281.                         text2,
  1282.                         ' ' * (colwidth2 - len2),
  1283.                         '|']))
  1284.                 else:
  1285.                     log.info(''.join([
  1286.                         '|',
  1287.                         ' ' * colwidth1,
  1288.                         '|',
  1289.                         text2,
  1290.                         ' ' * (colwidth2 - len2),
  1291.                         '|']))
  1292.                 log.info(''.join([
  1293.                     '+',
  1294.                     '-' * colwidth1,
  1295.                     '+',
  1296.                     '-' * colwidth2,
  1297.                     '+']))
  1298.                 continue
  1299.             if format == 'note':
  1300.                 if text1.startswith(' '):
  1301.                     log.info(''.join([
  1302.                         '|',
  1303.                         ' ' * (tablewidth + 1),
  1304.                         '|']))
  1305.                 
  1306.                 log.info(''.join([
  1307.                     '|',
  1308.                     text1,
  1309.                     ' ' * ((tablewidth - len1) + 1),
  1310.                     '|']))
  1311.                 log.info(''.join([
  1312.                     '+',
  1313.                     '-' * colwidth1,
  1314.                     '+',
  1315.                     '-' * colwidth2,
  1316.                     '+']))
  1317.                 continue
  1318.             if format == 'space':
  1319.                 log.info('')
  1320.                 continue
  1321.         
  1322.         for l in links:
  1323.             log.info('\n.. _`%s`: %s.html\n' % (l, l.replace('hp-', '')))
  1324.         
  1325.         log.info('')
  1326.     elif typ == 'man':
  1327.         log.info('.TH "%s" 1 "%s" Linux "User Manuals"' % (title, version))
  1328.         for line in text_list:
  1329.             (text1, text2, format, trailing_space) = line
  1330.             text1 = text1.replace('\\*', '*')
  1331.             text2 = text2.replace('\\*', '*')
  1332.             len1 = len(text1)
  1333.             len2 = len(text2)
  1334.             if format == 'summary':
  1335.                 log.info('.SH SYNOPSIS')
  1336.                 log.info('.B %s' % text1)
  1337.                 continue
  1338.             if format == 'name':
  1339.                 log.info('.SH NAME\n%s' % text1)
  1340.                 continue
  1341.             if format in ('option', 'example', 'note'):
  1342.                 if text1:
  1343.                     log.info('.IP "%s"\n%s' % (text1, text2))
  1344.                 else:
  1345.                     log.info(text2)
  1346.             text1
  1347.             if format in ('header', 'heading'):
  1348.                 log.info('.SH %s' % text1.upper().replace(':', '').replace('[', '').replace(']', ''))
  1349.                 continue
  1350.             if format in 'seealso, para':
  1351.                 log.info(text1)
  1352.                 continue
  1353.         
  1354.         log.info('')
  1355.     
  1356.  
  1357.