Archiv des LibreOffice- und OpenOffice.org-Wiki

[ÜberSicht] [TitelIndex] [WortIndex] [SeiteFinden

Besondere Lizenzbedingungen für Programmcode

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library 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 Lesser General Public License for more details.

' Created: 2008-05-27
' Last modified: 2008-05-27
' version 0.1 - first conversion from mediawiki to Confluence

' Writer2Confluence
' Creating a new document that contains the current document in Confluence wiki format
' written by Andreas Haupt, andreas.haupt @ sun.com
'
' this macro is based on Writer2MedieaWiki which is based on Writer2MoinMoin !
'   Writer2MediaWiki (c) by Henning Jacobs
'   Writer2MoinMoin (c) by Ian Laurenson, KlausHeinisch and Marc Santhoff
'
' Anyone may run this code.
' If you wish to modify or distribute this code, then
'   you are granted a license to do so under the terms
'   of the Gnu Lesser General Public License.
'   See:  http://www.gnu.org/licenses/lgpl.html
'
'*****************************************************************************

sub main
        Wiki
end sub

const sBOLDSTART = "{*}"
const sBOLDEND = "{*}"
const sUNDERSTART = "{+}"
const sUNDEREND = "{+}"
const sITALICSTART = "{_}"
const sITALICEND = "{_}"
const sMONOSTART = "{{"
const sMONOEND = "}}"
const sSUPERSTART = "{^}"
const sSUPEREND = "{^}"
const sSUBSTART = "{~}"
const sSUBEND = "{~}"
const sDELSTART = "{-}"                 
const sDELEND = "{-}"                   
const sFOOTSTART = ""
const sFOOTEND = ""                             
const sHEADCHAR = "h"
const sHORIZLINE = "----"
const sTABLESTART = ""
const sTABLEEND = ""
const sTABLEROWSTART = ""
const sTABLEROWSEP = ""
const sTABLESEP = "|"
const sTABLEHEADSEP = "||"
const sNEWLINE = "\\"
const sLITERALSTART = "{quote}"
const sLITERALEND = "{quote}"
const sORDEREDLIST = "# "
const sUNORDEREDLIST = "* "
const sHYPERSTART = "["
const sHYPERSEP = "|"
const sHYPEREND = "]"
const sPICTURESTART = "!image '"
const sPICTUREEND = "'!"
const sTYPE_PNG = ".png"        ' [ms]
const sCODESTART = "{code}"     ' [ms]
const sCODEEND = "{code}"               ' [ms]
const sBLANK = " "
const sINDENTCHAR = "  "
const sANCHORSTART = "{anchor:" ' AH
const sANCHOREND = "}"  ' AH
const sDEFAULTCODE = "oobas"

private sLineEnd as string

private s as string
private oVC
private bInCode as boolean
private bFootnote as boolean    ' AH
private sFootnote as string             ' AH
private sFootnoteCount          ' AH
private bFooter as boolean      ' AH
private sFooter as string       ' AH

'This routine processes all html files in a directory tree. 
sub Folders
dim mTextFile(0)

mTextFile(0) = createUnoStruct("com.sun.star.beans.PropertyValue")
mTextFile(0).Name = "FilterName"
mTextFile(0).Value = "Text"

basicLibraries.loadLibrary("Tools")
'ReadDirectories(ByVal AnchorDir As String, bRecursive as Boolean,  bcheckFileType as Boolean, bGetByTitle as Boolean, Optional sFileContent(), Optional sExtension as String)
mFiles = ReadDirectories("/var/www/html/dokuwiki/data/ref", true,  false, false,,"html")

'sStart = "file:///var/www/html/dokuwiki/data/"
'nStart = len(sStart) + 1

for i = 0 to uBound(mfiles)
        sFile = mFiles(i)
        if right(sFile,5) = ".html" then
        oSourceDoc = StarDesktop.loadComponentFromURL(sFile, "_blank", 0, Array())
        oText = oSourceDoc.text

        oDestDoc = StarDesktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, Array() ) 
        oDestText = oDestDoc.getText()
'       oCursor = oDestText.createTextCursor()
        oVC = oDestDoc.currentController.viewCursor
        subWiki(oText)

'       oVC.text.insertString(oVC.text.end, "[[http://api.openoffice.org/docs/common/" & mid(sFile, nStart) & "]]", false)
        oDestDoc.storeAsUrl(left(sFile,len(sFile)-4) & "txt", mTextFile())
        oDestDoc.close(true)

        oSourceDoc.close(false)
'       kill sFile      'Uncomment this line to remove the original file
        end if
next
end sub


'This is the main routine to run on the currently open document
sub Wiki
        globalscope.basiclibraries.loadLibrary("Tools")
        oSourceDoc = thisComponent
        oDestDoc= fnWiki(oSourceDoc)
        'oDestDoc.close(false)
end sub

' A very simple function to extract the footer text
' It does not consider left or right footer nor any particular formatting
sub subFooter(oSourceDoc As Object)
        ' Create a text cursor to get this page's page style
        Dim oTextCursor As Object
        oTextCursor =   oSourceDoc.Text.createTextCursor()
        
        ' Get style families, in particular page style to get to the footer information
        Dim oStyleFamilies As Object
        Dim oThisPageStyle As Object
        oStyleFamilies = oSourceDoc.getStyleFamilies()
        oThisPageStyle = oStyleFamilies.getByName("PageStyles").getByName(oTextCursor.PageStyleName)

        ' Set footer text
        if not isEmpty(oThisPageStyle.FooterText) Then
          sFooter       = oThisPageStyle.FooterText.string
          bFooter = true
        end if
end sub

function fnWiki(oSourceDoc)
        oText = oSourceDoc.text
        'Create a new document
        oNewDoc = StarDesktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, Array() ) 
        oNewText = oNewDoc.getText()
        oCursor = oNewText.createTextCursor()
        'oNewText.insertString(oCursor,sWiki , true)
        oVC = oNewDoc.currentController.viewCursor

        subFooter(oSourceDoc)
        subWiki(oText)
        
        'Copy to clipboard
        'There is a way of doing this via the API but this will do
        oVC.gotoStart(false)
        oVC.gotoEnd(true)
        oFrame = oNewDoc.CurrentController.Frame
        oDispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
        oDispatcher.executeDispatch(oFrame, ".uno:Copy", "", 0, array())
        
        fnWiki = oNewDoc
end function


sub subWiki(oText)
        sLineEnd = chr(10)
        
        'If not oDoc.supportsService("com.sun.star.text.TextDocument") then
        '       msgBox "Sorry - I can only create MediaWiki documents out of text documents", 16, "Error"
        '       exit function
        'end if
        s = ""
        oEnum1 = oText.createEnumeration
        ' loop over all paragraphs
        while oEnum1.hasMoreElements
                oTextElement = oEnum1.nextElement
                ' [ms, detecting graphics attached to paragraph]
                if oTextElement.supportsService("com.sun.star.text.Paragraph") Then
                        en = oTextElement.createContentEnumeration("com.sun.star.text.TextContent")
                        while en.hasMoreElements()
                                el = en.nextElement()
                                if el.supportsService("com.sun.star.text.TextGraphicObject") then
                                        if InStr(el.GraphicURL, "file:///") > 0 OR InStr(el.GraphicURL, "http://") > 0 then
                                                subAddString(sPICTURESTART & FileNameoutofPath(el.GraphicURL) & sPICTUREEND)
                                        else ' embedded picture, no location known
                                                subAddString(sPICTURESTART & el.getName() & sTYPE_PNG & sPICTUREEND)
                                        endif
                                
                                endif
                        wend
                ' [ms, end]     
                        subParagraph(oTextElement)
                elseif oTextElement.supportsService("com.sun.star.text.TextTable") Then
                        subTable(oTextElement)
                else    ' AH
                        Msgbox("Error: a text element which is neither a paragraph nor a table")        ' AH
                end if
        wend
        if bIncode then
                subAddString(sCODEEND & sLineEnd)
        end if
        if bFootnote then       ' AH
                subAddString(sHORIZLINE & sLineEnd)     ' AH
                subAddString(sFootnote & sLineEnd)      ' AH
        end if  'AH
        if bFooter then ' AH
                subAddString(sHORIZLINE & sLineEnd)     ' AH
                subAddString(sFooter & sLineEnd)        ' AH
        end if  'AH
end sub


sub subParagraph(oTextElement)

        oEnum2 = oTextElement.createEnumeration ' AH
        ' loop over all text portions
        while oEnum2.hasMoreElements    ' AH
                oTextPortion = oEnum2.nextElement       ' AH
                if oTextPortion.TextPortionType="Bookmark" Then ' AH
                subAddString( sANCHORSTART & oTextPortion.Bookmark.getName() & sANCHOREND & sBLANK )    ' AH
                end if  ' AH
        wend    ' AH

        nHeadLevel = oTextElement.ParaChapterNumberingLevel + 1
        bInlist = false
        sCode = oTextElement.paraStyleName
        sCode = fnInCode(sCode)
        if bIncode and sCode  = "" then
                subAddString(sCODEEND & sLineEnd)
                bInCode = false
        end if
        if nHeadLevel >= 1 and nHeadLevel <= 5 then
                ' sHead = string(nHeadLevel,  sHEADCHAR)
                sHead = sHEADCHAR & nHeadLevel & "."    ' AH
                subAddString(sLineEnd & sHead & sBLANK & oTextElement.string & sLineEnd)        ' AH
        elseif sCode <> "" then
                if not bInCode then
                        'subAddString(sCODESTART & sCode & sCODEEND & sLineEnd) [ms]
                        subAddString(sCODESTART & sLineEnd) ' [ms]
                        bInCode = true
                end if
                subAddString(oTextElement.string & sLineEnd)
        else
                '[ms, calculate indent, could be based on global and/or document setting]
                static L1Indent as integer
                static IndentLevel as integer
                static LastIndentLevel as integer
                static firstRun as boolean
                if (    (oTextElement.ParaLeftMargin > 0) _
                                AND ( InStr(oTextElement.ParaStyleName,"Index") = 0 ) _
                                AND ( InStr(oTextElement.ParaStyleName,"Hanging") = 0 ) _
                   ) then
                        ' the first found left Margin is indent Level 1 and divisor
                        ' not precise, but how can this be done better?
                        ' standard values are: 1251, 2501, ...
                        if NOT(Left(oTextElement.ParaStyleName, 8) = "Contents") then   
                                if NOT(firstRun) then
                                        firstRun = TRUE
                                        L1Indent = oTextElement.ParaLeftMargin - 1
                                        'msgbox "Setting L1Indent to " & L1Indent
                                end if
                                LastIndentLevel = IndentLevel
                                IndentLevel = (oTextElement.ParaLeftMargin - 1) / L1Indent
                                'msgbox "IndentLevel is " & IndentLevel
                        end if
                else
                        IndentLevel = 0
                end if
                'sINDENT = String(IndentLevel, sINDENTCHAR)     ' AH
                ' Since sINDENTCHAR can be a string and not just a character use this:
                sINDENT = fnString(IndentLevel, sINDENTCHAR)    ' AH
                '[ms, end]
        
                if oTextElement.NumberingIsNumber then 'if not isEmpty(oTextElement.NumberingLevel) then
                '       xray.xray oTextElement
                        bInlist = true
                        'subAddString(string((oTextElement.NumberingLevel + 1) * 2, " ")) ' [ms, indentation]
                        'subAddString(sBLANK & sINDENT) ' [ms, indentation]
                        if instr("0123456789", left(oTextElement.string, 1)) > 0 then
                                subAddString(String(IndentLevel+1, sORDEREDLIST) & sBLANK)
                        else
                                subAddString(String(IndentLevel+1, sUNORDEREDLIST) & sBLANK)
                        end if
                ' [ms, indentation]
                else
                        if (oTextElement.ParaLeftMargin > 0) then subAddString(sINDENT)
                ' [ms, end]
                end if
                oEnum2 = oTextElement.createEnumeration
                ' loop over all text portions
                while oEnum2.hasMoreElements
                        oTextPortion = oEnum2.nextElement
                        subAddString(fnTextPortion(oTextPortion, false))
                wend
                subAddString(sLineEnd)
                if oTextElement.bottomBorder.OuterLineWidth > 0 then
                        subAddString(sHORIZLINE & sLineEnd)
                else
                        if not bInList then subAddString(sLineEnd)
                end if
        end if
end sub


sub subTable(oTable)
        mCellnames = oTable.getCellNames
        
        nMaxCols = 0
        for i = 0 to uBound(mCellNames)
                sCellName = mCellNames(i)
                nCol = 0
                for j = 1 to len(sCellName)
                        ch = mid(sCellName, j, 1)
                        select case ch
                        case "A" to "Z"
                                nCol = nCol * 26 + (asc(ch) - asc("A"))
                        case "0" to "9"
                                'nRow = val(mid(sCellName, j)) - 1
                                exit for
                        end select
                next
                if nCol > nMaxCols then nMaxCols = nCol
        next
        
        nRows = oTable.rows.count - 1
        
        if nMaxCols = 0 then
                for i = 0 to nRows
                        oCell = oTable.getCellByPosition(0, i)
                        oCellEnum = oCell.createEnumeration
                        while oCellEnum.hasMoreElements
                                subParagraph(oCellEnum.nextElement)
                        wend
                next
                exit sub
        end if
                        
        dim mCells(nRows, nMaxCols)
        
        'for i = 0 to nRows
        '       for j = 0 to nmaxCols - 1
        '               mCells(i, j) = ""
        '       next
        'next
        
        for i = 0 to uBound(mCellNames)
                sCellName = mCellNames(i)
                nCol = 0
                for j = 1 to len(sCellName)
                        ch = mid(sCellName, j, 1)
                        select case ch
                        case "A" to "Z"
                                nCol = nCol * 26 + (asc(ch) - asc("A"))
                        case "0" to "9"
                                nRow = val(mid(sCellName, j)) - 1
                                exit for
                        end select
                next
                oCell = oTable.getCellByName(sCellName)
                sCell = " "
                oCellEnum = oCell.createEnumeration
                while oCellEnum.hasMoreElements
                        oTextElement = oCellEnum.nextElement
                        if sCell <> " " then
                                sCell = sCell & sNEWLINE
                        end if
        
                        if oTextElement.ParaStyleName = "Table Heading" then
                                sSep = sTABLEHEADSEP
                        else
                                sSep = sTABLESEP
                        end if
        
                        if oTextElement.NumberingIsNumber then
                                if instr("0123456789", left(oTextElement.string, 1)) > 0 then
                                        sCell = sCell & str(val(oTextElement.string))
                                else
                                        sCell = sCell & "* "
                                end if
                        end if
                        
                        oPortionEnum =  oTextElement.createEnumeration
                        while oPortionEnum.hasMoreElements
                                oTextPortion = oPortionEnum.nextElement
                                sCell = sCell & fnTextPortion(oTextPortion, true)
                        wend
                wend
                sCell =trim(sCell)
                select case oTextElement.paraAdjust
                case com.sun.star.style.ParagraphAdjust.CENTER
                        sCell = "  " & sCell & "  "
                case com.sun.star.style.ParagraphAdjust.RIGHT
                        sCell = "  " & sCell
                end select
                mCells(nRow, nCol) = sCell
        next
        
        subAddString(sTABLESTART & sLineEnd)
        for i = 0 to nRows
                sRow = ""
                sRow = sRow & sTableSep
                bHeading = false
                for j = 0 to nmaxCols
                        if mCells(i, j) <> "" then
                                if j = 0 and instr(mCells(i, j), chr(10)) = 0 then
                                        bHeading = true
                                else
                                        bHeading = false
                                end if
                        end if
                        sRow = sRow & mCells(i, j) & sBlank & sTableSep  'AH
                next
                if bHeading then
                        if i = 0 then
                                sRow = string(6, sHEADCHAR) & mCells(i, 0) & string(6, sHEADCHAR) & sLineEnd & sLineEnd
                        else
                                sRow = string(5, sHEADCHAR) & mCells(i, 0) & string(5, sHEADCHAR) & sLineEnd & sLineEnd
                        end if
                else
                        sRow = sRow & sLineEnd
                end if
        
                'subAddString(sTABLEROWSTART & sRow & sTABLEROWSEP & sLineEnd)
                subAddString(sTABLEROWSTART & sRow & sTABLEROWSEP)
        next
        subAddString(sTABLEEND & sLineEnd)
        
        subAddString(sLineEnd)
end sub


function fnTextPortion(oTextPortion, bInTable as boolean)

        if not isNull(oTextPortion.footnote) then
                'fnTextPortion = sFOOTStart & oTextPortion.footnote.string & sFOOTEND   ' AH
                sFootnoteCount  = sFootnoteCount + 1    ' AH
                fnTextPortion = sSUPERSTART & sFootnoteCount & sSUPEREND        ' AH
                sFootnote       = sFootnote & sLineEnd & fnTextPortion & sBLANK & oTextPortion.footnote.string  ' AH
                bFootnote       = true  ' AH
        elseif oTextPortion.hyperlinkURL <> "" then
                ' Exclude hyperlinks in the table of contents
                ' Confluence will automatically create hyperlinks here
                if NOT(Left(oTextPortion.ParaStyleName, 8) = "Contents") then   ' AH
                        'NB: If the link has separate text portions (i.e. formats inside it) this will repeat the link :(
                        fnTextPortion = sHYPERSTART & oTextPortion.string & sHYPERSEP & fnHyperConvert(oTextPortion.hyperlinkURL) & sHYPEREND   ' AH
                end if  ' AH
        elseif oTextPortion.TextPortionType = "Frame" then
                'The above condition may need to be tightened
                sName = oTextPortion.createContentEnumeration("com.sun.star.text.TextContent").nextElement.name
                if sName <> "" then
                        'fnTextPortion = sBLANK & sPICTURESTART & sName & sPICTUREEND & sBLANK [ms, embedded graphics]
                        fnTextPortion = sBLANK & sPICTURESTART & sName & sTYPE_PNG & sPICTUREEND & sBLANK
                end if
        ' [ms, detect and handle automatically inserted table of contents
        '  not so nice: returns empty lines into the target doc, does this matter?]
        elseif Left(oTextPortion.ParaStyleName, 8) = "Contents" then
                if oTextPortion.ParaStyleName = "Contents Heading" then
                        'fnTextPortion = "[[TableOfContents]]"  ' AH
                        fnTextPortion = sBOLDSTART & "Table of Contents" & sBOLDEND & sLineEnd & "{toc}"        ' AH
                else
                        fnTextPortion = ""
                endif
        ' [ms, end]
        else
                sPortion = oTextPortion.string
                if sPortion = "" then
                        fnTextPortion = ""
                        exit function
                end if
                if bInTable then
                        'In case the separators are actually in the text of the table
                        mSplits = split(sPortion, sTABLESEP)
                        sPortion = join(mSplits, sLITERALSTART & sTABLESEP & sLITERALEND)
                        mSplits = split(sPortion, sTABLEHEADSEP)
                        sPortion = join(mSplits, sLITERALSTART & sTABLEHEADSEP & sLITERALEND)   
                else
                        'In the unlikley event of a paragraph starting and finishing with separator characters.
                        sFirstChar = left(sPortion, 1)
                        if sFirstChar = sTABLESEP or sFirstChar = sTABLEHEADSEP then
                                sPortion = sLITERALSTART & sFirstChar & sLITERALEND & mid(sPortion,2)
                        end if
                end if
                'Convert smart quotes
                ' [ms, fixed char constants]
                mSplits = split(sPortion, chr(8221))
                sPortion = join(mSplits, chr(34))
                mSplits = split(sPortion, chr(8216))
                sPortion = join(mSplits, chr(39))
                mSplits = split(sPortion, chr(8217))
                sPortion = join(mSplits, chr(39))
                'Convert em dashes
                mSplits = split(sPortion, chr(8211))
                sPortion = join(mSplits, chr(45))
                ' [ms, end]
                'In case the text holds any of the formatting charaters make sure that they are treated literally
                mSplits = split(sPortion, sBOLDSTART)
                sPortion = join(mSplits, sLITERALSTART & sBOLDSTART & sLITERALEND)
                mSplits = split(sPortion, sUNDERSTART)
                sPortion = join(mSplits, sLITERALSTART & sUNDERSTART & sLITERALEND)
                mSplits = split(sPortion, sITALICSTART)
                sPortion = join(mSplits, sLITERALSTART & sITALICSTART & sLITERALEND)
                mSplits = split(sPortion, sMONOSTART)
                sPortion = join(mSplits, sLITERALSTART & sMONOSTART & sLITERALEND)
                mSplits = split(sPortion, sSUPERSTART)
                sPortion = join(mSplits, sLITERALSTART & sSUPERSTART & sLITERALEND)
                mSplits = split(sPortion, sSUBSTART)
                sPortion = join(mSplits, sLITERALSTART & sSUBSTART & sLITERALEND)
                mSplits = split(sPortion, sDELSTART)
                sPortion = join(mSplits, sLITERALSTART & sDELSTART & sLITERALEND)
                mSplits = split(sPortion, sFOOTSTART)
                sPortion = join(mSplits, sLITERALSTART & sFOOTSTART & sLITERALEND)
                mSplits = split(sPortion, sPICTURESTART)
                sPortion = join(mSplits, sLITERALSTART & sPICTURESTART & sLITERALEND)
                mSplits = split(sPortion, sCODESTART)
                sPortion = join(mSplits, sLITERALSTART & sCODESTART & sLITERALEND)
                mSplits = split(sPortion, sLineEnd)
                sPortion = join(mSplits, sNEWLINE & " ")
                
                'This is not very elegant as it will produce **bold**//**bold & italic**// 
                'rather than **bold//bold & italic//**
                if oTextPortion.charWeight > 100 then sPortion = sBOLDSTART & sPortion & sBOLDEND
                if oTextPortion.charPosture > 0 then sPortion = sITALICSTART & sPortion & sITALICEND
                if oTextPortion.charUnderline > 0 then sPortion = sUNDERSTART & sPortion & sUNDEREND
                if oTextPortion.charFontPitch = com.sun.star.awt.FontPitch.FIXED then sPortion = sMONOSTART & sPortion & sMONOEND
                if oTextPortion.charEscapement > 0 then sPortion = sSUPERSTART & sPortion & sSUPEREND
                if oTextPortion.charEscapement < 0 then sPortion = sSUBSTART & sPortion & sSUBEND
                if oTextPortion.charStrikeOut > 0 then sPortion = sDELSTART & sPortion & sDELEND
                fnTextPortion = sPortion
        end if
end function


function fnHyperConvert(sURL as string) as string
const sINTLINK = "index.php?page="

'sIDL = "vnd.sun.star.help://sbasic/text/sbasic/shared/"
'sGuide = "file:///var/www/html/dokuwiki/DevelopersGuide"
'nIDL = len(sIDL)
'nGuide = len(sGuide)
nStartInternalLink = instr(sUrl, sINTLINK)
        if nStartInternalLink > 0 then
                nStartInternalLink = nStartInternalLink + len(sINTLINK)
                fnHyperConvert = mid(sURL, nStartInternalLink)
        'elseif sIDL = left(sURL, nIDL) then
        '       sTemp = mid(sURL, nIDL + 1)
        '       sTemp = left(stemp,(instr(sTemp, ".xhp")-1))
        '       mSplits = split(sTemp, ".html")
        '       sTemp = join(mSplits, "")
        '       mSplits = split(sTemp, "/")
                fnHyperConvert = sTemp  'join(mSplits, ":")
        'elseif left(sURL, nGuide) = sGuide then
        '       sTemp = "http://api.openoffice.org/docs/DevelopersGuide" & mid(sURL, nGuide + 1)
        '       mSplits = split(sTemp, ".xhtml")
        '       fnHyperConvert = join(mSplits, ".htm")
        else
                fnHyperConvert = sURL
        end if
end function


function fnInCode(sParaStyleName)
        if sParaStyleName = "Preformatted Text" then
                fnInCode = sDEFAULTCODE
        else
                fnInCode = ""
        end if
end function


sub subAddString(sAdd as string)

        if sAdd = sLineEnd then 'A paragraph can't be > 64k therefore this hack makes sure of some paragraph breaks
                oVC.text.insertControlCharacter(oVC, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False)
        else
                oVC.text.insertString(oVC, sAdd , false)
        end if
end sub

' Similar to String() but it repeats a whole string not just a character
function fnString(n As Long,sString As String)
        for i=1 to n
                fnString = fnString & sString
        next
end function


KategorieMakro


LizenzBedingungen | AnbieterKennzeichnung | DatenschutzErklärung | Stand: 2013-04-28