Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #!/usr/bin/python
  2. #
  3. # Copyright (C) 2009 Chia-I Wu <olv@0xlab.org>
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # on the rights to use, copy, modify, merge, publish, distribute, sub
  9. # license, and/or sell copies of the Software, and to permit persons to whom
  10. # the Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice (including the next
  13. # paragraph) shall be included in all copies or substantial portions of the
  14. # Software.
  15. #
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
  19. # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. # IN THE SOFTWARE.
  23.  
  24. import sys
  25. import os.path
  26. import getopt
  27.  
  28. GLAPI = "../../glapi/gen"
  29. sys.path.append(GLAPI)
  30.  
  31. import gl_XML
  32. import glX_XML
  33.  
  34. class ApiSet(object):
  35.     def __init__(self, api, elts=["enum", "type", "function"]):
  36.         self.api = api
  37.         self.elts = elts
  38.  
  39.     def _check_enum(self, e1, e2, strict=True):
  40.         if e1.name != e2.name:
  41.             raise ValueError("%s: name mismatch" % e1.name)
  42.         if e1.value != e2.value:
  43.             raise ValueError("%s: value 0x%04x != 0x%04x"
  44.                     % (e1.name, e1.value, e2.value))
  45.  
  46.     def _check_type(self, t1, t2, strict=True):
  47.         if t1.name != t2.name:
  48.             raise ValueError("%s: name mismatch" % t1.name)
  49.         if t1.type_expr.string() != t2.type_expr.string():
  50.             raise ValueError("%s: type %s != %s"
  51.                     % (t1.name, t1.type_expr.string(), t2.type_expr.string()))
  52.  
  53.     def _check_function(self, f1, f2, strict=True):
  54.         if f1.name != f2.name:
  55.             raise ValueError("%s: name mismatch" % f1.name)
  56.         if f1.return_type != f2.return_type:
  57.             raise ValueError("%s: return type %s != %s"
  58.                     % (f1.name, f1.return_type, f2.return_type))
  59.         # there might be padded parameters
  60.         if strict and len(f1.parameters) != len(f2.parameters):
  61.             raise ValueError("%s: parameter length %d != %d"
  62.                     % (f1.name, len(f1.parameters), len(f2.parameters)))
  63.         if f1.assign_offset != f2.assign_offset:
  64.             if ((f1.assign_offset and f2.offset < 0) or
  65.                 (f2.assign_offset and f1.offset < 0)):
  66.                 raise ValueError("%s: assign offset %d != %d"
  67.                         % (f1.name, f1.assign_offset, f2.assign_offset))
  68.         elif not f1.assign_offset:
  69.             if f1.offset != f2.offset:
  70.                 raise ValueError("%s: offset %d != %d"
  71.                         % (f1.name, f1.offset, f2.offset))
  72.  
  73.         if strict:
  74.             l1 = f1.entry_points
  75.             l2 = f2.entry_points
  76.             l1.sort()
  77.             l2.sort()
  78.             if l1 != l2:
  79.                 raise ValueError("%s: entry points %s != %s"
  80.                         % (f1.name, l1, l2))
  81.  
  82.             l1 = f1.static_entry_points
  83.             l2 = f2.static_entry_points
  84.             l1.sort()
  85.             l2.sort()
  86.             if l1 != l2:
  87.                 raise ValueError("%s: static entry points %s != %s"
  88.                         % (f1.name, l1, l2))
  89.  
  90.         pad = 0
  91.         for i in xrange(len(f1.parameters)):
  92.             p1 = f1.parameters[i]
  93.             p2 = f2.parameters[i + pad]
  94.  
  95.             if not strict and p1.is_padding != p2.is_padding:
  96.                 if p1.is_padding:
  97.                     pad -= 1
  98.                     continue
  99.                 else:
  100.                     pad += 1
  101.                     p2 = f2.parameters[i + pad]
  102.  
  103.             if strict and p1.name != p2.name:
  104.                 raise ValueError("%s: parameter %d name %s != %s"
  105.                         % (f1.name, i, p1.name, p2.name))
  106.             if p1.type_expr.string() != p2.type_expr.string():
  107.                 if (strict or
  108.                     # special case
  109.                     f1.name == "TexImage2D" and p1.name != "internalformat"):
  110.                     raise ValueError("%s: parameter %s type %s != %s"
  111.                             % (f1.name, p1.name, p1.type_expr.string(),
  112.                                p2.type_expr.string()))
  113.  
  114.     def union(self, other):
  115.         union = gl_XML.gl_api(None)
  116.  
  117.         if "enum" in self.elts:
  118.             union.enums_by_name = other.enums_by_name.copy()
  119.             for key, val in self.api.enums_by_name.iteritems():
  120.                 if key not in union.enums_by_name:
  121.                     union.enums_by_name[key] = val
  122.                 else:
  123.                     self._check_enum(val, other.enums_by_name[key])
  124.  
  125.         if "type" in self.elts:
  126.             union.types_by_name = other.types_by_name.copy()
  127.             for key, val in self.api.types_by_name.iteritems():
  128.                 if key not in union.types_by_name:
  129.                     union.types_by_name[key] = val
  130.                 else:
  131.                     self._check_type(val, other.types_by_name[key])
  132.  
  133.         if "function" in self.elts:
  134.             union.functions_by_name = other.functions_by_name.copy()
  135.             for key, val in self.api.functions_by_name.iteritems():
  136.                 if key not in union.functions_by_name:
  137.                     union.functions_by_name[key] = val
  138.                 else:
  139.                     self._check_function(val, other.functions_by_name[key])
  140.  
  141.         return union
  142.  
  143.     def intersection(self, other):
  144.         intersection = gl_XML.gl_api(None)
  145.  
  146.         if "enum" in self.elts:
  147.             for key, val in self.api.enums_by_name.iteritems():
  148.                 if key in other.enums_by_name:
  149.                     self._check_enum(val, other.enums_by_name[key])
  150.                     intersection.enums_by_name[key] = val
  151.  
  152.         if "type" in self.elts:
  153.             for key, val in self.api.types_by_name.iteritems():
  154.                 if key in other.types_by_name:
  155.                     self._check_type(val, other.types_by_name[key])
  156.                     intersection.types_by_name[key] = val
  157.  
  158.         if "function" in self.elts:
  159.             for key, val in self.api.functions_by_name.iteritems():
  160.                 if key in other.functions_by_name:
  161.                     self._check_function(val, other.functions_by_name[key])
  162.                     intersection.functions_by_name[key] = val
  163.  
  164.         return intersection
  165.  
  166.     def difference(self, other):
  167.         difference = gl_XML.gl_api(None)
  168.  
  169.         if "enum" in self.elts:
  170.             for key, val in self.api.enums_by_name.iteritems():
  171.                 if key not in other.enums_by_name:
  172.                     difference.enums_by_name[key] = val
  173.                 else:
  174.                     self._check_enum(val, other.enums_by_name[key])
  175.  
  176.         if "type" in self.elts:
  177.             for key, val in self.api.types_by_name.iteritems():
  178.                 if key not in other.types_by_name:
  179.                     difference.types_by_name[key] = val
  180.                 else:
  181.                     self._check_type(val, other.types_by_name[key])
  182.  
  183.         if "function" in self.elts:
  184.             for key, val in self.api.functions_by_name.iteritems():
  185.                 if key not in other.functions_by_name:
  186.                     difference.functions_by_name[key] = val
  187.                 else:
  188.                     self._check_function(val, other.functions_by_name[key], False)
  189.  
  190.         return difference
  191.  
  192. def cmp_enum(e1, e2):
  193.     if e1.value < e2.value:
  194.         return -1
  195.     elif e1.value > e2.value:
  196.         return 1
  197.     else:
  198.         return 0
  199.  
  200. def cmp_type(t1, t2):
  201.     return t1.size - t2.size
  202.  
  203. def cmp_function(f1, f2):
  204.     if f1.name > f2.name:
  205.         return 1
  206.     elif f1.name < f2.name:
  207.         return -1
  208.     else:
  209.         return 0
  210.  
  211. def spaces(n, str=""):
  212.     spaces = n - len(str)
  213.     if spaces < 1:
  214.         spaces = 1
  215.     return " " * spaces
  216.  
  217. def output_enum(e, indent=0):
  218.     attrs = 'name="%s"' % e.name
  219.     if e.default_count > 0:
  220.         tab = spaces(37, attrs)
  221.         attrs += '%scount="%d"' % (tab, e.default_count)
  222.     tab = spaces(48, attrs)
  223.     val = "%04x" % e.value
  224.     val = "0x" + val.upper()
  225.     attrs += '%svalue="%s"' % (tab, val)
  226.  
  227.     # no child
  228.     if not e.functions:
  229.         print '%s<enum %s/>' % (spaces(indent), attrs)
  230.         return
  231.  
  232.     print '%s<enum %s>' % (spaces(indent), attrs)
  233.     for key, val in e.functions.iteritems():
  234.         attrs = 'name="%s"' % key
  235.         if val[0] != e.default_count:
  236.             attrs += ' count="%d"' % val[0]
  237.         if not val[1]:
  238.             attrs += ' mode="get"'
  239.  
  240.         print '%s<size %s/>' % (spaces(indent * 2), attrs)
  241.  
  242.     print '%s</enum>' % spaces(indent)
  243.  
  244. def output_type(t, indent=0):
  245.     tab = spaces(16, t.name)
  246.     attrs = 'name="%s"%ssize="%d"' % (t.name, tab, t.size)
  247.     ctype = t.type_expr.string()
  248.     if ctype.find("unsigned") != -1:
  249.         attrs += ' unsigned="true"'
  250.     elif ctype.find("signed") == -1:
  251.         attrs += ' float="true"'
  252.     print '%s<type %s/>' % (spaces(indent), attrs)
  253.  
  254. def output_function(f, indent=0):
  255.     attrs = 'name="%s"' % f.name
  256.     if f.offset > 0:
  257.         if f.assign_offset:
  258.             attrs += ' offset="assign"'
  259.         else:
  260.             attrs += ' offset="%d"' % f.offset
  261.     print '%s<function %s>' % (spaces(indent), attrs)
  262.  
  263.     for p in f.parameters:
  264.         attrs = 'name="%s" type="%s"' \
  265.                 % (p.name, p.type_expr.original_string)
  266.         print '%s<param %s/>' % (spaces(indent * 2), attrs)
  267.     if f.return_type != "void":
  268.         attrs = 'type="%s"' % f.return_type
  269.         print '%s<return %s/>' % (spaces(indent * 2), attrs)
  270.  
  271.     print '%s</function>' % spaces(indent)
  272.  
  273. def output_category(api, indent=0):
  274.     enums = api.enums_by_name.values()
  275.     enums.sort(cmp_enum)
  276.     types = api.types_by_name.values()
  277.     types.sort(cmp_type)
  278.     functions = api.functions_by_name.values()
  279.     functions.sort(cmp_function)
  280.  
  281.     for e in enums:
  282.         output_enum(e, indent)
  283.     if enums and types:
  284.         print
  285.     for t in types:
  286.         output_type(t, indent)
  287.     if enums or types:
  288.         print
  289.     for f in functions:
  290.         output_function(f, indent)
  291.         if f != functions[-1]:
  292.             print
  293.  
  294. def is_api_empty(api):
  295.     return bool(not api.enums_by_name and
  296.                 not api.types_by_name and
  297.                 not api.functions_by_name)
  298.  
  299. def show_usage(ops):
  300.     print "Usage: %s [-k elts] <%s> <file1> <file2>" % (sys.argv[0], "|".join(ops))
  301.     print "    -k elts   A comma separated string of types of elements to"
  302.     print "              skip.  Possible types are enum, type, and function."
  303.     sys.exit(1)
  304.  
  305. def main():
  306.     ops = ["union", "intersection", "difference"]
  307.     elts = ["enum", "type", "function"]
  308.  
  309.     try:
  310.         options, args = getopt.getopt(sys.argv[1:], "k:")
  311.     except Exception, e:
  312.         show_usage(ops)
  313.  
  314.     if len(args) != 3:
  315.         show_usage(ops)
  316.     op, file1, file2 = args
  317.     if op not in ops:
  318.         show_usage(ops)
  319.  
  320.     skips = []
  321.     for opt, val in options:
  322.         if opt == "-k":
  323.             skips = val.split(",")
  324.  
  325.     for elt in skips:
  326.         try:
  327.             elts.remove(elt)
  328.         except ValueError:
  329.             show_usage(ops)
  330.  
  331.     api1 = gl_XML.parse_GL_API(file1, glX_XML.glx_item_factory())
  332.     api2 = gl_XML.parse_GL_API(file2, glX_XML.glx_item_factory())
  333.  
  334.     set = ApiSet(api1, elts)
  335.     func = getattr(set, op)
  336.     result = func(api2)
  337.  
  338.     if not is_api_empty(result):
  339.         cat_name = "%s_of_%s_and_%s" \
  340.                 % (op, os.path.basename(file1), os.path.basename(file2))
  341.  
  342.         print '<?xml version="1.0"?>'
  343.         print '<!DOCTYPE OpenGLAPI SYSTEM "%s/gl_API.dtd">' % GLAPI
  344.         print
  345.         print '<OpenGLAPI>'
  346.         print
  347.         print '<category name="%s">' % (cat_name)
  348.         output_category(result, 4)
  349.         print '</category>'
  350.         print
  351.         print '</OpenGLAPI>'
  352.  
  353. if __name__ == "__main__":
  354.     main()
  355.