--- a/src/mediaserver/cdplugins/pycommon/conftree.py
+++ b/src/mediaserver/cdplugins/pycommon/conftree.py
@@ -15,7 +15,6 @@
# Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
from __future__ import print_function
import locale
@@ -25,10 +24,14 @@
import base64
import platform
-class ConfSimple:
- """A ConfSimple class reads a recoll configuration file, which is a typical
- ini file (see the Recoll manual). It's a dictionary of dictionaries which
- lets you retrieve named values from the top level or a subsection"""
+def _debug(s):
+ print("%s"%s, file=sys.stderr)
+
+class ConfSimple(object):
+ """A ConfSimple class reads a recoll configuration file, which is
+ a typical ini file (see the Recoll manual). It's a dictionary of
+ dictionaries which lets you retrieve named values from the top
+ level or a subsection"""
def __init__(self, confname, tildexp = False, readonly = True):
self.submaps = {}
@@ -37,93 +40,140 @@
self.confname = confname
try:
- f = open(confname, 'r')
+ f = open(confname, 'rb')
except Exception as exc:
- #print("Open Exception: %s" % exc, file=sys.stderr)
+ #_debug("Open Exception: %s" % exc)
# File does not exist -> empty config, not an error.
self.submaps = {}
- self.submaps[''] = {}
+ self.submaps[b''] = {}
return
- self.parseinput(f)
+ self._parseinput(f)
- def parseinput(self, f):
+ def _parseinput(self, f):
appending = False
- line = ''
- submapkey = ''
+ line = b''
+ submapkey = b''
for cline in f:
- cline = cline.rstrip("\r\n")
+ cline = cline.rstrip(b'\r\n')
if appending:
line = line + cline
else:
line = cline
line = line.strip()
- if line == '' or line[0] == '#':
- continue
-
- if line[len(line)-1] == '\\':
+ if line == b'' or line[0] == b'#'[0]:
+ continue
+
+ if line[len(line)-1] == b'\\'[0]:
line = line[0:len(line)-1]
appending = True
continue
+
appending = False
- #print(line)
- if line[0] == '[':
- line = line.strip('[]')
+ #_debug(line)
+ if line[0] == b'['[0]:
+ line = line.strip(b'[]')
if self.dotildexpand:
submapkey = os.path.expanduser(line)
+ if type(submapkey) == type(u''):
+ submapkey = submapkey.encode('utf-8')
else:
submapkey = line
- #print("Submapkey: [%s]" % submapkey)
- continue
- nm, sep, value = line.partition('=')
- if sep == '':
- continue
+ #_debug("Submapkey: [%s]" % submapkey)
+ continue
+
+ nm, sep, value = line.partition(b'=')
+ if sep == b'':
+ # No equal sign in line -> considered comment
+ continue
+
nm = nm.strip()
value = value.strip()
- #print("Name: [%s] Value: [%s]" % (nm, value))
-
+ #_debug("sk [%s] nm: [%s] value: [%s]" % (submapkey, nm, value))
if not submapkey in self.submaps:
self.submaps[submapkey] = {}
self.submaps[submapkey][nm] = value
- def get(self, nm, sk = ''):
+ def getbin(self, nm, sk = b''):
'''Returns None if not found, empty string if found empty'''
+ if type(nm) != type(b'') or type(sk) != type(b''):
+ raise TypeError("getbin: parameters must be binary not unicode")
+ #_debug("ConfSimple::getbin nm [%s] sk [%s]" % (nm, sk))
if not sk in self.submaps:
return None
if not nm in self.submaps[sk]:
return None
return self.submaps[sk][nm]
+
+ def get(self, nm, sk = b''):
+ dodecode = False
+ if type(nm) == type(u''):
+ dodecode = True
+ nm = nm.encode('utf-8')
+ if type(sk) == type(u''):
+ sk = sk.encode('utf-8')
+ #v = ConfSimple.getbin(self, nm, sk)
+ v = self.getbin(nm, sk)
+ if v and dodecode:
+ v = v.decode('utf-8')
+ return v
+
+ def getNamesbin(self, sk = b''):
+ if not sk in self.submaps:
+ return None
+ return list(self.submaps[sk].keys())
+
+ def getNames(self, sk = ''):
+ if not sk in self.submaps:
+ return None
+ dodecode = False
+ if type(sk) == type(u''):
+ dodecode = True
+ sk = sk.encode('utf-8')
+ names = self.getNamesbin(sk)
+ if names and dodecode:
+ names = [nm.decode('utf-8') for nm in names]
+ return names
def _rewrite(self):
if self.readonly:
raise Exception("ConfSimple is readonly")
tname = self.confname + "-"
- f = open(tname, 'w')
+ f = open(tname, 'wb')
# First output null subkey submap
- if '' in self.submaps:
- for nm,value in self.submaps[''].iteritems():
- f.write(nm + " = " + value + "\n")
- for sk,mp in self.submaps.iteritems():
- if sk == '':
- continue
- f.write("[" + sk + "]\n")
- for nm,value in mp.iteritems():
- f.write(nm + " = " + value + "\n")
+ if b'' in self.submaps:
+ for nm,value in self.submaps[b''].items():
+ f.write(nm + b'=' + value + b'\n')
+ for sk,mp in self.submaps.items():
+ if sk == b'':
+ continue
+ f.write(b'[' + sk + b']\n')
+ for nm,value in mp.items():
+ f.write(nm + b'=' + value + b'\n')
f.close()
os.rename(tname, self.confname)
- def set(self, nm, value, sk = ''):
+ def setbin(self, nm, value, sk = b''):
if self.readonly:
raise Exception("ConfSimple is readonly")
+ if sk not in self.submaps:
+ self.submaps[sk] = {}
self.submaps[sk][nm] = value
self._rewrite()
return True
- def getNames(self, sk = ''):
- if not sk in self.submaps:
- return None
- return list(self.submaps[sk].keys())
+ def set(self, nm, value, sk = b''):
+ if self.readonly:
+ raise Exception("ConfSimple is readonly")
+ if type(nm) == type(u''):
+ nm = nm.encode('utf-8')
+ if type(value) == type(u''):
+ value = value.encode('utf-8')
+ if type(sk) == type(u''):
+ sk = sk.encode('utf-8')
+ return self.setbin(nm, value, sk)
+
class ConfTree(ConfSimple):
"""A ConfTree adds path-hierarchical interpretation of the section keys,
@@ -131,26 +181,33 @@
given path, it will also be searched in the sections corresponding to
the ancestors. E.g. get(name, '/a/b') will also look in sections '/a' and
'/' or '' (the last 2 are equivalent)"""
- def get(self, nm, sk = ''):
- if sk == '' or sk[0] != '/':
- return ConfSimple.get(self, nm, sk)
-
- if sk[len(sk)-1] != '/':
- sk = sk + '/'
-
- # Try all sk ancestors as submaps (/a/b/c-> /a/b/c, /a/b, /a, '')
- while sk.find('/') != -1:
- val = ConfSimple.get(self, nm, sk)
- if val is not None:
- return val
- i = sk.rfind('/')
+
+ def getbin(self, nm, sk = b''):
+ if type(nm) != type(b'') or type(sk) != type(b''):
+ raise TypeError("getbin: parameters must be binary not unicode")
+ #_debug("ConfTree::getbin: nm [%s] sk [%s]" % (nm, sk))
+
+ if sk == b'' or sk[0] != b'/'[0]:
+ return ConfSimple.getbin(self, nm, sk)
+
+ if sk[len(sk)-1] == b'/'[0]:
+ sk = sk[:len(sk)-1]
+
+ # Try all sk ancestors as submaps (/a/b/c-> /a/b/c, /a/b, /a, b'')
+ while sk:
+ if sk in self.submaps:
+ return ConfSimple.getbin(self, nm, sk)
+ if sk + b'/' in self.submaps:
+ return ConfSimple.getbin(self, nm, sk+b'/')
+ i = sk.rfind(b'/')
if i == -1:
break
sk = sk[:i]
- return ConfSimple.get(self, nm)
-
-class ConfStack:
+ return ConfSimple.getbin(self, nm)
+
+
+class ConfStack(object):
""" A ConfStack manages the superposition of a list of Configuration
objects. Values are looked for in each object from the list until found.
This typically provides for defaults overriden by sparse values in the
@@ -172,31 +229,43 @@
conf = ConfTree(fname)
self.confs.append(conf)
- def get(self, nm, sk = ''):
+ # Accepts / returns binary strings (non-unicode)
+ def getbin(self, nm, sk = b''):
+ if type(nm) != type(b'') or type(sk) != type(b''):
+ raise TypeError("getbin: parameters must be binary not unicode")
for conf in self.confs:
- value = conf.get(nm, sk)
+ value = conf.getbin(nm, sk)
if value is not None:
return value
return None
-if __name__ == '__main__':
- def Usage():
- print("Usage: conftree.py <filename> <paramname> [<section>]",
- file=sys.stderr)
- sys.exit(1)
- section = ''
- if len(sys.argv) >= 3:
- fname = sys.argv[1]
- pname = sys.argv[2]
- if len(sys.argv) == 4:
- section = sys.argv[3]
- elif len(sys.argv) != 3:
- Usage()
- else:
- Usage()
-
- conf = ConfSimple(fname)
- if section:
- print("[%s] %s -> %s" % (section, pname, conf.get(pname)))
- else:
- print("%s -> %s" % (pname, conf.get(pname)))
+ def get(self, nm, sk = b''):
+ dodecode = False
+ if type(nm) == type(u''):
+ dodecode = True
+ nm = nm.encode('utf-8')
+ if type(sk) == type(u''):
+ sk = sk.encode('utf-8')
+ #v = ConfSimple.getbin(self, nm, sk)
+ v = self.getbin(nm, sk)
+ if v and dodecode:
+ v = v.decode('utf-8')
+ return v
+
+def stringToStrings(s):
+ '''Parse a string made of space-separated words and C-Style strings
+ (double-quoted with backslash escape). E.g.:
+ word1 word2 "compound \\"quoted\\" string" ->
+ ['word1', 'word2', 'compound "quoted string']'''
+ import shlex
+ lex = shlex.shlex(s, posix=True)
+ lex.quotes = '"'
+ lex.escape = '\\'
+ lex.escapedquotes = '"'
+ l = []
+ while True:
+ tok = lex.get_token()
+ if not tok:
+ break
+ l.append(tok)
+ return l