]> git.cworth.org Git - apitrace/commitdiff
More concise data model.
authorJosé Fonseca <jfonseca@vmware.com>
Mon, 15 Nov 2010 16:09:14 +0000 (16:09 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Mon, 15 Nov 2010 16:09:14 +0000 (16:09 +0000)
base.py
format.py [new file with mode: 0644]
glx.py
log.cpp
log.hpp
model.py [new file with mode: 0644]
opengl32.py
windows.py
xml2txt.py

diff --git a/base.py b/base.py
index d6ed0a2381bf2b6c65d89912b1b3d829d17c678e..f3beda567c79c4668792fd27204e81118863d1cc 100644 (file)
--- a/base.py
+++ b/base.py
@@ -100,14 +100,14 @@ class Concrete(Type):
         print '    Dump%s(%s);' % (self.id, instance)
     
 
-class Intrinsic(Concrete):
+class Literal(Concrete):
 
-    def __init__(self, expr, format):
+    def __init__(self, expr, format, base=10):
         Concrete.__init__(self, expr)
         self.format = format
 
     def _dump(self, instance):
-        print '    Log::TextF("%s", %s);' % (self.format, instance)
+        print '    Log::Literal%s(%s);' % (self.format, instance)
 
 
 class Const(Type):
@@ -143,7 +143,7 @@ class Pointer(Type):
         print '        Log::EndReference();'
         print '    }'
         print '    else'
-        print '        Log::Text("NULL");'
+        print '        Log::LiteralNull();'
 
     def wrap_instance(self, instance):
         self.type.wrap_instance("*" + instance)
@@ -172,10 +172,10 @@ class Enum(Concrete):
         print '    switch(%s) {' % instance
         for value in self.values:
             print '    case %s:' % value
-            print '        Log::Text("%s");' % value
+            print '        Log::LiteralNamedConstant("%s");' % value
             print '        break;'
         print '    default:'
-        print '        Log::TextF("%%i", %s);' % instance
+        print '        Log::LiteralSInt(%s);' % instance
         print '        break;'
         print '    }'
 
@@ -195,21 +195,17 @@ class Flags(Concrete):
         self.values = values
 
     def _dump(self, instance):
-        print '    bool l_First = true;'
         print '    %s l_Value = %s;' % (self.type, instance)
+        print '    Log::BeginBitmask("%s");' % (self.type,)
         for value in self.values:
             print '    if((l_Value & %s) == %s) {' % (value, value)
-            print '        if(!l_First)'
-            print '            Log::Text(" | ");'
-            print '        Log::Text("%s");' % value
+            print '        Log::LiteralNamedConstant("%s");' % value
             print '        l_Value &= ~%s;' % value
-            print '        l_First = false;'
             print '    }'
-        print '    if(l_Value || l_First) {'
-        print '        if(!l_First)'
-        print '            Log::Text(" | ");'
+        print '    if(l_Value) {'
         self.type.dump("l_Value");
         print '    }'
+        print '    Log::EndBitmask();'
 
 
 class Array(Type):
@@ -221,11 +217,13 @@ class Array(Type):
 
     def dump(self, instance):
         index = '__i' + self.type.id
+        print '    Log::BeginArray("%s", %s);' % (self.type, self.length)
         print '    for (int %s = 0; %s < %s; ++%s) {' % (index, index, self.length, index)
         print '        Log::BeginElement("%s");' % (self.type,)
         self.type.dump('(%s)[%s]' % (instance, index))
         print '        Log::EndElement();'
         print '    }'
+        print '    Log::EndArray();'
 
     def wrap_instance(self, instance):
         self.type.wrap_instance("*" + instance)
@@ -244,13 +242,16 @@ class Struct(Concrete):
 
     def __init__(self, name, members):
         Concrete.__init__(self, name)
+        self.name = name
         self.members = members
 
     def _dump(self, instance):
+        print '    Log::BeginStruct("%s");' % (self.name,)
         for type, name in self.members:
-            print '    Log::BeginElement("%s", "%s");' % (type, name)
+            print '    Log::BeginMember("%s", "%s");' % (type, name)
             type.dump('(%s).%s' % (instance, name))
-            print '    Log::EndElement();'
+            print '    Log::EndMember();'
+        print '    Log::EndStruct();'
 
 
 class Alias(Type):
@@ -478,7 +479,7 @@ class Interface(Type):
 class Method(Function):
 
     def __init__(self, type, name, args):
-        Function.__init__(self, type, name, args)
+        Function.__init__(self, type, name, args, call = '__stdcall')
 
 
 towrap = []
@@ -505,32 +506,36 @@ class _String(Type):
         Type.__init__(self, "char *")
 
     def dump(self, instance):
-        print '    Log::DumpString((const char *)%s);' % instance
+        print '    Log::LiteralString((const char *)%s);' % instance
 
 String = _String()
 
-class _WString(Type):
+
+class _Opaque(Type):
 
     def __init__(self):
-        Type.__init__(self, "wchar_t *")
+        Type.__init__(self, "void *")
 
     def dump(self, instance):
-        print '    Log::DumpWString(%s);' % instance
-
-WString = _WString()
-
-
-SChar = Intrinsic("signed char", "%i")
-UChar = Intrinsic("unsigned char", "%u")
-Short = Intrinsic("short", "%i")
-Int = Intrinsic("int", "%i")
-Long = Intrinsic("long", "%li")
-UShort = Intrinsic("unsigned short", "%u")
-UInt = Intrinsic("unsigned int", "%u")
-ULong = Intrinsic("unsigned long", "%lu")
-Float = Intrinsic("float", "%f")
-Double = Intrinsic("double", "%f")
-SizeT = Intrinsic("size_t", "%lu")
+        print '    Log::LiteralOpaque((const void *)%s);' % instance
+
+Opaque = _Opaque()
+
+
+Bool = Literal("bool", "Bool")
+SChar = Literal("signed char", "SInt")
+UChar = Literal("unsigned char", "UInt")
+Short = Literal("short", "SInt")
+Int = Literal("int", "SInt")
+Long = Literal("long", "SInt")
+LongLong = Literal("long long", "SInt")
+UShort = Literal("unsigned short", "UInt")
+UInt = Literal("unsigned int", "UInt")
+ULong = Literal("unsigned long", "UInt")
+Float = Literal("float", "Float")
+Double = Literal("double", "Float")
+SizeT = Literal("size_t", "UInt")
+WString = Literal("wchar_t *", "WString")
 
 
 def wrap():
diff --git a/format.py b/format.py
new file mode 100644 (file)
index 0000000..9842f23
--- /dev/null
+++ b/format.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+import sys
+
+
+class Formatter:
+    '''Plain formatter'''
+
+    def __init__(self, stream):
+        self.stream = stream
+
+    def text(self, text):
+        self.stream.write(text)
+
+    def newline(self):
+        self.text('\n')
+
+    def function(self, name):
+        self.text(name)
+
+    def variable(self, name):
+        self.text(name)
+
+    def literal(self, value):
+        self.text(str(value))
+
+    def address(self, addr):
+        self.text(str(addr))
+
+
+class AnsiFormatter(Formatter):
+    '''Formatter for plain-text files which outputs ANSI escape codes. See
+    http://en.wikipedia.org/wiki/ANSI_escape_code for more information
+    concerning ANSI escape codes.
+    '''
+
+    _csi = '\33['
+
+    _normal = '0m'
+    _bold = '1m'
+    _italic = '3m'
+    _red = '31m'
+    _green = '32m'
+    _blue = '34m'
+
+    def _escape(self, code):
+        self.text(self._csi + code)
+
+    def function(self, name):
+        self._escape(self._bold)
+        Formatter.function(self, name)
+        self._escape(self._normal)
+
+    def variable(self, name):
+        self._escape(self._italic)
+        Formatter.variable(self, name)
+        self._escape(self._normal)
+
+    def literal(self, value):
+        self._escape(self._blue)
+        Formatter.literal(self, value)
+        self._escape(self._normal)
+
+    def address(self, value):
+        self._escape(self._green)
+        Formatter.address(self, value)
+        self._escape(self._normal)
+
+
+class WindowsConsoleFormatter(Formatter):
+    '''Formatter for the Windows Console. See 
+    http://code.activestate.com/recipes/496901/ for more information.
+    '''
+
+    STD_INPUT_HANDLE  = -10
+    STD_OUTPUT_HANDLE = -11
+    STD_ERROR_HANDLE  = -12
+
+    FOREGROUND_BLUE      = 0x01
+    FOREGROUND_GREEN     = 0x02
+    FOREGROUND_RED       = 0x04
+    FOREGROUND_INTENSITY = 0x08
+    BACKGROUND_BLUE      = 0x10
+    BACKGROUND_GREEN     = 0x20
+    BACKGROUND_RED       = 0x40
+    BACKGROUND_INTENSITY = 0x80
+
+    _normal = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+    _bold = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
+    _italic = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+    _red = FOREGROUND_RED | FOREGROUND_INTENSITY
+    _green = FOREGROUND_GREEN | FOREGROUND_INTENSITY
+    _blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY
+
+    def __init__(self, stream):
+        Formatter.__init__(self, stream)
+
+        if stream is sys.stdin:
+            nStdHandle = self.STD_INPUT_HANDLE
+        elif stream is sys.stdout:
+            nStdHandle = self.STD_OUTPUT_HANDLE
+        elif stream is sys.stderr:
+            nStdHandle = self.STD_ERROR_HANDLE
+        else:
+            nStdHandle = None
+
+        if nStdHandle:
+            import ctypes
+            self.handle = ctypes.windll.kernel32.GetStdHandle(nStdHandle)
+        else:
+            self.handle = None
+
+    def _attribute(self, attr):
+        if self.handle:
+            import ctypes
+            ctypes.windll.kernel32.SetConsoleTextAttribute(self.handle, attr)
+
+    def function(self, name):
+        self._attribute(self._bold)
+        Formatter.function(self, name)
+        self._attribute(self._normal)
+
+    def variable(self, name):
+        self._attribute(self._italic)
+        Formatter.variable(self, name)
+        self._attribute(self._normal)
+
+    def literal(self, value):
+        self._attribute(self._blue)
+        Formatter.literal(self, value)
+        self._attribute(self._normal)
+
+    def address(self, value):
+        self._attribute(self._green)
+        Formatter.address(self, value)
+        self._attribute(self._normal)
+
+
+def DefaultFormatter(stream):
+    if sys.platform in ('linux2', 'cygwin'):
+        return AnsiFormatter(stream)
+    elif sys.platform in ('win32',):
+        return WindowsConsoleFormatter(stream)
+    else:
+        return Formatter(stream)
+
diff --git a/glx.py b/glx.py
index 79a4f466b3d4effc1533d02d7bb939650b08bf3b..697e3f99b41a577a70401f7fd759f83144724dfe 100644 (file)
--- a/glx.py
+++ b/glx.py
@@ -467,7 +467,7 @@ class GlxGetProcAddressFunction(DllFunction):
         print '    }'
 
 
-PROC = Intrinsic("__GLXextFuncPtr", "%p")
+PROC = Alias("__GLXextFuncPtr", Opaque)
 
 glXgetprocaddress = GlxGetProcAddressFunction(PROC, "glXGetProcAddress", [(Pointer(Const(GLubyte)), "procName")])
 libgl.functions.append(glXgetprocaddress)
diff --git a/log.cpp b/log.cpp
index 2493ec1fb5d3054808b9753bfacc6b8d8d39d190..2dc3775ecf2aba7eb891c87d376e9c732a25c0f3 100644 (file)
--- a/log.cpp
+++ b/log.cpp
@@ -109,7 +109,7 @@ WriteF(const char *format, ...)
 }
 
 static inline void 
-Escape(char c) 
+Escape(wchar_t c) 
 {
     switch(c) {
     case '&':
@@ -127,8 +127,21 @@ Escape(char c)
     case '\'':
         Write("&apos;");
         break;
+    case '\t':
+        Write("&#09;");
+        break;
+    case '\r':
+        Write("&#13;");
+        break;
+    case '\n':
+        Write("&#10;");
+        break;
     default:
-        Write(c);
+        if (c >= 0x20 && c <= 0x7e) {
+            Write((char)c);
+        } else {
+            Write('.');
+        }
     }
 }
 
@@ -141,6 +154,15 @@ Escape(const char *s)
     }
 }
 
+static inline void 
+Escape(const wchar_t *s)
+{
+    unsigned char c;
+    while((c = *s++) != 0) {
+        Escape(c);
+    }
+}
+
 static inline void
 EscapeF(const char *format, ...)
 {
@@ -255,19 +277,6 @@ void Close(void) {
     _Close();
 }
 
-void Text(const char *text) {
-    Escape(text);
-}
-
-void TextF(const char *format, ...) {
-    char szBuffer[4096];
-    va_list ap;
-    va_start(ap, format);
-    vsnprintf(szBuffer, sizeof(szBuffer), format, ap);
-    va_end(ap);
-    Escape(szBuffer);
-}
-
 void BeginCall(const char *function) {
     OS::AcquireMutex();
     Indent(1);
@@ -303,98 +312,140 @@ void EndReturn(void) {
     NewLine();
 }
 
-void BeginElement(const char *type, const char *name) {
-    BeginTag("elem", "type", type, "name", name);
+void BeginArray(const char *type, size_t length)
+{
+    BeginTag("array", "type", type);
+}
+
+void EndArray(void)
+{
+    EndTag("array");
 }
 
-void BeginElement(const char *type) {
+void BeginElement(const char *type)
+{
     BeginTag("elem", "type", type);
 }
 
-void EndElement(void) {
+void EndElement(void)
+{
     EndTag("elem");
 }
 
-void BeginReference(const char *type, const void *addr) {
+void BeginStruct(const char *type)
+{
+    BeginTag("struct", "type", type);
+}
+
+void EndStruct(void)
+{
+    EndTag("struct");
+}
+
+void BeginMember(const char *type, const char *name)
+{
+    BeginTag("member", "type", type, "name", name);
+}
+
+void EndMember(void)
+{
+    EndTag("member");
+}
+
+void BeginBitmask(const char *type)
+{
+    BeginTag("bitmask");
+}
+
+void EndBitmask(void)
+{
+    EndTag("bitmask");
+}
+
+void BeginReference(const char *type, const void *addr)
+{
     char saddr[256];
     snprintf(saddr, sizeof(saddr), "%p", addr);
     BeginTag("ref", "type", type, "addr", saddr);
 }
 
-void EndReference(void) {
+void EndReference(void)
+{
     EndTag("ref");
 }
 
-void DumpString(const char *str) {
-    const unsigned char *p = (const unsigned char *)str;
+void LiteralBool(bool value)
+{
+    BeginTag("bool");
+    WriteF("%u", value ? 0 : 1);
+    EndTag("bool");
+}
+
+void LiteralSInt(signed long long value)
+{
+    BeginTag("int");
+    WriteF("%lli", value);
+    EndTag("int");
+}
+
+void LiteralUInt(unsigned long long value)
+{
+    BeginTag("uint");
+    WriteF("%llu", value);
+    EndTag("uint");
+}
+
+void LiteralFloat(double value)
+{
+    BeginTag("float");
+    WriteF("%f", value);
+    EndTag("float");
+}
+
+void LiteralString(const char *str)
+{
     if (!str) {
-        Write("NULL");
+        LiteralNull();
         return;
     }
-    Write("\"");
-    unsigned char c;
-    while((c = *p++) != 0) {
-        if(c == '\"')
-            Write("\\\"");
-        else if(c == '\\')
-            Write("\\\\");
-        else if(c >= 0x20 && c <= 0x7e)
-            Write(c);
-        else if(c == '\t')
-            Write("&#09;");
-        else if(c == '\r')
-            Write("&#13;");
-        else if(c == '\n')
-            Write("&#10;");
-        else {
-            unsigned char octal0 = c & 0x7;
-            unsigned char octal1 = (c >> 3) & 0x7;
-            unsigned char octal2 = (c >> 3) & 0x7;
-            if(octal2)
-                WriteF("\\%u%u%u", octal2, octal1, octal0);
-            else if(octal1)
-                WriteF("\\%u%u", octal1, octal0);
-            else
-                WriteF("\\%u", octal0);
-        }
-    }
-    Write("\"");
+    BeginTag("string");
+    Escape(str);
+    EndTag("string");
 }
 
-void DumpWString(const wchar_t *str) {
-    const wchar_t *p = str;
+void LiteralWString(const wchar_t *str)
+{
     if (!str) {
-        Write("NULL");
+        LiteralNull();
         return;
     }
-    Write("L\"");
-    wchar_t c;
-    while((c = *p++) != 0) {
-        if(c == '\"')
-            Write("\\\"");
-        else if(c == '\\')
-            Write("\\\\");
-        else if(c >= 0x20 && c <= 0x7e)
-            Write((char)c);
-        else if(c == '\t')
-            Write("&#09;");
-        else if(c == '\r')
-            Write("&#13;");
-        else if(c == '\n')
-            Write("&#10;");
-        else {
-            unsigned octal0 = c & 0x7;
-            unsigned octal1 = (c >> 3) & 0x7;
-            unsigned octal2 = (c >> 3) & 0x7;
-            if(octal2)
-                WriteF("\\%u%u%u", octal2, octal1, octal0);
-            else if(octal1)
-                WriteF("\\%u%u", octal1, octal0);
-            else
-                WriteF("\\%u", octal0);
-        }
+    BeginTag("wstring");
+    Escape(str);
+    EndTag("wstring");
+}
+    
+void LiteralNamedConstant(const char *str)
+{
+    BeginTag("const");
+    Escape(str);
+    EndTag("const");
+}
+
+void LiteralOpaque(const void *addr)
+{
+    char saddr[256];
+    if (!addr) {
+        LiteralNull();
+        return;
     }
-    Write("\"");
+    snprintf(saddr, sizeof(saddr), "%p", addr);
+    BeginTag("opaque", "addr", saddr);
+    EndTag("opaque");
+}
+
+void LiteralNull(void)
+{
+    Tag("null");
 }
 
 } /* namespace Log */
diff --git a/log.hpp b/log.hpp
index 7ed928bb24e70a87195312ea4d858a92d283678e..4dc5337cf248f6b4e7f4c87b9d4b614a778c0e4b 100644 (file)
--- a/log.hpp
+++ b/log.hpp
@@ -32,9 +32,6 @@ namespace Log {
     void ReOpen(void);
     void Close(void);
     
-    void Text(const char *text);
-    void TextF(const char *format, ...);
-    
     void BeginCall(const char *function);
     void EndCall(void);
     
@@ -44,16 +41,33 @@ namespace Log {
     void BeginReturn(const char *type);
     void EndReturn(void);
 
+    void BeginArray(const char *type, size_t length);
+    void EndArray(void);
+
     void BeginElement(const char *type);
-    void BeginElement(const char *type, const char *name);
     void EndElement(void);
 
+    void BeginStruct(const char *type);
+    void EndStruct(void);
+
+    void BeginMember(const char *type, const char *name);
+    void EndMember(void);
+
+    void BeginBitmask(const char *type);
+    void EndBitmask(void);
+
     void BeginReference(const char *type, const void *addr);
     void EndReference(void);
 
-    void DumpString(const char *str);
-    void DumpWString(const wchar_t *str);
-    
+    void LiteralBool(bool value);
+    void LiteralSInt(signed long long value);
+    void LiteralUInt(unsigned long long value);
+    void LiteralFloat(double value);
+    void LiteralString(const char *str);
+    void LiteralWString(const wchar_t *str);
+    void LiteralNamedConstant(const char *str);
+    void LiteralOpaque(const void *addr);
+    void LiteralNull(void);
 }
 
 #endif /* _LOG_HPP_ */
diff --git a/model.py b/model.py
new file mode 100644 (file)
index 0000000..8c461f7
--- /dev/null
+++ b/model.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+'''Trace data model.'''
+
+
+import sys
+import string
+import format
+
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO
+
+
+class Node:
+    
+    def visit(self, visitor):
+        raise NotImplementedError
+
+    def __str__(self):
+        stream = StringIO()
+        formatter = format.DefaultFormatter(stream)
+        pretty_printer = PrettyPrinter(formatter)
+        self.visit(pretty_printer)
+        return stream.getvalue()
+
+
+class Literal(Node):
+    
+    def __init__(self, value):
+        self.value = value
+
+    def visit(self, visitor):
+        visitor.visit_literal(self)
+
+
+class NamedConstant(Node):
+    
+    def __init__(self, name):
+        self.name = name
+
+    def visit(self, visitor):
+        visitor.visit_named_constant(self)
+    
+
+class Bitmask(Node):
+    
+    def __init__(self, elements):
+        self.elements = elements
+
+    def visit(self, visitor):
+        visitor.visit_bitmask(self)
+
+
+class Array(Node):
+    
+    def __init__(self, elements):
+        self.elements = elements
+
+    def visit(self, visitor):
+        visitor.visit_array(self)
+
+
+class Struct(Node):
+    
+    def __init__(self, name, members):
+        self.name = name
+        self.members = members        
+
+    def visit(self, visitor):
+        visitor.visit_struct(self)
+
+        
+class Pointer(Node):
+    
+    def __init__(self, address, value):
+        self.address = address
+        self.address = value
+
+    def visit(self, visitor):
+        visitor.visit_pointer(self)
+
+
+class Call(Node):
+    
+    def __init__(self, no, name, args, ret, attrs = None):
+        self.no = no
+        self.name = name
+        self.args = args
+        self.ret = ret
+        if attrs is None:
+            self.attrs = {}
+        else:
+            self.attrs = attrs
+        
+    def visit(self, visitor):
+        visitor.visit_call(self)
+
+
+class Trace:
+    
+    def __init__(self, calls):
+        self.calls = calls
+        
+    def visit(self, visitor):
+        visitor.visit_trace(self)
+    
+    
+class Visitor:
+    
+    def visit_literal(self, node):
+        raise NotImplementedError
+    
+    def visit_named_constant(self, node):
+        raise NotImplementedError
+    
+    def visit_bitmask(self, node):
+        raise NotImplementedError
+    
+    def visit_array(self, node):
+        raise NotImplementedError
+    
+    def visit_struct(self, node):
+        raise NotImplementedError
+    
+    def visit_pointer(self, node):
+        raise NotImplementedError
+    
+    def visit_call(self, node):
+        raise NotImplementedError
+    
+    def visit_trace(self, node):
+        raise NotImplementedError
+
+
+class PrettyPrinter:
+
+    def __init__(self, formatter):
+        self.formatter = formatter
+    
+    def visit_literal(self, node):
+        if isinstance(node.value, basestring):
+            if len(node.value) >= 4096 or node.value.strip(string.printable):
+                self.formatter.text('...')
+                return
+
+            self.formatter.literal('"' + node.value + '"')
+            return
+
+        self.formatter.literal(str(node.value))
+    
+    def visit_named_constant(self, node):
+        self.formatter.literal(node.name)
+    
+    def visit_bitmask(self, node):
+        if len(node.elements) == 0:
+            self.formatter.literal('0')
+            return
+        if len(node.elements) > 1:
+            self.formatter.text('(')
+        sep = ''
+        for value in node.elements:
+            self.formatter.text(sep)
+            value.visit(self) 
+            sep = ' | '
+        if len(node.elements) > 1:
+            self.formatter.text(')')
+    
+    def visit_array(self, node):
+        self.formatter.text('{')
+        sep = ''
+        for value in node.elements:
+            self.formatter.text(sep)
+            value.visit(self) 
+            sep = ', '
+        self.formatter.text('}')
+    
+    def visit_struct(self, node):
+        self.formatter.text('{')
+        sep = ''
+        for name, value in node.members:
+            self.formatter.text(sep)
+            self.formatter.variable(name)
+            self.formatter.text(' = ')
+            value.visit(self) 
+            sep = ', '
+        self.formatter.text('}')
+    
+    def visit_pointer(self, node):
+        self.formatter.address(node.address)
+    
+    def visit_call(self, node):
+        self.formatter.text('%s ' % node.no)
+        self.formatter.function(node.name)
+        self.formatter.text('(')
+        sep = ''
+        for name, value in node.args:
+            self.formatter.text(sep)
+            self.formatter.variable(name)
+            self.formatter.text(' = ')
+            value.visit(self) 
+            sep = ', '
+        self.formatter.text(')')
+        if node.ret is not None:
+            self.formatter.text(' = ')
+            node.ret.visit(self)
+    
+    def visit_trace(self, node):
+        for call in node.calls:
+            call.visit(self)
+            self.formatter.newline()
+
index 7d3b4cd988aadd41a8d7f8dc16c212634c27da22..43a9e859eb9d30069edbb2924cfaae3915fe0173 100644 (file)
@@ -439,7 +439,7 @@ opengl32.functions += [
 ]
 
 HGLRC = Alias("HGLRC", HANDLE)
-PROC = Intrinsic("PROC", "%p")
+PROC = Alias("PROC", Opaque)
 
 PFD = Flags(DWORD, [
     "PFD_DOUBLEBUFFER",
index 9aebf1b4ff31336f2f08e9695ae4f9528f214c69..5aca7590272669faa9447624a6ff07807f0f9aa6 100644 (file)
 
 from base import *
 
-SHORT = Intrinsic("SHORT", "%i")
-USHORT = Intrinsic("USHORT", "%u")
-INT = Intrinsic("INT", "%i")
-UINT = Intrinsic("UINT", "%u")
-LONG = Intrinsic("LONG", "%li")
-ULONG = Intrinsic("ULONG", "%lu")
-FLOAT = Intrinsic("FLOAT", "%f")
+SHORT = Alias("SHORT", Short)
+USHORT = Alias("USHORT", UShort)
+INT = Alias("INT", Int)
+UINT = Alias("UINT", UInt)
+LONG = Alias("LONG", Long)
+ULONG = Alias("ULONG", ULong)
+LONGLONG = Alias("LONGLONG", LongLong)
+FLOAT = Alias("FLOAT", Float)
 
-INT32 = Intrinsic("INT32", "%i")
-UINT32 = Intrinsic("UINT32", "%i")
+INT32 = Literal("INT32", "UInt")
+UINT32 = Literal("UINT32", "UInt")
 
-BYTE = Intrinsic("BYTE", "0x%02lx")
-WORD = Intrinsic("WORD", "0x%04lx")
-DWORD = Intrinsic("DWORD", "0x%08lx")
+BYTE = Literal("BYTE", "UInt", base=16)
+WORD = Literal("WORD", "UInt", base=16)
+DWORD = Literal("DWORD", "UInt", base=16)
 
-BOOL = Intrinsic("BOOL", "%i")
+BOOL = Alias("BOOL", Bool)
 
 LPLONG = Pointer(LONG)
 LPWORD = Pointer(WORD)
@@ -55,17 +56,20 @@ LPCSTR = Const(String)
 LPWSTR = WString
 LPCWSTR = Const(WString)
 
-LARGE_INTEGER = Intrinsic("LARGE_INTEGER", "0x%llx")
+LARGE_INTEGER = Struct("LARGE_INTEGER", [
+    (LONGLONG, 'QuadPart'),
+])
+
 SIZE_T = Alias("SIZE_T", SizeT)
 
 HRESULT = Alias("HRESULT", Int)
 
-PVOID = Intrinsic("PVOID", "%p")
+PVOID = Alias("PVOID", Opaque)
 LPVOID = PVOID
-HANDLE = Intrinsic("HANDLE", "%p")
-HWND = Intrinsic("HWND", "%p")
-HDC = Intrinsic("HDC", "%p")
-HMONITOR = Intrinsic("HMONITOR", "%p")
+HANDLE = Alias("HANDLE", Opaque)
+HWND = Alias("HWND", Opaque)
+HDC = Alias("HDC", Opaque)
+HMONITOR = Alias("HMONITOR", Opaque)
 
 GUID = Struct("GUID", [
     (DWORD, "Data1"),
index 80e74ee65df9722490137604610003560521af77..e0c5efde50949eacd1dc524821e65b16dba0448f 100755 (executable)
@@ -30,6 +30,8 @@ import optparse
 import xml.parsers.expat
 import gzip
 
+from model import *
+
 
 ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4)
 
@@ -194,68 +196,11 @@ class GzipFile(gzip.GzipFile):
             pass
 
 
-class Formatter:
-    
-    def function(self, name):
-        return name
-        
-    def variable(self, name):
-        return name
-
-    def literal(self, value):
-        return str(value)
-    
-    def address(self, addr):
-        return addr
-
-
-class AnsiFormatter(Formatter):
-    '''Formatter for plain-text files which outputs ANSI escape codes. See
-    http://en.wikipedia.org/wiki/ANSI_escape_code for more information
-    concerning ANSI escape codes.
-    '''
-
-    _csi = '\33['
-
-    _normal = '0m'
-    _bold = '1m'
-    _italic = '3m'
-    _red = '31m'
-    _green = '32m'
-    _blue = '34m'
-
-    def _escape(self, code, text):
-        return self._csi + code + text + self._csi + self._normal
-
-    def function(self, name):
-        text = Formatter.function(self, name)
-        return self._escape(self._bold, text)
-        
-    def variable(self, name):
-        text = Formatter.variable(self, name)
-        return self._escape(self._italic, text)
-
-    def literal(self, value):
-        text = Formatter.literal(self, value)
-        return self._escape(self._blue, text)
-    
-    def address(self, value):
-        text = Formatter.address(self, value)
-        return self._escape(self._green, text)
-
-
-def DefaultFormatter():
-    if sys.platform in ('linux2', 'cygwin'):
-        return AnsiFormatter()
-    else:
-        return Formatter()
-
-
 class TraceParser(XmlParser):
 
-    def __init__(self, stream, formatter):
+    def __init__(self, stream):
         XmlParser.__init__(self, stream)
-        self.formatter = formatter
+        self.call_no = 0
 
     def parse(self):
         self.element_start('trace')
@@ -269,15 +214,16 @@ class TraceParser(XmlParser):
         name = attrs['name']
         args = []
         ret = None
-        duration = None
+        properties = {}
         while self.token.type == ELEMENT_START:
             if self.token.name_or_data == 'arg':
                 arg = self.parse_arg()
                 args.append(arg)
             elif self.token.name_or_data == 'ret':
                 ret = self.parse_ret()
-            elif self.token.name_or_data == 'duration':
-                duration = self.parse_duration()
+            elif self.token.name_or_data in ('duration', 'starttsc', 'endtsc'):
+                property = self.token.name_or_data
+                properties[property] = self.parse_hex(self.token.name_or_data)
             elif self.token.name_or_data == 'call':
                 # ignore nested function calls
                 self.parse_call()
@@ -285,7 +231,11 @@ class TraceParser(XmlParser):
                 raise TokenMismatch("<arg ...> or <ret ...>", self.token)
         self.element_end('call')
         
-        self.handle_call(name, args, ret, duration)
+        self.call_no += 1
+
+        call = Call(self.call_no, name, args, ret, properties)
+
+        self.handle_call(call)
 
     def parse_arg(self):
         attrs = self.element_start('arg')
@@ -302,18 +252,28 @@ class TraceParser(XmlParser):
 
         return value
 
-    def parse_duration(self):
-        attrs = self.element_start('duration')
-        value = int(self.character_data())
-        self.element_end('duration')
+    def parse_hex(self, token_name):
+        attrs = self.element_start(token_name)
+        value = int(self.character_data(), 16)
+        self.element_end(token_name)
         return value
 
     def parse_value(self):
-        if self.token.type == CHARACTER_DATA:
-            return self.formatter.literal(self.character_data())
         if self.token.type == ELEMENT_START:
-            if self.token.name_or_data == 'elem':
-                return self.parse_elems()
+            if self.token.name_or_data == 'int':
+                return self.parse_int()
+            if self.token.name_or_data == 'uint':
+                return self.parse_uint()
+            if self.token.name_or_data == 'float':
+                return self.parse_float()
+            if self.token.name_or_data == 'string':
+                return self.parse_string()
+            if self.token.name_or_data == 'wstring':
+                return self.parse_wstring()
+            if self.token.name_or_data == 'const':
+                return self.parse_const()
+            if self.token.name_or_data == 'bitmask':
+                return self.parse_bitmask()
             if self.token.name_or_data == 'ref':
                 return self.parse_ref()
         raise TokenMismatch("<elem ...>, <ref ...>, or text", self.token)
@@ -322,7 +282,7 @@ class TraceParser(XmlParser):
         elems = [self.parse_elem()]
         while self.token.type != ELEMENT_END:
             elems.append(self.parse_elem())
-        return '{' + ', '.join(elems) + '}'
+        return Struct("", elems)
 
     def parse_elem(self):
         attrs = self.element_start('elem')
@@ -332,39 +292,79 @@ class TraceParser(XmlParser):
         try:
             name = attrs['name']
         except KeyError:
-            pass
-        else:
-            value = name + ' = ' + value
+            name = ""
 
-        return value
+        return name, value
 
     def parse_ref(self):
         attrs = self.element_start('ref')
         if self.token.type != ELEMENT_END:
-            value = '&' + self.parse_value()
+            value = self.parse_value()
         else:
-            value = self.formatter.address(attrs['addr'])
+            value = None
         self.element_end('ref')
 
-        return value
+        return Pointer(attrs['addr'], value)
 
-    def handle_call(self, name, args, ret, duration):
-        s = ''
+    def parse_bitmask(self):
+        self.element_start('bitmask')
+        elems = []
+        while self.token.type != ELEMENT_END:
+            elems.append(self.parse_value())
+        self.element_end('bitmask')
+        return Bitmask(elems)
+
+    def parse_int(self):
+        self.element_start('int')
+        value = self.character_data()
+        self.element_end('int')
+        return Literal(int(value))
+
+    def parse_uint(self):
+        self.element_start('uint')
+        value = self.character_data()
+        self.element_end('uint')
+        return Literal(int(value))
+
+    def parse_float(self):
+        self.element_start('float')
+        value = self.character_data()
+        self.element_end('float')
+        return Literal(float(value))
+
+    def parse_string(self):
+        self.element_start('string')
+        value = self.character_data()
+        self.element_end('string')
+        return Literal(value)
+
+    def parse_wstring(self):
+        self.element_start('wstring')
+        value = self.character_data()
+        self.element_end('wstring')
+        return Literal(value)
+
+    def parse_const(self):
+        self.element_start('const')
+        value = self.character_data()
+        self.element_end('const')
+        return NamedConstant(value)
+
+    def handle_call(self, call):
+        pass
+
+
+class DumpTraceParser(TraceParser):
 
-        #if duration is not None:
-        #    s += '%8u ' % (duration)
+    def __init__(self, stream, formatter):
+        XmlParser.__init__(self, stream)
+        self.formatter = formatter
+        self.pretty_printer = PrettyPrinter(self.formatter)
+        self.call_no = 0
 
-        s += self.formatter.function(name)
-        s += '(' + ', '.join([self.formatter.variable(name) + ' = ' + value for name, value in args]) + ')'
-        if ret is not None:
-            s += ' = ' + ret
-        s += '\n'
-        
-        try:
-            sys.stdout.write(s)
-        except IOError: 
-            # catch broken pipe
-            sys.exit(0)
+    def handle_call(self, call):
+        call.visit(self.pretty_printer)
+        self.formatter.newline()
 
 
 class StatsTraceParser(TraceParser):
@@ -393,46 +393,59 @@ class StatsTraceParser(TraceParser):
         self.stats[name] = nr_calls, total_duration
 
 
-def main():
-    parser = optparse.OptionParser(
-        usage="\n\t%prog [options] [file] ...")
-    parser.add_option(
-        '-s', '--stats',
-        action="store_true",
-        dest="stats", default=False,
-        help="generate statistics instead")
-    parser.add_option(
-        '--color', '--colour',
-        type="choice", choices=('never', 'always', 'auto'), metavar='WHEN',
-        dest="color", default="always",
-        help="coloring: never, always, or auto [default: %default]")
-    (options, args) = parser.parse_args(sys.argv[1:])
-
-    if options.color == 'always' or options.color == 'auto' and sys.stdout.isatty():
-        formatter = DefaultFormatter()
-    else:
-        formatter = Formatter()
+class Main:
+
+    def __init__(self):
+        pass
+
+    def main(self):
+        optparser = self.get_optparser()
+        (options, args) = optparser.parse_args(sys.argv[1:])
     
-    if options.stats:
-        factory = StatsTraceParser
-    else:
-        factory = TraceParser
-
-    if args:
-        for arg in args:
-            if arg.endswith('.gz'):
-                stream = GzipFile(arg, 'rb')
-            elif arg.endswith('.bz2'):
-                from bz2 import BZ2File
-                stream = BZ2File(arg, 'rt')
-            else:
-                stream = open(arg, 'rt')
-            parser = factory(stream, formatter)
-            parser.parse()
-    else:
-            parser = factory(sys.stdin, formatter)
-            parser.parse()
+        if args:
+            for arg in args:
+                if arg.endswith('.gz'):
+                    from gzip import GzipFile
+                    stream = GzipFile(arg, 'rb')
+                elif arg.endswith('.bz2'):
+                    from bz2 import BZ2File
+                    stream = BZ2File(arg, 'rU')
+                else:
+                    stream = open(arg, 'rt')
+                self.process_arg(stream, options)
+        else:
+            self.process_arg(stream, options)
+
+    def get_optparser(self):
+        optparser = optparse.OptionParser(
+            usage="\n\t%prog [options] [traces] ...")
+        optparser.add_option(
+            '-s', '--stats',
+            action="store_true",
+            dest="stats", default=False,
+            help="generate statistics instead")
+        optparser.add_option(
+            '--color', '--colour',
+            type="choice", choices=('never', 'always', 'auto'), metavar='WHEN',
+            dest="color", default="always",
+            help="coloring: never, always, or auto [default: %default]")
+        return optparser
+
+    def process_arg(self, stream, options):
+        if options.color == 'always' or options.color == 'auto' and sys.stdout.isatty():
+            formatter = format.DefaultFormatter(sys.stdout)
+        else:
+            formatter = format.Formatter(sys.stdout)
+        
+        if options.stats:
+            factory = StatsTraceParser
+        else:
+            factory = DumpTraceParser
+
+        parser = DumpTraceParser(stream, formatter)
+        parser.parse()
 
 
 if __name__ == '__main__':
-    main()
+    Main().main()
+