Home | History | Annotate | Download | only in format
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """Formats as a .C file for compilation.
      7 """
      8 
      9 import os
     10 import re
     11 import types
     12 
     13 from grit import util
     14 
     15 
     16 def _FormatHeader(root, output_dir):
     17   """Returns the required preamble for C files."""
     18   # Find the location of the resource header file, so that we can include
     19   # it.
     20   resource_header = 'resource.h'  # fall back to this
     21   for output in root.GetOutputFiles():
     22     if output.attrs['type'] == 'rc_header':
     23       resource_header = os.path.abspath(output.GetOutputFilename())
     24       resource_header = util.MakeRelativePath(output_dir, resource_header)
     25   return """// This file is automatically generated by GRIT.  Do not edit.
     26 
     27 #include "%s"
     28 
     29 // All strings are UTF-8
     30 """ % (resource_header)
     31 # end _FormatHeader() function
     32 
     33 
     34 def Format(root, lang='en', output_dir='.'):
     35   """Outputs a C switch statement representing the string table."""
     36   from grit.node import message
     37   assert isinstance(lang, types.StringTypes)
     38 
     39   yield _FormatHeader(root, output_dir)
     40 
     41   yield 'const char* GetString(int id) {\n  switch (id) {'
     42 
     43   for item in root.ActiveDescendants():
     44     with item:
     45       if isinstance(item, message.MessageNode):
     46         yield _FormatMessage(item, lang)
     47 
     48   yield '\n    default:\n      return 0;\n  }\n}'
     49 
     50 
     51 def _HexToOct(match):
     52   "Return the octal form of the hex numbers"
     53   hex = match.group("hex")
     54   result = ""
     55   while len(hex):
     56     next_num = int(hex[2:4], 16)
     57     result += "\\" + '%03d' % int(oct(next_num), 10)
     58     hex = hex[4:]
     59   return match.group("escaped_backslashes") + result
     60 
     61 
     62 def _FormatMessage(item, lang):
     63   """Format a single <message> element."""
     64 
     65   message = item.ws_at_start + item.Translate(lang) + item.ws_at_end
     66   # output message with non-ascii chars escaped as octal numbers
     67   # C's grammar allows escaped hexadecimal numbers to be infinite,
     68   # but octal is always of the form \OOO
     69   message = message.encode('utf-8').encode('string_escape')
     70   # an escaped char is (\xHH)+ but only if the initial
     71   # backslash is not escaped.
     72   not_a_backslash = r"(^|[^\\])"  # beginning of line or a non-backslash char
     73   escaped_backslashes = not_a_backslash + r"(\\\\)*"
     74   hex_digits = r"((\\x)[0-9a-f]{2})+"
     75   two_digit_hex_num = re.compile(
     76     r"(?P<escaped_backslashes>%s)(?P<hex>%s)"
     77     % (escaped_backslashes, hex_digits))
     78   message = two_digit_hex_num.sub(_HexToOct, message)
     79   # unescape \ (convert \\ back to \)
     80   message = message.replace('\\\\', '\\')
     81   message = message.replace('"', '\\"')
     82   message = util.LINEBREAKS.sub(r'\\n', message)
     83 
     84   name_attr = item.GetTextualIds()[0]
     85 
     86   return '\n    case %s:\n      return "%s";' % (name_attr, message)
     87