#!/usr/local/bin/python
##
##
## QC2HTML Copyright (c) 1996, Olivier Montanuy
## Version 1.0, August 1st, 1996
##
##
## Run this Python program in a directory, with no arguments.
## It will look for file "progs.src", read it, and then process all
## .QC (Quake C) files into HTML, with anchors for functions.
## It assumes that file builtin.htm exists, and contains definitions
## for the Quake C buit-in types, variables, functions.
##
## About Python:
## see http://www.python.org/
## Basically it's a (slow) scripting language, that can run on
## Unix, Linux, Windows 95 (I recommend PythonWin there).
##
## Technical info:
## This program isn't a true Quake C analyser. It works with regular
## expressions,so it's slow as hell, and might bug in some cases.
## Go rewrite it in CAML or C (yacc) if you have time to waste.
##
## Disclaimer:
## Use at your own risk. No liabilities. None at all. Even toward *you*.
## Don't try to understand that code. You have been warned. If your brain
## fries, or you die laughting, I'm not feeling concerned.
##
## bugs: fileds are not tagged correctly
## file where the list of files shall be found
ProgsSrc = "progs.src"
## Pattern of the files to transform
## \n"
return res
#
# Html Trailer
#
def TransHtmlTrail(fileName):
return "\n
"
######################################################################
# Do not edit after this line
######################################################################
import regex
import regsub
import string
import fnmatch
import os
##
## Save a file
## info = (file, txt)
def FileWrite(info):
try:
(file, txt) = info
fp = open(file,"w")
fp.write(txt)
fp.close()
return info
except:
print "Can't write file ", file
return None
##
## Read a file
## file = filename
def FileRead(file):
try:
fp=open(file,"r")
txt=fp.read() #
fp.close()
return txt
except:
print "Can't read file ", file
return None
#
# convert extension of file name to .html
#
def FileHtml(file):
(root,ext)=os.path.splitext(file)
return root + ".htm"
##
## KeyWords
##
class KeyWords:
# IsKeyword(self, token)
Keys= {}
def __init__(self, keylist):
self.Keys= {}
for k in keylist:
self.Keys[k] = "" # declare all keywords
return
# return 1 if token exists
def IsKeyword(self, token):
if self.Keys.has_key(token):
return 1
return 0
##
## Modules
##
class Modules:
# Declaration of the paths of the modules
# m = Modules() # create an instance of class Modules
# mod = m.DeclarePath(file) # declare new module file, return module name
# m.DeclareBasePath(path) # set base path
# file = m.GetFile(mod) # get root file of a given module (no extension)
# Inquiries about module usage:
# m.NoneUsed() # clear off module used
# m.Used(mod) # declare module is used in the current file
# bool = m.IsUsed(mod) # return 1 if module exists
# Hidden variables:
# self._mods = { "moduleName":"modulePath", ...}
# self._curr ={ "moduleName":1, ...}
# self._base = "basePathForAllModules"
##
## m = Modules()
##
def __init__(self):
self._mods = {} # dictionary of known modules
self._curr = {} # dictionary of current modules
self._base = ""
return
##
## m.DeclarePath( file)
## file = "/directory/file.ext"
def DeclarePath(self, file):
(root, ext) = os.path.splitext(file) # get extension
(path, mod) = os.path.split(root) # get path
self._mods[mod]= path # declare
return mod # return module name
##
## m.DeclareBasePath( file)
## path = "/directory/"
def DeclareBasePath(self,file):
( self._base, name) = os.path.split(file)
return
##
## file= m.GetFile(mod)
## file = "/directory/file" no extension
def GetFile(self, mod):
if not self._mods.has_key(mod):
return ""
path= os.path.join(self._base,self._mods[mod])
return os.path.join(path, mod)
# m.NoneUsed()
# declare no modules are used yet
def NoneUsed(self):
self._curr = {}
return
# m.Used(mod)
# declare that module is used
def Used(self, mod):
self._curr[mod] = 1
# m.IsUsed(mod)
# check if module is used
def IsUsed(self, mod):
return self._curr.has_key(token)
##
## Anchors
##
class Anchors:
# a =Anchors(KnownAnchors)
# a.DeclareModule(mod) # declare name of current module
# a.Declare(anchor) # declare an achor
# bool = a.IsKnown(anchor) # returns true if it is an anchor
# file = a.GetFile(anchor) # return Href of anchor
# hidden variables
# dictionary of anchors
#_known = {} # {"name":"module", ...}
# duplicated anchors
#_dupli = {} # {"name":[ "module1", "module2", ...], ...}
# name of current module
_currentMod ="" # "moduleName"
# anchor pattern
_apatn = regex.compile("")
def __init__(self, knownanchor):
self.Required = {}
self.Mods = Modules()
self._known = {}
self._dupli = {}
# declare all known anchors
#for kn in known:
# (file, anchlist) = kn
# self.DeclareModule(file)
# for anch in anchlist:
# self.Declare(anch)
# self._currentMod = ""
for file in knownanchor:
self.LookForAnchors(file)
return
# a.LookForAnchors(file)
# try to find known anchors in file
def LookForAnchors(self, file):
text = FileRead(file)
if text == None: # can't read file
return
self.DeclareModule(file)
print "Looking for anchors in ", file
pos = 0
while(1):
pos = self._apatn.search(text, pos)
if pos<0: break
pos = pos + len(self._apatn.group(0))
# print " Found: ", self._apatn.group(1)
anchor = self._apatn.group(1)
#
self.Declare(anchor)
# hack: declare a required function
if anchor[0:2] == "f_":
self.Required[anchor] = 1
self._currentMod = ""
return
# a.DeclareModule(mod)
# mod = name of current module
def DeclareModule(self, file):
self._currentMod = self.Mods.DeclarePath(file)
return
# a.Declare(anchor)
# anchor = string, name of an anchor detected
# Declare anchor, only if not known already
def Declare(self, anchor):
if self._currentMod == None or self._currentMod == "":
print "ERROR no current module"
return
# detect duplicate anchors
if self._known.has_key(anchor): #
if self._known[anchor] != "": # not a predeclared anchor
if not self._dupli.has_key(anchor): self._dupli[anchor] = []
self._dupli[anchor].append( self._currentMod )
return
# declare anchor, only if not known
self._known[anchor] = self._currentMod
# a.PreDeclare(anchor)
# anchor = string, name of an anchor detected
# Pre-declare anchor
def PreDeclare(self, anchor):
# do not pre-declare if already known
if self._known.has_key(anchor): return
# pre-declare anchor, only if not known
self._known[anchor] = ""
## bool= a.IsKnown(anchor)
## return 1 if anchor is really an achor
def IsKnown(self, anchor):
return self._known.has_key(anchor)
##
## file = a.GetFile(anchor)
## file = file reference, for anchor, suitable for use in
def GetFile(self, anchor):
if not self._known.has_key(anchor):
print "ERROR unknown anchor: ", anchor
return ""
mod = self._known[anchor] # get module name
return FileHtml(self.Mods.GetFile(mod)) # get file name
##
## anchor = a.Href(anchor, title)
## title
def Href(self, anchor, title):
#return "" + title + ""
return "" + title + ""
def LateResolve(self, text):
liste = string.splitfields(text, "@-@%@-@")
for l in xrange(1, len(liste), 2):
liste[l]= self.GetFile(liste[l]) # anchor
return string.joinfields(liste,"")
##
## Translation table: [ (ExpC, Sub ,FFun, Start), ... ]
##
class Translater:
ExpC = None # compiler regular expression
Sub = "" # substitution string
FFun = None # function to execute
Start = 0 # 0 if invalid, -1 if no more position
Size = 0 # size of match
##
## Initialise
##
def __init__(self, t):
(exp , sub, ffun) = t
self.ExpC = regex.compile(exp)
self.Sub = sub
self.FFun = ffun
self.Reset()
return
def Reset(self):
self.Start = 0
self.Size = 0
##
## find next occurence
##
def FindNext(self, text, pos):
if self.Start < 0: # no more patterns of that kind
return -1
if (self.Start > 0)&(self.Start>=pos): # position is valid
return self.Start
else:
self.Start = self.ExpC.search(text,pos)
if self.Start >= 0:
self.Size = self.ExpC.match(text,self.Start)
return self.Start #last posisition found
##
## apply function
##
def ApplyFunction(self, infos):
if self.FFun == None:
return ""
return self.FFun(self.ExpC, infos)
##
## translate some text
##
def Translate(self, text):
if self.Sub == None:
return ""
return regsub.sub(self.ExpC.realpat, self.Sub, text)
##
## Add an anchor to translation table
##
def TransTableAdd(word):
t=Translater( ("\\b\("+word+"\)\\b", "\\1", None))
TransTable.append(t)
return
##
## Reset the translation table
##
def TransTableReset():
for translater in TransTable:
translater.Reset()
return
#
## Compile translation table from TransDef
#
TransTable = map(Translater,TransDef)
##
## Infos structure for functions
##
class Transform:
FileName = "" # Obtain the current File name from here
BasePath = ""
LineNumber = 0 # Obtain the current Line Number from here
def __init__(self, file):
# declare known keywords, for user-defined functions
self.Keys = KeyWords(KeywordList)
# declare anchors, for user-defined functions
self.Anchs = Anchors(KnownAnchors)
liste = self._getFileList(file)
self.TransFileList(liste)
return
##
## infos._getFileList()
## find, in file, a list of files to parse
def _getFileList(self, file):
print "Looking for file definitions in %s" % file
txt = FileRead(file)
# find file names according to TransPattern
patn = regex.compile(TransPattern)
liste=[]
pos = 0
while 1:
pos = patn.search(txt,pos)
if pos<0: break
pos = pos+len(patn.group(0))
name = patn.group(1)
print "found ", name
liste.append( name)
# save list in HTM
res = []
res.append("Quake-C modules
")
res.append("Generated by qc2html.py
")
res.append("Underpowered by Python.")
res.append("")
for name in liste:
(root, ext) = os.path.splitext(name)
res.append("
Maybe you would like the No frame version.
") res.append("