Code Search for Developers
 
 
  

xmlgenerator.rb from The Nebula Device at Krugle


Show xmlgenerator.rb syntax highlighted

=begin
XML file format:

  <class name='nGfxServer2' package='gfx2' parent='nroot'>
    <properties>
      <property name="propertyname">
        <doc>...</doc>
        <getterslist>
          <getter [type="count"] name="gettername" fourCC="GJNT">
            [<doc>...</doc>]
          </getter>
          ...
        </getterlist>
        <setterlist>
          <setter type="begin|add|end" name="settername" fourCC="BJNT">
            [<doc>...</doc>]
          </setter>
          ...
        </setterlist>
        <valueformat>
          <value name="valuename" type="integer|string|..." editor="text_input|slider|select|checkbox" [index="yes"]>
            [<doc>...</doc>]
          </value>
          <value name="valuename" type="integer|string|...">
            [<doc>...</doc>]
          </value>
          <value name="valuename" type="string" restricted="enum">
            <enum name="dx7"/>
            <enum name="dx8"/>
            ...
          </value>
          ...
        </valueformat>
      </property>
      <property>
        ...
      </property>
    </properties>
    <methods>
      <method name="methodname" fourCC="GHTR">
        [<doc>...</doc>]
        <output>
          <value name="valuename" type="integer|string|...">
            [<doc>...</doc>]
          </value>
          <value name="valuename" type="string" restricted="enum">
            <enum name="dx7"/>
            <enum name="dx8"/>
            ...
          </value>
          ...
        </output>
        <input>
          <value name="valuename" type="integer|string|...">
            [<doc>...</doc>]
          </value>
          <value name="valuename" type="string" restricted="enum">
            <enum name="dx7"/>
            <enum name="dx8"/>
            ...
          </value>
          ...
        </input>
      </method>
      <method>
        ...
      </method>
    </methods>
  </class>

Command comments format:

/**
    @cppclass <cpp class name>
    
    @superclass <cpp parent class name>

    @classinfo <documentation>
*/

getter/setter:
/**
    @property <property name>

    @format
      type(name;attr1=val1;attr2=val2..) -- comment
      type(name;attr1=val1;attr2=val2..) -- comment
      ...

    @info <documentation>
*/

/**
    @cmd <command name>

    @cmdtype <getter|[count], setter|[begin,add,end]>

    @property <property name>

    @info <documentation>
*/

other commands (methods):
/**
    @cmd <command name>

    @input
      type(name;attr1=val1;attr2=val2..) -- comment
      type(name;attr1=val1;attr2=val2..) -- comment
      ...

    @output
      type(name;attr1=val1;attr2=val2..) -- comment
      type(name;attr1=val1;attr2=val2..) -- comment
      ...

    @info <documentation>
*/

attr=val:
attr - name of the attribute
val - attribute value: val=val1[,val2...,valN]
For example:
  index=yes - used if some property is indexed (array or you can get it by name)

=end

require 'rexml/document'
include REXML

INDIR = "../code/"
OUTDIR = "../code/"

INDENT = "  "

CLASS_REGEX = /^\s*(template\s*<\s*([^,>]+(?:\s*,[^,>]+)*)\s*>\s+)?class\s+(\w[\w\d]*)(\s*:\s*(public|private|protected\s+)?(.+(\s*<\s*[^>]+\s*>)?))?(\s*\{)?\s*$/
ENUM_REGEX = /^\s*enum(\s+\w[\w\d]*)?(\s*\{)?\s*$/
UNION_REGEX = /^\s*union(\s+\w[\w\d]*)?(\s*\{)?\s*$/
STRUCT_REGEX = /^\s*struct(\s+\w[\w\d]*)?(\s*\{)?\s*$/
CLASSCONSTRUCTOR_REGEX = /^\s*(\w[\w\d]*)\s*\(([^\)]+)?\)\s*;\s*(.*)$/
CLASSDESTRUCTOR_REGEX = /^\s*(virtual\s+)?(~\w[\w\d]*)\s*\(\s*\)\s*;\s*(.*)$/
CLASSMETHOD_REGEX = /^\s*(.+?)(\*|&|\s+)(\w[\w\d]*)\s*\(([^\)]+)?\)\s*(const\s*)?;\s*(.*)$/
CLASSPROPERTY_REGEX = /^\s*(.+?)(\*|&|\s+)(\w[\w\d]*)\s*;\s*(.*)$/

CMDFUNCTIONDECL_REGEX = /^\s*static\s+void\s+n_(\w[\w\d]*)\s*\(\s*void\s*\*.*,\s*nCmd\s*\*.*\)\s*;/
INITCMDFUNCTIONDEF_REGEX = /^.*n_initcmds\s*\(.*\)\s*/
CMDFUNCTIONDEF_REGEX = /^.*n_(\w[\w\d]*)\s*\(\s*void\s*\*.*,\s*nCmd\s*\*.*\)\s*/
ADDCMDFUNCTION_REGEX = /^\s*\w[\w\d]*\s*->\s*AddCmd\s*\(\s*"([a-z]+)_([a-z\d]+)_([a-z]+)"\s*,\s*'(....)'\s*,\s*n_([a-z\d]+)\)\s*;/
CMDTYPES_HASH = {"v" => "void", "i" => "integer", "f" => "float", "s" => "string", "b" => "boolean", "o" => "object"}

def getElement(parentElement, elementName, addNew = true)
  result = nil
  result = parentElement.elements[elementName]
  result = parentElement.add_element(elementName) if !result && addNew
  return result
end

def getElementWithAttribute(parentElement, elementName, attrName, attrValue, addNew = false)
  result = nil
  parentElement.each_element_with_attribute(attrName, attrValue, 1, elementName){|e|
    result = e
  }
  result = parentElement.add_element(elementName, {attrName => attrValue}) if !result && addNew
  return result
end
  
class Processor
  def initialize
    @indent = 0
    @newline = true
  end
  
  def dispatchExtComment(hf, firstStr)
    commentStr = ""
    curStr = firstStr
    while !(curStr =~ /^(.*?)\*\//)
      commentStr += curStr
      curStr = hf.gets
    end
    commentStr += $1
    return commentStr
  end
    
  def setDirs(inD, outD)
    @inDir = inD
    @outDir = outD
  end
  
  def showProcessInfo(modName, packName, fileName)
    $stderr.print " " * 79 + "\r"
    formatStr = "m[%d/%#{@modsCount.to_s.size}d] #{modName}, p[%d/%#{@packsCount.to_s.size}d] #{packName}, f[%d/%#{@filesCount.to_s.size}d] #{fileName}\r"
    $stderr.printf formatStr, @modsCount, @curModNum, @packsCount, @curPackNum, @filesCount, @curFileNum
  end
  
  alias oldPrint print
  alias oldPuts puts
  
  def print(*s)
    if s
      oldPrint INDENT * @indent if @newline
      str = s.join
      @newline = (str[-1..-1] == "\n")
      oldPrint str
    end
  end
  
  def puts(*s)
    if s
      print s, "\n"
      #oldPrint "\n"
      #@newline = true
    end
  end
  
  attr_reader :indent
  def indentInc
    @indent += 1    
  end
  
  def indentDec
    @indent -= 1 if @indent > 0
  end

  def processModule(mod, outShiftDir = "")
  end

  def process(modules)
    if !(modules && modules.index("nebula2") == nil)
      $stderr.puts "Main package processing."
      puts "--------<<Start main>>----------"
      Dir.chdir(@inDir)
      @modsCount = 1
      @curModNum = 1
      processModule("nebula2")
      puts "---------<<End main>>-----------"
    end

    $stderr.puts "\nContrib modules processing."
    puts "\n--------<<Start contrib>>----------"
    Dir.chdir(@inDir + "contrib")
    @curModNum = 1
    @modsCount = Dir["*"].size
    Dir["*"].sort.each {|mod|
      if FileTest.directory?(mod) &&
         mod != "." && mod != ".." && mod != "CVS" &&
         !(modules && modules.index(mod) == nil)
      then
        processModule(mod, "contrib/")
      end
      @curModNum += 1
    }
    puts "---------<<End contrib>>-----------"
  end
end

#--------------------------------------------------------------------------------------

class CmdProcessor < Processor
  def initialize
    super
    @fourCC = []
  end
  
  def saveFourCC
    @fourCC.sort!{|a, b| a[0]<=>b[0]}
    
    fourCCElements = Element.new("elements")
    fourCCElements.add_attribute("size", @fourCC.size.to_s)
    prevCode = nil
    @fourCC.each{|e|
      code = e[0]
      if prevCode && prevCode == code
        code += "(duplicate)"
      end
      fourCCElements.add_element("fourCC", {"code" => code, "cmd" => e[1], "class" => e[2], "package" => e[3]})
      prevCode = e[0]
    }
    fourCCDoc = Document.new
    fourCCDoc.add_element(fourCCElements)
    Dir.chdir(@outDir)
    puts "Writing fourCC file (" + @outDir + "fourCC.xml)"
    File.open("fourCC.xml", "w"){|f|
      fourCCDoc.write(f, 2, false, true)
    }
  end
  
  def getFourCC(cmdName, pack)
    res = @fourCC.find{|e| e[1] == cmdName && e[3] == pack}
    return res[0] if res
    return "----"
  end
  
  def dispatchDoc(docStr)
    indentInc
    
    atBlocks = {}
    restBlocks = ""
    atName = ""
    needEnd = ""
    
    docStr.each{|line|
      #line.strip!
      if line != ""
        if line =~ /^\s*@\s*(\w[\w\d]*)\s+(.*)\s*$/
          if needEnd == ""
            atName = $1
            if $2 then atBlocks[atName] = $2 + " " else atBlocks[atName] = "" end
            needEnd = "verbatim" if line == "verbatim"
            needEnd = "code" if line == "code"
          else
            if $1 == "end" + needEnd
              needEnd = ""
            else
              if atName != ""
                atBlocks[atName] += line + " "
              else
                restBlocks += line + " "
              end
            end
          end
        elsif atName != ""
          atBlocks[atName] += line + " "
        else
          restBlocks += line + " "
        end
      else
        atName = ""
      end
    }
    
    indentDec
    return [atBlocks, restBlocks]
  end
  
  def dispatchCmdParamDesc(descStr, valueFormatElement)
    indentInc
    
    valueElement = valueFormatElement.add_element("value")
    if descStr.strip == 'v'
      valueElement.add_attribute("type", "void")
    elsif descStr =~ /^([ifsbo]+)\s*\(\s*(\w[\w\d]*)\s*(;\s*\w[\w\d]*\s*=\s*[^;]+\s*)*\)\s*(?:--\s*(.+)\s*)?$/
      typeSize = $1.size
      if typeSize > 1
        if (typeSize <= 4) && ($1 == 'f' * typeSize) # fff or ffff
          valueElement.add_attribute("type", "vector" + typeSize.to_s)
        else
          valueElement.add_element("error").add_text("Wrong parameter type!")
        end
      else
        valueElement.add_attribute("type", CMDTYPES_HASH[$1])
      end
      valueElement.add_attribute("name", $2)
      valueElement.add_element("doc").add_text(CData.new($4)) if $4
      if $3
        attrList = $3.slice(1..-1)
        attrList.split(';').each{|av|
          if av =~ /^\s*(\w[\w\d]*)\s*=\s*(.+?\s*(,.+?)?)\s*$/
            attrName = $1
            if $3
              valueElement.add_attribute("restricted", attrName)
              $2.split(',').each{|e|
                valueElement.add_element(attrName, {"name" => e.strip})
              }
            else
              valueElement.add_attribute($1, $2)
            end
          else
            valueElement.add_element("error").add_text("Wrong <attr=val> statement: " + attrList)
          end
        }
      end
    else
      valueElement.add_element("error").add_text("Wrong parameter description!")
    end

    indentDec
  end
  
  def processCmdFile(fileName, destDir, pack)
    indentInc
    
    fileName =~ /(.+)_cmds.cc/
    xmlFileName = $1
    
    begin
      File.open(fileName, "r"){|cf|
        #puts file + " cmds present"
        scriptElement = Element.new("class")
        scriptElement.add_attribute("name", "")
        scriptElement.add_attribute("parent", "")
        scriptElement.add_attribute("package", pack)
        
        scriptPropertiesElement = scriptElement.add_element("properties")
        scriptMethodsElement = scriptElement.add_element("methods")
        while cf.gets
          case $_
            when CMDFUNCTIONDECL_REGEX
              # do nothing
            when ADDCMDFUNCTION_REGEX
              @fourCC.push [$4, $2, $5, pack]
            when /^\s*\/\*\*(.*)$/ #extract documentation
              commentLine = dispatchExtComment(cf, $1)
              dDoc = dispatchDoc(commentLine)
              atBlocks = dDoc[0]
              restBlocks = dDoc[1].strip
              scriptPropertyElement = nil
              if atBlocks.has_key? "cppclass"
                superClass = atBlocks["superclass"].strip
                classInfo = atBlocks["classinfo"].strip
                
                if classInfo && classInfo != ""
                  docElement = scriptElement.add_element("doc")
                  docElement.add_text(CData.new(classInfo))
                end
                scriptElement.attributes["name"] = atBlocks["cppclass"].strip
                scriptElement.attributes["parent"] = superClass if superClass && superClass != ""
              elsif atBlocks.has_key? "cmd"
                if atBlocks.has_key? "property"
                  cmdName = atBlocks["cmd"].strip
                  cmdType = atBlocks["cmdtype"].strip
                  propertyName = atBlocks["property"].strip
                  info = atBlocks["info"].strip
                  
                  scriptPropertyElement = getElementWithAttribute(scriptPropertiesElement, "property", "name", propertyName, true)
                  
                  fourCC = getFourCC(cmdName, pack)
                  type = cmdType.split
                  if type[0] == "getter"
                    getterListElement = getElement(scriptPropertyElement, "getterlist")
                    getterElement = getElementWithAttribute(getterListElement, "getter", "name", cmdName, true)
                    getterElement.add_attribute("fourCC", fourCC)
                    if info
                      docElement = getElement(getterElement, "doc")
                      docElement.add_text(CData.new(info))
                    end
                    if type[1] && type[1] == "count"
                      getterElement.add_attribute("type", "count")
                    end
                  elsif type[0] == "setter"
                    setterListElement = getElement(scriptPropertyElement, "setterlist")
                    setterElement = getElementWithAttribute(setterListElement, "setter", "name", cmdName, true)
                    setterElement.add_attribute("fourCC", fourCC)
                    if info
                      docElement = getElement(setterElement, "doc")
                      docElement.add_text(CData.new(info))
                    end
                    if type[1] && (type[1] == "begin" || type[1] == "add" || type[1] == "end")
                      setterElement.add_attribute("type", type[1])
                    end
                  else
                    docElement = getElement(scriptPropertyElement, "doc")
                    docElement.add_element("error").add_text("Wrong command type!")
                  end
                elsif atBlocks.has_key?("output") && atBlocks.has_key?("input")
                  cmdName = atBlocks["cmd"].strip
                  output = atBlocks["output"].strip
                  input = atBlocks["input"].strip
                  info = atBlocks["info"].strip
                  
                  scriptMethodElement = getElementWithAttribute(scriptMethodsElement, "method", "name", cmdName, true)
                  scriptMethodElement.add_attribute("fourCC", getFourCC(cmdName, pack))
                  
                  if info
                    docElement = getElement(scriptMethodElement, "doc")
                    docElement.add_text(CData.new(info))
                  end
                  
                  outputElement = getElement(scriptMethodElement, "output")
                  output.each{|l|
                    dispatchCmdParamDesc(l.strip, outputElement)
                  }
                  
                  inputElement = getElement(scriptMethodElement, "input")
                  input.each{|l|
                    dispatchCmdParamDesc(l.strip, inputElement)
                  }
                end
              elsif atBlocks.has_key? "property"
                propertyName = atBlocks["property"].strip
                format = atBlocks["format"].strip
                info = atBlocks["info"].strip
                
                scriptPropertyElement = getElementWithAttribute(scriptPropertiesElement, "property", "name", propertyName, true)
                
                if info
                  docElement = getElement(scriptPropertyElement, "doc")
                  docElement.add_text(CData.new(info))
                end
                if format
                  valueFormatElement = getElement(scriptPropertyElement, "valueformat")
                  format.each{|l|
                    dispatchCmdParamDesc(l.strip, valueFormatElement)
                  }
                  # trick
                  valueFormatElement.each_element("value"){|valueElement|
                    case valueElement.attributes["type"]
                      #when "void"
                      when "integer"
                        valueElement.add_element("editor", {"type" => "text_input"})
                      when "float"
                        valueElement.add_element("editor", {"type" => "slider"})
                      when "string"
                        valueElement.add_element("editor", {"type" => "select"})
                      when "boolean"
                        valueElement.add_element("editor", {"type" => "checkbox"})
                      when "object"
                        valueElement.add_element("editor", {"type" => "text_input"})
                    end
                  }
                end
              end
            when INITCMDFUNCTIONDEF_REGEX
              # do nothing
            when CMDFUNCTIONDEF_REGEX
              # do nothing
          end
        end
        
        if scriptMethodsElement.size + scriptPropertiesElement.size > 0
          puts "There are script commands for " + xmlFileName
          
          xmlScriptFile = destDir + "/" + xmlFileName + ".xml"
          
          xmlScriptDoc = Document.new
          xmlScriptDoc.add_element(scriptElement)
          File.open(xmlScriptFile, "w"){|xf| xmlScriptDoc.write(xf, 2, false, true) }
          indentDec
          return scriptMethodsElement.size + scriptPropertiesElement.size
        else
          indentDec
          return 0
        end
      }
    rescue SystemCallError
      indentDec
      return 0
    end
    
    indentDec
    return 0
  end

  def processModule(mod, outShiftDir = "")
    puts "\nProcess: " + mod
    
    indentInc
    
    outPath = @outDir + outShiftDir + mod
    
    begin
      Dir.mkdir(outPath)
      rescue SystemCallError
        #do nothing
    end
    
    begin
      Dir.mkdir(outPath + "/desc")
      rescue SystemCallError
        #do nothing
    end
    
    begin
      Dir.chdir(mod + "/src")
      rescue SystemCallError
        puts "Error (" + $! + ") while changing to <inc> dir:\n" + @inDir + mod + "/src\n"
        return
    end
        
    @curPackNum = 1
    @packsCount = Dir["*"].size
    packagesProcessed = 0
    Dir["*"].sort.each {|pack|
      if !FileTest.file?(pack) && pack != "." && pack != ".." && pack != "CVS"
        puts "Module: " + pack

        begin
          Dir.mkdir(outPath + "/desc/" + pack)
          rescue SystemCallError
            #do nothing
        end
    
        begin
          Dir.chdir(pack)
          rescue SystemCallError
            puts "Error (" + $! + ") while changing to <mod> dir:\n" + @inDir + mod + "/src/" + pack + "\n"
            next
        end
        
        # files processing
        @curFileNum = 1
        @filesCount = Dir["*.h"].size # n*.h
        elementsProcessed = 0
        Dir["*_cmds.cc"].sort.each{|file| # n*.h
          showProcessInfo(mod, pack, file)
          scriptElement = processCmdFile(file, outPath + "/desc/" + pack, pack)
          @curFileNum += 1
        }
        Dir.chdir("..")
      end
      @curPackNum += 1
    }
    Dir.chdir("../..")
    
    indentDec
  end
end

#--------------------------------------------------------------------------------------

class CCProcessor < Processor
  def dispatchComment(commentStr)
    return [$2.strip, false] if commentStr =~ /^\/\/(\/?<?)?(.+)$/      
    return [$1.strip, true]  if commentStr =~ /^\/\*(.*)$/
    return [nil, false]
  end
  
  def dispatchMethodOut(methodElement, outStr)
    outElement = Element.new("out", methodElement)
    if outStr =~ /^\s*(virtual\s+)?(friend\s+)?(static\s+)?(inline\s+)?(.+)\s*(\*|&)?$/
      methodElement.add_attribute("virtual", "yes") if $1
      methodElement.add_attribute("friend", "yes") if $2
      methodElement.add_attribute("static", "yes") if $3
      methodElement.add_attribute("inline", "yes") if $4
      typeStr = $5
      typeStr += $6 if $6
      dispatchType(outElement, typeStr)
    else
      outElement.add_attribute("outerror", outStr)
    end
    return outElement
  end
  
  def dispatchMethodIn(methodElement, inStr, num)
    inElement = Element.new("in", methodElement)
    if inStr =~ /^\s*(.+?)(\*|&|\s+)(\w[\w\d]*(?:\[\s*\])?)(\s*=\s*([^\)]+))?$/
      dispatchType(inElement, $1.strip + $2.strip)
      inElement.add_attribute("name", $3)
      inElement.add_attribute("defval", $5) if $4
    elsif inStr =~ /^\s*(.+?)\s*(\*|&)?$/
      typeStr = $1.strip
      typeStr += $2 if $2
      dispatchType(inElement, typeStr)
      inElement.add_attribute("name", "")
    else
      inElement.add_attribute("inerror", inStr)
    end
    inElement.add_attribute("num", num.to_s)
    return inElement
  end
  
  def dispatchType(propertyElement, typeStr)
    if typeStr =~ /^\s*(static\s+)?(const\s+)?(.+)\s*(\*|&)?$/
      propertyElement.add_attribute("static", "yes") if $1
      propertyElement.add_attribute("const", "yes") if $2
      t = $3
      t += $4 if $4
      propertyElement.add_attribute("type", t)
    else
      propertyElement.add_attribute("typeerror", typeStr)    
    end
  end
  
  def processEnum(hf, inEnum)
    while hf.gets
      if !inEnum
        inEnum = true if $_ =~ /^\s*\{/
      elsif $_ =~ /^\s*};/
        return
      end
    end
  end
  
  def processUnion(hf, inUnion)
    while hf.gets
      if !inUnion
        inUnion = true if $_ =~ /^\s*\{/
      elsif $_ =~ /^\s*};/
        return
      end
    end
  end
  
  def processStruct(hf, inStruct)
    while hf.gets
      if !inStruct
        inStruct = true if $_ =~ /^\s*\{/
      elsif $_ =~ /^\s*};/
        return
      end
    end
  end
  
  def processClass(hf, xmlElement, nameOfClass, inClass, modName)
    indentInc
    
    elementsProcessed = 1
    commentLine = ""
    extCommentMode = false
    accessMode = "private"
    methodsElement = Element.new("methods", xmlElement)
    propertiesElement = Element.new("properties", xmlElement)
    while hf.gets
      if !inClass
        inClass = true if $_ =~ /^\s*\{/
      else
        case $_
          when /^\s*};/
            break
          when /^\s*(public|private|protected)\s*:/ # public:, private: or protected: accessors
            accessMode = $1
            commentLine = ""
          when /^\s*\/\/\/?(.*)$/ # comment
            commentLine += $1
          when /^\s*\/\*(.*)/ # extended comment
            commentLine += dispatchExtComment(hf, $1)
          when CLASSCONSTRUCTOR_REGEX
            methodElement = methodsElement.add_element("constructor", {"name"=>$1, "access"=>accessMode})
            methodElement.add_element("doc").add_text(commentLine.strip) if commentLine != ""
            commentLine = ""
            n = 1
            $2.split(",").each{|inBlock|
              dispatchMethodIn(methodElement, inBlock.strip, n)
              n += 1
            } if $2
          when CLASSDESTRUCTOR_REGEX
            methodElement = methodsElement.add_element("destructor", {"name"=>$2, "access"=>accessMode})
            methodElement.add_element("doc").add_text(commentLine.strip) if commentLine != ""
            commentLine = ""
            methodElement.add_attribute("virtual", "yes") if $1
          when CLASSMETHOD_REGEX
            methodElement = methodsElement.add_element("method", {"name"=>$3, "access"=>accessMode})
            methodElement.add_element("doc").add_text(commentLine.strip) if commentLine != ""
            commentLine = ""
            methodElement.add_attribute("const", "yes") if $5
            outStr = $1.strip
            outStr += $2.strip if $2
            dispatchMethodOut(methodElement, outStr)
            n = 1
            $4.split(",").each{|inBlock|
              dispatchMethodIn(methodElement, inBlock.strip, n)
              n += 1
            } if $4
          when CLASSPROPERTY_REGEX
            propertyElement = propertiesElement.add_element("property", {"name"=>$3})
            typeStr = $1.strip
            typeStr += $2.strip if $2
            dispatchType(propertyElement, typeStr)
            p = dispatchComment($4.strip)
            if p[0] then
              if !p[1]
                commentLine += p[0]
              else
                commentLine += dispatchExtComment(hf, p[0])
              end
            end
            propertyElement.add_element("doc").add_text(commentLine.strip) if commentLine != ""
            commentLine = ""
          when ENUM_REGEX
            processEnum(hf, $2 != nil)
            commentLine = ""
          when UNION_REGEX
            processUnion(hf, $2 != nil)
            commentLine = ""
          when STRUCT_REGEX
            processStruct(hf, $2 != nil)
            commentLine = ""
          when CLASS_REGEX
            nameOfSubClass = $3
            parentClass = $4 ? $6 : nil
            xmlSubElement = Element.new("class", xmlElement)
            xmlSubElement.add_element("template", {"val"=>$2}) if $1
            xmlSubElement.add_attribute("name", nameOfSubClass)
            if parentClass
              parentElement = xmlSubElement.add_element("parent", {"class" => parentClass})
              if $5
                parentElement.add_attribute("access", $5.strip)
              else
                parentElement.add_attribute("access", "private") #???
              end
            end
            xmlSubElement.add_attribute("package", modName)
            xmlSubElement.add_attribute("access", accessMode)
            xmlSubElement.add_element("doc").add_text(commentLine.strip) if commentLine != ""
            elementsProcessed += processClass(hf, xmlSubElement, nameOfSubClass, $8 != nil, modName)
            commentLine = ""
        end
      end
      @lineNum += 1
    end
    
    indentDec
    return elementsProcessed
  end

  def processFile(hFile, destDir, modName)
    indentInc
    
    elementsProcessed = 0
    commentLine = ""
    nameOfClass = nil
    parentClass = nil
    cppElement = Element.new("classes")
    xmlElement = nil
    @lineNum = 1
    @indent = 2
    File.open(hFile, "r"){|hf|
      while hf.gets
        if $_ =~ /^\s*\/\*\*(.*)/
          commentLine += dispatchExtComment(hf, $1)
        elsif $_ =~ CLASS_REGEX
          nameOfClass = $3
          parentClass = $4 ? $6 : nil
          xmlElement = Element.new("class", cppElement)
          xmlElement.add_element("doc").add_text("\n" + commentLine + "      ") if commentLine != ""
          xmlElement.add_element("template", {"val"=>$2}) if $1
          xmlElement.add_attribute("name", nameOfClass)
          if parentClass
            parentElement = xmlElement.add_element("parent", {"class" => parentClass})
            if $5
              parentElement.add_attribute("access", $5.strip)
            else
              parentElement.add_attribute("access", "private") #???
            end
          end
          xmlElement.add_attribute("package", modName)
          elementsProcessed += processClass(hf, xmlElement, nameOfClass, $8 != nil, modName)
          commentLine = ""
        end
      @lineNum += 1
      end
    }
    
    if elementsProcessed > 0
      xmlCppFile = destDir + "/" + hFile[0..-3] + ".xml"
      
      begin
        Dir.mkdir(destDir)
        rescue SystemCallError
          #do nothing
      end

      xmlCppDoc = Document.new
      xmlCppDoc.add_element(cppElement)
      File.open(xmlCppFile, "w"){|xf| xmlCppDoc.write(xf, 2, false, true) }      
    end
    
    puts elementsProcessed.to_s + " class" + (elementsProcessed != 1 ? "es" : "  ") + " in " + hFile
    
    indentDec
    return elementsProcessed
  end
  
  def processModule(mod, outShiftDir = "")
    puts "\nProcess: " + mod
    
    indentInc
    
    outPath = @outDir + outShiftDir + mod
    
    begin
      Dir.mkdir(outPath)
      rescue SystemCallError
        #do nothing
    end
    
    begin
      Dir.mkdir(outPath + "/desc")
      rescue SystemCallError
        #do nothing
    end
    
    begin
      Dir.chdir(mod + "/inc")
      rescue SystemCallError
        puts "Error (" + $! + ") while changing to <inc> dir:\n" + @inDir + mod + "/inc\n"
        return
    end
        
    @curPackNum = 1
    @packsCount = Dir["*"].size
    packagesProcessed = 0
    Dir["*"].sort.each {|pack|
      if !FileTest.file?(pack) && pack != "." && pack != ".." && pack != "CVS"
        puts "Module: " + pack

        begin
          Dir.mkdir(outPath + "/desc/" + pack)
          rescue SystemCallError
            #do nothing
        end
    
        begin
          Dir.chdir(pack)
          rescue SystemCallError
            puts "Error (" + $! + ") while changing to <mod> dir:\n" + @inDir + mod + "/inc/" + pack + "\n"
            next
        end
        
        # files processing
        @curFileNum = 1
        @filesCount = Dir["*.h"].size # n*.h
        elementsProcessed = 0
        Dir["*.h"].sort.each{|file| # n*.h
          showProcessInfo(mod, pack, file)
          elementsProcessed += processFile(file, outPath + "/desc/" + pack + "/cpp", mod)
          @curFileNum += 1
        }
        if elementsProcessed == 0
          Dir.delete(outPath + "/desc/" + pack)
        else
          packagesProcessed += 1
        end
        Dir.chdir("..")
      end
      @curPackNum += 1
    }
    if packagesProcessed == 0
      Dir.delete(outPath + "/desc/")
    end
    Dir.chdir("../..")
    
    indentDec
  end
end

workdir = Dir.pwd.sub(/\/bin$/, "/code/")

modules = ["nebula2"]
Dir.chdir(workdir + "contrib")
Dir["*"].sort.each {|mod|
  if FileTest.directory?(mod) && mod != "." && mod != ".." && mod != "CVS"
    modules.push(mod)
  end
}
Dir.chdir(workdir + "../bin/")

selmodules = nil
print "\nChoose action:\n1. Process all modules.\n2. Select modules to process.\n: "
choice = STDIN.gets

if choice.to_i == 2
  selmodules = []
  modules.each_with_index{|m, i|
    printf "%3d: %s\n", i + 1, m
  }
  puts "Choose modules number separated by space:"
  STDIN.gets.split.each{|n|
    num = n.to_i
    if num > 0 && num <= modules.size
      selmodules.push(modules[num - 1])
    end
  }
end

$stdout = File.open("xmlgenerator.log", "w")

$stderr.puts "\n---------<<Cpp processing>>----------"
ccp = CCProcessor.new
ccp.setDirs(workdir, workdir)
ccp.process selmodules

$stderr.puts "\n\n---------<<Cmd processing>>----------"
cmdp = CmdProcessor.new
cmdp.setDirs(workdir, workdir)
cmdp.process selmodules
cmdp.saveFourCC

$stdout.close

$stderr.puts "\n\nPress ENTER to exit..."
STDIN.getc




See more files for this project here

The Nebula Device

Realtime 3D game/visualization engine, written in C++, scriptable through Tcl/Tk, Python and Lua. Supports D3D and OpenGL for rendering, runs under Linux and Windows.

Project homepage: http://sourceforge.net/projects/nebuladevice
Programming language(s): C,C++,Python
License: other

  linux/
    README
  macosx/
    README
  win32/
    nebula.ico
  win32d/
  xmlgenerator.rb