#!/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)