This repository has been archived by the owner on Feb 17, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
9b79187
commit dec08e9
Showing
1 changed file
with
1,216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
//}}} |