1#!/usr/bin/python
2#
3# a python script used to generate some C constant tables from a key charmap file
4#
5# usage:
6#    progname file.kcm > charmap-tab.h
7#
8import sys, os, string, re
9
10header = """\
11#include "android_charmap.h"
12
13/* the following is automatically generated by the 'gen-charmap.py' script
14 * do not touch. the generation command was:
15 *   gen-charmap.py\
16"""
17
18header2 = """
19 */
20"""
21
22kmap_header = """\
23static const AKeyEntry  _%(name)s_keys[] =
24{
25   /* keycode                   base   caps    fn  caps+fn   number */
26"""
27
28
29kmap_footer = """\
30};
31
32static const AKeyCharmap  _%(name)s_charmap =
33{
34    _%(name)s_keys,
35    %(count)d,
36    "%(name)s"
37};
38"""
39
40
41re_mapname = re.compile( r".*/(\w+).kcm" )
42re_start = re.compile( r"(\w+)\s*(.*)" )
43re_char  = re.compile( r"('.')\s*(.*)" )
44re_hex   = re.compile( r"(0x\w+)\s*(.*)" )
45
46specials = { 'COMMA': 'Comma',
47             'PERIOD': 'Period',
48             'AT': 'At',
49             'LEFT_BRACKET': 'LeftBracket',
50             'RIGHT_BRACKET': 'RightBracket',
51             'SLASH': 'Slash',
52             'BACKSLASH': 'Backslash',
53             'GRAVE': 'Grave',
54             'MINUS': 'Minus',
55             'EQUALS': 'Equals',
56             'SEMICOLON': 'Semicolon',
57             'APOSTROPHE': 'Apostrophe',
58             'SPACE': 'Space',
59             'ENTER': 'Newline',
60             'TAB': 'Tab',
61             'STAR': 'Star',
62             'POUND': 'Pound',
63             'PLUS': 'Plus',
64             'DEL': 'Del'
65           }
66
67entries = []
68
69def match_char_or_hex(line):
70    m = re_char.match(line)
71    if not m:
72        m = re_hex.match(line)
73    return m
74
75def quote(s):
76    if s == "'''":
77        s = "'\\''"
78    elif s == "'\\'":
79        s = "'\\\\'"
80    return s
81
82def process_line(line,result):
83    m = re_start.match(line)
84    if not m:
85        print "bad bad line: " + line
86        return -1
87    keycode = m.group(1)
88    line    = m.group(2)
89    m = match_char_or_hex(line)
90    if not m:
91        print "character expected in: " + line
92        return -1
93    disp = quote(m.group(1))
94    line = m.group(2)
95    m = match_char_or_hex(line)
96    if not m:
97        print "character expected in: " + line
98        return -1
99    number = quote(m.group(1))
100    line = m.group(2)
101    m = match_char_or_hex(line)
102    if not m:
103        print "character expected in: " + line
104        return -1
105    base = quote(m.group(1))
106    line = m.group(2)
107    m = match_char_or_hex(line)
108    if not m:
109        print "character expected in: " + line
110        return -1
111    caps = quote(m.group(1))
112    line = m.group(2)
113    m = match_char_or_hex(line)
114    if not m:
115        print "character expected in: " + line
116        return -1
117    fn = quote(m.group(1))
118    line = m.group(2)
119    m = match_char_or_hex(line)
120    if not m:
121        print "character expected in: " + line
122        return -1
123    caps_fn = quote(m.group(1))
124
125    if specials.has_key(keycode):
126        keycode = specials[keycode]
127    keycode = "kKeyCode" + keycode
128
129    result.append( (keycode,base,caps,fn,caps_fn,number) )
130    return 0
131
132def process_file( file ):
133    result = []
134    fp = open(file,"rb")
135    for line in fp.xreadlines():
136        line = line.strip()
137        if not line:   # skip empty lines
138            continue
139        if line[0] == '#' or line[0] == '[':  # skip
140            continue
141        if process_line(line,result) < 0:
142            break
143    fp.close()
144    return result
145
146class KMap:
147    def __init__(self,name,results):
148        self.name    = name
149        self.results = results
150
151    def dump(self):
152        t = { 'name': self.name, 'count':len(self.results) }
153        print kmap_header % t
154        for item in self.results:
155            print "    { %-22s, %5s, %5s, %5s, %6s, %5s }," % item
156        print kmap_footer % t
157
158kmaps = []
159
160if len(sys.argv) < 2:
161    print "usage: progname  charmap.kcm [charmap2.kcm ...] > charmap-tab.h"
162else:
163    genline = ""
164    for filepath in sys.argv[1:]:
165        m = re_mapname.match(filepath)
166        if not m:
167            print "%s is not a keyboard charmap name" % filepath
168            os.exit(1)
169
170        mapname = m.group(1)
171        genline = genline + " " + mapname + ".kcm"
172
173    for filepath in sys.argv[1:]:
174        m = re_mapname.match(filepath)
175        mapname = m.group(1)
176        result = process_file( filepath )
177        kmap = KMap(mapname,result)
178        kmaps.append(kmap)
179
180    print header + genline + header2
181    for kmap in kmaps:
182        kmap.dump()
183
184    print "const AKeyCharmap*  android_charmaps[%d] = {" % len(kmaps),
185    comma = ""
186    for kmap in kmaps:
187        print "%s&_%s_charmap" % (comma, kmap.name),
188        comma = ", "
189    print "};"
190    print "const int           android_charmap_count = %d;" % len(kmaps)
191