Skip to content
This repository has been archived by the owner on Feb 17, 2018. It is now read-only.

Commit

Permalink
Added script
Browse files Browse the repository at this point in the history
PhilipBorgesen authored Jan 29, 2017
1 parent 9b79187 commit dec08e9
Showing 1 changed file with 1,216 additions and 0 deletions.
1,216 changes: 1,216 additions & 0 deletions TVPaint_EXPORT_v1.0.grg
Original file line number Diff line number Diff line change
@@ -0,0 +1,1216 @@
PARAM none
//////////////////////////////////////////////////////////////////////////////////////////
// TVPaint Export v1.0 //
// Author: Philip B�rgesen (https://github.com/PhilipBorgesen) //
// //
// This script has been designed to work with TVPaint 11 for which it has been tested. //
// Correct behavior with any other version has not been tested and cannot be assumed. //
// //
// If you have questions or problems with the script, you can try to contact me through //
// the GitHub repository created for the script: //
// //
// Repository: https://github.com/PhilipBorgesen/tvpExport //
// Issues: https://github.com/PhilipBorgesen/tvpExport/issues //
// //
// Before contacting me, please read the documentation written as comments throughout //
// the script as they document how to use and tailor it. //
// For information on how to use the script from TVPaint, please visit: //
// //
// - https://www.tvpaint.com/doc/tvp11/index.php?id=lesson-advanced-functions-george- //
// editing-executing //
// - http://wiki.tvpaint.com/index.php?title=Running_George_Scripts //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MIT License //
// //
// Copyright (c) 2017 Philip Jon B�rgesen //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in all //
// copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //
// SOFTWARE. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
//
// Exports all non-hidden layers of all non-hidden TVPaint scenes as sequences of PNG
// images. The absolute file path for each exported frame is defined by a template with
// placeholders substituted by actual values.
//
// The template is declared by the George variable 'fileNameTemplate', which should
// be updated to match the file path scheme of the hosting operating system and the
// actual naming conventions / file structure of the project.
// For more information on file path schemes, see Wikipedia:
//
// https://en.wikipedia.org/wiki/Path_(computing)#Representations_of_paths_by_operating_system_and_shell
//
// (Linux and macOS are both Unix-like systems)
//
// When saving a frame, the following placeholder values in the template will be
// considered for replacement:
// <sceneName> : The name of the TVPaint scene that the frame belongs to.
// <sq####> : ??? ID of the TVPaint file. Parsed from the project file name.
// <sh####> : Shot ID of the TVPaint file. Parsed from the project file name.
// <v###> : Version number of the TVPaint file. Parsed from the project file name.
// <layerName> : The name of the TVPaint layer that the frame belongs to.
// <lfsq####> : The number of the frame on the scene timeline, starting with 0001.
//
// The script expects the TVPaint project file name to follow the pattern:
// COM_<sq####>_<sh####>_ani_<v###>_pz.tvpp
// E.g.:
// COM_sq0111_sh0111_ani_v001_pz.tvpp
//
// If this naming convention doesn't match the actual naming convention used by the
// project, the George function 'parseFilename' should be updated accordingly.

fileNameTemplate = "P:/production/output/tvPaintTEST/shots/<sq####>/<sh####>/2DElements/<sceneName>/<v###>/<layerName>/COM_<sq####>_<sh####>_2D_<sceneName>_<v###>_<layerName>_<lfsq####>.png"

// Set to 1 to never again be prompted whether you want to overwrite a file.
// Obviously something you should be careful with!
overwriteDontWarn = 0

// Change these to use other placeholder values for the substituted variables.
// The number of #'s in a placeholder define the minimum number of characters the
// substituted variabel should use. If the substituted variabel uses fewer characters
// the value will be prefixed with zeroes to satisfy the intended size.
sceneNamePlaceholder = "<sceneName>"
sqPlaceholder = "<sq####>"
shPlaceholder = "<sh####>"
vPlaceholder = "<v###>"
layerNamePlaceholder = "<layerName>"
lfsqPlaceholder = "<lfsq####>"

// Don't touch!
main()

//
// Given the basename of a TVPaint file, such as "COM_sq0111_sh0111_ani_v001_pz.tvpp",
// this function extracts the values to use for <sq####>, <sh####> and <v###>.
// The extracted values should be returned as a string with the values separated by '/'.
// If this function doesn't return exactly three values (separated by '/'), the rest of
// the script will believe the function to have failed and will abort the script.
//
FUNCTION parseFilename(filename) // (string) -> "<sq####>/<sh####>/<v###>"
LOCAL num sq sh v

num = NewParse(filename, "_")

IF num != 6
num = num-1
tvWarn("ERROR: Filename doesn't match expected pattern (found " num " underscores, expected 6)")
RETURN ""
END

IF CMP("COM", var(1)) == 0
tvWarn("ERROR: Filename doesn't start with 'COM_'")
RETURN ""
END

IF CMP("ani", var(4)) == 0
tvWarn("ERROR: Filename doesn't contain '_ani_'")
RETURN ""
END

IF CMP("pz.tvpp", var(6)) == 0
tvWarn("ERROR: Filename doesn't end with '_pz.tvpp'")
RETURN ""
END

sq = var(2)
sh = var(3)
v = var(5)

RETURN sq"/"sh"/"v
END

///////////////////////////////////
// Actual script -- don't touch! //
///////////////////////////////////

FUNCTION main() // () ->
LOCAL template projectID

template = getBaseTemplate()
IF CMP(template, "") == 1
RETURN ""
END

projectID = tvProjectCurrentID()
exportProject(template, projectID)
END

FUNCTION getBaseTemplate() // () -> string
LOCAL baseName res num sq sh v msg template

baseName = getFileBaseName()
IF LEN(baseName) == 0
RETURN ""
END

res = parseFilename(baseName)
num = NewParse(res, "/")

IF num != 3
tvWarn("ERROR: 'parseFilename' failed to parse the file name '" baseName "'")
RETURN ""
END

sq = var(1)
sh = var(2)
v = var(3)

template = substitute(fileNameTemplate, sqPlaceholder, sq)
template = substitute(template, shPlaceholder, sh)
template = substitute(template, vPlaceholder, v)

return template
END

FUNCTION getFileBaseName() // () -> string
LOCAL filePath lastSep res

filePath = tvProjectName(tvProjectCurrentID())
filePath = Replace(filePath, "\", "/") // In case of Windows

IF CMP(filePath, "/") == 1
tvWarn("Couldn't read naming convention based values from file name. Has the project been saved?")
RETURN ""
END

lastSep = LastPos(filePath, "/")

res = CUT(filePath, lastSep+1, LEN(filePath))
RETURN res
END

FUNCTION substitute(template, placeholder, value) // (string, string, string) -> string
LOCAL padding minWidth diff debug

padding = "</>0000000000000000000000000000000000000000000000000000000000000000000000"
minWidth = calculcateMinWidth(placeholder)
diff = minWidth-LEN(value)-1
IF diff > 0
padding = LeftString(padding, diff+3)
ELSE
padding = ""
END
value = padding""value
template = Replace(template, placeholder, value)
template = Replace(template, "</>", "")
RETURN template
END

FUNCTION calculcateMinWidth(placeholder) // (string) -> integer
LOCAL temp res

temp = Replace(placeholder, "#", "")

res = LEN(placeholder) - LEN(temp)
RETURN res
END

FUNCTION exportProject(template, projectID) // (string, ID) ->
LOCAL orginalProject originalConfig loop pos clipID

orginalProject = tvProjectCurrentID()
tvProjectSelect(projectID)
originalConfig = prepareExportConfiguration()

loop = 1
pos = 0
WHILE loop
clipID = tvClipEnumId(-1, pos)
IF CMP(clipID, "NONE") == 0
IF shouldExportClip(clipID) == 1
exportClip(template, clipID)
END
pos = pos+1
ELSE
loop = 0
END
END

resetProjectConfiguration(originalConfig)
tvProjectSelect(orginalProject)
END

// Setup export settings common for all layers
FUNCTION prepareExportConfiguration() // () -> "origSM|origASM|origClip|origBG|origLayer|origImage"
LOCAL origASM origLayer

origSM = tvSaveMode("PNG")
origASM = tvAlphaSaveMode("NoPreMultiply")
origClip = tvClipCurrentId()
origBG = tvBackground("")
origLayer = tvLayerCurrentID()
origImage = tvLayerGetImage()

tvBackground("NONE")

RETURN origSM"|"origASM"|"origClip"|"origBG"|"origLayer"|"origImage
END

// Reset export settings set by 'prepareExportConfiguration'
FUNCTION resetProjectConfiguration(originalConfig) // ("origASM|origClip|origLayer|origImage|origBG") ->
NewParse(originalConfig, "|")
tvSaveMode(var(1))
tvAlphaSaveMode(var(2))
tvClipSelect(var(3))
tvBackground(var(4))
tvLayerSet(var(5))
tvLayerImage(var(6))
END

FUNCTION shouldExportClip(clipID) // (ID) -> boolean
LOCAL shouldExport

shouldExport = (tvClipHidden(clipID) == 0)

RETURN shouldExport
END

FUNCTION exportClip(template, clipID) // (string, ID) ->
LOCAL sceneName

sceneName = tvClipName(clipID)
template = substitute(template, sceneNamePlaceholder, sceneName)

tvClipSelect(clipID)
doExportClip(template)
END

FUNCTION doExportClip(template) // (string) ->
LOCAL loop pos layerID frameCount

frameCount = tvLastImage() + 1

loop = 1
pos = 0
WHILE loop
layerID = tvLayerGetID(pos)
IF CMP(layerID, "NONE") == 0
IF shouldExportLayer(layerID) == 1
exportLayer(template, layerID, frameCount)
END
pos = pos+1
ELSE
loop = 0
END
END
END

// Whether the layer with ID 'layerID' should be exported
FUNCTION shouldExportLayer(layerID) // (ID) -> boolean
LOCAL display opacity isVisible

num = NewParse(tvLayerInfo(layerID), "|")

display = var(1)
opacity = var(3)

isVisible = (CMP(display, "ON") == 1) && (opacity > 0)

RETURN isVisible
END

FUNCTION exportLayer(template, layerID, frameCount) // (string, ID, integer) ->
LOCAL layerName originalLayer

NewParse(tvLayerInfo(layerID), "|")
layerName = var(4)
template = substitute(template, layerNamePlaceholder, layerName)

tvLayerSet(layerID)
doExportLayer(template, frameCount)
END

FUNCTION doExportLayer(template, frameCount) // (string, integer) ->
LOCAL i

FOR i = 1 TO frameCount
exportFrame(template, i-1)
END

END

FUNCTION exportFrame(template, frameIdx) // (string, integer) ->
template = substitute(template, lfsqPlaceholder, frameIdx+1)
tvInfoBar("Exporting: "template)
tvLayerImage(frameIdx)
saveFrame(template)
END

FUNCTION saveFrame(file) // (string) ->
LOCAL dir

dir = getFileDir(file)
makeDir(dir)

IF fileExists(file)
IF shouldOverwrite(file) != 1
RETURN ""
END
END

tvSaveImage(file)
END

FUNCTION makeDir(dir) // (string) -> string
LOCAL res

res = tvWriteTextFile("MkDir", dir)
IF CMP(res, "Exists") != 1
makeDir(getFileDir(dir))
res = tvWriteTextFile("MkDir", dir)
END

RETURN res
END

FUNCTION fileExists(file) // (string) -> boolean
LOCAL res

res = tvWriteTextFile("Exists", file)
res = CMP(res, "") == 0

RETURN res
END

FUNCTION getFileDir(file) // (string) -> string
LOCAL dir lastSep

dir = Replace(file, "\", "/")
lastSep = LastPos(dir, "/")
dir = CUT(file, 1, lastSep-1)

RETURN dir
END

// Whether the file at the specified location should be overwritten with the frame
// currently being exported.
FUNCTION shouldOverwrite(file) // (string) -> boolean
LOCAL options info overwrite skip overwriteAll res action

IF CMP(overwriteDontWarn, "1") == 1
RETURN 1
END

file = Replace(file, "/", "\")

info = "'"file"' already exists. What to do?"
overwrite = "Overwrite file"
skip = "Skip frame"
overwriteAll = "Overwrite it and don't warn me again"

options = info"|"overwrite"|"skip"|"overwriteAll

action = "-1"
WHILE action == "-1"
res = tvListRequest(options)
PARSE res action res
IF CMP(action, "-1") == 1
tvWarn("Sorry, but you need to make a choice. Don't be shy!")
ELSE
IF CMP(action, "0") == 1
tvWarn("Silly user, you can't select the question! Please try again - and good luck :)")
action = "-1"
END
END
END

IF CMP(action, "1") == 1
RETURN 1
END

IF CMP(action, "2") == 1
RETURN 0
END

IF CMP(action, "3") == 1
overwriteDontWarn = 1
RETURN 1
END
END

///////////////////////////////////////
// TVPaint command wrapper functions //
///////////////////////////////////////

FUNCTION tvListRequest(options) // (string) -> string
tv_ListRequest options
RETURN result
END

FUNCTION tvBackground(args) // (string) -> string
tv_Background args
RETURN result
END

FUNCTION tvWriteTextFile(mode, file) // (string, string) -> string
tv_WriteTextFile mode '"'file'"'
RETURN result
END

FUNCTION tvRequest(msg) // (string) -> boolean
tv_Request msg"|Yes|No"
RETURN result
END

FUNCTION tvSaveImage(file) // (string) ->
tv_SaveImage file
END

FUNCTION tvLayerGetImage() // () -> integer
tv_LayerGetImage
RETURN result
END

FUNCTION tvLayerImage(num) // (integer) ->
tv_LayerImage num
END

FUNCTION tvClipCurrentId() // () -> ID
tv_ClipCurrentId
RETURN result
END

FUNCTION tvClipSelect(clipID) // (ID) ->
tv_ClipSelect clipID
END

FUNCTION tvClipName(clipID) // (ID) -> string
tv_ClipName clipID
RETURN result
END

FUNCTION tvClipHidden(clipID) // (ID) -> string
tv_ClipHidden clipID
RETURN result
END

FUNCTION tvClipEnumId(parent, pos) // (???, integer) -> ID
tv_ClipEnumId parent pos
RETURN result
END

FUNCTION tvWarn(msg) // (string) ->
tv_Warn msg
END

FUNCTION tvProjectCurrentID() // () -> ID
tv_ProjectCurrentID
RETURN result
END

FUNCTION tvLayerInfo(id) // (integer) -> "display|pos|opacity|name|type|start|end"
LOCAL display pos opacity name type start end temp

tv_LayerInfo id
PARSE result display pos opacity name type start end temp
RETURN display"|"pos"|"opacity"|"name"|"type"|"start"|"end
END

FUNCTION tvSaveMode(mode) // (string) -> string
tv_SaveMode mode
RETURN result
END

FUNCTION tvAlphaSaveMode(mode) // (string) -> string
tv_AlphaSaveMode mode
RETURN result
END

FUNCTION tvLayerSet(id) // (ID) ->
tv_layerSet id
END

FUNCTION tvLayerGetID(id) // (ID) -> string
tv_LayerGetID id
RETURN result
END

FUNCTION tvProjectSelect(projectID) // (ID) ->
tv_ProjectSelect projectID
END

FUNCTION tvLayerCurrentID() // () -> ID
tv_LayerCurrentID
RETURN result
END

FUNCTION tvProjectName(projectID) // (ID) -> string
LOCAL projectName temp

tv_ProjectInfo projectID
PARSE result projectName temp

RETURN projectName
END

FUNCTION tvLastImage() // () -> integer
tv_LastImage
RETURN result
END

FUNCTION tvInfobar(msg) // (string) ->
tv_infobar msg
END

////////////////////////////////
// Embedded TVPaint functions //
////////////////////////////////

// The following scripts have been embedded as a transportable work-around
// for George's one-include-per-file limit:
//
// http://wiki.tvpaint.com/index.php?title=George_Procedures_:_Basic
// http://wiki.tvpaint.com/index.php?title=George_Procedures_:_Advanced
//
// =========================================================================
// THESE ARE NOT COVERED BY THE MIT LICENSE. I CLAIM NO COPYRIGHT OVER THEM.
// =========================================================================

//{{{** BASIC FUNCTIONS

//{{{ Find
//------------------------------------------
//
// Find
//
// Function: find a character into a string
// from a specified start position
//
// Call: Find(string,car,start)
//
// Arguments:
// string = characters string
// car = character to look for
// start = start position in string
//
// Return: position of character
// 0 if character does not exist
// into string
// -1 if invalid position
// (negative, null or higher
// than string length)
//
//------------------------------------------

FUNCTION Find(string,car,start)
LOCAL i size
i = start
size = LEN(string)

IF ((start <= 0) || (start > size) || (CMP(car,"") == 1))
RETURN -1
END
DO
IF (CMP(CHAR(string,i),car) == 1)
RETURN i
END
UNTIL ((i=i+1) > size)
RETURN 0
END
//}}}

//{{{ FirstPos(string,car)
//------------------------------------------
//
// FirstPos
//
// Function: find first occurence of a
// character into a string
//
// Call: FirstPos(string,car)
//
// Arguments:
// string = characters string
// car = character to look for
//
// Return: position of character
// or 0 id character does not
// exist into string.
//
//------------------------------------------

FUNCTION FirstPos(string,car)
RETURN Find(string,car,1)
END
//}}}

//{{{ LastPos(string,car)
//------------------------------------------
//
// LastPos
//
// Function: find last occurence of a
// character into a string
//
// Call: LastPos(string,car)
//
// Arguments:
// string = characters string
// car = character to look for
//
// Return: position of character
// or 0 if character does not
// exist into string.
//
//------------------------------------------

FUNCTION LastPos(string,car)
LOCAL loop myChar
pos = LEN(string)
loop = 1
WHILE loop
myChar = CHAR(string,pos)

IF CMP(myChar,car) == 1
loop =0
ELSE
pos = pos-1
END
IF pos<1
loop=0
END
END
RETURN pos
END
//}}}

//{{{ FindString(string,search,start)
//------------------------------------------
//
// FindString
//
// Function: find a substring into a string
// from a specified start position
//
// Call: FindString(string,search,start)
//
// Arguments:
// string = characters string
// search = substring to look for
// start = start position in string
//
// Return: start position of substring
// 0 if substring does not exist
// into string
// -1 if invalid start position
// (negative, null or higher
// than string length) or if
// substring is empty
//
//------------------------------------------

FUNCTION FindString(string,search,start)
LOCAL found j pos lastpos lstr lsrch
found = 0
lastpos = start
lstr = LEN(string)
lsrch = LEN(search)

IF (CMP(search,"") == 1)
RETURN -1
END
WHILE ((pos = Find(string,CHAR(search,1),lastpos)) > 0)
j = 1
found = 1
IF (j == lsrch)
RETURN pos
END
WHILE ((j < lsrch) && (found == 1))
IF ((pos+j) > lstr)
RETURN 0
ELSE
IF (CMP(CHAR(search,j+1),CHAR(string,pos+j)) == 0)
lastpos = pos+j
found = 0
END
END
j = j+1
END
IF (found == 1)
RETURN pos
END
END
RETURN pos
END
//}}}

//{{{ LeftString(string,number)
//------------------------------------------
//
// LeftString
//
// Function: extract a substring beginning
// at the start of a string
//
// Call: LeftString(string,number)
//
// Arguments:
// string = characters string
// number = number of character to
// extract from string
//
// Return: result substring
// or 0 if number is negative
// or null.
//
//------------------------------------------

FUNCTION LeftString(string,number)
LOCAL size
size = LEN(string)

IF (number > 0)
IF (number > size)
number = size
END
RETURN CUT(string,1,number)
END
RETURN 0
END
//}}}

//{{{ RightString(string,number)
//------------------------------------------
//
// RightString
//
// Function: extract a substring ending
// at the end of a string
//
// Call: RightString(string,number)
//
// Arguments:
// string = characters string
// number = number of character to
// extract from string
//
// Return: result substring
// or 0 if number is negative
// or null.
//
//------------------------------------------

FUNCTION RightString(string,number)
LOCAL size
size = LEN(string)

IF (number > 0)
IF (number > size)
number = size
END
RETURN CUT(string,size-number+1,size)
END
RETURN 0
END
//}}}

//{{{ MidString(string,first,size)
//------------------------------------------
//
// MidString
//
// Function: extract a substring from a
// string
//
// Call: MidString(string,first,size)
//
// Arguments:
// string = characters string
// first = start position in string
// cha?ne
// size = number of characters
//
// Return: result substring
// or 0 if number or first are
// negatives or null.
//
//------------------------------------------

FUNCTION MidString(string,first,size)
LOCAL ln
ln = LEN(string)

IF ((first > 0) && (size > 0))
IF ((first+size-1) > ln)
size = ln-first+1
END
RETURN CUT(string,first,first+size-1)
END
RETURN 0
END
//}}}

//{{{ InsertAtPos(string,insert,pos)
//------------------------------------------
//
// InsertAtPos
//
// Function: insert a string in another
// string at a specified position
//
// Call: InsertAtPos(string,insert,pos)
//
// Arguments:
// string = characters string
// insert = string to insert
// pos = start position for insertion
//
// Return: result string after insertion
// or 0 if start position is
// invalid (negative, null or
// higher than string length)
//
//------------------------------------------

FUNCTION InsertAtPos(string,insert,pos)
LOCAL workstr str1 size
size = LEN(string)

IF ((pos < 0) || (pos > size))
RETURN 0
END
IF (pos == 0)
RETURN insert""string
END
IF (pos == size)
RETURN string""insert
END
workstr = CUT(string,1,pos)
IF (pos < size)
str1 = CUT(string,pos+1,size)
RETURN workstr""insert""str1
ELSE
RETURN workstr""insert
END
END
//}}}

//}}}**

//{{{** ADVANCED STRING FUNCTIONS

//{{{ InsertAfter(string,insert,search)
//------------------------------------------
//
// InsertAfter
//
// Function: insert a string after each
// occurence of a character or
// a set of characters into
// another string
//
// Call: InsertAfter(string,insert,search)
//
// Arguments:
// string = characters string
// insert = string to insert
// search = character or substring
// to look for
//
// Return: result string after insertion
//
//------------------------------------------

FUNCTION InsertAfter(string,insert,search)
LOCAL pos workstr size
pos = 1
workstr = string
size = LEN(search)

WHILE ((pos = FindString(workstr,search,pos)) > 0)
workstr = InsertStringAtPos(workstr,insert,pos+size-1)
pos = pos+size+LEN(insert)
END
RETURN workstr
END
//}}}

//{{{ InsertBefore
//------------------------------------------
//
// InsertBefore
//
// Function: insert a string before each
// occurence of a character or
// a set of characters into
// another string
//
// Call: InsertBefore(string,insert,search)
//
// Arguments:
// string = characters string
// insert = string to insert
// search = character or substring
// to look for
//
// Return: result string after insertion
//
//------------------------------------------

FUNCTION InsertBefore(string,insert,search)
LOCAL pos workstr
pos = 1
workstr = string

WHILE ((pos = FindString(workstr,search,pos)) > 0)
workstr = InsertStringAtPos(workstr,insert,pos-1)
pos = pos+LEN(search)+LEN(insert)
END
RETURN workstr
END
//}}}

//{{{ Delete
//------------------------------------------
//
// Delete
//
// Function: delete all occurences of a
// substring into a string
//
// Call: Delete(string,search)
//
// Arguments:
// string = characters string
// search = substring to delete
//
// Return: result string after deletion
//
//------------------------------------------

FUNCTION Delete(string,search)
LOCAL workstr str1 str2 pos size
workstr = string
pos = 1
size = LEN(search)

WHILE ((pos = FindString(workstr,search,1)) > 0)
IF ((pos != 1) && ((pos+size) < LEN(workstr)))
str1 = CUT(workstr,1,pos-1)
str2 = CUT(workstr,pos+size,LEN(workstr))
workstr = str1""str2
ELSE
IF (pos == 1)
IF ((size+1) < LEN(workstr))
workstr = CUT(workstr,size+1,LEN(workstr))
ELSE
workstr = ""
END
ELSE
workstr = CUT(workstr,1,pos-1)
END
END
END
RETURN workstr
END
//}}}

//{{{ Replace
//------------------------------------------
//
// Replace
//
// Function: replace each occurence of a
// substring into a string with
// another string
//
// Call: Replace(string,search,repl)
//
// Arguments:
// string = characters string
// search = substring to look for
// repl = replacement substring
//
// Return: result string after replacement
//
//------------------------------------------

FUNCTION Replace(string,search,repl)
LOCAL pos workstr str1 str2 size
pos = 1
workstr = string
size = LEN(search)

// Change by Philip B�rgesen
IF CMP(string, search) == 1
RETURN repl
END

WHILE ((pos = FindString(workstr,search,pos)) > 0)
IF (pos == 1)
str1 = CUT(workstr,size+1,LEN(workstr))
workstr = repl""str1
pos = 0
ELSE
str1 = CUT(workstr,1,pos-1)
IF ((pos+size) < LEN(workstr))
str2 = CUT(workstr,pos+size,LEN(workstr))
workstr = str1""repl""str2
ELSE
workstr = str1""repl
END
END
pos = pos+LEN(repl)
END
RETURN workstr
END
//}}}

//{{{ NewParse
//------------------------------------------
//
// NewParse
//
// Function: cut a string into several parts and
// store each part into a variable.
// The string is cut before each
// occurence of a specified character.
//
// Call: NewParse(string,divider)
//
// Arguments:
// string = characters string
// divider = character used as a separator
// between each part of the string
//
// Return: number of variables created.
// This function create global variables
// named var(1), var(2)...var(N), where
// N is the value returned by the function.
//
// Note: if the string contained two or more
// successive separators, no variable is
// created for these parts of the string.
// For example, if you call the NewParse
// function for "First;;Second" with
// divider=";", only two variables are
// created (var(1)="First" and
// var(2)="Second").
//
//------------------------------------------

FUNCTION NewParse(string,divider)
LOCAL pos i workstr size
i = 0
pos = 1
workstr = string

IF ((CMP(workstr,"") == 0) && (CMP(divider,"") == 0) && (CMP(workstr,divider) == 0))
WHILE ((pos = Find(workstr,divider,1)) > 0)
IF ((pos != 1) && (pos != LEN(workstr)))
i = i+1
var(i) = CUT(workstr,1,pos-1)
workstr = CUT(workstr,pos+1,LEN(workstr))
ELSE
IF (pos == 1)
IF (pos != LEN(workstr))
workstr = CUT(workstr,2,LEN(workstr))
ELSE
workstr = ""
END
ELSE
workstr = CUT(workstr,pos,LEN(workstr))
END
END
END
if (CMP(workstr,0) == 0)
i = i+1
var(i) = workstr
END
END
RETURN i
END
//}}}

//{{{ FileRequester
//------------------------------------------
//
// FileRequester
//
// Function: open a file requester
//
// Call: FileRequester(title,path,file,pattern)
//
// Arguments:
// title = requester title
// path = default directory
// file = default filename
// pattern = default pattern
//
// Return: 0 if user clicks on Cancel
// 1 if user chooses a file. This
// function creates three global
// variables: pathname (path
// to choosen file), filename
// (name of choosen file without
// extension) and extension
// (extension of choosen file)
//
//------------------------------------------

FUNCTION FileRequester(title,path,file,pattern)
LOCAL fullname point slash size titre

pathname = ""
filename = ""
extension = ""

IF (CMP(pattern,0) == 1)
titre = "|"
ELSE
titre = "|"pattern
END
IF (CMP(file,0) == 1)
titre = "|"titre
ELSE
titre = "|"file""titre
END
IF (CMP(path,0) == 1)
titre = "|"titre
ELSE
titre = "|"path""titre
END
IF (CMP(title,0) == 1)
titre = "Choose a file"titre
ELSE
titre = title""titre
END

tv_ReqFile titre
fullname = Result
size = LEN(fullname)

IF (CMP(fullname,"Cancel") == 1)
RETURN 0
ELSE
IF ((point = LastPos(fullname,".")) != 0)
extension = CUT(fullname,point+1,size)
size = point-1
fullname = CUT(fullname,1,size)
END
IF ((slash = LastPos(fullname,"\")) != 0)
filename = CUT(fullname,slash+1,size)
size = slash-1
pathname = CUT(fullname,1,size)
END
RETURN 1
END
END
//}}}

0 comments on commit dec08e9

Please sign in to comment.