home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / gtk-2.0 / codegen / docextract.py < prev    next >
Encoding:
Python Source  |  2007-11-01  |  6.3 KB  |  186 lines

  1. # -*- Mode: Python; py-indent-offset: 4 -*-
  2. '''Simple module for extracting GNOME style doc comments from C
  3. sources, so I can use them for other purposes.'''
  4.  
  5. import sys, os, string, re
  6.  
  7. __all__ = ['extract']
  8.  
  9. class FunctionDoc:
  10.     def __init__(self):
  11.         self.name = None
  12.         self.params = []
  13.         self.description = ''
  14.         self.ret = ''
  15.     def set_name(self, name):
  16.         self.name = name
  17.     def add_param(self, name, description):
  18.         if name == '...':
  19.             name = 'Varargs'
  20.         self.params.append((name, description))
  21.     def append_to_last_param(self, extra):
  22.         self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra)
  23.     def append_to_named_param(self, name, extra):
  24.         for i in range(len(self.params)):
  25.             if self.params[i][0] == name:
  26.                 self.params[i] = (name, self.params[i][1] + extra)
  27.                 return
  28.         # fall through to adding extra parameter ...
  29.         self.add_param(name, extra)
  30.     def append_description(self, extra):
  31.         self.description = self.description + extra
  32.     def append_return(self, extra):
  33.         self.ret = self.ret + extra
  34.  
  35.     def get_param_description(self, name):
  36.         for param, description in self.params:
  37.             if param == name:
  38.                 return description
  39.         else:
  40.             return ''
  41.  
  42. comment_start_pat = re.compile(r'^\s*/\*\*\s')
  43. comment_end_pat = re.compile(r'^\s*\*+/')
  44. comment_line_lead = re.compile(r'^\s*\*\s*')
  45. funcname_pat = re.compile(r'^(\w+)\s*:?')
  46. return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$',
  47.                         re.IGNORECASE)
  48. param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$')
  49.  
  50. def parse_file(fp, doc_dict):
  51.     line = fp.readline()
  52.     in_comment_block = 0
  53.     while line:
  54.         if not in_comment_block:
  55.             if comment_start_pat.match(line):
  56.                 in_comment_block = 1
  57.                 cur_doc = FunctionDoc()
  58.                 in_description = 0
  59.                 in_return = 0
  60.             line = fp.readline()
  61.             continue
  62.  
  63.         # we are inside a comment block ...
  64.         if comment_end_pat.match(line):
  65.             if not cur_doc.name:
  66.                 sys.stderr.write("no function name found in doc comment\n")
  67.             else:
  68.                 doc_dict[cur_doc.name] = cur_doc
  69.             in_comment_block = 0
  70.             line = fp.readline()
  71.             continue
  72.  
  73.         # inside a comment block, and not the end of the block ...
  74.         line = comment_line_lead.sub('', line)
  75.         if not line: line = '\n'
  76.  
  77.         if not cur_doc.name:
  78.             match = funcname_pat.match(line)
  79.             if match:
  80.                 cur_doc.set_name(match.group(1))
  81.         elif in_return:
  82.             match = return_pat.match(line)
  83.             if match:
  84.                 # assume the last return statement was really part of the
  85.                 # description
  86.                 return_start = match.group(1)
  87.                 cur_doc.ret = match.group(2)
  88.                 cur_doc.description = cur_doc.description + return_start + \
  89.                                       cur_doc.ret
  90.             else:
  91.                 cur_doc.append_return(line)
  92.         elif in_description:
  93.             if line[:12] == 'Description:':
  94.                 line = line[12:]
  95.             match = return_pat.match(line)
  96.             if match:
  97.                 in_return = 1
  98.                 return_start = match.group(1)
  99.                 cur_doc.append_return(match.group(2))
  100.             else:
  101.                 cur_doc.append_description(line)
  102.         elif line == '\n':
  103.             # end of parameters
  104.             in_description = 1
  105.         else:
  106.             match = param_pat.match(line)
  107.             if match:
  108.                 param = match.group(1)
  109.                 desc = match.group(2)
  110.                 if param == 'returns':
  111.                     cur_doc.ret = desc
  112.                 else:
  113.                     cur_doc.add_param(param, desc)
  114.             else:
  115.                 # must be continuation
  116.                 try:
  117.                     if param == 'returns':
  118.                         cur_doc.append_return(line)
  119.                     else:
  120.                         cur_doc.append_to_last_param(line)
  121.                 except:
  122.                     sys.stderr.write('something weird while reading param\n')
  123.         line = fp.readline()
  124.  
  125. def parse_dir(dir, doc_dict):
  126.     for file in os.listdir(dir):
  127.         if file in ('.', '..'): continue
  128.         path = os.path.join(dir, file)
  129.         if os.path.isdir(path):
  130.             parse_dir(path, doc_dict)
  131.         if len(file) > 2 and file[-2:] == '.c':
  132.             parse_file(open(path, 'r'), doc_dict)
  133.  
  134. def extract(dirs, doc_dict=None):
  135.     if not doc_dict: doc_dict = {}
  136.     for dir in dirs:
  137.         parse_dir(dir, doc_dict)
  138.     return doc_dict
  139.  
  140. tmpl_section_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
  141. def parse_tmpl(fp, doc_dict):
  142.     cur_doc = None
  143.  
  144.     line = fp.readline()
  145.     while line:
  146.         match = tmpl_section_pat.match(line)
  147.         if match:
  148.             cur_doc = None  # new input shouldn't affect the old doc dict
  149.             sect_type = match.group(1)
  150.             sect_name = match.group(2)
  151.  
  152.             if sect_type == 'FUNCTION':
  153.                 cur_doc = doc_dict.get(sect_name)
  154.                 if not cur_doc:
  155.                     cur_doc = FunctionDoc()
  156.                     cur_doc.set_name(sect_name)
  157.                     doc_dict[sect_name] = cur_doc
  158.         elif line == '<!-- # Unused Parameters # -->\n':
  159.             cur_doc = None # don't worry about unused params.
  160.         elif cur_doc:
  161.             if line[:10] == '@Returns: ':
  162.                 if string.strip(line[10:]):
  163.                     cur_doc.append_return(line[10:])
  164.             elif line[0] == '@':
  165.                 pos = string.find(line, ':')
  166.                 if pos >= 0:
  167.                     cur_doc.append_to_named_param(line[1:pos], line[pos+1:])
  168.                 else:
  169.                     cur_doc.append_description(line)
  170.             else:
  171.                 cur_doc.append_description(line)
  172.  
  173.         line = fp.readline()
  174.  
  175. def extract_tmpl(dirs, doc_dict=None):
  176.     if not doc_dict: doc_dict = {}
  177.     for dir in dirs:
  178.         for file in os.listdir(dir):
  179.             if file in ('.', '..'): continue
  180.             path = os.path.join(dir, file)
  181.             if os.path.isdir(path):
  182.                 continue
  183.             if len(file) > 2 and file[-2:] == '.sgml':
  184.                 parse_tmpl(open(path, 'r'), doc_dict)
  185.     return doc_dict
  186.