diff options
Diffstat (limited to 'backend/scripts/pixma_gen_options.py')
-rwxr-xr-x | backend/scripts/pixma_gen_options.py | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/backend/scripts/pixma_gen_options.py b/backend/scripts/pixma_gen_options.py new file mode 100755 index 0000000..c4c75e0 --- /dev/null +++ b/backend/scripts/pixma_gen_options.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python + +import sys,os,re + +class Error(Exception): + pass + + +class ParseError(Error): + def __init__(self, errline): + Error.__init__(self, errline) + + +class Struct: + pass + + +def createCNameMap(): + t = '' + for i in range(256): + if ((ord('A') <= i) and (i <= ord('Z'))) or \ + ((ord('a') <= i) and (i <= ord('z'))) or \ + ((ord('0') <= i) and (i <= ord('9'))): + t += chr(i) + else: + t += '_' + return t + + +def seekBegin(f): + while True: + line = f.readline() + if not line: + return False + if line.startswith('BEGIN SANE_Option_Descriptor'): + return True + + +def parseVerbatim(o, line): + words = line.split(None, 1) + if (len(words) < 2) or (words[1][0] != '@'): + return False + o[words[0]] = words[1] + return True + + +def parseLine_type(o, line): + words = line.split(None, 2) + otype = words[1] + o['type'] = 'SANE_TYPE_' + otype.upper() + if otype == 'group': + g.ngroups += 1 + oname = '_group_%d' % g.ngroups + o['size'] = 0 + else: + temp = words[2] + idx = temp.find('[') + if idx == -1: + oname = temp + o['size'] = 1 + else: + oname = temp[0:idx] + o['size'] = int(temp[idx+1:-1]) + o['name'] = oname + + +def parseLine_title(o, line): + o['title'] = line.split(None, 1)[1] + + +def parseLine_desc(o, line): + o['desc'] = line.split(None, 1)[1] + + +def parseLine_unit(o, line): + o['unit'] = 'SANE_UNIT_' + line.split(None, 1)[1].upper() + + +def parseLine_default(o, line): + o['default'] = line.split(None, 1)[1] + + +def parseLine_cap(o, line): + words = line.split() + o['cap'] = ['SANE_CAP_' + s.upper() for s in words[1:]] + + +def parseLine_constraint(o, line): + c = line.split(None,1)[1] + if c[0] == '{': + o['constraint'] = c[1:-1].split('|') + elif c[0] == '(': + o['constraint'] = tuple(c[1:-1].split(',')) + else: + sys.stderr.write('Ignored: %s\n' % line) + + +def parseLine_info(o, line): + words = line.split() + o['info'] = ['SANE_INFO_' + s.upper() for s in words[1:]] + +def parseLine_rem(o, line): + pass + +def normalize(o): + if 'cname' not in o: + cname = o['name'].translate(cnameMap) + o['cname'] = cname + else: + cname = o['cname'] + o['cname_opt'] = 'opt_' + cname + o['cname_con'] = 'constraint_' + cname + if 'title' not in o: + o['title'] = 'NO TITLE' + if 'desc' not in o: + o['desc'] = '@sod->title' % o + if 'unit' not in o: + o['unit'] = 'SANE_UNIT_NONE' + if 'constraint_type' not in o: + if 'constraint' not in o: + ct = 'SANE_CONSTRAINT_NONE' + elif isinstance(o['constraint'], list): + if o['type'] == 'SANE_TYPE_STRING': + ct = 'SANE_CONSTRAINT_STRING_LIST' + else: + ct = 'SANE_CONSTRAINT_WORD_LIST' + elif isinstance(o['constraint'], tuple): + ct = 'SANE_CONSTRAINT_RANGE' + elif isinstance(o['constraint'], str): + oc = o['constraint'] + if oc.startswith('@range'): + ct = 'SANE_CONSTRAINT_RANGE' + elif oc.startswith('@word_list'): + ct = 'SANE_CONSTRAINT_WORD_LIST' + elif oc.startswith('@string_list'): + ct = 'SANE_CONSTRAINT_STRING_LIST' + o['constraint_type'] = ct + return o + + +def parseFile(f): + if not seekBegin(f): + return None + options = [ { + 'name' : '', + 'cname' : 'opt_num_opts', + 'title' : '@SANE_TITLE_NUM_OPTIONS', + 'desc' : '@SANE_DESC_NUM_OPTIONS', + 'type' : 'SANE_TYPE_INT', + 'unit' : 'SANE_UNIT_NONE', + 'size' : 1, + 'cap' : ['SANE_CAP_SOFT_DETECT'], + 'constraint_type' : 'SANE_CONSTRAINT_NONE', + 'default' : '@w = ' + opt_prefix + 'last' + } ] + o = {} + while True: + line = f.readline() + if not line: + break + line = line.strip() + if not line: + continue + token = line.split(None, 1)[0].lower() + if token == 'end': + break + if token == 'type': + if 'name' in o: + options.append(o) + o = {} + funcName = 'parseLine_' + token + if funcName in globals(): + if not parseVerbatim(o, line): + func = globals()[funcName] + func(o, line) + else: + sys.stderr.write('Skip: %s\n' % line) + if 'name' in o: + options.append(o) + return [normalize(o) for o in options] + + +def genHeader(options): + print """ +typedef union { + SANE_Word w; + SANE_Int i; + SANE_Bool b; + SANE_Fixed f; + SANE_String s; + void *ptr; +} option_value_t; +""" + print 'typedef enum {' + for o in options: + print ' %(cname_opt)s,' % o + print ' ' + opt_prefix + 'last' + print '} option_t;' + print """ + +typedef struct { + SANE_Option_Descriptor sod; + option_value_t val,def; + SANE_Word info; +} option_descriptor_t; + + +struct pixma_sane_t; +static int build_option_descriptors(struct pixma_sane_t *ss); +""" + + +def genMinMaxRange(n, t, r): + if t == 'SANE_TYPE_FIXED': + r = ['SANE_FIX(%s)' % x for x in r] + print 'static const SANE_Range ' + n + ' = ' + print ' { ' + r[0] + ',' + r[1] + ',' + r[2] + ' };' + + +def genList(n, t, l): + if t == 'SANE_TYPE_INT': + etype = 'SANE_Word' + l = [str(len(l))] + l + elif t == 'SANE_TYPE_FIXED': + etype = 'SANE_Word' + l = [str(len(l))] + ['SANE_FIX(%s)' % x for x in l] + elif t == 'SANE_TYPE_STRING': + etype = 'SANE_String_Const' + l = ['SANE_I18N("%s")' % x for x in l] + ['NULL'] + print 'static const %s %s[%d] = {' % (etype, n, len(l)) + for x in l[0:-1]: + print '\t' + x + ',' + print '\t' + l[-1] + ' };' + + +def genConstraints(options): + for o in options: + if 'constraint' not in o: continue + c = o['constraint'] + oname = o['cname_con'] + otype = o['type'] + if isinstance(c, tuple): + genMinMaxRange(oname, otype, c) + elif isinstance(c, list): + genList(oname, otype, c) + print + +def buildCodeVerbatim(o): + for f in ('name', 'title', 'desc', 'type', 'unit', 'size', 'cap', + 'constraint_type', 'constraint', 'default'): + if (f not in o): continue + temp = o[f] + if (not isinstance(temp,str)) or \ + (len(temp) < 1) or (temp[0] != '@'): + continue + o['code_' + f] = temp[1:] + +def ccode(o): + buildCodeVerbatim(o) + if 'code_name' not in o: + o['code_name'] = '"' + o['name'] + '"' + for f in ('title', 'desc'): + cf = 'code_' + f + if cf in o: continue + o[cf] = 'SANE_I18N("' + o[f] + '")' + + for f in ('type', 'unit', 'constraint_type'): + cf = 'code_' + f + if cf in o: continue + o[cf] = o[f] + + if 'code_size' not in o: + otype = o['type'] + osize = o['size'] + if otype == 'SANE_TYPE_STRING': + code = str(osize + 1) + elif otype == 'SANE_TYPE_INT' or otype == 'SANE_TYPE_FIXED': + code = str(osize) + ' * sizeof(SANE_Word)' + elif otype == 'SANE_TYPE_BUTTON': + code = '0' + else: + code = 'sizeof(SANE_Word)' + o['code_size'] = code + + if ('code_cap' not in o) and ('cap' in o): + o['code_cap'] = reduce(lambda a,b: a+'|'+b, o['cap']) + else: + o['code_cap'] = '0' + + if ('code_info' not in o) and ('info' in o): + o['code_info'] = reduce(lambda a,b: a+'|'+b, o['info']) + else: + o['code_info'] = '0' + + if ('code_default' not in o) and ('default' in o): + odefault = o['default'] + otype = o['type'] + if odefault == '_MIN': + rhs = 'w = sod->constraint.range->min' + elif odefault == '_MAX': + rhs = 'w = sod->constraint.range->max' + elif otype in ('SANE_TYPE_INT', 'SANE_TYPE_BOOL'): + rhs = 'w = %(default)s' + elif otype == 'SANE_TYPE_FIXED': + rhs = 'w = SANE_FIX(%(default)s)' + elif otype == 'SANE_TYPE_STRING': + rhs = 's = SANE_I18N("%(default)s")' + o['code_default'] = rhs % o + if 'code_default' in o: + code = ' opt->def.%(code_default)s;\n' + if o['constraint_type'] != 'SANE_CONSTRAINT_STRING_LIST': + code += ' opt->val.%(code_default)s;\n' + else: + code += ' opt->val.w = find_string_in_list' \ + '(opt->def.s, sod->constraint.string_list);\n' + o['full_code_default'] = code % o + else: + o['full_code_default'] = '' + + if ('code_constraint' not in o) and ('constraint' in o): + ct = o['constraint_type'] + idx = len('SANE_CONSTRAINT_') + ctype = ct[idx:].lower() + if ctype == 'range': + rhs = '&%(cname_con)s' % o + else: + rhs = '%(cname_con)s' % o + o['code_constraint'] = ctype + ' = ' + rhs + if 'code_constraint' in o: + code = ' sod->constraint.%(code_constraint)s;\n' + o['full_code_constraint'] = code % o + else: + o['full_code_constraint'] = '' + + return o + +def genBuildOptions(options): + print """ +static +int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list) +{ + int i; + for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {} + return i; +} + +static +int build_option_descriptors(struct pixma_sane_t *ss) +{ + SANE_Option_Descriptor *sod; + option_descriptor_t *opt; + + memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));""" + + for o in options: + o = ccode(o) + otype = o['type'] + code = '\n opt = &(OPT_IN_CTX[%(cname_opt)s]);\n' \ + ' sod = &opt->sod;\n' \ + ' sod->type = %(code_type)s;\n' \ + ' sod->title = %(code_title)s;\n' \ + ' sod->desc = %(code_desc)s;\n' + if otype != 'SANE_TYPE_GROUP': + code += ' sod->name = %(code_name)s;\n' \ + ' sod->unit = %(code_unit)s;\n' \ + ' sod->size = %(code_size)s;\n' \ + ' sod->cap = %(code_cap)s;\n' \ + ' sod->constraint_type = %(code_constraint_type)s;\n' \ + '%(full_code_constraint)s' \ + ' OPT_IN_CTX[%(cname_opt)s].info = %(code_info)s;\n' \ + '%(full_code_default)s' + sys.stdout.write(code % o) + print + print ' return 0;\n' + print '}' + print + +g = Struct() +g.ngroups = 0 +opt_prefix = 'opt_' +con_prefix = 'constraint_' +cnameMap = createCNameMap() +options = parseFile(sys.stdin) +print "/* Automatically generated from pixma_sane.c */" +if (len(sys.argv) == 2) and (sys.argv[1] == 'h'): + genHeader(options) +else: + genConstraints(options) + genBuildOptions(options) |