home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / docs / qcspec3 / qc2html.py < prev    next >
Encoding:
Python Source  |  1996-08-07  |  20.7 KB  |  665 lines

  1. #!/usr/local/bin/python 
  2. ## 
  3. ##
  4. ##     QC2HTML Copyright (c) 1996, Olivier Montanuy 
  5. ##          Version 1.0,  August 1st, 1996
  6. ##
  7. ##
  8. ## Run this Python program in a directory, with no arguments. 
  9. ## It will look for file "progs.src", read it, and then process all
  10. ## .QC (Quake C) files into HTML, with anchors for functions.
  11. ## It assumes that file builtin.htm exists, and contains definitions
  12. ## for the Quake C buit-in types, variables, functions.
  13. ##
  14. ## About Python:
  15. ##  see http://www.python.org/
  16. ##  Basically it's a (slow) scripting language, that can run on
  17. ##  Unix, Linux, Windows 95 (I recommend PythonWin there).
  18. ##
  19. ## Technical info: 
  20. ##  This program isn't a true Quake C analyser. It works with regular 
  21. ##  expressions,so it's slow as hell, and might bug in some cases. 
  22. ##  Go rewrite it in CAML or C (yacc) if you have time to waste.
  23. ##
  24. ## Disclaimer:
  25. ##  Use at your own risk. No liabilities. None at all. Even toward *you*.
  26. ##  Don't try to understand that code. You have been warned. If your brain
  27. ##  fries, or you die laughting, I'm not feeling concerned.
  28. ##
  29.  
  30. ## bugs: fileds are not tagged correctly
  31.  
  32. ## file where the list of files shall be found
  33. ProgsSrc = "progs.src"
  34. ## Pattern of the files to transform
  35. ##   <anything>.qc
  36. TransPattern = "\(\w[a-zA-Z0-9_]*[.]qc\)"
  37. ## Quake-C  keywords
  38. KeywordList = [ 'do', 'else', 'for', 'if', 'local', 'return', 'while' ]
  39. ##
  40. ## Built-in Required functions, or documented function:
  41. ##
  42. ## use a tag <a name="f_xxxx">xxxx</a> to define
  43. ## them, where xxxx is the name of the function.
  44. ## qc2html will look for that tag in the KnownAnchor
  45. ## files, and link the function definition to it.
  46. ## That's an easy way to document your functions.
  47. ##
  48. ##
  49. ## Declare all the files that contain known anchors
  50. ##  Those anchors will be found according to pattern <a name="...">
  51. ##  To define anchors not to be referenced by quake-C, use <A NAME="..."> 
  52. #KnownAnchors = [ ... , "manual.htm" ]
  53. KnownAnchors = ["qc-mdl.htm", "qc-types.htm", "qc-defs.htm", "qc-vars.htm", "qc-enty.htm", 
  54.                 "qc-glob.htm", "qc-built.htm", "qc-netf.htm", "qc-net.htm", ]
  55.  
  56. #
  57. ##
  58. ## User defined functions
  59. ##
  60. #  TransTableAdd(expc.group(1)) #add to translation table
  61. # declare expc.group(1) as an anchor location
  62. def UNewAnchor1(expc, infos):
  63.   infos.Anchs.Declare( expc.group(1))
  64.   return ""
  65. ## declare a variable  
  66. def UVariable123(expc, infos):
  67.   space = expc.group(1)
  68.   if space == None: space = ""
  69.   typ= expc.group(2)
  70.   name = expc.group(3)
  71.   # this is a hack, because return val; is confused with a declaration
  72.   if typ == "return": 
  73.     return expc.group(0) #everything 
  74.   # check if variable is known
  75.   if infos.Anchs.IsKnown(typ):
  76.     typ = infos.Anchs.Href( typ, typ )
  77.   if infos.Anchs.IsKnown(name): 
  78.     name = infos.Anchs.Href( name, name)  
  79.   else:
  80.     infos.Anchs.Declare(name)
  81.     name = "<a name=\"" + name + "\">" + name + "</a>"
  82.   return space + typ + " <b>" + name + "</b>;"
  83. ## declare a constant
  84. def UConstant1234(expc, infos):
  85.   space = expc.group(1)
  86.   if space == None: space = ""
  87.   typ= expc.group(2)
  88.   name = expc.group(3)
  89.   value = expc.group(4)
  90.   if not infos.Anchs.IsKnown(name):
  91.     infos.Anchs.Declare(name)
  92.     name = "<a name=\"" + name + "\">" + name + "</a>"
  93.   if infos.Anchs.IsKnown(typ):
  94.     typ = infos.Anchs.Href( typ, typ )
  95.   return space + typ + " <b>" + name + "</b> = " + value + ";"
  96. ## transform expc.group(1)
  97. def UToken1(expc, infos):
  98.   token = expc.group(1)
  99.   if infos.Keys.IsKeyword(token):
  100.     return "<b>"+token+"</b>"
  101.   elif infos.Anchs.IsKnown(token):
  102.     return infos.Anchs.Href(token, token)
  103.   return token
  104. ## define a new function
  105. def UFunction1(expc, infos):
  106.   token = expc.group(1)
  107.   infos.Anchs.Declare(token)  # declare function
  108.   # required functions have anchor = "f_xxxx"
  109.   fname = "f_"+token
  110.   if infos.Anchs.Required.has_key(fname): #required
  111.     func = infos.Anchs.Href(fname, token) 
  112.   else:                       # normal function
  113.     func = token 
  114.   return ") <b>"+ func + "</b><a name=\""+token+"\">=</a>"
  115. ## pre-declare a new function
  116. def UFDeclare1(expc, infos):
  117.   token = expc.group(1)
  118.   infos.Anchs.PreDeclare(token) # pre-declare function
  119.   func = infos.Anchs.Href(token, token) # point to function
  120.   return ") " + func + ";"
  121. # declare a ".xxxx" stuff
  122. def UDotField12(expc, infos):
  123.   field = expc.group(1)
  124.   paren = expc.group(2)
  125.   if paren == None:  paren = ""
  126.   hack = "dot_" + field
  127.   if infos.Anchs.IsKnown(hack):
  128.     field =  infos.Anchs.Href(hack, field)
  129.   return "." + field + paren
  130. # declare a new dollar definition (for models)
  131. def UDollar12(expc, infos):
  132.   token = expc.group(1) # definition
  133.   data = expc.group(2)  # data of definition
  134.   hack = "s_"+token     # anchor is s_xxxx
  135.   anchor = infos.Anchs.Href(hack, token) # anchor "$"
  136.   return "<b>$</b>" + anchor + " <b>" + data + "</b>"
  137. ##
  138. ## Translation table = [ (Exp, Sub ,FFun), ... ]
  139. ##
  140. ##  Exp = regular expression to be matched, with groups
  141. ##  Sub = substituted regular expression, with groups 
  142. ##  FFun = None or User-defined function to execute on expression
  143. ##
  144. TransDef = [
  145. # Strings:   anything in quotes, is highlighted
  146. ( "\"\(.*\)\"",  
  147.   "<b>\"\\1\"</b>",  None ),
  148. # Comments: 
  149. # ex:   // anything
  150. ( "//\(.*\)\n", 
  151.   "<i>//\\1</i>\n",   None),
  152. # Comments
  153. # ex:   /* anything */
  154. ( "/[*]\([^*]*\)[*]/", 
  155.   "<i>/*\\1*/</i>\n",   None),
  156. # < and >
  157. ( "<", "<", None),
  158. ( ">", ">", None),
  159. ( "&", "&", None),
  160. # dot field 
  161. ( "[.]\([a-zA-Z_][a-zA-Z0-9_]*\)\([ \t]*()\)?",
  162.   None, UDotField12),
  163. # builtin function definition
  164. # ex: ") scv_xxx = #"
  165. ( ")[ _t]*\(\w[a-zA-Z0-9_]*\)[ \t]*=[ \t]*#[ \t]*\([0-9]+\)[ \t]*;",
  166.   ") <b>\\1</b> = #<b>\\2</b>;", None),
  167. # function definition  
  168. # ex:   ") boss_missile ="
  169. ( ")[ \t]*\(\w[a-zA-Z0-9_]*\)[ \t]*=",
  170.   None, UFunction1),
  171. # function declaration
  172. # ex:   ") movetarget_f;"
  173. ( ")[ \t]*\(\w[a-zA-Z0-9_]*\)[ \t]*;",
  174.   None, UFDeclare1),
  175. # variable declaration
  176. # ex:   "float current_yaw;"
  177. ( "^\([ \t]*\)\(\w[a-zA-Z0-9_]*\)[ \t]+\(\w[a-zA-Z0-9_]*\)[ \t]*;",
  178.   None, UVariable123),
  179. # constant declaration
  180. # ex:   "float ATTN_STATIC = 3;"
  181. ( "^\([ \t]*\)\(\w[a-zA-Z0-9_]*\)[ \t]+\(\w[a-zA-Z0-9_]*\)[ \t]*=[ \t]*\(.*\);",
  182.   None, UConstant1234),
  183. # definition
  184. # ex: $skin skin 
  185. ( "^$\(\w[a-zA-Z0-9_]*\)[ \t]+\(.*\)",
  186.   None, UDollar12),
  187. # token
  188. ( "\\b\([a-zA-Z0-9_][a-zA-Z0-9_---]*\)\\b",
  189.   None,  UToken1) ] 
  190. ## RegExp
  191. ## "\w+"        = one or more word characters
  192. ## "\(\w+\)"    = a word in a group (group(1), group(2), etc...)
  193. ## "\\b"        = a word boundary
  194. ## " *"         = zero or more spaces
  195.  
  196. #
  197. # Html Header
  198. #
  199. def TransHtmlHead(fileName):
  200.  res = "<html><head><title>" + fileName + "</title></head>"
  201.  res = res + "<body bgcolor=\"#C0F0D0\">\n"
  202.  res = res + "<base target=examine>\n<pre>\n" 
  203.  return res 
  204. #
  205. # Html Trailer
  206. #
  207. def TransHtmlTrail(fileName):
  208.  return "\n</pre></body></html>"
  209.  
  210. ######################################################################
  211. # Do not edit after this line
  212. ######################################################################
  213. import regex
  214. import regsub
  215. import string
  216. import fnmatch
  217. import os
  218.  
  219. ##
  220. ## Save a file
  221. ##  info = (file, txt)
  222. def FileWrite(info):
  223.   try:
  224.     (file, txt) = info
  225.     fp = open(file,"w")
  226.     fp.write(txt)
  227.     fp.close()
  228.     return info
  229.   except:
  230.     print "Can't write file ", file
  231.     return None
  232. ##
  233. ## Read a file
  234. ## file = filename
  235. def FileRead(file):
  236.   try: 
  237.     fp=open(file,"r")
  238.     txt=fp.read() #
  239.     fp.close()
  240.     return txt
  241.   except:
  242.     print "Can't read file ", file
  243.     return None
  244. #
  245. # convert extension of file name to .html 
  246. #
  247. def FileHtml(file):
  248.   (root,ext)=os.path.splitext(file)
  249.   return root + ".htm"
  250.  
  251. ##
  252. ## KeyWords
  253. ##
  254. class KeyWords:
  255.    # IsKeyword(self, token)
  256.    Keys= {}
  257.    def __init__(self, keylist):
  258.      self.Keys= {}
  259.      for k in keylist:
  260.        self.Keys[k] = "" # declare all keywords
  261.      return
  262.    # return 1 if token exists
  263.    def IsKeyword(self, token):
  264.      if self.Keys.has_key(token):
  265.        return 1
  266.      return 0
  267. ##
  268. ## Modules
  269. ##
  270. class Modules:
  271.   # Declaration of the paths of the modules
  272.   #  m = Modules()        # create an instance of class Modules
  273.   #  mod = m.DeclarePath(file)    # declare new module file, return module name
  274.   #  m.DeclareBasePath(path)    # set base path
  275.   #  file = m.GetFile(mod)    # get root file of a given module (no extension)
  276.   # Inquiries about module usage:
  277.   #  m.NoneUsed()        # clear off module used
  278.   #  m.Used(mod)        # declare module is used in the current file
  279.   #  bool = m.IsUsed(mod)    # return 1 if module exists
  280.   # Hidden variables:
  281.   # self._mods = { "moduleName":"modulePath", ...}
  282.   # self._curr ={ "moduleName":1, ...}
  283.   # self._base = "basePathForAllModules"
  284.   ##
  285.   ## m = Modules()
  286.   ##
  287.   def __init__(self):
  288.     self._mods = {}  # dictionary of known modules     
  289.     self._curr = {} # dictionary of current modules
  290.     self._base = ""
  291.     return
  292.   ##
  293.   ## m.DeclarePath( file)
  294.   ##   file = "/directory/file.ext"
  295.   def DeclarePath(self, file):
  296.     (root, ext) = os.path.splitext(file) # get extension
  297.     (path, mod) = os.path.split(root)    # get path
  298.     self._mods[mod]= path # declare
  299.     return mod # return module name
  300.   ##
  301.   ## m.DeclareBasePath( file)
  302.   ##  path = "/directory/"
  303.   def DeclareBasePath(self,file):
  304.     ( self._base, name) = os.path.split(file)
  305.     return
  306.   ##
  307.   ## file= m.GetFile(mod)
  308.   ##  file = "/directory/file"  no extension
  309.   def GetFile(self, mod):
  310.     if not self._mods.has_key(mod):
  311.       return ""
  312.     path= os.path.join(self._base,self._mods[mod])
  313.     return os.path.join(path, mod)
  314.   # m.NoneUsed()
  315.   #   declare no modules are used yet
  316.   def NoneUsed(self):
  317.     self._curr = {}
  318.     return
  319.   # m.Used(mod)
  320.   #   declare that module is used
  321.   def Used(self, mod):
  322.     self._curr[mod] = 1
  323.   # m.IsUsed(mod)
  324.   #   check if module is used
  325.   def IsUsed(self, mod):
  326.     return self._curr.has_key(token)
  327. ##
  328. ## Anchors
  329. ##
  330. class Anchors:
  331.   # a =Anchors(KnownAnchors)
  332.   # a.DeclareModule(mod)    # declare name of current module
  333.   # a.Declare(anchor)        # declare an achor
  334.   # bool = a.IsKnown(anchor)    # returns true if it is an anchor
  335.   # file = a.GetFile(anchor)    # return Href of anchor
  336.   # hidden variables
  337.   # dictionary of anchors 
  338.   #_known = {} # {"name":"module", ...}
  339.   # duplicated anchors
  340.   #_dupli = {} # {"name":[ "module1", "module2", ...], ...}
  341.   # name of current module
  342.   _currentMod ="" # "moduleName"
  343.   # anchor pattern
  344.   _apatn = regex.compile("<a[ \t]+name=\"\(\w[a-zA-Z0-9_---]*\)\">")
  345.   def __init__(self, knownanchor):
  346.     self.Required = {}
  347.     self.Mods = Modules()
  348.     self._known = {}
  349.     self._dupli = {}
  350.     # declare all known anchors
  351.     #for kn in known:
  352.     #  (file, anchlist) = kn 
  353.     #  self.DeclareModule(file)
  354.     #  for anch in anchlist:
  355.     #    self.Declare(anch)
  356.     #  self._currentMod = ""
  357.     for file in knownanchor:
  358.       self.LookForAnchors(file)
  359.     return
  360.   # a.LookForAnchors(file)
  361.   #  try to find known anchors in file
  362.   def LookForAnchors(self, file):
  363.     text = FileRead(file)
  364.     if text == None: # can't read file
  365.       return
  366.     self.DeclareModule(file)
  367.     print "Looking for anchors in ", file
  368.     pos = 0
  369.     while(1):
  370.       pos = self._apatn.search(text, pos)
  371.       if pos<0: break
  372.       pos = pos + len(self._apatn.group(0))
  373. #      print "   Found: ", self._apatn.group(1)
  374.       anchor = self._apatn.group(1)
  375.       # 
  376.       self.Declare(anchor)
  377.       # hack: declare a required function
  378.       if anchor[0:2] == "f_":
  379.         self.Required[anchor] = 1
  380.     self._currentMod = ""
  381.     return
  382.   # a.DeclareModule(mod)
  383.   #  mod = name of current module
  384.   def DeclareModule(self, file):
  385.     self._currentMod = self.Mods.DeclarePath(file)
  386.     return
  387.   # a.Declare(anchor)
  388.   #  anchor = string, name of an anchor detected
  389.   #   Declare anchor, only if not known already
  390.   def Declare(self, anchor):
  391.     if self._currentMod == None  or self._currentMod == "":
  392.       print "ERROR no current module"
  393.       return
  394.     # detect duplicate anchors
  395.     if self._known.has_key(anchor): #  
  396.       if self._known[anchor] != "":  # not a  predeclared anchor
  397.         if not self._dupli.has_key(anchor): self._dupli[anchor] = []
  398.         self._dupli[anchor].append( self._currentMod )
  399.         return
  400.     # declare anchor, only if not known
  401.     self._known[anchor] = self._currentMod
  402.   # a.PreDeclare(anchor)
  403.   #  anchor = string, name of an anchor detected
  404.   # Pre-declare anchor
  405.   def PreDeclare(self, anchor):
  406.     # do not pre-declare if already known
  407.     if self._known.has_key(anchor): return
  408.     # pre-declare anchor, only if not known
  409.     self._known[anchor] = ""
  410.   ## bool= a.IsKnown(anchor)
  411.   ##  return 1 if anchor is really an achor
  412.   def IsKnown(self, anchor):
  413.     return self._known.has_key(anchor)
  414.   ##
  415.   ## file = a.GetFile(anchor)
  416.   ##  file = file reference, for anchor, suitable for use in <A HREF="">
  417.   def GetFile(self, anchor): 
  418.     if not self._known.has_key(anchor):
  419.       print "ERROR unknown anchor: ", anchor
  420.       return ""
  421.     mod = self._known[anchor] # get module name
  422.     return FileHtml(self.Mods.GetFile(mod)) # get file name
  423.   ##
  424.   ## anchor = a.Href(anchor, title) 
  425.   ##   <a href=" file(anchor) # anchor "> title </a>
  426.   def Href(self, anchor, title):
  427.     #return "<a href=\"" + self.GetFile(anchor) + "#" + pointer + "\">" + title + "</a>"
  428.     return "<a href=\"" + "@-@%@-@" + anchor + "@-@%@-@"+ "#" + anchor + "\">" + title + "</a>"
  429.   def LateResolve(self, text):
  430.     liste = string.splitfields(text, "@-@%@-@")
  431.     for l in xrange(1, len(liste), 2):
  432.       liste[l]= self.GetFile(liste[l]) # anchor
  433.     return string.joinfields(liste,"")
  434. ##
  435. ## Translation table: [ (ExpC, Sub ,FFun, Start), ... ]
  436. ##
  437. class Translater:
  438.   ExpC = None # compiler regular expression
  439.   Sub = ""    # substitution string
  440.   FFun = None # function to execute
  441.   Start = 0   # 0 if invalid, -1 if no more position
  442.   Size = 0    # size of match
  443.   ##
  444.   ## Initialise
  445.   ##
  446.   def __init__(self, t):
  447.     (exp , sub, ffun) = t
  448.     self.ExpC = regex.compile(exp)
  449.     self.Sub = sub
  450.     self.FFun = ffun
  451.     self.Reset()
  452.     return
  453.   def Reset(self):
  454.     self.Start = 0
  455.     self.Size = 0
  456.   ##
  457.   ## find next occurence
  458.   ##
  459.   def FindNext(self, text, pos):
  460.     if self.Start < 0:    # no more patterns of that kind
  461.       return -1
  462.     if (self.Start > 0)&(self.Start>=pos):   # position is valid
  463.       return self.Start
  464.     else:
  465.       self.Start = self.ExpC.search(text,pos)  
  466.       if self.Start >= 0:
  467.         self.Size = self.ExpC.match(text,self.Start)
  468.       return self.Start  #last posisition found
  469.   ##
  470.   ## apply function
  471.   ##
  472.   def ApplyFunction(self, infos):
  473.     if self.FFun == None:
  474.       return ""
  475.     return self.FFun(self.ExpC, infos)
  476.   ##
  477.   ## translate some text
  478.   ##
  479.   def Translate(self, text):
  480.     if self.Sub == None:
  481.       return ""
  482.     return regsub.sub(self.ExpC.realpat, self.Sub, text)   
  483. ##
  484. ## Add an anchor to translation table
  485. ##
  486. def TransTableAdd(word):
  487.   t=Translater( ("\\b\("+word+"\)\\b", "<A HREF=\"#\\1\">\\1</A>", None))
  488.   TransTable.append(t)
  489.   return
  490. ##
  491. ## Reset the translation table
  492. ##
  493. def TransTableReset():
  494.   for translater in TransTable:
  495.     translater.Reset()
  496.   return
  497.   
  498. ## Compile translation table from TransDef
  499. #
  500. TransTable = map(Translater,TransDef)
  501.  
  502.  
  503.  
  504.   
  505. ##
  506. ## Infos structure for functions
  507. ##
  508. class Transform:
  509.   FileName = ""  # Obtain the current File name from here
  510.   BasePath = ""
  511.   LineNumber = 0 # Obtain the current Line Number from here
  512.   def __init__(self, file):
  513.     # declare known keywords, for user-defined functions
  514.     self.Keys = KeyWords(KeywordList)
  515.     # declare anchors, for user-defined functions
  516.     self.Anchs = Anchors(KnownAnchors)
  517.     liste = self._getFileList(file)
  518.     self.TransFileList(liste)
  519.     return
  520.   ##
  521.   ## infos._getFileList()
  522.   ##  find, in file,  a list of files to parse
  523.   def _getFileList(self, file): 
  524.     print "Looking for file definitions in %s" % file
  525.     txt = FileRead(file)
  526.     # find file names according to TransPattern
  527.     patn = regex.compile(TransPattern) 
  528.     liste=[]
  529.     pos = 0
  530.     while 1:
  531.       pos = patn.search(txt,pos)
  532.       if pos<0: break
  533.       pos = pos+len(patn.group(0))
  534.       name = patn.group(1)
  535.       print "found ", name
  536.       liste.append( name)
  537.     # save list in HTM  
  538.     res = []
  539.     res.append("<html><head><title>")
  540.     res.append("Modules of Quake-C")
  541.     res.append("</title></head><body>")
  542.     res.append("<base target=examine>")
  543.     res.append("<h2>Quake-C modules</h2>")
  544.     res.append("<small>Generated by <a href=\"qc2html.py\">qc2html.py</a><br>")
  545.     res.append("Underpowered by <a href=\"http://www.python.org\">Python</a>.</small>")
  546.     res.append("<p><ul>")
  547.     for name in liste:
  548.       (root, ext) = os.path.splitext(name) 
  549.       res.append("<li> <a href=\"" + FileHtml(root) + "\">" + name + "</a>")
  550.     res.append("</ul></p>")
  551.     res.append("</body></html>")
  552.     file = self.SaveHtmlRaw(file, string.joinfields(res,"\n"))
  553.     # create a void
  554.     #res = []
  555.     #res.append("<html><body>")
  556.     #res.append("<h2>Quake-C</h2>")
  557.     #res.append("</body></html>")
  558.     #vide = self.SaveHtmlRaw("void", string.joinfields(res,"\n"))
  559.     # create a frame
  560.     res = []
  561.     res.append("<frameset cols=\"30%,*\">")
  562.     res.append("  <frame src=\""+file+"\" name=menu>")
  563.     res.append("  <frame src=\"qk-menu.htm\" name=content>")
  564.     res.append("</frameset>")
  565.     res.append("<noframes>")
  566.     res.append("<h2>Your browser is not frame capable (shame)!</h2>")
  567.     res.append("<p>Maybe you would like the <a href=\""+ file + "\">No frame version</a>.</p>")
  568.     res.append("</noframes>")
  569.     self.SaveHtmlRaw("index", string.joinfields(res,"\n"))   
  570.     # transform all the files in the list
  571.     return liste
  572.   ##
  573.   ## res = self.TransformText(text)
  574.   ##  res= Transformed text
  575.   ##
  576.   def TransformText(self, text):
  577.     #
  578.     # Translate text
  579.     #
  580.     TransTableReset()    # Clear search indexes in translation table
  581.     liste = []        # clear result
  582.     pos = 0         # current position
  583.     end = 0         # current length  
  584.     textlen = len(text) # length of text
  585.     while end < textlen:
  586.       # find closest regular expression in translation table
  587.       pos = textlen
  588.       mintranslater = None
  589.       for translater in TransTable:
  590.         if translater.FindNext(text, end) < 0 : # no more patterns of that kind
  591.           continue #next translater
  592.         if translater.Start < pos: # check is closest pattern
  593.           #print " pos = ", translater.Start, " for ", translater.Sub
  594.           pos = translater.Start
  595.           mintranslater = translater
  596.       # Preserve text that wasn't matched by regular expressions
  597.       liste.append( text[end:pos] )
  598.       # Add result of regular expressions
  599.       if pos >= textlen:  # no regular expressions were matched
  600.         end = textlen       # jump to end of text
  601.       else:               # one regular expression matched
  602.         translater = mintranslater  
  603.         # find end of matched area
  604.         end = pos + translater.Size
  605.         # text[pos:end] = matched expression
  606.         # transform the matched area, with a function
  607.         res = translater.ApplyFunction(self)
  608.         # transform the matched area, with regsub
  609.         res = res + translater.Translate(text[pos:end])
  610.     # append result
  611.         liste.append(res)
  612.     return string.joinfields(liste,"") # faster than + on strings
  613.   ##
  614.   ## Transform a list of files
  615.   ##
  616.   def TransFileList(self, liste):
  617.     #
  618.     print "Transforming all files..."
  619.     processed = []
  620.     for name in liste:
  621.       if name == None or len(name)<1: 
  622.         continue
  623.       file = name
  624.       print "Parsing File", file
  625.       try:
  626.         text= FileRead(file)
  627.       except:
  628.         print "Can't read file " + file 
  629.       if text != None:
  630.         #declare module
  631.         self.LineNumber = 0
  632.         self.FileName = file
  633.         self.BasePath = ""
  634.         # make module current, for anchors
  635.         self.Anchs.DeclareModule(file)
  636.         # transform
  637.         text = self.TransformText(text)
  638.         processed.append((file, text))
  639. #        self.SaveHtml(file, text) # temporary file
  640.     # resolve anchors, once everything is processed
  641.     for pro in processed:
  642.       (file, text) = pro
  643.       text = self.Anchs.LateResolve(text)
  644.       self.SaveHtml(file, text)
  645.     return
  646.   def SaveHtmlRaw(self, file, text):
  647.     file = FileHtml(file)
  648.     print "Saving file: ", file
  649.     try:
  650.       FileWrite( (file , text)) 
  651.     except:
  652.       print "Can't write file " + file
  653.     return file
  654.   def SaveHtml(self, file, text):
  655.     res = TransHtmlHead(file) + text + TransHtmlTrail(file)
  656.     return self.SaveHtmlRaw(file, res)
  657. #
  658.     
  659. #
  660. # Parse all the files
  661. #   
  662. print "Parsing files..."
  663. infos = Transform(ProgsSrc)
  664.