All of lore.kernel.org
 help / color / mirror / Atom feed
From: Aldrin Martoq <amartoq@dcc.uchile.cl>
To: alsa-devel <alsa-devel@alsa-project.org>
Subject: [PATCH] 1/2 alsa-python: API coverage documentation tool
Date: Fri, 07 Mar 2008 22:47:25 -0300	[thread overview]
Message-ID: <1204940845.6474.14.camel@localhost> (raw)

[-- Attachment #1: Type: text/plain, Size: 3447 bytes --]

HG Log:
-------
Added python tool of alsa-lib C API coverage for alsa-python binding.


Description:
------------

The following patch is a python tool that shows how much of the
asoundlib API is being covered by the alsa-python binding. It works by
parsing the C source code and comparing with the official Doxygen
documentation from alsa website.

It will help the following users:
- alsa-python developers: know how is mapped the original C API, so
which python function/variable may be used.
- python binding developers: know how much of the C API is covered. It
could help for mistakes (free() instead of using
snd_ctl_card_info_free), know what is missing, and statistic interest ;)



Sample output:
--------------

Functions
---------
1   const char* snd_asoundlib_version ( void )
        Returns the ALSA sound library version in ASCII format.
          => Used in    :     alsacard.c: asoundlib_version

Defines
-------
N/A #define SND_CONTROL_DLSYM_VERSION _dlsym_control_001
        dlsym version for interface entry callback
          **** NOT AVAILABLE/USED SND_CONTROL_DLSYM_VERSION ****
2   #define SND_CTL_ASYNC
        Async notification (flag for open mode)
          => As constant:  alsacontrol.c: open_mode["ASYNC"]
          => As constant: alsahcontrol.c: open_mode["ASYNC"]
1   #define snd_ctl_card_info_alloca ( ptr )
        allocate an invalid snd_ctl_card_info_t using standard alloca
          => Used in    :  alsacontrol.c: pyalsacontrol_cardinfo


Stats:
------

After every section, the program shows some stats about usage. This is
the current usage of each doxygen module:

Global defines and functions  
 16 missing ( 94%)   0 excluded (  0%) of  17 total (  6% covered).
Error handling                
  9 missing ( 90%)   0 excluded (  0%) of  10 total ( 10% covered).
Control Interface             
137 missing ( 53%)   0 excluded (  0%) of 257 total ( 47% covered).
High level Control Interface  
 21 missing ( 46%)   0 excluded (  0%) of  46 total ( 54% covered).
Setup Control Interface       
  4 missing (100%)   0 excluded (  0%) of   4 total (  0% covered).
MIDI Sequencer                
 25 missing ( 61%)   7 excluded ( 17%) of  41 total ( 39% covered).
Sequencer Client Interface    
 15 missing ( 35%)  14 excluded ( 33%) of  43 total ( 65% covered).
Sequencer Port Interface      
 48 missing ( 74%)   6 excluded (  9%) of  65 total ( 26% covered).
Sequencer Port Subscription   
  3 missing (  7%)  15 excluded ( 33%) of  46 total ( 93% covered).
Sequencer Queue Interface     
 58 missing ( 84%)   0 excluded (  0%) of  69 total ( 16% covered).
Sequencer Event API           
 42 missing ( 93%)   0 excluded (  0%) of  45 total (  7% covered).
Sequencer Miscellaneous       
  0 missing ( N/A)   0 excluded ( N/A) of   0 total ( N/A covered).
Sequencer Event Type Checks   
  7 missing ( 23%)   0 excluded (  0%) of  30 total ( 77% covered).
Sequencer Event Definitions   
 35 missing ( 40%)   0 excluded (  0%) of  87 total ( 60% covered).
Sequencer Middle Level Interfa
 38 missing ( 78%)   0 excluded (  0%) of  49 total ( 22% covered).
Sequencer event <-> MIDI byte 
 11 missing (100%)   0 excluded (  0%) of  11 total (  0% covered).
Mixer Interface               
 44 missing ( 75%)   0 excluded (  0%) of  59 total ( 25% covered).
Simple Mixer Interface        
 14 missing ( 18%)   0 excluded (  0%) of  78 total ( 82% covered).


Cheers!


-- 
Aldrin Martoq <amartoq@dcc.uchile.cl>

[-- Attachment #2: doc-alsa-python-coverage --]
[-- Type: text/x-patch, Size: 25733 bytes --]

diff --git a/doc/.hgignore b/doc/.hgignore
new file mode 100644
--- /dev/null
+++ b/doc/.hgignore
@@ -0,0 +1,3 @@
+syntax: glob
+
+cache/*
diff --git a/doc/APICoverage.py b/doc/APICoverage.py
new file mode 100644
--- /dev/null
+++ b/doc/APICoverage.py
@@ -0,0 +1,385 @@
+#! /usr/bin/python
+
+# APICoverage.py -- helper for API coverage tools
+# Copyright(C) 2008 by Aldrin Martoq <amartoq@dcc.uchile.cl>
+#  Licensed under GPL v2 (see below).
+#
+# Description:
+#    This file provides the base for creating an API coverage tool. It may
+#    be used in other projects, for an example see the coverage.py tool.
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2 as
+#  published by the Free Software Foundation.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+import os, pickle, urllib, sys
+from pyparsing import *
+from htmlentitydefs import entitydefs
+from htmllib import HTMLParser
+from formatter import AbstractFormatter, DumbWriter
+
+# cache dir (preparsed source and HTML asoundlib API)
+cache = 'cache'
+# directory of source code
+source_dir = '.'
+# base url
+api_url = ''
+# summary (section) counter
+summary_total = summary_miss = summary_exc = 0
+# subsection (defines, typedefs, etc) counter
+count_total = count_miss = count_exc = 0
+
+if not os.path.exists(cache):
+    print "Creating cache dir: %s" % cache
+    os.makedirs(cache)
+
+def read_source(name):
+    """ Reads the specified source file """
+    filename = os.path.join(source_dir, name)
+    return (name, "".join(open(filename).readlines()), filename)
+
+def list_to_str(alist):
+    tmp = []
+    for i in alist:
+        if type(i) is ParseResults:
+            tmp.append(list_to_str(i))
+        else:
+            tmp.append(str(i))
+    return tmp
+            
+
+def get_cached_parse(index_parser_list, name):
+    """
+    Generate the scan lists from the parsers, store it in a file in the
+    cachedir and return it; if the file already exists it just return it
+    without processing.
+    """
+    name = os.path.join(cache, name)
+
+    if os.path.exists(name):
+        modified = False
+        for source, parser in index_parser_list:
+            if os.stat(source[2]).st_mtime > os.stat(name).st_mtime:
+                modified = True
+        if not modified:
+            return pickle.load(open(name))
+
+    print "generating cache, file: %s" % name,
+    dict = {}
+    for source, parser in index_parser_list:
+        print source[0],
+        sys.stdout.flush()
+        list = []
+        for tokenlist, start, end in parser.scanString(source[1]):
+            tlist = list_to_str(tokenlist)
+            list.append((tlist, int(start), int(end)))
+        dict[source[0]] = list
+    pickle.dump(dict, open(name, "wb"))
+    print
+    return dict
+
+# API html parsing/caching
+
+def get_cached_api(url, name):
+    """
+    Download the HTML API from the specified url and stores it in a
+    file in the cachedir; if the file already exists it just returns it
+    contents.
+    """
+    name = os.path.join(cache, name)
+    if os.path.exists(name):
+        data = "".join(open(name).readlines())
+    else:
+        print "downloading %s" % url
+        data = urllib.urlopen(url).read()
+        open(name, "w").write(data)
+    return data
+
+
+
+class AsoundlibAPIHTMLParser(HTMLParser):
+    """
+    Customized HTMLParser, it adds some markers for easy parsing the
+    HTML asoundlib API from the alsa website.
+    """
+    
+    HTMLParser.entitydefs['nbsp'] = ' '
+    
+    def __init__(self, name, data):
+        f = AbstractFormatter(DumbWriter(open(name, 'w'), 100))
+        HTMLParser.__init__(self, f)
+        self.feed(data)
+        self.close()
+
+    def start_h1(self, attrs):
+        HTMLParser.start_h1(self, attrs)
+        self.handle_data("--- titlestart")
+        self.do_br(None)
+
+    def start_table(self, attrs):
+        if len(attrs) == 1 and attrs[0] == ("class", "memname"):
+            self.handle_data("--- itemstart")
+            self.do_br(None)
+
+    def start_tr(self, attrs):
+        self.do_br(None)
+
+    def anchor_end(self):
+        pass
+
+def parse_asoundlib_api(lines):
+    """
+    Parses an html file (given as a set of lines including '\n').
+    Returns a list of: title, defines, typedefs, enums, functions.
+    """
+    state = 0
+    defines = []
+    typedefs = []
+    enums = []
+    functions = []
+    current = None
+    title = None
+    name = ""
+    comment = ""
+    enumsublist = []
+    for line in lines:
+        line = line[:-1]
+        if False:
+            if id(current) == id(defines):
+                print "defines   ",
+            elif id(current) == id(typedefs):
+                print "typedefs  ",
+            elif id(current) == id(enums):
+                print "enums     ",
+            elif id(current) == id(functions):
+                print "functions ",
+            else:
+                print "          ",
+            print "%s %d %s" % (id(current), state, line)
+
+        if line.startswith('Define Documentation'):
+            current = defines
+            state = 0
+        elif line.startswith('Typedef Documentation'):
+            current = typedefs
+            state = 0
+        elif line.startswith('Enumeration Type Documentation'):
+            current = enums
+            state = 0
+        elif line.startswith('Function Documentation'):
+            current = functions
+            state = 0
+        elif line.startswith('--- itemstart'):
+            state = 1
+        elif line.startswith('--- titlestart'):
+            state = 5
+        elif state == 5:
+            title = line
+            state = 0
+        elif current == None:
+            continue
+        elif state == 1:
+            if line == "":
+                state = 2
+            else:
+                name += line
+        elif state == 2:
+            if id(current) == id(enums):
+                state = 3
+            else:
+                comment = line
+                current.append((name, comment))
+                name = ""
+                comment = ""
+                state = 0
+        elif state == 3 and line.startswith('Enumerator:'):
+            state = 4
+            enumsublist = []
+        elif state == 4:
+            if line == "":
+                current.append((name, comment, enumsublist))
+                name = ""
+                comment = ""
+                state = 0
+            else:
+                enum, subcomment = line.split(' ', 1)
+                enumsublist.append((enum, subcomment))
+
+    return (title, defines, typedefs, enums, functions)
+        
+
+def print_name(d0, d1, name, look_constant, look_usage, exclude_list):
+    """ 
+    Prints a defined entry (typedef, function, etc) and its usage to stdout.
+    It also updates counters ({summary,count}_{total,miss,exc}).
+
+    Parameters:
+      d0 -- entry prototype
+      d1 -- entry documentation (one liner)
+      name -- entry name (define, function name, etc)
+      look_constant -- lookup name for constant (a defined python function)
+      look_usage -- lookup name for usage (a defined python function)
+    """
+    global summary_total, summary_miss, summary_exc
+    global count_total, count_miss, count_exc
+    summary_total += 1
+    count_total += 1
+    lc = look_constant(name)
+    uc = look_usage(name)
+    usecount = len(lc) + len(uc)
+    exccount = 0
+    for token, comment in exclude_list:
+        if token == name:
+            exccount += 1
+    if usecount == 0:
+        if exccount > 0:
+            used = "EXC"
+            summary_exc += 1
+            count_exc += 1
+        else:
+            used = "N/A"
+            summary_miss += 1
+            count_miss += 1
+    else:
+        used = "%s" % usecount
+        
+    print "%-4s%s" % (used, d0)
+    print "%8s%s" % ("", d1)
+
+    if usecount > 0:
+        excstr = "Comment"
+    else:
+        excstr = "Excluded"
+    for token, comment in exclude_list:
+        if token == name:
+            print "%10s==> %11s: %s" % ("", excstr, comment)
+    for s in lc:
+        print "%10s=> As constant: %s" % ("", s)
+    for s in uc:
+        print "%10s=> Used in    : %s" % ("", s)
+    if used == "N/A":
+        print " "*10 + "**** NOT AVAILABLE/USED %s ****" % name
+
+
+def _print_stat(title, section, missing, excluded, total):
+    if total == 0:
+        fmissing = "N/A"
+        fexcluded = "N/A"
+        fcovered = "N/A"
+    else:
+        fmissing = (100*(float(missing)/float(total)))
+        fexcluded = (100*(float(excluded)/float(total)))
+        fcovered = 100 - fmissing
+        fmissing = "%3.0f%%" % fmissing
+        fexcluded = "%3.0f%%" % fexcluded
+        fcovered = "%3.0f%%" % fcovered
+    print "STAT %-30.30s %-12.12s: " % (title, section) + \
+        "%3d missing (%4s) %3d excluded (%4s) of %3d total (%4s covered)." % \
+        (missing, fmissing, excluded, fexcluded, total, fcovered)
+
+
+def print_stat(title, section):
+    """
+    Print STATS line for the given title and section. It will
+    reset the section counters (count_{total,miss}).
+    """
+    global count_total, count_miss, count_exc
+    _print_stat(title, section, count_miss, count_exc, count_total)
+    count_total = count_miss = count_exc = 0
+
+def print_summary_stat(title):
+    """
+    Print STATS line for the last given title and section. It will
+    reset the title summary counters (summary_{total,miss}).
+    """
+    global summary_total, summary_miss, summary_exc
+    _print_stat(title, "SUMMARY", summary_miss, summary_exc, summary_total)
+    summary_total = summary_miss = summary_exc = 0
+
+
+def parse_excludes(excludes):
+    list = []
+    for line in excludes.splitlines():
+        s = line.split(' ', 1)
+        if len(s) > 1:
+            token = s[0]
+            comment = s[1]
+            list.append((token, comment))
+    return list
+
+
+
+def print_api_coverage(urls, look_constant, look_usage, excludes):
+    
+    el = parse_excludes(excludes)
+
+    for url in urls:
+        data = get_cached_api(api_url + url, url)
+        tmp = os.path.join(cache, 'tmp')
+        AsoundlibAPIHTMLParser(tmp, data)
+        (title, defines, typedefs, enums, functions) = \
+            parse_asoundlib_api(open(tmp).readlines())
+        print title
+        print "="*len(title)
+        print "\n"*2
+        #print "%s\n%s\n%s\n%s\n%s\n\n" % \
+        #    (title, defines, typedefs, enums, functions)
+        summary_total = 0
+        summary_miss = 0
+        if len(defines) > 0:
+            print "Defines"
+            print "-------"
+            for d in defines:
+                name = d[0].split(' ')[1]
+                print_name(d[0], d[1], name, look_constant, look_usage, el)
+            print_stat(title, "Defines")
+            print "\n"*2
+        if len(typedefs) > 0:
+            print "Typedefs"
+            print "--------"
+            for d in typedefs:
+                names = d[0].split(' ')
+                name = names[-1]
+                if ')' in name:
+                    names = d[0].split('(')
+                    name = names[-2].split()[-1]
+                print_name(d[0], d[1], name, look_constant, look_usage, el)
+            print_stat(title, "Typedefs")
+            print "\n"*2
+        if len(enums) > 0:
+            print "Enumerations"
+            print "------------"
+            for e in enums:
+                print "%s" % e[0]
+                for d in e[2]:
+                    name = d[0]
+                    print_name(d[0], d[1], name, look_constant, look_usage, el)
+            print_stat(title, "Enumerations")
+            print "\n"*2
+        if len(functions) > 0:
+            print "Functions"
+            print "---------"
+            for d in functions:
+                name = None
+                for n in d[0].split(' '):
+                    if n.startswith('snd_'):
+                        name = n
+                    elif n.startswith('('):
+                        break
+                if name != None:
+                    print_name(d[0], d[1], name, look_constant, look_usage, el)
+            print_stat(title, "Functions")
+            print "\n"*2
+        print_summary_stat(title)
+        print "\n"*4
+
diff --git a/doc/alsa-python-coverage.py b/doc/alsa-python-coverage.py
new file mode 100755
--- /dev/null
+++ b/doc/alsa-python-coverage.py
@@ -0,0 +1,364 @@
+#! /usr/bin/python
+
+# coverage.py -- python coverage of asoundlib API
+# Copyright(C) 2008 by Aldrin Martoq <amartoq@dcc.uchile.cl>
+#  Licensed under GPL v2 (see below).
+#
+# Description:
+#    This tool aims to help in completing the python binding of the asoundlib
+#    API. Actually, it's being coded for the current pyalsa, but it can be
+#    easily modified to support other styles of codes (mainly by changing the
+#    pyparsing objects used to scan the source code).
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2 as
+#  published by the Free Software Foundation.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+from APICoverage import *
+import APICoverage
+from pprint import pprint
+import time
+
+__author__ = "Aldrin Martoq <amartoq@dcc.uchile.cl>"
+__version__ = "1.0"
+__license__ = "GNU General Public License version 2"
+__copyright__ = "Copyright(C) 2008 by Aldrin Martoq <amartoq@dcc.uchile.cl>"
+
+
+# setup and do the work
+APICoverage.source_dir = '../pyalsa'
+APICoverage.api_url = 'http://www.alsa-project.org/alsa-doc/alsa-lib/'
+
+time_start = time.time()
+
+# common C parser
+ident = Word(alphas + "_", alphanums + "_")
+type_and_var = \
+    Optional(oneOf("const unsigned struct")) \
+    + ident + Optional(Word("*")) + ident
+args = OneOrMore(type_and_var) + ZeroOrMore("," + type_and_var)
+function_declaration = type_and_var + "(" + Group(args) + ")"
+function_define = \
+    "#define" + ident \
+    + "(" + OneOrMore(ident) + ZeroOrMore("," + ident) + Optional("...") + ")"
+function_define_block = \
+    "#define" + ident + "{"
+#    + Group(("(" + args + Optional("...") + ")") | "{")
+
+# common asoundlib parser
+snd_ = Regex("snd_[\w_]+")
+SND_ = Regex("SND_[\w_]+")
+
+# pyalsa/alsaseq.c parser
+alsaseq_SEQ = Regex("SEQ_[\w_]+")
+alsaseq_Constant = \
+    "TCONSTADD(module," + alsaseq_SEQ + "," + quotedString + "," + alsaseq_SEQ
+alsaseq_typedef = \
+    Literal("typedef") \
+    + "struct" \
+    + "{" \
+    + "PyObject_HEAD" \
+    + Optional(";") \
+    + OneOrMore((type_and_var + ";") | cppStyleComment) \
+    + "}" \
+    + ident.setName("struct_name")
+alsaseq_function = \
+    "static" \
+    + function_declaration.setName("static_function")
+alsaseq_index = function_define | function_define_block \
+    | alsaseq_typedef | alsaseq_function
+
+# pyalsa/{alsacard, alsacontrol, alsahcontrol, alsamixer}.c parser
+addspace = Regex("add_space[0-9]")
+addspace_def = \
+    Suppress(addspace + "(") \
+    + quotedString + Suppress(",") + ident + Suppress(");")
+alsaall_Constant = \
+    Suppress(Literal("#define") \
+    + addspace \
+    + "(pname, name) { \\" \
+    + "o = PyInt_FromLong(") \
+    + SND_ \
+    + Suppress("##name); \\") \
+    + Suppress("PyDict_SetItemString(d1, pname, o); \\") \
+    + Suppress("Py_DECREF(o); }") \
+    + OneOrMore(Group(addspace_def)) \
+    + Suppress("PyDict_SetItemString(d,") \
+    + quotedString
+
+
+
+alsaall_typedef = \
+    Literal("struct") \
+    + "{" \
+    + "PyObject_HEAD" \
+    + Optional(";") \
+    + OneOrMore((type_and_var + ";") | cppStyleComment) \
+    + "}"
+alsaall_function = \
+    "static" \
+    + function_declaration.setName("static_function")
+alsaall_index = function_define | alsaall_typedef | alsaall_function
+
+# read all files
+pyalsaseq = read_source('alsaseq.c')
+pyalsacard = read_source('alsacard.c')
+pyalsacontrol = read_source('alsacontrol.c')
+pyalsahcontrol = read_source('alsahcontrol.c')
+pyalsamixer = read_source('alsamixer.c')
+
+# parse all files with parser
+index = get_cached_parse([
+        (pyalsaseq, alsaseq_index),
+        (pyalsacard, alsaall_index),
+        (pyalsacontrol, alsaall_index),
+        (pyalsahcontrol, alsaall_index),
+        (pyalsamixer, alsaall_index)
+        ], "index")
+index_snd_ = get_cached_parse([
+        (pyalsaseq, snd_),
+        (pyalsacard, snd_),
+        (pyalsacontrol, snd_),
+        (pyalsahcontrol, snd_),
+        (pyalsamixer, snd_)
+        ], "index_snd_")
+index_SND_ = get_cached_parse([
+        (pyalsaseq, SND_),
+        (pyalsacard, SND_),
+        (pyalsacontrol, SND_),
+        (pyalsahcontrol, SND_),
+        (pyalsamixer, SND_)
+        ], "index_SND_")
+index_Constant_alsaseq = get_cached_parse([
+        (pyalsaseq, alsaseq_Constant)
+        ], "index_Constant_alsaseq")
+index_Constant_alsaall = get_cached_parse([
+        (pyalsacard, alsaall_Constant),
+        (pyalsacontrol, alsaall_Constant),
+        (pyalsahcontrol, alsaall_Constant),
+        (pyalsamixer, alsaall_Constant)
+        ], "index_Constant_alsaall")
+
+# urls of doxygen documentation
+urls = [
+    # globals
+    "group___global.html",
+    # error handling
+    "group___error.html",
+    # control
+    "group___control.html",
+    "group___h_control.html",
+    "group___s_control.html",
+    # sequencer
+    "group___sequencer.html",
+    "group___seq_client.html",
+    "group___seq_port.html",
+    "group___seq_subscribe.html",
+    "group___seq_queue.html",
+    "group___seq_event.html",
+    "group___seq_misc.html",
+    "group___seq_ev_type.html",
+    "group___seq_events.html",
+    "group___seq_middle.html",
+    "group___m_i_d_i___event.html",
+    # mixer
+    "group___mixer.html",
+    "group___simple_mixer.html"
+    ]
+
+def look_constant(name):
+    """
+    Look name for constant declarations.
+    
+    Returns:
+      a list of strings with the file and python constant.
+    """
+    nlist = []
+    for file in index_Constant_alsaseq:
+        for lc in index_Constant_alsaseq[file]:
+            tokens, start, end = lc
+            rs = "SND_" + tokens[5]
+            if rs == name:
+                nlist.append("%14s: %s" % (file, tokens[5]))
+                nlist.append("%14s: %s[%s]" % 
+                              (file, tokens[1].lower(), tokens[3]))
+    for file in index_Constant_alsaall:
+        for lc in index_Constant_alsaall[file]:
+            tokens, start, end = lc
+            prefix = tokens[0]
+            dictname = tokens[-1].split('"')[1]
+            for i in range(1, len(tokens)-1):
+                rs = prefix + tokens[i][1]
+                if rs == name:
+                    nlist.append("%14s: %s[%s]" %
+                                 (file, dictname, tokens[i][0]))
+
+    return nlist
+
+def look_usage(name):
+    """
+    Look name for usage (appareance) in C functions, structs, etc.
+
+    Returns:
+      a list of strings with the file and matched function/struct/define.
+    """
+    name = name.strip()
+    dict = {}
+    for file in index_snd_:
+        list = []
+        for lu in index_snd_[file]:
+            tokens, start, end = lu
+            rs = tokens[0]
+            if rs == name:
+                list.append(start)
+        dict[file] = list
+    for file in index_SND_:
+        list = []
+        for lu in index_SND_[file]:
+            tokens, start, end = lu
+            rs = tokens[0]
+            if rs == name:
+                list.append(start)
+        if dict.has_key(file):
+            dict[file].extend(list)
+        else:
+            dict[file] = list
+
+    nlist = []
+    for file in dict:
+        for lstart in dict[file]:
+            if not index.has_key(file):
+                continue
+            found = None
+            previous = None
+            for call in index[file]:
+                tokens, start, end = call
+                if start > lstart:
+                    found = previous
+                    break
+                previous = tokens[2]
+                if tokens[0] == 'typedef':
+                    previous = tokens[-1]
+                elif tokens[0] == '#define':
+                    previous = tokens[1]
+                elif previous == '*':
+                    previous = tokens[3]
+                #print "%8s: %5d - %20s %s" % (file, start, name, previous)
+            if found != None:
+                nlist.append("%14s: %s" % (file, found))
+                #print "FOUND: %8s: %5d %s" % (file, lstart, found)
+    return nlist
+
+
+# Following string contains excluded/commented API tokens, one per line.
+# Format is:
+# token comment
+comments = """
+SND_SEQ_DLSYM_VERSION I think there is no real use in pyalsa
+
+snd_seq_open_lconf need a snd_config port for implementing it
+snd_seq_poll_descriptors_revents no real use in pyalsa
+snd_seq_system_info_copy no real use in pyalsa
+snd_seq_system_info_free no real use in pyalsa
+snd_seq_system_info_malloc snd_seq_system_info_alloca used instead
+snd_seq_system_info_sizeof currently not used
+
+snd_seq_client_info_copy no real use in pyalsa
+snd_seq_client_info_free no real use in pyalsa
+snd_seq_client_info_malloc snd_seq_client_info_alloca used instead
+snd_seq_client_pool_copy no real use in pyalsa
+snd_seq_client_pool_free no real use in pyalsa
+snd_seq_client_pool_get_client snd_seq_client_id used instead
+snd_seq_client_pool_malloc no real use in pyalsa
+snd_seq_client_pool_set_input_pool snd_seq_set_client_pool_input used instead
+snd_seq_client_pool_set_output_pool snd_seq_set_client_pool_output used instead
+snd_seq_client_pool_set_output_room snd_seq_set_client_pool_output_room used instead
+snd_seq_client_pool_sizeof currently not used
+snd_seq_set_client_pool snd_seq_set_client_pool_* used instead
+snd_seq_client_info_set_name snd_seq_set_client_name used instead
+snd_seq_client_info_sizeof currently not used
+
+snd_seq_get_port_info snd_seq_get_any_port_info used instead
+snd_seq_port_info_copy no real use in pyalsa
+snd_seq_port_info_free no real use in pyalsa
+snd_seq_port_info_malloc snd_seq_port_info_alloca used instead
+snd_seq_port_info_set_addr snd_seq_port_info_set_client, snd_seq_port_info_set_port used instead
+snd_seq_port_info_sizeof currently not used
+
+snd_seq_port_subscribe_copy no real use in pyalsa
+snd_seq_port_subscribe_free no real use in pyalsa
+snd_seq_port_subscribe_malloc snd_seq_port_subscribe_alloca used instead
+snd_seq_port_subscribe_sizeof currently not used
+snd_seq_query_subscribe_copy no real use in pyalsa
+snd_seq_query_subscribe_free no real use in pyalsa
+snd_seq_query_subscribe_get_client snd_seq_query_subscribe_get_addr used instead
+snd_seq_query_subscribe_get_index currently not used
+#snd_seq_query_subscribe_get_num_subs 
+snd_seq_query_subscribe_get_port snd_seq_query_subscribe_get_addr used instead
+snd_seq_query_subscribe_get_root currently not used
+snd_seq_query_subscribe_get_type currently not used
+snd_seq_query_subscribe_malloc no real use in pyalsa
+snd_seq_query_subscribe_set_client snd_seq_query_subscribe_set_index used instead
+snd_seq_query_subscribe_set_port snd_seq_query_subscribe_set_index used instead
+snd_seq_query_subscribe_sizeof currently not used
+"""
+
+
+print """
+*******************************
+PYALSA/ASOUNDLIB COVERAGE/USAGE
+*******************************
+
+
+Notes:
+* For re-generating this file, you need inet access (for downloading the
+  doxygen HTML from www.alsa-project.org site).
+* Some cached information about parsing is in the 'cache' directory:
+  * If you change a source file, the program will regenerate the cache.
+  * HTML API from www.alsa-project.org is never refreshed, remove manually.
+* Doxygen Modules are underlined by ======= .
+* Doxygen Sections are Underlined by ------- . The parsed sections are:
+  * CPP #defines
+  * Type definitions
+  * Enumerations
+  * Functions
+* The first line of each item is the "C Prototype". First 3 columns are:
+  * Number of times found in checked code
+  * N/A if the item is not being used/was not found
+  * EXC if the item is excluded (will not be used/implemented)
+* The next line is the one-liner documentation.
+* Following lines are usage/definition until next item.
+* There are lines that summaries the coverage, they start with '^STAT'.
+
+
+
+"""
+
+
+print_api_coverage(urls, look_constant, look_usage, comments)
+
+# print end line
+time_end = time.time()
+time_diff = time_end - time_start
+
+print """%s
+Generated for ALSA project by alsa-python-coverage.py %s
+%s UTC (%s@%s %3.3f seconds).
+""" % ("-"*72,
+       __version__,
+       time.asctime(time.gmtime(time_start)), 
+       os.getlogin(),
+       os.uname()[1],
+       time_diff
+       )
+print

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

             reply	other threads:[~2008-03-08  1:47 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-08  1:47 Aldrin Martoq [this message]
2008-03-18 17:16 ` [PATCH] 1/2 alsa-python: API coverage documentation tool Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1204940845.6474.14.camel@localhost \
    --to=amartoq@dcc.uchile.cl \
    --cc=alsa-devel@alsa-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.