#!/usr/bin/python
#
# a python script used to generate some C constant tables from a key charmap file
#
# usage:
#    progname file.kcm > charmap-tab.h
#
import sys, os, string, re

header = """\
#include "android_charmap.h"

/* the following is automatically generated by the 'gen-charmap.py' script
 * do not touch. the generation command was:
 *   gen-charmap.py\
"""

header2 = """
 */
"""

kmap_header = """\
static const AKeyEntry  _%(name)s_keys[] =
{
   /* keycode                   base   caps    fn  caps+fn   number */
"""


kmap_footer = """\
};

static const AKeyCharmap  _%(name)s_charmap =
{
    _%(name)s_keys,
    %(count)d,
    "%(name)s"
};
"""


re_mapname = re.compile( r".*/(\w+).kcm" )
re_start = re.compile( r"(\w+)\s*(.*)" )
re_char  = re.compile( r"('.')\s*(.*)" )
re_hex   = re.compile( r"(0x\w+)\s*(.*)" )

specials = { 'COMMA': 'Comma',
             'PERIOD': 'Period',
             'AT': 'At',
             'LEFT_BRACKET': 'LeftBracket',
             'RIGHT_BRACKET': 'RightBracket',
             'SLASH': 'Slash',
             'BACKSLASH': 'Backslash',
             'GRAVE': 'Grave',
             'MINUS': 'Minus',
             'EQUALS': 'Equals',
             'SEMICOLON': 'Semicolon',
             'APOSTROPHE': 'Apostrophe',
             'SPACE': 'Space',
             'ENTER': 'Enter',
             'TAB': 'Tab'
           }

entries = []

def match_char_or_hex(line):
    m = re_char.match(line)
    if not m:
        m = re_hex.match(line)
    return m

def quote(s):
    if s == "'''":
        s = "'\\''"
    elif s == "'\\'":
        s = "'\\\\'"
    return s

def process_line(line,result):
    m = re_start.match(line)
    if not m:
        print "bad bad line: " + line
        return -1
    keycode = m.group(1)
    line    = m.group(2)
    m = match_char_or_hex(line)
    if not m:
        print "character expected in: " + line
        return -1
    base = quote(m.group(1))
    line = m.group(2)
    m = match_char_or_hex(line)
    if not m:
        print "character expected in: " + line
        return -1
    caps = quote(m.group(1))
    line = m.group(2)
    m = match_char_or_hex(line)
    if not m:
        print "character expected in: " + line
        return -1
    fn = quote(m.group(1))
    line = m.group(2)
    m = match_char_or_hex(line)
    if not m:
        print "character expected in: " + line
        return -1
    caps_fn = quote(m.group(1))
    line = m.group(2)
    m = match_char_or_hex(line)
    if not m:
        print "character expected in: " + line
        return -1
    number = quote(m.group(1))

    if specials.has_key(keycode):
        keycode = specials[keycode]
    keycode = "kKeyCode" + keycode

    result.append( (keycode,base,caps,fn,caps_fn,number) )
    return 0

def process_file( file ):
    result = []
    fp = open(file,"rb")
    for line in fp.xreadlines():
        line = line.strip()
        if not line:   # skip empty lines
            continue
        if line[0] == '#' or line[0] == '[':  # skip
            continue
        if process_line(line,result) < 0:
            break
    fp.close()
    return result

class KMap:
    def __init__(self,name,results):
        self.name    = name
        self.results = results

    def dump(self):
        t = { 'name': self.name, 'count':len(self.results) }
        print kmap_header % t
        for item in self.results:
            print "    { %-22s, %5s, %5s, %5s, %6s, %5s }," % item
        print kmap_footer % t

kmaps = []

if len(sys.argv) < 2:
    print "usage: progname  charmap.kcm [charmap2.kcm ...] > charmap-tab.h"
else:
    genline = ""
    for filepath in sys.argv[1:]:
        m = re_mapname.match(filepath)
        if not m:
            print "%s is not a keyboard charmap name" % filepath
            os.exit(1)

        mapname = m.group(1)
        genline = genline + " " + mapname + ".kcm"

    for filepath in sys.argv[1:]:
        m = re_mapname.match(filepath)
        mapname = m.group(1)
        result = process_file( filepath )
        kmap = KMap(mapname,result)
        kmaps.append(kmap)

    print header + genline + header2
    for kmap in kmaps:
        kmap.dump()

    print "const AKeyCharmap*  android_charmaps[%d] = {" % len(kmaps),
    comma = ""
    for kmap in kmaps:
        print "%s&_%s_charmap" % (comma, kmap.name),
        comma = ", "
    print "};"
    print "const int           android_charmap_count = %d;" % len(kmaps)
