#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2012 Adrian Musceac # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # 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, see . import os, sys, glob import io import re, string """Script which generates an API documentation file for Nasal libraries located inside $FGROOT/Nasal/ Usage: nasal_api_doc.py parse [path to $FGROOT/Nasal/] Or configure the local path below, and ommit the path in the console. The API doc in HTML format is generated in the current working directory""" ########### Local $FGROOT/Nasal/ path ########## NASAL_PATH="../fgfs/fgdata/Nasal/" def get_files(nasal_dir): if nasal_dir[-1]!='/': nasal_dir+='/' try: os.stat(nasal_dir) except: print("The path does not exist") sys.exit() fgroot_dir = nasal_dir.rstrip('/').replace('Nasal','') try: f_version = open(fgroot_dir+'version','rb') version = f_version.read(256).rstrip('\n') finally: f_version.close() top_level = [] modules = [] top_namespaces = [] files_list = os.listdir(nasal_dir) for f in files_list: if f.find(".nas")!=-1: top_level.append(f) continue if os.path.isdir(nasal_dir + f): modules.append(f) top_level.sort() modules.sort() if len(top_level) ==0: print("This does not look like the correct $FGROOT/Nasal path") sys.exit() if len(modules)==0: print("Warning: could not find any submodules") for f in top_level: namespace=f.replace(".nas","") functions=parse_file(nasal_dir + f) top_namespaces.append([namespace,functions]) for m in modules: files=glob.glob(nasal_dir+m+"/*.nas") for f in files: functions=parse_file(f) top_namespaces.append([m,functions]) output_text(top_namespaces,modules,version) def output_text(top_namespaces,modules,version): fw=open('./nasal_api_doc.html','wb') buf='\ Nasal API\ \n\ ' buf+='

\ Nasal $FGROOT Library
Flightgear version: '+version+'\
This file is generated automatically by scripts/python/nasal_api_doc.py\

\
Nasal documentation  \ Flightgear Nasal documentation\n
 ' buf+='

\n' done=[] for namespace in top_namespaces: color='0000cc' if namespace[0] in modules: color='cc0000' if namespace[0] not in done: buf+=''+namespace[0]+' 
\n' done.append(namespace[0]) buf+='

\n' done2=[] for namespace in top_namespaces: if namespace[0] not in done2: buf+='
\n' buf += '

'+namespace[0]+'

\n' done2.append(namespace[0]) for functions in namespace[1]: class_func=functions[0].split('.') if len(class_func)>1: f_name='' if class_func[1].find('_')==0: f_name=''+class_func[1]+'' else: f_name=class_func[1] if class_func[1]!='': buf+= '

'\ +namespace[0]+''+ "." + ''+class_func[0]+''+'.'+f_name+''+' ( '+ functions[1]+ ' )' +'

\n' else: buf+= '

'\ +namespace[0]+''+ "." + ''+class_func[0]+'' +'

\n' else: if functions[0].find('_')==0: f_name=''+functions[0]+'' else: f_name=functions[0] buf+= '

'\ +namespace[0]+''+ "." + ''+f_name+''+ ' ( '+ functions[1]+ ' )' +'

\n' for comment in functions[2]: if comment.find('=====')!=-1: buf+='
' else: tempComment = comment.replace('#','').replace('<','<').replace('>','>') if tempComment.strip()!="": buf+= '
'+tempComment+'

\n' buf+='
\n' if namespace[0] not in done2: buf+='
\n' buf+='' fw.write(buf) fw.close() def parse_file(filename): with open(filename,'rb') as fr: content = fr.readlines() i=0 retval=[] classname="" for line in content: match=re.search(r'^var\s+([A-Za-z0-9_-]+)\s*=\s*func\s*\(?([A-Za-z0-9_\s,=.\n-]*)\)?',line) if match is not None: func_name=match.group(1) comments=[] param=match.group(2) if(line.find(')')==-1 and line.find('(')!=-1): k=i+1 while(content[k].find(')')==-1): param+=content[k].rstrip('\n') k+=1 param+=content[k].split(')')[0] j=i-1 count=0 while ( j>i-35 and j>-1): if count>3: break if len(content[j])<2: j-=1 count+=1 continue if re.search(r'^\s*#',content[j]) is not None: comments.append(content[j].rstrip('\n')) j-=1 else: break if(len(comments)>1): comments.reverse() retval.append((func_name, param,comments)) i+=1 continue match3=re.search(r'^var\s*([A-Za-z0-9_-]+)\s*=\s*{\s*(\n|})',line) if match3 is not None: classname=match3.group(1) comments=[] j=i-1 count=0 while ( j>i-35 and j>-1): if count>3: break if len(content[j])<2: j-=1 count+=1 continue if re.search(r'^\s*#',content[j]) is not None: comments.append(content[j].rstrip('\n')) j-=1 else: break if(len(comments)>1): comments.reverse() retval.append((classname+'.', '',comments)) i+=1 continue match2=re.search(r'^\s*([A-Za-z0-9_-]+)\s*:\s*func\s*\(?([A-Za-z0-9_\s,=.\n-]*)\)?',line) if match2 is not None: func_name=match2.group(1) comments=[] param=match2.group(2) if(line.find(')')==-1 and line.find('(')!=-1): k=i+1 while(content[k].find(')')==-1): param+=content[k].rstrip('\n') k+=1 param+=content[k].split(')')[0] j=i-1 count=0 while ( j>i-35 and j>-1): if count>3: break if len(content[j])<2: j-=1 count+=1 continue if re.search(r'^\s*#',content[j]) is not None: comments.append(content[j].rstrip('\n')) j-=1 else: break if(len(comments)>1): comments.reverse() if classname =='': continue retval.append((classname+'.'+func_name, param,comments)) i+=1 continue match4=re.search(r'^([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)\s*=\s*func\s*\(?([A-Za-z0-9_\s,=\n.-]*)\)?',line) if match4 is not None: classname=match4.group(1) func_name=match4.group(2) comments=[] param=match4.group(3) if(line.find(')')==-1 and line.find('(')!=-1): k=i+1 while(content[k].find(')')==-1): param+=content[k].rstrip('\n') k+=1 param+=content[k].split(')')[0] j=i-1 count=0 while ( j>i-35 and j>-1): if count>3: break if len(content[j])<2: j-=1 count+=1 continue if re.search(r'^\s*#',content[j]) is not None: comments.append(content[j].rstrip('\n')) j-=1 else: break if(len(comments)>1): comments.reverse() retval.append((classname+'.'+func_name, param,comments)) i+=1 continue i+=1 return retval if __name__ == "__main__": if len(sys.argv) <2: print('Usage: nasal_api_doc.py parse [path to $FGROOT/Nasal/]') sys.exit() else: if sys.argv[1]=='parse': if len(sys.argv) <3: nasal_path=NASAL_PATH else: nasal_path=sys.argv[2] get_files(nasal_path) else: print('Usage: nasal_api_doc.py parse [path to $FGROOT/Nasal/]') sys.exit()