/*
-----------------------------------------------------------------------------
This source file is part of OpenSpace3D
For the latest info, see http://www.openspace3d.com
Copyright (c) 2012 I-maginer
This program 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 of the License, or (at your option) any later
version.
This program 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.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt
-----------------------------------------------------------------------------
*/
/*! \mainpage OpenSpace3D high level libraries API
*
* \section intro_sec Introduction
* This API provide an high level method to easily develop OpenSpace3D applications and PlugITs
*
*/
/*! @defgroup toolslib OpenSpace3D high level Tools
* OpenSpace3D high level Tools
* @{
*/
/*! @defgroup toolslist List tools
* List tools
* @{
*/
/** @} */
/*! @defgroup toolsstr String tools
* String tools
* @{
*/
/** @} */
/*! @defgroup toolscommon Common tools
* Common tools
* @{
*/
/** @} */
/*! @defgroup toolsfile File tools
* File tools
* @{
*/
/** @} */
/*! @defgroup toolsdl Network requests and download tools
* Network requests and download tools
* @{
*/
/** @} */
/*! @defgroup toolsvec Vector tools
* Vector tools
* @{
*/
/** @} */
/*! @defgroup toolsdate Date tools
* Date tools
* @{
*/
/** @} */
/*! @defgroup csvtools CSV parser / writer
* CSV tools
* @{
*/
/** @} */
/** @} */
/*! @ingroup plugITApi
* \brief Add a log message in the OS3D log window
*
* Prototype: fun [S] S
*
* \param S : the message to print in the log window
*
* \return S : the same message
**/
proto addLogMessage = fun [S] S;;
/*! @ingroup plugITApi
* \brief Add a log message in the OS3D log window from a list
*
* Prototype: fun [S [S r1]] I
*
* \param S : the message prefix
* \param [S r1] : a list of messages to print in the log window
*
* \return 0
**/
proto addLogMessageMulti = fun [S [S r1]] I;;
proto strreplace = fun [S S S] S;;
fun getInfo(l,a)=
if l==nil then nil else
let l->[q nxt] in
if !strcmp hd q a then
hd tl q
else
getInfo nxt a;;
fun getInfos(l,a)=
if l==nil then nil else
let l->[q nxt] in
if !strcmp hd q a then
tl q
else
getInfos nxt a;;
fun getInfoI(l,a)=
if l==nil then nil else
let l->[q nxt] in
if !strcmpi hd q a then
hd tl q
else
getInfoI nxt a;;
fun chgusm2(l,a,b,s,k)=
if l==nil then
if k then
s::nil
else nil
else
let l->[ll n] in
let hd strextr ll -> [h [hh _]] in
if (!strcmp h a)&&((b==nil)||(!strcmpi b substr hh 0 strlen b)) then
s::chgusm2 n a b s 0
else
ll::chgusm2 n a b s k;;
fun chgusm(a,b,line)=
_saveusmini linebuild chgusm2 (lineextr _loadusmini nil) a b line 1;;
/*! @ingroup toolslist
* \brief Concat two list to one
*
* Prototype: fun [[u0 r1] [u0 r1]] [u0 r1]
*
* \param [u0 r1] : first list to concat
* \param [u0 r1] : second list to concat
*
* \return [u0 r1] : concatened list
**/
fun lcat(p, q)=
if p==nil then
q
else
(hd p)::lcat (tl p) q;;
/*! @ingroup toolslist
* \brief Split a list in two list at given position
*
* Prototype: fun [[u0 r1] I] [[u0 r1] [u0 r1]]
*
* \param [u0 r1] : list to split
* \param I : position (start at 0), use a negative value for a position from the list end
*
* \return [[u0 r1] [u0 r1]] : splited list
**/
fun splitList(l, pos)=
let if pos < 0 then ((sizelist l) + (pos + 1)) else pos -> pos in
if (((pos + 1) > (sizelist l)) || (pos == 0)) then [nil l] else
let nil -> l1 in
let nil -> l2 in
(
let sizelist l -> size in
let size - 1 -> i in
while (i >= 0) do
(
let nth_list l i -> elt in
if (i < pos) then
set l1 = elt::l1
else
set l2 = elt::l2;
set i = i - 1;
);
[l1 l2];
);;
/*! @ingroup toolslist
* \brief move an elements in a list
*
* Prototype: fun [[u0 r1] I I] [u0 r1]
*
* \param [u0 r1] : list to split
* \param I : position to get the element
* \param I : position to move the element
*
* \return [u0 r1] : new list
**/
fun moveListElement(l, pos, to)=
if (to < 0) || (to >= (sizelist l)) || (pos < 0) || (pos >= (sizelist l)) then l else
let nil -> newlist in
(
let (sizelist l) - 1 -> i in
while i >= 0 do
(
let nth_list l i -> elt in
if (i == pos) then
set newlist = (nth_list l to)::newlist
else if (i == to) then
set newlist = (nth_list l pos)::newlist
else
set newlist = elt::newlist;
set i = i - 1;
);
newlist;
);;
/*! \brief Divide list
*
* Prototype: fun [u0 [u0 r1] [u0 r1] [u0 r1] fun [u0 u0] I] [u0 r1]
*
* Private
*
* \return [[u0 r1] [u0 r1]]
**/
fun divideList(x,p,r1,r2,f)=
if p==nil then [r1 r2]
else let p->[a n] in
let exec f with [a x] -> r in
if r==0 then divideList x n r1 r2 f
else if r<0 then divideList x n a::r1 r2 f
else divideList x n r1 a::r2 f;;
/*! \brief Divide string list
*
* Prototype: fun [[S r1] [[S r1] r1] [[S r1] r1] [[S r1] r1] fun [[S r1] [S r1]] I] [[S r1] r1]
*
* Private
*
* \return [[[S r1] r1] [[S r1] r1]]
**/
fun divideListString(x,p,r1,r2,f)=
if p==nil then [r1 r2]
else let p->[a n] in
let exec f with [strcatn a strcatn x] -> r in
if r==0 then divideListString x n r1 r2 f
else if r<0 then divideListString x n a::r1 r2 f
else divideListString x n r1 a::r2 f;;
/*! \brief Divide list by position
*
* Prototype: fun [[u0 r1] [[u0 r1] r1] [[u0 r1] r1] [[u0 r1] r1] I fun [[u0 r1] [u0 r1]] I] [[u0 r1] r1]
*
* Private
*
* \return [[[u0 r1] r1] [[u0 r1] r1]]
**/
fun divideListPos(x,p,r1,r2,pos,f)=
if p==nil then [r1 r2]
else let p->[a n] in
let exec f with [(nth_list a pos) (nth_list x pos)] -> r in
if r==0 then divideListPos x n r1 r2 pos f
else if r<0 then divideListPos x n a::r1 r2 pos f
else divideListPos x n r1 a::r2 pos f;;
/*! \brief Divide list by position
*
* Prototype: fun [[[S u0] r1] [[[S u0] r1] r1] [[[S u0] r1] r1] [[[S u0] r1] r1] I fun [[[S u0] r1] [[S u0] r1]] I] [[[S u0] r1] r1]
*
* Private
*
* \return [[[[S u0] r1] r1] [[[S u0] r1] r1]]
**/
fun divideList3(x,p,r1,r2,f)=
if p==nil then [r1 r2]
else let p->[a n] in
let a->[aa _] in
let x->[xx _] in
let exec f with [aa xx] -> r in
if r==0 then divideList3 x n r1 r2 f
else if r<0 then divideList3 x n a::r1 r2 f
else divideList3 x n r1 a::r2 f;;
/*! \brief Extract list
*
* Prototype: fun [[u0 r1] u0 fun [u0 u0] I] [u0 r1]
*
* Private
*
* \return [[u0 r1] [u0 r1]]
**/
fun extractList(l, e, f) =
if l == nil then [nil nil] else
let l -> [head tail] in
let extractList tail e f -> [left right] in
if exec f with [head e] then
[head::left right]
else
[left head::right];;
/*! @ingroup toolscommon
* \brief Test if an int is smaller than another int
*
* Use with quicksort function
*
* Prototype: fun [I I] I
*
* \param I : first int to test
* \param I : second int to test
*
* \return I : 1 if smaller -1 otherwise
**/
fun isSmallerI(s, t)= if (s < t) then 1 else -1;;
/*! @ingroup toolscommon
* \brief Test if a int is larger than another int
*
* Use with quicksort function
0
* Prototype: fun [I I] I
*
* \param I : first int to test
* \param I : second int to test
*
* \return I : 1 if larger -1 otherwise
**/
fun isLargerI(s, t)= if (s > t) then 1 else -1;;
/*! @ingroup toolscommon
* \brief Test if an float is smaller than another float
*
* Use with quicksort function
*
* Prototype: fun [F F] I
*
* \param F : first float to test
* \param F : second float to test
*
* \return I : 1 if smaller -1 otherwise
**/
fun isSmallerF(s, t)= if (s <. t) then 1 else -1;;
/*! @ingroup toolscommon
* \brief Test if a float is larger than another float
*
* Use with quicksort function
0
* Prototype: fun [F F] I
*
* \param F : first float to test
* \param F : second float to test
*
* \return I : 1 if larger -1 otherwise
**/
fun isLargerF(s, t)= if (s >. t) then 1 else -1;;
/*! @ingroup toolsstr
* \brief Test if a string is smaller than another string
*
* Use with quicksort function
*
* Prototype: fun [S S] I
*
* \param S : first string to test
* \param S : second string to test
*
* \return I : 1 if smaller 0 otherwise
**/
fun isSmaller(s, t)= ((strcmp s t) < 0);;
/*! @ingroup toolsstr
* \brief Test if a string is larger than another string
*
* Use with quicksort function
0
* Prototype: fun [S S] I
*
* \param S : first string to test
* \param S : second string to test
*
* \return I : superior to 0 if larger
**/
fun isLarger(s, t)= ((strcmp s t) > 0);;
/*! @ingroup toolsstr
* \brief Test if a string is equal to another string
*
* Use with quicksort function
*
* Prototype: fun [S S] I
*
* \param S : first string to test
* \param S : second string to test
*
* \return I : different to 0 if not equal
**/
fun suppDoublon(s1, s2)= strcmpi s1 s2;;
/*! @ingroup toolscommon
* \brief Test if a value is equal to another value
*
* Use with quicksort function
*
* Prototype: fun [u0 u0] I
*
* \param u0 : first value to test
* \param u0 : second value to test
*
* \return I : 1 if not equal 0 otherwise
**/
fun suppDoublon2(s1, s2)= s1!=s2;;
/*! @ingroup toolsstr
* \brief Test if a string is equal to another string case sensivity
*
* Use with quicksort function
*
* Prototype: fun [S S] I
*
* \param S : first string to test
* \param S : second string to test
*
* \return I : different to 0 if not equal
**/
fun suppDoublonCaseSensivity(s1, s2)= strcmp s1 s2;;
/*! @ingroup toolslist
* \brief Sort a list
*
* Prototype: fun [[u0 r1] fun [u0 u0] I] [u0 r1]
*
* \param [u0 r1] : list to sort
* \param fun [u0 u0] I : function for sort test (suppDoublon for example)
*
* \return [u0 r1] : sorted list
**/
fun quicksort(l,f)=
if l==nil then nil
else let l->[vl nl] in
let divideList vl nl nil nil f->[va na] in
lcat quicksort va f vl::quicksort na f;;
/*! @ingroup toolslist
* \brief Sort a list by position
*
* Prototype: fun [[[u0 r1] r1] I fun [u0 u0] I] [[u0 r1] r1]
*
* \param [u0 r1] : list to sort
* \param fun [u0 u0] I : function for sort test (suppDoublon for example)
*
* \return [[u0 r1] r1] : sorted list
**/
fun quicksortByPos(l,pos,f)=
if l==nil then nil
else let l->[vl nl] in
let divideListPos vl nl nil nil pos f->[va na] in
lcat quicksortByPos va pos f vl::quicksortByPos na pos f;;
/*! @ingroup toolslist
* \brief Sort a string list
*
* Prototype: fun [[[S r1] r1] fun [S S] I] [S r1]
*
* \param [[S r1] r1] : list to sort
* \param fun [S S] I : function for sort test (suppDoublon for example)
*
* \return [S r1] : sorted list
**/
fun quicksortList(l,f)=
if l==nil then nil
else let l->[vl nl] in
let divideListString vl nl nil nil f->[va na] in
lcat quicksortList va f vl::quicksortList na f;;
/*! @ingroup toolslist
* \brief Sort a string list
*
* Prototype: fun [[[[S u0] r1] r1]] fun [S S] I] [[[S u0] r1] r1]]
*
* \param [S r1] : list to sort
* \param fun [S S] I : function for sort test (suppDoublon for example)
*
* \return [[[S u0] r1] r1]] : sorted list
**/
fun quicksort3(l,f)=
if l==nil then nil
else let l->[vl nl] in
let divideList3 vl nl nil nil f->[va na] in
lcat quicksort3 va f vl::quicksort3 na f;;
/*! @ingroup toolslist
* \brief Sort a list
*
* Prototype: fun [[u0 r1] fun [u0 u0] I] [u0 r1]
*
* \param [u0 r1] : list to sort
* \param fun [u0 u0] I : function for sort test (suppDoublon for example)
*
* \return [u0 r1] : sorted list
**/
fun sortlist(l,f)=
if l == nil then nil else
let l -> [head tail] in
let extractList tail head f -> [left right] in
lcat (sortlist left f) head::(sortlist right f);;
/*! @ingroup toolslist
* \brief Reverse a list
*
* Prototype: fun [[u0 r1]] I
*
* \param [u0 r1] : list to revert
*
* \return [u0 r1] : reversed list
**/
fun revertlist(list)=
if list==nil then nil else
let list -> [first next] in
lcat revertlist next first::nil;;
/*! @ingroup toolslist
* \brief Test if a string exist in a list
*
* Prototype: fun [[S r1] S] I
*
* \param [S r1] : list
* \param S : string to search
*
* \return I : 1 if the string exist in the list 0 otherwise
**/
fun isStringInList(l, string)=
(l!=nil)&&((!strcmp string hd l)||(isStringInList tl l string));;
/*! @ingroup toolslist
* \brief Test if a string exist in a list case insensitivity
*
* Prototype: fun [[S r1] S] I
*
* \param [S r1] : list
* \param S : string to search
*
* \return I : 1 if the string exist in the list 0 otherwise
**/
fun isStringInListi(l, string)=
(l!=nil)&&((!strcmpi string hd l)||(isStringInListi tl l string));;
/*! @ingroup toolslist
* \brief Test if a string exist in a list case insensitivity
*
* Prototype: fun [[S r1] S I I] I
*
* \param [S r1] : list
* \param S : string to search
* \param I : position
* \param I : length
*
* \return I : 1 if the string exist in the list 0 otherwise
**/
fun isStringInListiPos(l, string, pos, length)=
(l!=nil)&&((!strcmpi string (substr (hd l) pos length))||(isStringInListiPos tl l string pos length));;
/*! @ingroup toolslist
* \brief Add a string element as unique
*
* Prototype: fun [[S r1] S] [S r1]
*
* \param [S r1] : list
* \param S : unique element
*
* \return [S r1] : new list
**/
fun addUniqueStr(l, str)=
if (isStringInList l str) then
l
else
str::l;;
/*! @ingroup toolslist
* \brief Add a string element as unique, case insensitivity
*
* Prototype: fun [[S r1] S] [S r1]
*
* \param [S r1] : list
* \param S : unique element
*
* \return [S r1] : new list
**/
fun addUniqueStri(l, str)=
if (isStringInListi l str) then
l
else
str::l;;
/*! @ingroup toolslist
* \brief get a string position in a list
*
* Prototype: fun [[S r1] S] I
*
* \param [S r1] : list
* \param S : string to search
*
* \return I : string position or nil if not found
**/
fun getStringPosInList(l, string)=
if !(isStringInList l string) then nil else
let 0 -> i in
(
while ((l != nil) && (strcmp string hd l)) do
(
set i = i + 1;
set l = tl l;
);
i;
);;
/*! @ingroup toolslist
* \brief get a string position in a list case insensitivity
*
* Prototype: fun [[S r1] S] I
*
* \param [S r1] : list
* \param S : string to search
*
* \return I : string position or nil if not found
**/
fun getStringPosInListi(l, string)=
if !(isStringInListi l string) then nil else
let 0 -> i in
(
while ((l != nil) && (strcmpi string hd l)) do
(
set i = i + 1;
set l = tl l;
);
i;
);;
/*! @ingroup toolslist
* \brief Test if a string exist in a list as the first word of the string
*
* Prototype: fun [[S r1] S] I
*
* \param [S r1] : list
* \param S : string to search
*
* \return I : 1 if the string exist in the list 0 otherwise
**/
fun isFirstWordInList(l, string)=
(l!=nil)&&((!strcmp (hd hd (strextr string)) (hd l))||(isFirstWordInList tl l string));;
/*! @ingroup toolslist
* \brief Test if a string exist in a list as the first word of the string case insensitivity
*
* Prototype: fun [[S r1] S] I
*
* \param [S r1] : list
* \param S : string to search
*
* \return I : 1 if the string exist in the list 0 otherwise
**/
fun isFirstWordInListi(l, string)=
(l!=nil)&&((!strcmpi (hd hd (strextr string)) (hd l))||(isFirstWordInListi tl l string));;
/*! @ingroup toolslist
* \brief Test if the first string of a list match to a word
*
* Prototype: fun [[[S r1] r1] S] I
*
* \param [[S r1] r1] : list
* \param S : string to compare
*
* \return I : 1 if the string exist in the list 0 otherwise
**/
fun isFirstStringInList(l, string)=
let hd hd l -> tstr in
(l!=nil)&&((!strcmp string tstr)||(isFirstStringInList tl l string));;
/*! @ingroup toolslist
* \brief Test if the first tuple value in list is present
*
* Prototype: fun [[[u0 u1] r1] u0] I
*
* \param [[I u0] r1] : list
* \param u0 : value to compare
*
* \return I : 1 if the value exist in the list 0 otherwise
**/
fun isT1InList(l, val)=
let hd l -> [cval _] in
(l!=nil)&&((cval == val)||(isT1InList tl l val));;
/*! @ingroup toolslist
* \brief Test if the second tuple value in list is present
*
* Prototype: fun [[[u0 u1] r1] u1] I
*
* \param [[I u0] r1] : list
* \param u1 : value to compare
*
* \return I : 1 if the value exist in the list 0 otherwise
**/
fun isT2InList(l, val)=
let hd l -> [_ cval] in
(l!=nil)&&((cval == val)||(isT2InList tl l val));;
/*! @ingroup toolsfile
* \brief Get a file path and file name from a path
*
* Prototype: fun [S S] [S S]
*
* \param S : the path
* \param S : set to nil
*
* \return [S S] : the path and the filename
**/
fun getPathFile(longfile, file)=
if (longfile==nil) || (strlen longfile)==0 || (nth_char longfile ((strlen longfile)-1)) == '/ || (nth_char longfile ((strlen longfile)-1)) == '\ then
(
let if (nth_char longfile ((strlen longfile)-1)) == '/ then "/" else "\\" -> slash in
if (strfind "." file 0) != nil then
[longfile file]
else if file != nil then
[strcatn longfile::file::slash::nil nil]
else
[longfile nil];
)
else
getPathFile
substr longfile 0 (strlen longfile)-1
strcat
substr longfile ((strlen longfile)-1) 1
file;;
/*! @ingroup toolsfile
* \brief Get the last directory from a path
*
* Prototype: fun [S] S
*
* \param S : the path
*
* \return S : the last directory
**/
fun getlastPathDir(path)=
while ((strfind "/" path 0) != nil) do
set path = substr path ((strfind "/" path 0) + 1) 2048;
path;;
/*! @ingroup toolsfile
* \brief Get file extension from a path
*
* Prototype: fun [S] S
*
* \param S : the path
*
* \return S : the file extension
**/
fun getFileExt(file)=
let getPathFile file "" -> [_ file2] in
let 0 -> pos in
(
while (strfind "." file2 pos + 1) != nil do
(
set pos = strfind "." file2 pos + 1;
);
if pos == 0 then nil else
substr file2 (pos + 1) 1024;
);;
/*! @ingroup toolsfile
* \brief Get file path without the file extension
*
* Prototype: fun [S] S
*
* \param S : the path
*
* \return S : the file path without the file extension
**/
fun getFilePathWithoutExt(file)=
substr file 0 (strfind "." file 0);;
/*! @ingroup toolsfile
* \brief Get path without the file name
*
* Prototype: fun [S] S
*
* \param S : the path
*
* \return S : the path without the file
**/
fun getFileDirectory(file)=
let getPathFile file "" -> [dir _] in
dir;;
/*! @ingroup toolsfile
* \brief Get the file name without Path and Extension
*
* Prototype: fun [S] S
*
* \param S : the path
*
* \return S : the file name
**/
fun getFileNameWithoutExt(file)=
let getPathFile file "" -> [_ file2] in
let 0 -> lastdot in
let -1 -> cpos in
let while (set cpos = (strfind "." file2 cpos + 1)) != nil do set lastdot = cpos -> pos in
substr file2 0 pos;;
/*! @ingroup toolsfile
* \brief Manage relative paths (relativ files should start with ./)
*
* Prototype: fun [S] S
*
* \param S : the path to add
* \param S : the relative file path
*
* \return S : the complete path
**/
fun getRelativePath(path, file)=
if !strcmp substr file 0 2 "./" then
strcatn path::"/"::(substr file 2 strlen file)::nil
else file;;
/*! @ingroup toolsfile
* \brief Create a new folder
*
* Prototype: fun [S] S
*
* \param S : the path to add
*
* \return I : 1 on succes, 0 otherwise
**/
fun createFolder(path)=
let strcat path "/0" -> fdir in
(
_storepack "" fdir;
let _checkpack fdir -> pf in
if (pf == nil) then
(
0;
)
else
(
_deletepack pf;
1;
);
);;
fun cutDotName(name)= [(substr name 0 (strfind "." name 0)) (substr name ((strfind "." name 0) + 1) 1024)];;
fun makeDotName(id, name)= strcatn id::"."::name::nil;;
fun isExtInListi(l, string)=
if (l==nil) then 0 else
let hd l -> ext in
let if ((strfind "*." ext 0) == 0) then (substr ext 2 (strlen ext) - 2) else ext -> ext in
(l!=nil)&&((!strcmpi string ext)||(isExtInListi tl l string));;
/*! @ingroup toolsfile
* \brief Compute a name with only allowed char from a string
*
* Prototype: fun [S] S
*
* \param S : original string
*
* \return I : 1 on succes, 0 otherwise
**/
fun getShortName(name)=
let strdup name -> cpname in
//do strlowercase on the copied string, this modify the original string otherwise
let strlowercase cpname -> nname in
(
let "a"::"b"::"c"::"d"::"e"::"f"::"g"::"h"::"i"::"j"::"k"::"l"::"m"::"n"::"o"::"p"::"q"::"r"::"s"::"t"::"u"::"v"::"w"::"x"::"y"::"z"::"0"::"1"::"2"::"3"::"4"::"5"::"6"::"7"::"8"::"9"::nil -> alphanum in
let 0 -> pos in
let "" -> fname in
(
while ((strlen nname) > 0) do
(
let substr nname 0 1 -> letter in
if (!isStringInList alphanum letter) then nil else
set fname = strcat fname letter;
set nname = substr nname 1 strlen nname;
);
fname;
);
);;
/*! @ingroup toolsfile
* \brief Get the files list from a directory, with a file extension mask
*
* Prototype: fun [S [S r1]] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files
**/
fun getFilesFromDir(dir, mask)=
let !strcmp (hd mask) "*.*" -> all in
let _listoffiles dir -> files in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if (!all && (mask != nil) && !(isExtInListi mask ext)) then nil else
set lfiles = lcat lfiles file::nil;
set files = tl files;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files list from a directory, with a file extension mask and filter
*
* Prototype: fun [S [S r1] fun [S] I ] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files
**/
fun getFilesFromDirFilter(dir, mask, cbfilter)=
let !strcmp (hd mask) "*.*" -> all in
let _listoffiles dir -> files in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if ((!all && (mask != nil) && !(isExtInListi mask ext)) || ((cbfilter != nil) && ((exec cbfilter with [file]) != 1))) then nil else
set lfiles = lcat lfiles file::nil;
set files = tl files;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files list from a directory, with a file extension mask and case sensitive
*
* Prototype: fun [S [S r1]] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files
**/
fun getFilesFromDir2(dir, mask)=
let !strcmp (hd mask) "*.*" -> all in
let _listoffiles2 dir -> files in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if (!all && (mask != nil) && !(isExtInListi mask ext)) then nil else
set lfiles = lcat lfiles file::nil;
set files = tl files;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files list from a directory, with a file extension mask and case sensitive and filter
*
* Prototype: fun [S [S r1] fun [S] I ] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files
**/
fun getFilesFromDirFilter2(dir, mask, cbfilter)=
let !strcmp (hd mask) "*.*" -> all in
let _listoffiles2 dir -> files in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if ((!all && (mask != nil) && !(isExtInListi mask ext)) || ((cbfilter != nil) && ((exec cbfilter with [file]) != 1))) then nil else
set lfiles = lcat lfiles file::nil;
set files = tl files;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files names list from a directory, with a file extension mask
*
* Prototype: fun [S [S r1]] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files names
**/
fun getFilesNamesFromDir(dir, mask)=
let !strcmp (hd mask) "*.*" -> all in
let _listoffiles dir -> files in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if (!all && (mask != nil) && !(isExtInListi mask ext)) then nil else
let getPathFile file "" -> [_ fname] in
set lfiles = lcat lfiles fname::nil;
set files = tl files;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files names list from a directory, with a file extension mask and case sensitive
*
* Prototype: fun [S [S r1]] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files names
**/
fun getFilesNamesFromDir2(dir, mask)=
let !strcmp (hd mask) "*.*" -> all in
let _listoffiles2 dir -> files in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if (!all && (mask != nil) && !(isExtInListi mask ext)) then nil else
let getPathFile file "" -> [_ fname] in
set lfiles = lcat lfiles fname::nil;
set files = tl files;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Replace spaces in a file name and removes special characters that are unsupported on some platforms
*
* Prototype: fun [S] S
*
* \param S : the path to sanitize
*
* \return [S r1] : path with sanitized file name
**/
fun sanitizeFileName(file)=
if (file == nil) then nil else
let getPathFile file "" -> [dir filename] in
let strdup filename -> cpname in
//do strlowercase on the copied string, this modify the original string otherwise
let strreplace (strlowercase cpname) " " "_" -> nname in
(
let "a"::"b"::"c"::"d"::"e"::"f"::"g"::"h"::"i"::"j"::"k"::"l"::"m"::"n"::"o"::"p"::"q"::"r"::"s"::"t"::"u"::"v"::"w"::"x"::"y"::"z"::"0"::"1"::"2"::"3"::"4"::"5"::"6"::"7"::"8"::"9"::"-"::"_"::"."::nil -> charset in
let 0 -> pos in
let strlen nname -> len in
let "" -> fname in
(
//while ((strlen nname) > 0) do
while (pos < len) do
(
//let substr nname 0 1 -> letter in
let substr nname pos 1 -> letter in
if (!isStringInList charset letter) then nil else
set fname = strcat fname letter;
//set nname = substr nname 1 strlen nname;
set pos = pos + 1;
);
strcat dir fname;
);
);;
/*! @ingroup toolsstr
* \brief Get the boolean value of a string
*
* Prototype: fun [S] I
*
* \param S : the boolean value "enable" "1" "on" "true" "yes"
*
* \return I : 1 if the boolean value is correct, 0 otherwise
**/
fun getBooleanFromString(str)= if (!strcmpi strtrim str "enable") || (!strcmpi strtrim str "ON") || (!strcmpi strtrim str "true") || (!strcmpi strtrim str "yes") || ((atoi str) == 1) then 1 else 0;;
/*! @ingroup toolsstr
* \brief Compare the last word of a string
*
* Prototype: fun [S S] I
*
* \param S : the word to compare
* \param S : the full string
*
* \return I : 1 if the word is at the end of the string, 0 otherwise
**/
fun isLastWordfromString(word, string)= !strcmpi word (substr string ((strlen string) - (strlen word)) (strlen word));;
/*! @ingroup toolsstr
* \brief Compare the first word of a string
*
* Prototype: fun [S S] I
*
* \param S : the word to compare
* \param S : the full string
*
* \return I : 1 if the word is at the beginning of the string, 0 otherwise
**/
fun isFirstWordfromString(word, string)= !strcmpi word (substr string 0 (strlen word));;
/*! @ingroup toolsstr
* \brief Make the first letter uppercase
*
* Prototype: fun [S] S
*
* \param S : the text
*
* \return S : The text with first letter uppercase
**/
fun capitalizeFirstLetter(s)=
let struppercase (strdup s) -> up in
let substr up 0 1 -> majc in
strcat majc (substr s 1 (strlen s));;
/*! @ingroup toolslist
* \brief Transform a string list to lowercase
*
* Prototype: fun [[S r1]] [S r1]
*
* \param [S r1] : the string list
*
* \return [S r1] : the same string list with lowercase values
**/
fun listLowercase(l)=
let sizelist l -> size in
let nil -> ndata in
let 0 -> i in
(
while i < size do
(
let nth_list l i -> elem in
set ndata = lcat ndata (strlowercase elem)::nil;
set i = i + 1;
);
ndata;
);;
/*! @ingroup toolsfile
* \brief List the directories of a path
*
* Prototype: fun [S] [S r1]
*
* \param S : the path directory
*
* \return [S r1] : a list of directories
**/
fun getDirListFromPath(path)=
let nil -> lpaths in
(
let _listofsubdir path -> ldirs in
let sizelist ldirs -> size in
let 0 -> i in
while i < size do
(
let nth_list ldirs i -> dir in
set lpaths = lcat lpaths dir::(getDirListFromPath dir);
set i = i + 1;
);
lpaths
);;
/*! @ingroup toolsfile
* \brief List the files from a directory path recursively
*
* Prototype: fun [S] [S r1]
*
* \param S : the path directory
*
* \return [S r1] : a list of files
**/
fun getFilesFromDirRecursive(dir)=
if (isLastWordfromString ".svn" dir) then nil else
let _listoffiles dir -> lfiles in
let _listofsubdir dir -> lsubdirs in
(
while (lsubdirs != nil) do
(
let hd lsubdirs -> elem in
set lfiles = lcat lfiles (getFilesFromDirRecursive elem);
set lsubdirs = tl lsubdirs;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files list from a directory, with a file extension mask and filter recursively
*
* Prototype: fun [S [S r1] fun [S] I ] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files
**/
fun getFilesFromDirFilterRecursive(dir, mask, cbfilter)=
let _listoffiles dir -> files in
let _listofsubdir dir -> lsubdirs in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if (((mask != nil) && !(isExtInListi mask ext)) || ((cbfilter != nil) && ((exec cbfilter with [file]) != 1))) then nil else
set lfiles = lcat lfiles file::nil;
set files = tl files;
);
while (lsubdirs != nil) do
(
let hd lsubdirs -> elem in
set lfiles = lcat lfiles (getFilesFromDirFilterRecursive elem mask cbfilter);
set lsubdirs = tl lsubdirs;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief List the files from a directory path recursively case sensitive
*
* Prototype: fun [S] [S r1]
*
* \param S : the path directory
*
* \return [S r1] : a list of files
**/
fun getFilesFromDirRecursive2(dir)=
if (isLastWordfromString ".svn" dir) then nil else
let _listoffiles2 dir -> lfiles in
let _listofsubdir2 dir -> lsubdirs in
(
while (lsubdirs != nil) do
(
let hd lsubdirs -> elem in
set lfiles = lcat lfiles (getFilesFromDirRecursive2 elem);
set lsubdirs = tl lsubdirs;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Get the files list from a directory, with a file extension mask and case sensitive and filter recursively
*
* Prototype: fun [S [S r1] fun [S] I ] [S r1]
*
* \param S : the path to list
* \param [S r1] : a list of string mask (ex : "pkg"::"bmp"::nil)
*
* \return [S r1] : a list of found files
**/
fun getFilesFromDirFilterRecursive2(dir, mask, cbfilter)=
let _listoffiles2 dir -> files in
let _listofsubdir2 dir -> lsubdirs in
let nil -> lfiles in
(
while (files != nil) do
(
let hd files -> file in
let getFileExt file -> ext in
if (((mask != nil) && !(isExtInListi mask ext)) || ((cbfilter != nil) && ((exec cbfilter with [file]) != 1))) then nil else
set lfiles = lcat lfiles file::nil;
set files = tl files;
);
while (lsubdirs != nil) do
(
let hd lsubdirs -> elem in
set lfiles = lcat lfiles (getFilesFromDirFilterRecursive2 elem mask cbfilter);
set lsubdirs = tl lsubdirs;
);
lfiles;
);;
/*! @ingroup toolsfile
* \brief Delete all the files of a directory
*
* Prototype: fun [S] I
*
* \param S : the path directory
*
* \return 0
**/
fun cleanDirectory(dir)=
let _listoffiles dir -> lfiles in
let _listofsubdir dir -> lsubdirs in
(
let sizelist lsubdirs -> size in
let 0 -> i in
while i < size do
(
let nth_list lsubdirs i -> elem in
cleanDirectory elem;
set i = i + 1;
);
let sizelist lfiles -> size in
let 0 -> i in
while i < size do
(
let nth_list lfiles i -> elem in
_deletepack _checkpack elem;
set i = i + 1;
);
_deletepack _checkpack dir;
);
0;;
/*! @ingroup toolsfile
* \brief Remove the last '/' from a directory path
*
* Prototype: fun [S] I
*
* \param S : the directory path
*
* \return S : the directory path without the last slash
**/
fun getDirectoryWithoutLastSlash(dir)=
if isLastWordfromString "/" dir then
substr dir 0 ((strlen dir) - 1)
else
dir;;
/*! @ingroup toolsfile
* \brief Remove the first '/' from a directory path
*
* Prototype: fun [S] I
*
* \param S : the directory path
*
* \return S : the directory path without the first slash
**/
fun getDirectoryWithoutFirstSlash(dir)=
if isFirstWordfromString "/" dir then
substr dir 1 ((strlen dir) - 1)
else
dir;;
/*! @ingroup toolslist
* \brief apply a function to a list
*
* Prototype: fun [[u0 r1] fun [u0 u1] I u1] I
*
* \param [u0 r1] : the list
* \param fun [u0 u1] I : the function to call for each list element
* \param u1 : a user parameter
*
* \return I : 0
**/
fun apply_on_list(l,f,x)=
if l==nil then 0
else let l -> [a nxt] in
(exec f with [a x];
apply_on_list nxt f x);;
/*! @ingroup toolslist
* \brief apply a function to a list reserved
*
* Prototype: fun [[u0 r1] fun [u0 u1] u0 u1] [u0 r1]
*
* \param [u0 r1] : the list
* \param fun [u0 u1] u0 : the function to call for each list element
* \param u1 : a user parameter
*
* \return [u0 r1] : the new list
**/
fun rev_apply_on_list(l,f,x)=
if l==nil then 0
else let l -> [a nxt] in
(rev_apply_on_list nxt f x;
exec f with [a x];0);;
/*! @ingroup toolslist
* \brief Search an element in a list
*
* Prototype: fun [[u0 r1] fun [u0 u1] I u1] u0
*
* \param [u0 r1] : the list
* \param fun [u0 u1] I : the function to call for each list element to compare
* \param u1 : a user parameter
*
* \return u0 : the element found or nil
**/
fun search_in_list(l,f,x)=
if l==nil then nil
else let l -> [a nxt] in
if exec f with [a x] then a
else search_in_list nxt f x;;
/*! @ingroup toolslist
* \brief Remove an element in a list
*
* Prototype: fun [[u0 r1] u0] [u0 r1]
*
* \param [u0 r1] : the list
* \param u0 : the list element to remove
*
* \return [u0 r1] : the list without the element
**/
fun remove_from_list(l,p)=
if l==nil then nil
else let l -> [a nxt] in
if a==p then nxt
else a::remove_from_list nxt p;;
fun remove_nth_from_list (list, n)=
if n < 0
then
list
else
let list -> [first next] in
if n==0
then
next
else
first::remove_nth_from_list next n-1;;
fun replace_in_list(list, old, new)=
if list==nil
then
nil
else
let list -> [first next] in
if first==old
then
new::next
else
first::replace_in_list next old new;;
fun replace_nth_in_list(list, n, new)=
if list==nil
then
nil
else
let list -> [first next] in
if n==0
then
new::next
else
first::replace_nth_in_list next n-1 new;;
fun add_nth_in_list (list, n, x)=
if n < 0
then
lcat list x::nil
else
let list -> [first next] in
if n==0
then
x::list
else
first::add_nth_in_list next n-1 x;;
fun tlr2(l, n)=
let sizelist l -> size in
let 0 -> i in
let 0 -> nn in
let nil -> nl in
(
while i < size do
(
let nth_list l i -> lelt in
(
while (nn < n) do
(
set lelt = tl lelt;
set nn = nn + 1;
);
set nl = lcat nl lelt::nil;
);
set i = i + 1;
);
nl;
);;
/*! @ingroup toolslist
* \brief Remove an string in a list
*
* Prototype: fun [[S r1] S] [S r1]
*
* \param [S r1] : the list
* \param S : the list element to remove
*
* \return [S r1] : the list without the element
**/
fun remove_string_from_list(l, elt)=
if l==nil
then
nil
else
let hd l -> elm in
if !strcmpi elm elt then
tl l
else
(hd l)::remove_string_from_list tl l elt;;
/*! @ingroup toolslist
* \brief Remove an indexed element in a list
*
* Prototype: fun [[[u0 u1] r1] u0] [[u0 u1] r1]
*
* \param [[u0 u1] r1] : the list
* \param u0 : the index to remove
*
* \return [[u0 u1] r1] : the list without the element
**/
fun remove_idx_from_list(l, idx)=
if l==nil
then
nil
else
let hd l -> [id _] in
if id == idx then
tl l
else
(hd l)::remove_idx_from_list tl l idx;;
/*! @ingroup toolslist
* \brief Remove a string indexed element in a list
*
* Prototype: fun [[[S u0] r1] S] [[S u0] r1]
*
* \param [[S u0] r1] : the list
* \param S : the index to remove
*
* \return [[S u0] r1] : the list without the element
**/
fun remove_sid_from_list(l, sid)=
if l==nil
then
nil
else
let hd l -> [id _] in
if (!strcmp id sid) then
tl l
else
(hd l)::remove_sid_from_list tl l sid;;
/*! @ingroup toolslist
* \brief Remove a string indexed element in a list case incensivity
*
* Prototype: fun [[[S u0] r1] S] [[S u0] r1]
*
* \param [[S u0] r1] : the list
* \param S : the index to remove
*
* \return [[S u0] r1] : the list without the element
**/
fun remove_sid_from_listi(l, sid)=
if l==nil
then
nil
else
let hd l -> [id _] in
if (!strcmpi id sid) then
tl l
else
(hd l)::remove_sid_from_listi tl l sid;;
fun remove_first_string_from_list(l, elt)=
if l==nil
then
nil
else
let hd hd l -> elm in
if !strcmpi elm elt then
tl l
else
(hd l)::remove_first_string_from_list tl l elt;;
fun remove_all_first_string_from_list(l, elt)=
if l==nil
then
nil
else
let hd hd l -> elm in
if !strcmpi elm elt then
remove_all_first_string_from_list tl l elt
else
(hd l)::remove_all_first_string_from_list tl l elt;;
fun remove_first_and_second_string_from_list(l, elt1, elt2)=
if l==nil
then
nil
else
let hd hd l -> elm1 in
let hd tl hd l -> elm2 in
if (!strcmpi elm1 elt1) && (!strcmpi elm2 elt2) then
tl l
else
(hd l)::remove_first_and_second_string_from_list tl l elt1 elt2;;
fun remove_all_first_string_from_second_elem_list(l, elt)=
if l==nil
then
nil
else
let hd l -> [_ nl] in
let hd nl -> elm in
if !strcmpi elm elt then
remove_all_first_string_from_second_elem_list tl l elt
else
(hd l)::remove_all_first_string_from_second_elem_list tl l elt;;
fun remove_first_and_second_string_from_second_elem_list(l, elt1, elt2)=
if l==nil
then
nil
else
let hd l -> [_ nl] in
let hd nl -> elm1 in
let hd tl nl -> elm2 in
if (!strcmpi elm1 elt1) && (!strcmpi elm2 elt2) then
tl l
else
(hd l)::remove_first_and_second_string_from_second_elem_list tl l elt1 elt2;;
fun remove_first_string_from_list_start_with(l, elt)=
if l==nil
then
nil
else
let hd hd l -> elm in
if !strcmpi (substr elm 0 (strlen elt)) elt then
remove_first_string_from_list_start_with tl l elt
else
(hd l)::remove_first_string_from_list_start_with tl l elt;;
fun remove_first_string_from_second_element_list_start_with(l, elt)=
if l==nil
then
nil
else
let hd l -> [_ nl] in
let hd nl -> elm in
if !strcmpi (substr elm 0 (strlen elt)) elt then
remove_first_string_from_list_start_with tl l elt
else
(hd l)::remove_first_string_from_list_start_with tl l elt;;
fun pos_sid_in_list(l,p,n)=
if l==nil then nil
else let l -> [[a _] nxt] in
if (!strcmp a p) then n
else pos_sid_in_list nxt p n+1;;
fun pos_in_list(l,p,n)=
if l==nil then nil
else let l -> [a nxt] in
if a==p then n
else pos_in_list nxt p n+1;;
fun create_tab(n,f,x)=
let mktab n nil -> t in
(let 0->i in while i l in
if f==nil then [l l]
else let f->[a b] in
(mutate b<-[_ l]; [a l]);;
fun getFifo(f)=
if f==nil then [nil nil]
else let f->[a b] in
if a==b then [hd a nil]
else [hd a [tl a b]];;
fun sizeFifo(f)=
if f==nil then 0
else let f->[a _] in sizelist a;;
fun concFifo(f,g)=
if f==nil then g
else if g==nil then f
else let f->[a b] in let g->[c d] in
(mutate b<-[_ c]; [a d]);;
fun hexListToBignumList(l)=
let sizelist l -> size in
let nil -> ndata in
let 0 -> i in
(
while i < size do
(
let nth_list l i -> elt in
set ndata = lcat ndata (BigFromAsc elt)::nil;
set i = i + 1;
);
ndata;
);;
/*! @ingroup toolslist
* \brief Rename a string indexed element in a list
*
* Prototype: fun [[[S u0] r1] S S] [[S u0] r1]
*
* \param [[S u0] r1] : the list
* \param S : the index to rename
* \param S : the new index name
*
* \return [[S u0] r1] : the list updated
**/
fun rename_sid_from_list(l, sid, nid)=
let switchstr l sid -> selt in
let switchstr l nid -> nelt in
if (l == nil || (selt == nil) || (nelt != nil))
then
l
else
let pos_sid_in_list l sid 0 -> pos in
add_nth_in_list (remove_nth_from_list l pos) pos [nid selt];;
/*! @ingroup toolsstr
* \brief Replace a string in an another string
*
* Prototype: fun [S S S] S
*
* \param S : the string to change
* \param I : char to find
* \param S : the string to replace with
*
* \return S : the new string
**/
fun strreplaceChar(s, from, to)=
let strlen s -> size in
let 0 -> pos in
while (pos < size) do
(
if (nth_char s pos) != from then
set pos = pos + 1
else
(
set s = strcatn (substr s 0 pos)::to::(substr s (pos + 1) (strlen s))::nil;
set size = strlen s;
set pos = pos + 1 + strlen to;
);
);
s;;
/*! @ingroup toolsstr
* \brief Replace a string in an another string
*
* Prototype: fun [S S S] S
*
* \param S : the string to change
* \param S : the string to find
* \param S : the string to replace with
*
* \return S : the new string
**/
fun strreplace(s, from, to)=
let 0 -> pos in
let strlen from -> fsize in
let strlen to -> tsize in
let if (tsize == 0) then 1 else tsize -> tsize in
if (fsize <= 0) then s else
(
while ((set pos = strfind from s pos) != nil) do
(
set s = strcatn (substr s 0 pos)::to::(substr s (pos + fsize) ((strlen s) - pos))::nil;
set pos = pos + tsize;
);
s;
);;
/*! @ingroup toolsstr
* \brief Replace a string in an another string, case insensivity
*
* Prototype: fun [S S S] S
*
* \param S : the string to change
* \param S : the string to find
* \param S : the string to replace with
*
* \return S : the new string
**/
fun strreplacei(s, from, to)=
let 0 -> pos in
let strlen from -> fsize in
let strlen to -> tsize in
let if (tsize == 0) then 1 else tsize -> tsize in
if (fsize <= 0) then s else
(
while ((set pos = strfindi from s pos) != nil) do
(
set s = strcatn (substr s 0 pos)::to::(substr s (pos + fsize) ((strlen s) - pos))::nil;
set pos = pos + tsize;
);
s;
);;
/*! @ingroup toolsstr
* \brief convert a string to a list of words
*
* Prototype: fun [S] [S r1]
*
* \param S : string
*
* \return [S r1] : the list of words
**/
fun strToWordList(s)=
let strextr s -> l in
let nil -> nl in
(
while (l != nil) do
(
let hd l -> lw in
while (lw != nil) do
(
set nl = (hd lw)::nl;
set lw = tl lw;
);
set l = tl l;
);
revertlist nl;
);;
/*! @ingroup toolsstr
* \brief replace key by value position in arg list ("my string is $1 with $2" "val1"::"val2"::nil)
*
* Prototype: fun [S S [S r1]] S
*
* \param S : string
* \param S : the key "$" for example
* \param [S r1] : list of arguments
*
* \return S : the converted string
**/
fun replaceByKeyIndex(s, key, args)=
let sizelist args -> size in
(
while (size > 0) do
(
set s = strreplace s (strcat key (itoa size)) (nth_list args (size - 1));
set size = size - 1;
);
s;
);;
/*! @ingroup toolsstr
* \brief replace key by value position in arg list ("my string is $1 with $2" "val1 val2")
*
* Prototype: fun [S S S] S
*
* \param S : string
* \param S : the key "$" for example
* \param S : arguments
*
* \return S : the converted string
**/
fun replaceByKeyIndex2(s, key, args)=
let strToWordList args -> lp in
let sizelist lp -> size in
(
while (size >= 0) do
(
if (size == 0) then
set s = strreplace s (strcat key (itoa size)) args
else
set s = strreplace s (strcat key (itoa size)) (nth_list lp (size - 1));
set size = size - 1;
);
s;
);;
/*! @ingroup toolsstr
* \brief Concat a string list with a defined separator
*
* Prototype: fun [[S r1] S] S
*
* \param [S r1] : the string list
* \param S : the separator to use
*
* \return S : the new string
**/
fun strcatnSep(l, sep)=
let sizelist l -> size in
let nil -> ndata in
let 0 -> i in
(
while i < size do
(
let nth_list l i -> elem in
if i == 0 then
set ndata = elem
else
set ndata = strcatn ndata::sep::elem::nil;
set i = i + 1;
);
ndata;
);;
/*! @ingroup toolsstr
* \brief Concat a string list with a defined separator and limits
*
* Prototype: fun [[S r1] S I] S
*
* \param [S r1] : the string list
* \param S : the separator to use
*
* \return S : the new string
**/
fun strcatnSepLimits(l, sep, nb)=
let sizelist l -> size in
let nil -> ndata in
let 0 -> i in
(
while ((i < size) && (i < nb)) do
(
let nth_list l i -> elem in
if i == 0 then
set ndata = elem
else
set ndata = strcatn ndata::sep::elem::nil;
set i = i + 1;
);
ndata;
);;
/*! @ingroup toolsstr
* \brief Concat a string list with a defined separator and a line feed
*
* Prototype: fun [[[S r1] r1] S] S
*
* \param [[S r1] r1] : the string list
* \param S : the separator to use
*
* \return S : the new string
**/
fun strcatnlSep(l, sep)=
if l == nil then nil else
let sizelist l -> size in
let nil -> ndata in
let 0 -> i in
(
while i < size do
(
let nth_list l i -> elem in
if i == 0 then
set ndata = (strcatnSep elem sep)
else
set ndata = strcatn ndata::"\n"::(strcatnSep elem sep)::nil;
set i = i + 1;
);
ndata;
);;
fun strfindiList(l, s)=
let nil -> found in
(
let sizelist l -> size in
let 0 -> i in
while ((i < size) && (found == nil)) do
(
let nth_list l i -> elt in
let strfindi elt s 0 -> pos in
if (pos == nil) then nil else
set found = [i pos];
set i = i + 1;
);
found;
);;
/*! @ingroup toolsstr
* \brief Protect special character with a '\'
*
* Prototype: fun [S] S
*
* \param S : the string to protect
*
* \return S : the new string
**/
fun addSlashes(s)=
let "" -> ret in
(
let strlen s -> size in
let 0 -> i in
while (i < size) do
(
let nth_char s i -> char in
if (char == 34) || (char == 39) || (char == 92) || (char == 96) then
set ret = strcatn ret::(ctoa 92)::(ctoa char)::nil
else
set ret = strcat ret (ctoa char);
set i = i + 1;
);
ret;
);;
/*! @ingroup toolsstr
* \brief Remove special character protection '\'
*
* Prototype: fun [S] S
*
* \param S : the string
*
* \return S : the new string
**/
fun stripSlashes(s)=
if ((s == nil) || (!strcmp s "")) then s else
(
let strlen s -> size in
let 0 -> pos in
while (pos < size) do
(
if ((((nth_char s pos) == 92) && ((nth_char s pos + 1) == 92)) || ((nth_char s pos) != 92)) then
set pos = pos + 1
else
(
set s = strcat (substr s 0 pos) (substr s (pos + 1) (strlen s));
set size = strlen s;
set pos = pos + 1;
);
);
s;
);;
/*! @ingroup toolsstr
* \brief Protect char character with a char
*
* Prototype: fun [S I I] S
*
* \param S : the string to protect
* \param I : char to protect
* \param I : char to add
*
* \return S : the new string
**/
fun addChar(s, p, c)=
let "" -> ret in
(
let strlen s -> size in
let 0 -> i in
while (i < size) do
(
let nth_char s i -> char in
if (char == p) then
set ret = strcatn ret::(ctoa c)::(ctoa char)::nil
else
set ret = strcat ret (ctoa char);
set i = i + 1;
);
ret;
);;
/*! @ingroup toolsstr
* \brief Remove special character protection '\'
*
* Prototype: fun [S I] S
*
* \param S : the string
* \param I : char to remove
*
* \return S : the new string
**/
fun stripChar(s, c)=
if ((s == nil) || (!strcmp s "")) then s else
(
let strlen s -> size in
let 0 -> pos in
while (pos < size) do
(
if ((nth_char s pos) != c) then
set pos = pos + 1
else
(
set s = strcat (substr s 0 pos) (substr s (pos + 1) (strlen s));
set size = strlen s;
set pos = pos + 1;
);
);
s;
);;
/*! @ingroup toolsstr
* \brief Truncate a string
*
* Prototype: fun [S I S] S
*
* \param S : the string
* \param I : the maximun string length
* \param S : the string to add to the end (...)
*
* \return S : the new string
**/
fun strTruncate(s, maxlen, rp)=
if (strlen s) > maxlen then
strcat substr s 0 (maxlen - (strlen rp)) rp
else
s;;
/*! @ingroup toolsstr
* \brief Quote a string
*
* Prototype: fun [S S] S
*
* \param S : the string
* \param S : the character to use for quotes '"'
*
* \return S : the new string
**/
fun strQuote(s, q)= strcatn q::(strtrim s)::q::nil;;
/*! @ingroup toolsstr
* \brief Quote a string list
*
* Prototype: fun [[S r1] S] [S r1]
*
* \param [S r1] : the string list
* \param S : the character to use for quotes '"'
*
* \return [S r1] : the new string list
**/
fun listQuote(l, q)=
let nil -> nl in
(
let sizelist l -> size in
let 0 -> i in
while i < size do
(
let nth_list l i -> elt in
set nl = lcat nl (strQuote elt q)::nil;
set i = i + 1;
);
nl;
);;
/*! @ingroup toolsstr
* \brief Remove spaces and first / last character of a string
*
* Prototype: fun [S S S] S
*
* \param S : the string
* \param S : the first character to remove
* \param S : the last character to remove
*
* \return S : the new string
**/
fun strtrimChar(str, first, last)=
let strtrim str -> str in
let if (first == nil) then str else if (!strcmp (substr str 0 1) first) then substr str 1 (strlen str) -1 else str -> str in
let if (last == nil) then str else if (!strcmp (substr str (strlen str) -1 1) last) then substr str 0 (strlen str) -1 else str -> str in
str;;
/*! @ingroup toolsstr
* \brief Convert a String to a list of lines
*
* Prototype: fun [S] [S r1]
*
* \param S : the string
*
* \return [S r1] : the list of string lines
**/
fun strToList(s)=
let nil -> ret in
let strextr s -> l in
(
while (l != nil) do
(
let hd l -> line in
set ret = (strcatnSep line " ")::ret;
set l = tl l;
);
revertlist ret;
);;
fun removeNthChar(s, p)=
if ((s == nil) || (!strcmp s "") || (p == nil)) then s else
(
let strlen s -> size in
let 0 -> pos in
while (pos < size) do
(
if (pos == p) then
set pos = pos + 1
else
(
set s = strcat (substr s 0 pos) (substr s (pos + 1) (strlen s));
set size = strlen s;
set pos = pos + 1;
);
);
s;
);;
fun contcatQuotedList(l, c)=
if (l == nil) then nil else
let l -> [line next] in
(
let nil -> lp in
(
while (((mod (sizelist (set lp = (strfind2List line (ctoa c) 0))) 2) != 0) && (next != nil)) do
(
set line = strcatn line::"\n"::(hd next)::nil;
set next = tl next;
);
);
line::(contcatQuotedList next c);
);;
/*! @ingroup toolsstr
* \brief Convert a String to a list of lines but protect line with char
*
* Prototype: fun [S I] [S r1]
*
* \param S : the string
* \param I : char condition
*
* \return [S r1] : the list of string lines
**/
fun strToQuotedList(s, c)=
let nil -> ret in
let strextr s -> l in
(
while (l != nil) do
(
let hd l -> line in
set ret = (strcatnSep line " ")::ret;
set l = tl l;
);
contcatQuotedList revertlist ret c;
);;
/*! @ingroup toolsstr
* \brief Change the line separation character
*
* Prototype: fun [S S] S
*
* \param S : the string
* \param S : the line separation character
*
* \return S : the new string
**/
fun oneLineTransform(s, sep)=
strcatnSep (strToList s) sep;;
/*! @ingroup toolsstr
* \brief Convert a string to a list by a defined separator
*
* Prototype: fun [S S] [S r1]
*
* \param S : the string
* \param S : separator ';'
*
* \return [S r1] : the string list
**/
fun strToListSep(s, sep)=
let nil -> ret in
let 0 -> spos in
(
while (strfindi sep s spos) != nil do
(
let strfindi sep s spos -> fpos in
let substr s spos (fpos - spos) -> value in
(
set ret = value::ret;
set spos = fpos + strlen sep;
);
);
if (spos >= strlen s) then nil else
set ret = (substr s spos ((strlen s) - spos))::ret;
revertlist ret;
);;
/*! @ingroup toolsstr
* \brief Convert a string to a list by a defined open / close separators
*
* Prototype: fun [S S S] [S r1]
*
* \param S : the string
* \param S : open separator '['
* \param S : close separator ']'
*
* \return [S r1] : the string list
**/
fun strToListOpenCloseSep(s, osep, csep)=
let nil -> ret in
let 0 -> spos in
(
while (strfindi osep s spos) != nil do
(
let strfindi osep s spos -> fpos in
let strfindi csep s fpos + (strlen osep) -> epos in
let substr s (fpos + (strlen osep)) (epos - (fpos + (strlen osep))) -> value in
(
set ret = value::ret;
set spos = epos + strlen csep;
);
);
revertlist ret;
);;
/*! @ingroup toolsstr
* \brief Convert a string to a list by a defined separator
*
* Prototype: fun [S S fun [S] S] [S r1]
*
* \param S : the string
* \param S : separator ';'
* \param fun [S] S : callback to modify the value
*
* \return [S r1] : the string list
**/
fun strToListSepCb(s, sep, cb)=
let nil -> ret in
let 0 -> spos in
(
while (strfindi sep s spos) != nil do
(
let strfindi sep s spos -> fpos in
let substr s spos (fpos - spos) -> value in
(
set ret = (exec cb with [value])::ret;
set spos = fpos + strlen sep;
);
);
if (spos >= strlen s) then nil else
set ret = (substr s spos ((strlen s) - spos))::ret;
revertlist ret;
);;
/*! @ingroup toolsstr
* \brief Convert list of words and lines to a string
*
* Prototype: fun [[[S r1] r1]] S
*
* \param [[S r1] r1] : list of words and lines
*
* \return S : the formated string
**/
fun strbuildn(l)=
let nil -> ret in
(
let sizelist l -> size in
let 0 -> i in
while (i < size) do
(
let nth_list l i -> line in
set ret = lcat ret (strcatnSep line " ")::nil;
set i = i + 1;
);
if ret == nil then nil else strcatnSep ret "\n";
);;
/*! @ingroup toolsstr
* \brief Convert list of lines to a string
*
* Prototype: fun [[S r1]] S
*
* \param [S r1] : list of lines
*
* \return S : the formated string
**/
fun listToString(l)=
let nil -> ret in
(
let sizelist l -> size in
let 0 -> i in
while (i < size) do
(
let nth_list l i -> line in
let strextr line -> lp in
let sizelist lp -> s2 in
let 0 -> s in
while (s < s2) do
(
set ret = lcat ret (strcatnSep (nth_list lp s) " ")::nil;
set s = s + 1;
);
set i = i + 1;
);
if ret == nil then nil else strcatnSep ret "\n";
);;
/*! @ingroup toolsstr
* \brief Check is a string is a number or a float
*
* Prototype: fun [S] I
*
* \param S : string
*
* \return I : return 1 if the string is a number else 0
**/
fun isNumber(s)=
let if ((s == nil) || ((strlen s) == 0)) then 0 else 1 -> ret in
(
let strlen s -> size in
let 0 -> i in
while (i < size && ret) do
(
let nth_char s i -> char in
if (((char >= 48) && (char <= 57)) || (char == 46) || ((char == 45) && (i == 0))) then nil else
set ret = 0;
set i = i + 1;
);
ret;
);;
/*! @ingroup toolsstr
* \brief get the line after a keyword, for example "KEYWORD value"
*
* Prototype: fun [S S] S
*
* \param S : string
* \param S : keyword
*
* \return S : the value if the keyword exist nil otherwise
**/
fun getNextToValue(cont, keyword)=
let strextr cont -> lcont in
let sizelist lcont -> size in
let 0 -> i in
let nil -> ret in
(
while ((i < size) && (ret == nil)) do
(
let nth_list lcont i -> [word next] in
if strcmpi keyword (strtrim word) then nil else
set ret = strcatnSep next " ";
set i = i + 1;
);
ret;
);;
/*! @ingroup toolsstr
* \brief transform a float into a clean readable string
*
* Prototype: fun [F] S
*
* \param F : float value
*
* \return S : the value cleaned float string
**/
fun floatToString(float)=
let if (absf float) >. (itof (ftoi absf float)) then (ftoa float) else itoa (ftoi float) -> s in
let strfind "." s 0 -> dotpos in
if (dotpos == nil) then
s
else
(
while ((strfind "0" s ((strlen s) -1)) != nil) do
set s = substr s 0 ((strlen s) -1);
s;
);;
/*! @ingroup toolsstr
* \brief invert switchstr parameter
*
* Prototype: fun [[u0 S] S] u0
*
* \param [u0 S] : list
* \param S : value to get
*
* \return u0 : corresponding value
**/
fun switchstrInv(l, s)=
if (l == nil) || (s == nil) then nil else
let hd l -> [v t] in
if (!strcmp t s) then
v
else
switchstrInv tl l s;;
/*! @ingroup toolsstr
* \brief invert switchstri parameter
*
* Prototype: fun [[u0 S] S] u0
*
* \param [u0 S] : list
* \param S : value to get
*
* \return u0 : corresponding value
**/
fun switchstriInv(l, s)=
if (l == nil) || (s == nil) then nil else
let hd l -> [v t] in
if (!strcmpi t s) then
v
else
switchstriInv tl l s;;
/*! @ingroup toolsstr
* \brief invert switch parameter
*
* Prototype: fun [[u0 I] I] u0
*
* \param [u0 I] : list
* \param I : value to get
*
* \return u0 : corresponding value
**/
fun switchInv(l, s)=
if (l == nil) || (s == nil) then nil else
let hd l -> [v t] in
if (t == s) then
v
else
switchInv tl l s;;
/* ********************************************************************************************* /
HTTP DOWNLOAD
/ ********************************************************************************************* */
typeof lHTTP_COOKIES = [[S S] r1];;
typeof lHTTP_REQUEST = [ObjCURL r1];;
var iCURL_REQUEST_TIMEOUT = 5;;
fun strIsUrl(url)= if (strfind "://" url 0) != nil then 1 else 0;;
fun urlDecode(s)=
strreplace webtostr s "\\u0026" "&";;
fun makeSimpleJson(lp)=
let "{" -> s in
(
while (lp != nil) do
(
let hd lp -> [key val] in
set s = strcatn s::"'"::key::"':"::val::nil;
set lp = tl lp;
if (lp == nil) then nil else
set s = strcat s ", ";
);
strcat s "}";
);;
fun cbCheckInternetConnection(inet, p, data, code)=
let p -> [url cbfun param] in
if (code == 0) then
(
0;
)
else if (code == 1) then
(
exec cbfun with [url param 1];
0;
)
else
(
exec cbfun with [url param 0];
0;
);
0;;
/*! @ingroup toolsdl
* \brief Test the Internet connection availability (multiplatform)
*
* Prototype: fun [S fun [S u0 I] I u0] I
*
* \return 0
**/
fun checkInternetConnection(url, cbfun, param)=
let if (url == nil) || !(strIsUrl url) then "http://www.google.com" else url -> url in
INETGetURL _channel url 0 @cbCheckInternetConnection [url cbfun param];
0;;
/*! @ingroup toolsdl
* \brief Kill all current download requests
*
* Prototype: fun [] I
*
* \return 0
**/
fun clearHttpRequest()=
let lHTTP_REQUEST -> l in
while (l != nil) do
(
_KILLcurlRequest hd l;
set l = tl l;
);
set lHTTP_REQUEST = nil;
0;;
/*! @ingroup toolsdl
* \brief Kill a download request
*
* Prototype: fun [ObjCURL] I
*
* \param ObjCURL : the request to kill
*
* \return 0
**/
fun killHttpRequest(req)=
if (req == nil) then nil else
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST req;
_KILLcurlRequest req;
);
0;;
/*! @ingroup toolsdl
* \brief Clear all http cookies
*
* Prototype: fun [] I
*
* \return 0
**/
fun clearHttpCookies()=
set lHTTP_COOKIES = nil;
0;;
/*! @ingroup toolsdl
* \brief Get the domain of an url
*
* Prototype: fun [S] S
*
* \param S : the url
*
* \return S : the url domain
**/
fun getHttpDomain(url)=
let if (!strcmp (substr url 0 8) "https://") then
substr url 8 ((strlen url) - 8)
else if (!strcmp (substr url 0 7) "http://") then
substr url 7 ((strlen url) - 7)
else if (!strcmp (substr url 0 7) "file://") then
substr url 7 ((strlen url) - 7)
else if (!strcmp (substr url 0 6) "ftp://") then
substr url 6 ((strlen url) - 6)
else url
-> baseurl in
substr baseurl 0 (strfind "/" baseurl 0);;
/*! @ingroup toolsdl
* \brief Get Html header from an http response
*
* Prototype: fun [S] S
*
* \param S : the response
*
* \return S : the header
**/
fun getHtmlHeader(cont)=
let strextr cont -> lcont in
let sizelist lcont -> size in
let 0 -> i in
let 0 -> pos in
(
while ((i < size) && (pos <= 0)) do
(
let hd nth_list lcont i -> word in
if word != nil then nil else
set pos = i;
set i = i + 1;
);
let splitList lcont pos -> [l1 l2] in
[(strbuildn l1) (strbuildn tl l2)];
);;
fun decompHtmlCookie(cookie)=
let strToListSep cookie ";" -> l in
let [nil nil nil 0 0] -> pout in
(
let sizelist l -> size in
let 0 -> i in
while i < size do
(
let nth_list l i -> elt in
if (!strcmpi "Domain=" (substr elt 0 7)) then
mutate pout <- [_ (substr elt 7 ((strlen elt) - 7)) _ _ _]
else if (!strcmpi "Path=" (substr elt 0 5)) then
mutate pout <- [_ _ (substr elt 5 ((strlen elt) - 5)) _ _]
else if (!strcmpi "Secure" (substr elt 0 6)) then
mutate pout <- [_ _ _ 1 _]
else if (!strcmpi "HttpOnly" (substr elt 0 8)) then
mutate pout <- [_ _ _ _ 1]
else
mutate pout <- [elt _ _ _ _];
set i = i + 1;
);
pout;
);;
/*! @ingroup toolsdl
* \brief Get Html Status code from header
*
* Prototype: fun [S] I
*
* \param S : the header
*
* \return I : the html status code
**/
fun getHtmlStatus(header)=
let getNextToValue header "status:" -> status in
let atoi (hd lineextr status) -> code in
(
if (code != nil) then nil else
let getNextToValue header "HTTP/1.1" -> status in
set code = atoi (hd lineextr status);
if (code != nil) then nil else
let getNextToValue header "HTTP/1.0" -> status in
set code = atoi (hd lineextr status);
code;
);;
fun setHtmlCookie(url, header)=
let getHttpDomain url -> baseurl in
let getNextToValue header "Set-Cookie:" -> cookie in
if (cookie == nil) then nil else
(
//_fooS strcatn ">>>>>>>>> add cookie : "::cookie::" on "::baseurl::nil;
set lHTTP_COOKIES = remove_sid_from_list lHTTP_COOKIES baseurl;
set lHTTP_COOKIES = [baseurl cookie]::lHTTP_COOKIES;
);
0;;
fun makeHtmlCookieHeader(url)=
let getHttpDomain url -> baseurl in
let switchstri lHTTP_COOKIES baseurl -> cookie in
if (cookie == nil) then nil else
strcatn "Cookie: "::cookie::(ctoa 13)::(ctoa 10)::nil;;
fun makeHtmlCookie(url)=
let getHttpDomain url -> baseurl in
let switchstri lHTTP_COOKIES baseurl -> cookie in
cookie;;
fun getHtmlCookie(url)=
let getHttpDomain url -> baseurl in
switchstri lHTTP_COOKIES baseurl;;
fun cbDownloadFile(curlobj, p, data, code)=
let p -> [str url cbfun] in
if (code == -1) then
(
mutate p <- [(strcat str data) _ _];
0;
)
// download finished
else if (code == 0) then
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url str];
)
else
(
_fooS strcatn ">>>>>>>>> Http download failed : "::url::" with code : "::(itoa code)::nil;
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url nil];
0;
);
0;;
/*! @ingroup toolsdl
* \brief Download an url
*
* Prototype: fun [S fun [S S] u0] I
*
* \param S : the url to download
* \param fun [S S] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun downloadFile(file, cbfun)=
if strIsUrl file then
let makeHtmlCookie file -> cookie in
let _CRcurlRequest _channel file -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_FOLLOWLOCATION 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbDownloadFile ["" file cbfun])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [file nil];
nil;
);;
/*! @ingroup toolsdl
* \brief Download an url
*
* Prototype: fun [S fun [S S] u0] I
*
* \param S : the url to download
* \param fun [S S] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun downloadFilePost(file, params, headeradd, cbfun)=
if strIsUrl file then
let makeHtmlCookie file -> cookie in
let _CRcurlRequest _channel file -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_FOLLOWLOCATION 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (headeradd == nil) then nil else
_SETcurlOptionList objcurl CURLOPT_HTTPHEADER headeradd;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
if (params == nil || (!strcmp (strtrim params) "")) then nil else
(
_SETcurlOption objcurl CURLOPT_POST 1;
_SETcurlOptionS objcurl CURLOPT_POSTFIELDS params;
);
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbDownloadFile ["" file cbfun])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [file nil];
nil;
);;
fun cbDownloadFileW(curlobj, p, data, code)=
let p -> [url wfile cbfun] in
if (code == -1) then
(
_appendpack data wfile;
0;
)
// download finished
else if (code == 0) then
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url wfile];
)
else
(
_fooS strcatn ">>>>>>>>> Http download failed : "::url::" with code : "::(itoa code)::nil;
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url wfile];
0;
);
0;;
/*! @ingroup toolsdl
* \brief Download an url in a file
*
* Prototype: fun [S fun [S S] u0] I
*
* \param S : the url to download
* \param w : the file to write
* \param fun [S W] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun downloadFileW(file, wfile, cbfun)=
if strIsUrl file then
let makeHtmlCookie file -> cookie in
let _CRcurlRequest _channel file -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_FOLLOWLOCATION 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbDownloadFileW [file wfile cbfun])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [file nil];
nil;
);;
proto cbGetContentLength = fun [ObjCURL [S S fun [S I] I] S I] I;;
fun cbGetContentLength(curlobj, p, data, code)=
let p -> [str url cbfun] in
if (code == -1) then
(
mutate p <- [(strcat str data) _ _];
0;
)
// download finished
else if (code == 0) then
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
let getHtmlHeader str -> [header cont] in
let getNextToValue header "Location:" -> location in
(
if (location != nil) then
(
let makeHtmlCookie location -> cookie in
let _CRcurlRequest _channel location -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_NOBODY 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetContentLength ["" location cbfun])::lHTTP_REQUEST;
);
0;
)
else
(
let atoi getNextToValue header "Content-Length:" -> length in
exec cbfun with [url length];
0;
);
);
)
else
(
_fooS strcatn ">>>>>>>>> Http get content size failed : "::url::" with code : "::(itoa code)::nil;
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url nil];
0;
);
0;;
/*! @ingroup toolsdl
* \brief Get content size of an url
*
* Prototype: fun [S fun [S I] u0] I
*
* \param S : the url to download
* \param fun [S I] u0 : the callback with url and content length
*
* \return ObjCURL : the new request
**/
fun getUrlContentLenght(file, cbfun)=
if strIsUrl file then
let makeHtmlCookie file -> cookie in
let _CRcurlRequest _channel file -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_NOBODY 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetContentLength ["" file cbfun])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [file nil];
nil;
);;
proto cbGetContentDate = fun [ObjCURL [S S fun [S S] I] S I] I;;
fun cbGetContentDate(curlobj, p, data, code)=
let p -> [str url cbfun] in
if (code == -1) then
(
mutate p <- [(strcat str data) _ _];
0;
)
// download finished
else if (code == 0) then
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
let getHtmlHeader str -> [header cont] in
let getNextToValue header "Location:" -> location in
(
if (location != nil) then
(
let makeHtmlCookie location -> cookie in
let _CRcurlRequest _channel location -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_NOBODY 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetContentDate ["" location cbfun])::lHTTP_REQUEST;
);
0;
)
else
(
let getNextToValue header "Last-Modified:" -> date in
let getNextToValue header "ETag:" -> tag in
exec cbfun with [url (if (tag == nil) then date else tag)];
0;
);
);
)
else
(
_fooS strcatn ">>>>>>>>> Http get content date failed : "::url::" with code : "::(itoa code)::nil;
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url nil];
0;
);
0;;
/*! @ingroup toolsdl
* \brief Get content date of an url
*
* Prototype: fun [S fun [S S] u0] I
*
* \param S : the url to download
* \param fun [S S] u0 : the callback with url and content date or tag
*
* \return ObjCURL : the new request
**/
fun getUrlContentDate(file, cbfun)=
if strIsUrl file then
let makeHtmlCookie file -> cookie in
let _CRcurlRequest _channel file -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_NOBODY 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetContentDate ["" file cbfun])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [file nil];
nil;
);;
proto cbGetContentInfos = fun [ObjCURL [S S fun [S S I] I] S I] I;;
fun cbGetContentInfos(curlobj, p, data, code)=
let p -> [str url cbfun] in
if (code == -1) then
(
mutate p <- [(strcat str data) _ _];
0;
)
// download finished
else if (code == 0) then
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
let getHtmlHeader str -> [header cont] in
let getNextToValue header "Location:" -> location in
(
if (location != nil) then
(
let makeHtmlCookie location -> cookie in
let _CRcurlRequest _channel location -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_NOBODY 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetContentInfos ["" location cbfun])::lHTTP_REQUEST;
);
0;
)
else
(
let getNextToValue header "Last-Modified:" -> date in
let getNextToValue header "ETag:" -> tag in
let atoi getNextToValue header "Content-Length:" -> length in
exec cbfun with [url (if (tag == nil) then date else tag) length];
0;
);
);
)
else
(
_fooS strcatn ">>>>>>>>> Http get content date failed : "::url::" with code : "::(itoa code)::nil;
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url nil nil];
0;
);
0;;
/*! @ingroup toolsdl
* \brief Get content infos of an url
*
* Prototype: fun [S fun [S S I] u0] I
*
* \param S : the url to download
* \param fun [S S I] u0 : the callback with url and content date or tag and length
*
* \return ObjCURL : the new request
**/
fun getUrlContentInfos(file, cbfun)=
if strIsUrl file then
let makeHtmlCookie file -> cookie in
let _CRcurlRequest _channel file -> objcurl in
(
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_NOBODY 1;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetContentInfos ["" file cbfun])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [file nil nil];
nil;
);;
fun cbGetUrlContent(curlobj, p, data, code)=
let p -> [str url cbfun fullres] in
if (code == -1) then
(
mutate p <- [(strcat str data) _ _ _];
0;
)
// download finished
else if (code == 0) then
(
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
let getHtmlHeader str -> [header cont] in
(
setHtmlCookie url header;
exec cbfun with [url (if fullres then str else cont)];
);
)
else
(
_fooS strcatn ">>>>>>>>> Http download failed : "::url::" with code : "::(itoa code)::nil;
set lHTTP_REQUEST = remove_from_list lHTTP_REQUEST curlobj;
exec cbfun with [url nil];
0;
);
0;;
fun deleteUrlEx(url, params, cbfun, headeradd, fullres)=
let makeHtmlCookie url -> cookie in
if strIsUrl url then
let _CRcurlRequest _channel url -> objcurl in
(
if !fullres then nil else
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
_SETcurlOptionS objcurl CURLOPT_CUSTOMREQUEST "DELETE";
if (headeradd == nil) then nil else
_SETcurlOptionList objcurl CURLOPT_HTTPHEADER headeradd;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
if (params == nil || (!strcmp (strtrim params) "")) then nil else
(
_SETcurlOption objcurl CURLOPT_POST 1;
_SETcurlOptionS objcurl CURLOPT_POSTFIELDS params;
);
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetUrlContent ["" url cbfun fullres])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [url nil];
nil;
);;
fun postUrlEx(url, params, cbfun, headeradd, fullres)=
let makeHtmlCookie url -> cookie in
if strIsUrl url then
let _CRcurlRequest _channel url -> objcurl in
(
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (headeradd == nil) then nil else
_SETcurlOptionList objcurl CURLOPT_HTTPHEADER headeradd;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
if (params == nil || (!strcmp (strtrim params) "")) then nil else
(
_SETcurlOption objcurl CURLOPT_POST 1;
_SETcurlOptionS objcurl CURLOPT_POSTFIELDS params;
);
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetUrlContent ["" url cbfun fullres])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [url nil];
nil;
);;
fun getUrlEx(url, params, cbfun, headeradd, fullres)=
let makeHtmlCookie url -> cookie in
if strIsUrl url then
let _CRcurlRequest _channel url -> objcurl in
(
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_FOLLOWLOCATION 1;
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (headeradd == nil) then nil else
_SETcurlOptionList objcurl CURLOPT_HTTPHEADER headeradd;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
if (params == nil || (!strcmp (strtrim params) "")) then nil else
(
_SETcurlOption objcurl CURLOPT_HTTPGET 1;
_SETcurlOptionS objcurl CURLOPT_POSTFIELDS params;
);
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetUrlContent ["" url cbfun fullres])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [url nil];
nil;
);;
fun postUrlMultiPartEx(url, lparams, cbfun, headeradd, fullres)=
if strIsUrl url then
let makeHtmlCookie url -> cookie in
let _CRcurlRequest _channel url -> objcurl in
(
_SETcurlOption objcurl CURLOPT_HEADER 1;
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
if (headeradd == nil) then nil else
_SETcurlOptionList objcurl CURLOPT_HTTPHEADER headeradd;
if (cookie == nil) then nil else
_SETcurlOptionS objcurl CURLOPT_COOKIE cookie;
let sizelist lparams -> size in
let 0 -> i in
while i < size do
(
let nth_list lparams i -> [name value file] in
(
if(file == nil) then
(
_ADDcurlFormField objcurl name value;
)
else
(
_ADDcurlFileFormField objcurl name _checkpack file;
);
);
set i = i + 1;
);
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetUrlContent ["" url cbfun fullres])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [url nil];
nil;
);;
/*! @ingroup toolsdl
* \brief Download an url using the GET method
*
* Prototype: fun [S S fun [S S] u0] I
*
* \param S : the url to download
* \param S : the url parameters ("login=toto&pass=tata")
* \param fun [S S] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun getUrl(url, params, cbfun)=
getUrlEx url params cbfun nil 0;;
/*! @ingroup toolsdl
* \brief Download an url using the POST method
*
* Prototype: fun [S S fun [S S] u0] I
*
* \param S : the url to download
* \param S : the url parameters ("login=toto&pass=tata")
* \param fun [S S] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun postUrl(url, params, cbfun)=
postUrlEx url params cbfun nil 0;;
/*! @ingroup toolsdl
* \brief Download an url using the POST method with multipart
*
* Prototype: fun [S [[S S S] r1] fun [S S] u0] I
*
* \param S : the url to download
* \param [[S S S] r1]: list of parameters [name value file]
* \param fun [S S] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun postUrlMultiPart(url, lparams, cbfun)=
postUrlMultiPartEx url lparams cbfun nil 0;;
/*! @ingroup toolsdl
* \brief Call the DELETE method on an url
*
* Prototype: fun [S S fun [S S] u0] I
*
* \param S : the url
* \param S : the url parameters ("login=toto&pass=tata")
* \param fun [S S] u0 : the callback with url and data
*
* \return ObjCURL : the new request
**/
fun deleteUrl(url, params, cbfun)=
deleteUrlEx url params cbfun nil 0;;
fun sendMail(server, port, from , to, cc, subject, message, lparams, cbfun)=
if (server != nil) && (from != nil) && (to != nil) && (message != nil) && (subject != nil) then
//TODO check mail form
let if ((cc == nil) || (!strcmp cc "")) then 0 else 1 -> havecc in
let if (port == nil) then 25 else port -> port in
let strcatn "smtp://"::server::nil -> url in
let _CRcurlRequest _channel url -> objcurl in
let (strcat (ctoa 13) (ctoa 10)) -> ends in
(
_SETcurlOption objcurl CURLOPT_HEADER 0;
_SETcurlOption objcurl CURLOPT_SSL_VERIFYPEER 0;
_SETcurlOption objcurl CURLOPT_PORT port;
_SETcurlOption objcurl CURLOPT_CONNECTTIMEOUT iCURL_REQUEST_TIMEOUT;
_SETcurlOptionS objcurl CURLOPT_MAIL_FROM from;
let if (!havecc) then to::nil else to::cc::nil -> rcpt in
_SETcurlOptionList objcurl CURLOPT_MAIL_RCPT rcpt;
let strcatn "To: \""::to::"\" <"::to::">"::ends::
"From: \""::from::"\" <"::from::">"::ends::nil
-> headeradd in
let if (havecc) then strcat headeradd (strcatn "Cc: \""::cc::"\" <"::cc::">"::ends::nil) else headeradd -> headeradd in
let strcatn headeradd::"Reply-To: \""::from::"\" <"::from::">"::ends::nil -> headeradd in
let strcatn headeradd::"Message-ID: <"::(itoa time)::"-"::(_MD5value strcat from to)::"@"::(getHttpDomain server)::">"::ends::nil -> headeradd in
let hd strextr (ctime time) -> [dayname [monthname [day [hour [year _]]]]] in
let strcat headeradd
strcatn "Subject: "::(strtoutf8 subject)::"\n"::
"Date: "::dayname::", "::day::" "::monthname::" "::year::" "::hour::" +0000\n"::
nil
-> headeradd in
(
let sizelist lparams -> size in
if (size == 0) then
(
set headeradd = strcatn headeradd::ends::message::ends::ends::nil;
0;
)
else
let strcat "----=_NextPart_" (_MD5value itoa _tickcount) -> boundary in
(
set headeradd = strcat headeradd "MIME-Version: 1.0\n";
set headeradd = strcat headeradd "Content-Type: multipart/mixed;";
set headeradd = strcatn headeradd::" boundary=\""::boundary::"\""::ends::nil;
set headeradd = strcatn headeradd::"Content-Description: multipart-1"::ends::ends::nil;
set headeradd = strcatn headeradd::"--"::boundary::ends::nil;
set headeradd = strcatn headeradd::"Content-Type: text/plain"::ends::nil;
set headeradd = strcatn headeradd::"Content-Transfer-Encoding: 8BIT"::nil;
set headeradd = strcatn headeradd::"Content-Disposition: inline"::ends::nil;
set headeradd = strcatn headeradd::"Content-Description: text-part-1"::ends::ends::nil;
set headeradd = strcatn headeradd::(strtoutf8 message)::ends::ends::nil;
let 0 -> i in
while i < size do
(
let nth_list lparams i -> [name value file] in
(
if(file == nil) then
(
set headeradd = strcatn headeradd::"--"::boundary::ends::nil;
set headeradd = strcatn headeradd::"Content-Type: text/plain"::ends::nil;
set headeradd = strcatn headeradd::"Content-Transfer-Encoding: BASE64"::ends::nil;
set headeradd = strcatn headeradd::"Content-Disposition: inline"::ends::nil;
set headeradd = strcatn headeradd::"Content-Description: "::name::ends::ends::nil;
set headeradd = strcatn headeradd::(base64_encode value)::ends::ends::nil;
)
else
(
let getFileExt file -> ext in
let getPathFile file "" -> [_ filename] in
let if (!strcmpi ext "jpg") || (!strcmpi ext "jpeg") then
"image/jpeg"
else if (!strcmpi ext "png") then
"image/png"
else "text/plain"
-> mimetype in
(
set headeradd = strcatn headeradd::"--"::boundary::ends::nil;
set headeradd = strcatn headeradd::"Content-Type: "::mimetype::ends::nil;
set headeradd = strcatn headeradd::"Content-Transfer-Encoding: BASE64"::ends::nil;
set headeradd = strcatn headeradd::"Content-Disposition: attachment; filename="::filename::ends::nil;
set headeradd = strcatn headeradd::"Content-Description: File_"::(itoa i)::ends::ends::nil;
set headeradd = strcatn headeradd::(base64_encode _getpack _checkpack file)::ends::ends::nil;
);
);
);
set i = i + 1;
);
set headeradd = strcatn headeradd::"--"::boundary::ends::nil;
0;
);
_SETcurlOptionS objcurl CURLOPT_UPLOAD headeradd;
);
set lHTTP_REQUEST = (_CALLcurlRequest objcurl @cbGetUrlContent ["" url cbfun 0])::lHTTP_REQUEST;
hd lHTTP_REQUEST;
)
else
(
exec cbfun with [server "Mail Error"];
nil;
);;
/* ********************************************************************************************* /
Vector
/ ********************************************************************************************* */
/*! @ingroup toolsvec
* \brief Test if the coordinates are in the rectangle
*
* Prototype: fun [I I [I I I I]] I
*
* \param I : x coord
* \param I : y coord
* \param [I I I I] : rectangle x y width height
*
* \return I : return 1 if the coords are in the rectangle
**/
fun isCoordInRect(x, y, rect)=
let rect -> [rx ry rw rh] in
(x > rx) && (y > ry) && (x < (rx + rw)) && (y < (ry + rh));;
/*! @ingroup toolsvec
* \brief Get the smallest float value
*
* Prototype: fun [F F] F
*
* \param F : first value
* \param F : second value
*
* \return F : the smallest value
**/
fun minf(a, b)=
if a <. b then a else b;;
/*! @ingroup toolsvec
* \brief Convert a float value to a rounded int value (float to rounded integer)
*
* Prototype: fun [F] I
*
* \param F : float value
*
* \return I : rounded int value
**/
fun ftori(val)=
if (val >=. 0.0) then
ftoi (val +. 0.5)
else
ftoi (val +. 0.5);;
/*! @ingroup toolsvec
* \brief Test if a vector is set to 0
*
* Prototype: fun [[I I I]] I
*
* \param [I I I] : int vector
*
* \return I : 1 if the vector is 0, 0 otherwise
**/
fun zeroVector(vec)=
let vec -> [x y z] in
if (x || y || z) then
0
else
1;;
/*! @ingroup toolsvec
* \brief Test if a float vector is set to 0
*
* Prototype: fun [[F F F]] I
*
* \param [F F F] : float vector
*
* \return I : 1 if the vector is 0, 0 otherwise
**/
fun zeroVectorF(vec)=
let vec -> [x y z] in
if (((x != 0.0) && (x != nil)) || ((y != 0.0) && (y != nil)) || ((z != 0.0) && (z != nil))) then
0
else
1;;
/*! @ingroup toolsvec
* \brief Test if a vector is set to 0
*
* Prototype: fun [[I I I]] I
*
* \param [I I I] : int vector
*
* \return I : 1 if the vector is 0, 0 otherwise
**/
fun vectorIsZero(vec)=
let vec -> [x y z] in
x == 0 && y == 0 && z == 0;;
/*! @ingroup toolsvec
* \brief Test if a 2d vector is set to 0
*
* Prototype: fun [[I I]] I
*
* \param [I I] : int vector
*
* \return I : 1 if the vector is 0, 0 otherwise
**/
fun vector2dIsZero(vec)=
let vec -> [x y] in
x == 0 && y == 0;;
/*! @ingroup toolsvec
* \brief Test if a float vector is set to 0
*
* Prototype: fun [[F F F]] I
*
* \param [F F F] : float vector
*
* \return I : 1 if the vector is 0, 0 otherwise
**/
fun vectorIsZeroF(vec)=
let vec -> [x y z] in
x == 0.0 && y == 0.0 && z == 0.0;;
/*! @ingroup toolsvec
* \brief Test if a 2d float vector is set to 0
*
* Prototype: fun [[F F]] I
*
* \param [F F] : float vector
*
* \return I : 1 if the vector is 0, 0 otherwise
**/
fun vector2dIsZeroF(vec)=
let vec -> [x y] in
x == 0.0 && y == 0.0;;
/*! @ingroup toolsvec
* \brief Test if two vectors are equal
*
* Prototype: fun [[I I I] [I I I]] I
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return I : 1 if the two vectors are equal, 0 otherwise
**/
fun vectorEqual(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
x1 == x2 && y1 == y2 && z1 == z2;;
/*! @ingroup toolsvec
* \brief Test if two float vectors are equal
*
* Prototype: fun [[F F F] [F F F]] I
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return I : 1 if the two vectors are equal, 0 otherwise
**/
fun vectorEqualF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
x1 == x2 && y1 == y2 && z1 == z2;;
/*! @ingroup toolsvec
* \brief Normalize a float vector
*
* Prototype: fun [[F F F]] [F F F]
*
* \param [F F F] : float vector
*
* \return [F F F] : normalized float vector
**/
fun normalizeVectorF(vec)=
let vec -> [x y z] in
let sqrt (x *. x +. y *. y +. z *. z) -> sum in
let if (sum == 0.0) then 1.0 else 1.0 /. sum -> coef in
[(x *. coef) (y *. coef) (z *. coef)];;
/*! @ingroup toolsvec
* \brief Get the average of a vector
*
* Prototype: fun [[F F F]] F
*
* \param [F F F] : float vector
*
* \return F : average
**/
fun vectorAverageF(vec)=
let vec -> [x y z] in
x +. y +. z /. 3.0;;
/*! @ingroup toolsvec
* \brief Get the cube of a vector
*
* Prototype: fun [[F F F]] F
*
* \param [F F F] : float vector
*
* \return F : cube (x * y * z)
**/
fun vectorCubeF(vec)=
let vec -> [x y z] in
x *. y *. z;;
/*! @ingroup toolsvec
* \brief Get a vector length
*
* Prototype: fun [[I I I]] F
*
* \param [I I I] : int vector
*
* \return F : vector length
**/
fun getVectorLength(vec1)=
let vec1 -> [x1 y1 z1] in
sqrt itof (x1 * x1 + y1 * y1 + z1 * z1);;
/*! @ingroup toolsvec
* \brief Get a vector length
*
* Prototype: fun [[F F F]] F
*
* \param [F F F] : float vector
*
* \return F : vector length
**/
fun getVectorLengthF(vec1)=
let vec1 -> [x1 y1 z1] in
sqrt (x1 *. x1 +. y1 *. y1 +. z1 *. z1);;
/*! @ingroup toolsvec
* \brief Get a vector 4 length
*
* Prototype: fun [[F F F F]] F
*
* \param [F F F F] : float vector
*
* \return F : vector length
**/
fun getVector4LengthF(vec1)=
let vec1 -> [x1 y1 z1 w1] in
sqrt (x1 *. x1 +. y1 *. y1 +. z1 *. z1 +. w1 *. w1);;
/*! @ingroup toolsvec
* \brief Get the distance between 2 vectors
*
* Prototype: fun [[I I I] [I I I]] F
*
* \param [I I I] : int vector
* \param [I I I] : int vector
*
* \return F : vector length
**/
fun getVectorDistance(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
sqrt ((sqr itof(x1 - x2)) +. (sqr itof(y1 - y2)) +. (sqr itof(z1 - z2)));;
/*! @ingroup toolsvec
* \brief Get the distance between 2 2D vectors
*
* Prototype: fun [[I I] [I I]] F
*
* \param [I I] : int vector
* \param [I I] : int vector
*
* \return F : vector length
**/
fun getVector2dDistance(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
sqrt ((sqr itof(x1 - x2)) +. (sqr itof(y1 - y2)));;
/*! @ingroup toolsvec
* \brief Get the distance between 2 vectors
*
* Prototype: fun [[F F F] [F F F]] F
*
* \param [F F F] : float vector
* \param [F F F] : float vector
*
* \return F : vector length
**/
fun getVectorDistanceF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
sqrt ((sqr(x1 -. x2)) +. (sqr(y1 -. y2)) +. (sqr(z1 -. z2)));;
/*! @ingroup toolsvec
* \brief Cross product of two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : vector result
**/
fun crossVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(y1 * z2 - z1 * y2) (z1 * x2 - x1 * z2) (x1 * y2 - y1 * x2)];;
/*! @ingroup toolsvec
* \brief Cross product of two vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return [F F F] : float vector result
**/
fun crossVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(y1 *. z2 -. z1 *. y2) (z1 *. x2 -. x1 *. z2) (x1 *. y2 -. y1 *. x2)];;
/*! @ingroup toolsvec
* \brief Dot product of two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return F : dot product result
**/
fun dotVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
x1 * x2 + y1 * y2 + z1 * z2;;
/*! @ingroup toolsvec
* \brief Dot product of two vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return F : dot product result
**/
fun dotVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
x1 *. x2 +. y1 *. y2 +. z1 *. z2;;
/*! @ingroup toolsvec
* \brief Get the angle between 2 vectors in radian
*
* Prototype: fun [[I I I] [I I I]] F
*
* \param [I I I] : int vector
* \param [I I I] : int vector
*
* \return F : angle between the 2 vectors
**/
fun getVectorAngle(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
let sqrt itof ((x1 * x1 + y1 * y1 + z1 * z1) * (x2 * x2 + y2 * y2 + z2 * z2)) -> lengthsproduct in
if (lengthsproduct == 0.0) then acos 0.0 else
acos ((itof (x1 * x2 + y1 * y2 + z1 * z2)) /. lengthsproduct);;
/*! @ingroup toolsvec
* \brief Get the angle between 2 2D vectors in degree
*
* Prototype: fun [[I I] [I I]] F
*
* \param [I I] : int vector
* \param [I I] : int vector
*
* \return F : angle between the 2 vectors
**/
fun getVector2dAngle(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
let itof (x2 - x1) -> x in
let itof (y2 - y1) -> y in
(atan2 y x) *. 180.0 /. PIf;;
/*! @ingroup toolsvec
* \brief Get the angle between 2 vectors in radian
*
* Prototype: fun [[F F F] [F F F]] F
*
* \param [F F F] : float vector
* \param [F F F] : float vector
*
* \return F : angle between the 2 vectors
**/
fun getVectorAngleF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
let sqrt ((x1 *. x1 +. y1 *. y1 +. z1 *. z1) *. (x2 *. x2 +. y2 *. y2 +. z2 *. z2)) -> lengthsproduct in
if (lengthsproduct == 0.0) then acos 0.0 else
acos ((x1 *. x2 +. y1 *. y2 +. z1 *. z2) /. lengthsproduct);;
/*! @ingroup toolsvec
* \brief Get the oriented angle between 2 vectors in radian, between pi and -pi
*
* Prototype: fun [[F F F] [F F F] [F F F]] F
*
* \param [F F F] : float vector
* \param [F F F] : float vector
* \param [F F F] : normal of the plane containing both vector. Used for the angle orientation
*
* \return F : angle between the 2 vectors
**/
fun getVectorOrientedAngleF(vec1, vec2, planenormal)=
//atan2 (dotVectorF (crossVectorF vec1 vec2) planenormal) (dotVectorF vec1 vec2);;
let acos (dotVectorF (normalizeVectorF vec1) (normalizeVectorF vec2)) -> angle in
let crossVectorF vec1 vec2 -> cross in
if (dotVectorF planenormal cross) <. 0.0 then (-.angle) else angle;;
/*! @ingroup toolsvec
* \brief Min of two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : min result
**/
fun minVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(min x1 x2) (min y1 y2) (min z1 z2)];;
/*! @ingroup toolsvec
* \brief Min of two vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first int vector
* \param [F F F] : second int vector
*
* \return [F F F] : min result
**/
fun minVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(minf x1 x2) (minf y1 y2) (minf z1 z2)];;
/*! @ingroup toolsvec
* \brief Min of two vectors 2
*
* Prototype: fun [[F F] [F F]] [F F]
*
* \param [F F] : first int vector
* \param [F F] : second int vector
*
* \return [F F] : min result
**/
fun minVector2F(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(minf x1 x2) (minf y1 y2)];;
/*! @ingroup toolsvec
* \brief Max of two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : max result
**/
fun maxVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(max x1 x2) (max y1 y2) (max z1 z2)];;
/*! @ingroup toolsvec
* \brief Max of two vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first int vector
* \param [F F F] : second int vector
*
* \return [F F F] : max result
**/
fun maxVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(maxf x1 x2) (maxf y1 y2) (maxf z1 z2)];;
/*! @ingroup toolsvec
* \brief Max of two vectors
*
* Prototype: fun [[F F] [F F]] [F F]
*
* \param [F F] : first int vector
* \param [F F] : second int vector
*
* \return [F F] : max result
**/
fun maxVector2F(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(maxf x1 x2) (maxf y1 y2)];;
/*! @ingroup toolsvec
* \brief Substract two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : vector result
**/
fun subVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 - x2) (y1 - y2) (z1 - z2)];;
/*! @ingroup toolsvec
* \brief Substract two float vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return [F F F] : float vector result
**/
fun subVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 -. x2) (y1 -. y2) (z1 -. z2)];;
/*! @ingroup toolsvec
* \brief Substract two vectors 2
*
* Prototype: fun [[I I] [I I]] [I I]
*
* \param [I I] : first int vector
* \param [I I] : second int vector
*
* \return [I I] : vector result
**/
fun subVector2(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 - x2) (y1 - y2)];;
/*! @ingroup toolsvec
* \brief Substract two float vectors 2
*
* Prototype: fun [[F F] [F F]] [F F]
*
* \param [F F] : first float vector
* \param [F F] : second float vector
*
* \return [F F] : float vector result
**/
fun subVector2F(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 -. x2) (y1 -. y2)];;
/*! @ingroup toolsvec
* \brief Add two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : vector result
**/
fun addVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 + x2) (y1 + y2) (z1 + z2)];;
/*! @ingroup toolsvec
* \brief Add two float vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return [F F F] : float vector result
**/
fun addVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 +. x2) (y1 +. y2) (z1 +. z2)];;
/*! @ingroup toolsvec
* \brief Add two vectors
*
* Prototype: fun [[I I] [I I]] [I I]
*
* \param [I I] : first int vector
* \param [I I] : second int vector
*
* \return [I I] : vector result
**/
fun addVector2(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 + x2) (y1 + y2)];;
/*! @ingroup toolsvec
* \brief Add two float vectors 2
*
* Prototype: fun [[F F] [F F]] [F F]
*
* \param [F F] : first float vector
* \param [F F] : second float vector
*
* \return [F F] : float vector result
**/
fun addVector2F(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 +. x2) (y1 +. y2)];;
/*! @ingroup toolsvec
* \brief Divide two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : vector result
**/
fun divideVector(vec1, vec2)=
if vectorIsZero vec2 then nil else
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 / x2) (y1 / y2) (z1 / z2)];;
/*! @ingroup toolsvec
* \brief Divide two float vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return [F F F] : float vector result
**/
fun divideVectorF(vec1, vec2)=
if vectorIsZeroF vec2 then nil else
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 /. x2) (y1 /. y2) (z1 /. z2)];;
/*! @ingroup toolsvec
* \brief Divide two vectors 2
*
* Prototype: fun [[I I] [I I]] [I I]
*
* \param [I I] : first int vector
* \param [I I] : second int vector
*
* \return [I I] : vector result
**/
fun divideVector2(vec1, vec2)=
if vector2dIsZero vec2 then nil else
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 / x2) (y1 / y2)];;
/*! @ingroup toolsvec
* \brief Divide two float vectors 2
*
* Prototype: fun [[F F] [F F]] [F F]
*
* \param [F F] : first float vector
* \param [F F] : second float vector
*
* \return [F F] : float vector result
**/
fun divideVector2F(vec1, vec2)=
if vector2dIsZeroF vec2 then nil else
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 /. x2) (y1 /. y2)];;
/*! @ingroup toolsvec
* \brief Multiply two vectors
*
* Prototype: fun [[I I I] [I I I]] [I I I]
*
* \param [I I I] : first int vector
* \param [I I I] : second int vector
*
* \return [I I I] : vector result
**/
fun multiplyVector(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 * x2) (y1 * y2) (z1 * z2)];;
/*! @ingroup toolsvec
* \brief Multiply two vectors 2
*
* Prototype: fun [[I I] [I I]] [I I]
*
* \param [I I] : first int vector
* \param [I I] : second int vector
*
* \return [I I] : vector result
**/
fun multiplyVector2(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 * x2) (y1 * y2)];;
/*! @ingroup toolsvec
* \brief Multiply two float vectors
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : first float vector
* \param [F F F] : second float vector
*
* \return [F F F] : float vector result
**/
fun multiplyVectorF(vec1, vec2)=
let vec1 -> [x1 y1 z1] in
let vec2 -> [x2 y2 z2] in
[(x1 *. x2) (y1 *. y2) (z1 *. z2)];;
/*! @ingroup toolsvec
* \brief Multiply two float vectors 2
*
* Prototype: fun [[F F] [F F]] [F F]
*
* \param [F F] : first float vector
* \param [F F] : second float vector
*
* \return [F F] : float vector result
**/
fun multiplyVector2F(vec1, vec2)=
let vec1 -> [x1 y1] in
let vec2 -> [x2 y2] in
[(x1 *. x2) (y1 *. y2)];;
/*! @ingroup toolsvec
* \brief Project an int vector onto another int vector
*
* Prototype: fun [[I I I] [I I I]] [F F F]
*
* \param [I I I] : int vector to project
* \param [I I I] : int vector on which the vector is projected
*
* \return [F F F] : vector result, nil if the second vector is the zero vector
**/
fun projectVector(vec1, vec2)=
let vec2 -> [x2 y2 z2] in
if (x2 == 0 && y2 == 0 && z2 == 0) then nil else
let (itof (dotVector vec1 vec2)) /. (itof (dotVector vec2 vec2)) -> scalar in
[(scalar *. (itof x2)) (scalar *. (itof y2)) (scalar *. (itof z2))];;
/*! @ingroup toolsvec
* \brief Project a float vector onto another float vector
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : float vector to project
* \param [F F F] : float vector on which the vector is projected
*
* \return [F F F] : float vector result, nil if the second vector is the zero vector
**/
fun projectVectorF(vec1, vec2)=
let vec2 -> [x2 y2 z2] in
if (x2 == 0.0 && y2 == 0.0 && z2 == 0.0) then nil else
let (dotVectorF vec1 vec2) /. (dotVectorF vec2 vec2) -> scalar in
[(scalar *. x2) (scalar *. y2) (scalar *. z2)];;
/*! @ingroup toolsvec
* \brief Project an int vector onto a plane defined by its int normal vector
*
* Prototype: fun [[I I I] [I I I]] [F F F]
*
* \param [I I I] : int vector to project
* \param [I I I] : normal vector of the plane
*
* \return [F F F] : vector result, nil if the normal is the zero vector
**/
fun projectVectorOnPlane(vec, planenormal)=
let planenormal -> [x y z] in
if (x == 0 && y == 0 && z == 0) then nil else
let (itof (dotVector vec planenormal)) /. (itof (dotVector planenormal planenormal)) -> scalar in
let [(scalar *. (itof x)) (scalar *. (itof y)) (scalar *. (itof z))] -> vectorproj in
let vec -> [vx vy vz] in
subVectorF [(itof vx) (itof vy) (itof vz)] vectorproj;;
/*! @ingroup toolsvec
* \brief Project a float vector onto a plane defined by its float normal vector
*
* Prototype: fun [[F F F] [F F F]] [F F F]
*
* \param [F F F] : float vector to project
* \param [F F F] : normal vector of the plane
*
* \return [F F F] : float vector result, nil if the normal is the zero vector
**/
fun projectVectorOnPlaneF(vec, planenormal)=
let planenormal -> [x y z] in
if (x == 0.0 && y == 0.0 && z == 0.0) then nil else
let (dotVectorF vec planenormal) /. (dotVectorF planenormal planenormal) -> scalar in
let [(scalar *. x) (scalar *. y) (scalar *. z)] -> vectorproj in
subVectorF vec vectorproj;;
/*! @ingroup toolsvec
* \brief Intersection point between a plane and a vector
*
* Prototype: fun [[F F F] [F F F] [F F F] [F F F]] [F F F]
*
* \param [F F F] : float vector
* \param [F F F] : float point lying on the vector
* \param [F F F] : plane normal float vector
* \param [F F F] : float point lying on the plane
*
* \return [F F F] : intersection point, nil if it does not exist
**/
fun vectorPlaneIntersectionF(vec, vecpoint, planenormal, planepoint)=
let normalizeVectorF vec -> vec in
let normalizeVectorF planenormal -> planenormal in
let dotVectorF planenormal planepoint -> planeconstant in
let dotVectorF planenormal vec -> divisor in
//let if (divisor == 0.0) then 0.000001 else divisor -> divisor in
if (divisor == 0.0) then nil else
let (planeconstant -. (dotVectorF planenormal vecpoint)) /. divisor -> t in
let vec -> [dx dy dz] in
let vecpoint -> [px py pz] in
[(dx *. t +. px) (dy *. t +. py) (dz *. t +. pz)];;
/*! @ingroup toolsvec
* \brief Get a plane normal from 3 points belonging to the plane
*
* Prototype: fun [[F F F][F F F][F F F]] [F F F]
*
* \param [F F F] : first point coordinates
* \param [F F F] : second point coordinates
* \param [F F F] : third point coordinates
*
* \return [F F F] : plane normal
**/
fun getPlaneNormalF(point1, point2, point3)=
let subVectorF point2 point1 -> vec1 in
let subVectorF point3 point1 -> vec2 in
normalizeVectorF (crossVectorF vec1 vec2);;
/*! @ingroup toolsvec
* \brief Get vector X value
*
* Prototype: fun [[F F F]] F
*
* \param [F F F] : float vector
*
* \return F : X float result
**/
fun getVectorXF(vec)=
let vec -> [x1 y1 z1] in
x1;;
/*! @ingroup toolsvec
* \brief Get vector Y value
*
* Prototype: fun [[F F F]] F
*
* \param [F F F] : float vector
*
* \return F : Y float result
**/
fun getVectorYF(vec)=
let vec -> [x1 y1 z1] in
y1;;
/*! @ingroup toolsvec
* \brief Get vector Z value
*
* Prototype: fun [[F F F]] F
*
* \param [F F F] : float vector
*
* \return F : Z float result
**/
fun getVectorZF(vec)=
let vec -> [x1 y1 z1] in
z1;;
/*! @ingroup toolsvec
* \brief Get the shortest angle
*
* Prototype: fun [F] F
*
* \param F : angle in degree
*
* \return F : the shortest angle in degree
**/
fun getShortestAngle(p, q) =
let (absf (q -. p)) -> path1 in
let (absf (q +. 360.0 -. p)) -> path2 in
let (absf (q -. 360.0 -. p)) -> path3 in
let minf path1 minf path2 path3 -> minpath in
if (minpath == path1) then
q
else if (minpath == path2) then
(q +. 360.0)
else
(q -. 360.0);;
/*! @ingroup toolsvec
* \brief Get quaternion inverse
*
* Prototype: fun [[F F F F]] [F F F F]
*
* \param [F F F F] : quaternion
*
* \return [F F F F] : the inversed quaternion
**/
fun quatInverse(quat)=
let quat -> [x y z w] in
let w*.w+.x*.x+.y*.y+.z*.z -> norm in
if (norm <=. 0.0) then
[x y z w]
else
let 1.0 /. norm -> inorm in
[(-.x*.inorm) (-.y*.inorm) (-.z*.inorm) (w*.inorm)];;
/*! @ingroup toolsvec
* \brief LookAt function that return pitch yaw roll in radian
*
* Prototype: fun [[F F F] [F F F] [F F F]] [F F F]
*
* \param [F F F] : source vector
* \param [F F F] : target vector
*
* \return [F F F] : pitch yaw roll in radian
**/
fun lookAtPYR(src, target, flipz)=
let subVectorF target src -> [dx dy dz] in
let sqrt (dx *. dx +. dy *. dy +. dz *. dz) -> lenght in
let if lenght >. 0.0 then
[dx /. lenght dy /. lenght dz /. lenght]
else
[dx dy dz]
-> [dx dy dz] in
let asin dy -> pitch in
let if (flipz) then (atan2 (-.dx) dz) +. PIf *. 0.5 else atan2 dx dz -> yaw in
[pitch yaw 0.0];;
fun reorientQuat(quat, upvec)=
let normalizeVectorF (crossVectorF [0.0 1.0 0.0] upvec) -> rotaxis in
let dotVectorF [0.0 1.0 0.0] upvec -> dotproduct in
let acos dotproduct -> angle in
SO3MathsQuatAdd (SO3MathsQuatFromAngleAxis angle rotaxis) quat;;
fun lookAtQuat(src, target, upaxis)=
let normalizeVectorF (subVectorF target src) -> forward in
let normalizeVectorF crossVectorF upaxis forward -> right in
let normalizeVectorF crossVectorF forward right -> up in
let dotVectorF up upaxis -> dotf in
let normalizeVectorF (multiplyVectorF [dotf dotf dotf] forward) -> up in
let up -> [upx upy upz] in
let forward -> [fx fy fz] in
let right -> [rx ry rz] in
let mktab 3 nil -> rotmat in
(
//init matrix
let 0 -> t in
while (t < 3) do
(
set rotmat.(t) = mktab 3 0.0;
set t = t + 1;
);
set rotmat.(0).(0) = rx;
set rotmat.(0).(1) = upx;
set rotmat.(0).(2) = -.fx;
set rotmat.(1).(0) = ry;
set rotmat.(1).(1) = upy;
set rotmat.(1).(2) = -.fy;
set rotmat.(2).(0) = rz;
set rotmat.(2).(1) = upz;
set rotmat.(2).(2) = -.fz;
let rotmat.(0).(0) +. rotmat.(1).(1) +. rotmat.(2).(2) -> trace in
let acos ((trace -. 1.0) *. 0.5) -> angle in
let [((rotmat.(2).(1) -. rotmat.(1).(2)) *. 0.5) ((rotmat.(0).(2) -. rotmat.(2).(0)) *. 0.5) ((rotmat.(1).(0) -. rotmat.(0).(1)) *. 0.5)] -> rotaxis in
SO3MathsQuatFromAngleAxis angle rotaxis;
);;
/* ********************************************************************************************* /
Date
/ ********************************************************************************************* */
/*! @ingroup toolsdate
* \brief get the number of day for a month depending of the year
*
* Prototype: fun [I I] I
*
* \param I : the month
* \param I : the year
*
* \return I : the number of days
**/
fun getMonthDays(month, year)=
if (month <= 0) then nil else
let if ((mod year 4)==0 && (mod year 100) != 0) || (mod year 400)==0 then 29 else 28 -> feb in
let 0::31::feb::31::30::31::30::31::31::30::31::30::31::nil -> nbdays in
nth_list nbdays month;;
/*! @ingroup toolsdate
* \brief test if a date string is valid
*
* Prototype: fun [S] I
*
* \param S : the date in string format ("Tue Jan 21 11:24:53 1997")
*
* \return I : 1 if valid, 0 otherwise
**/
fun isDateString(date)=
let hd strextr date -> [dayname [monthname [day [hour [year _]]]]] in
((strfind dayname "SunMonTueWedThuFriSat" 0) != nil) &&
((strfind monthname "JanFebMarAprMayJunJulAugSepOctNovDec" 0) != nil) &&
((atoi day) != 0) &&
((strlen hour) == 8) &&
(!strcmp (substr hour 2 1) ":") &&
(!strcmp (substr hour 5 1) ":") &&
(let (atoi (substr hour 0 2)) -> H in (H>=0) && (H<24)) &&
(let (atoi (substr hour 3 2)) -> M in (M>=0) && (M<60)) &&
(let (atoi (substr hour 6 2)) -> Sc in (Sc>=0) && (Sc<60)) &&
((strlen year) == 4) &&
((atoi year) != 0);;
/*! @ingroup toolsdate
* \brief get the number of seconds from a complete date time
*
* Prototype: fun [I I I I I I] I
*
* \param I : the day
* \param I : the month
* \param I : the year
* \param I : the hours
* \param I : the minutes
* \param I : the seconds
*
* \return I : the number of seconds from 1970
**/
fun getSecondsFromDateTime(day, month, year, hours, minutes, seconds)=
let (year * 365 * 3600 * 24) - (1970 * 365 * 3600 * 24) -> years in
let
let 0 -> nbsec in
(
let 1 -> i in
while i < month do
(
set nbsec = nbsec + ((getMonthDays i year) * 3600 * 24);
set i = i + 1;
);
nbsec;
)
-> months in
let day * 3600 * 24 -> days in
let hours * 3600 -> hours in
let minutes * 60 -> minutes in
years + months + days + hours + minutes;;
/*! @ingroup toolsdate
* \brief get the decomposed date time from a string date
*
* Prototype: fun [S] [I I I I I I]
*
* \param S : the date in string format ("Tue Jan 21 11:24:53 1997")
*
* \return [I I I I I I] : return nil is the input string is not a valid date
* \I : the day
* \I : the month
* \I : the year
* \I : the hours
* \I : the minutes
* \I : the seconds
**/
fun getDateTimeFromString(date)=
if (!isDateString date) then nil else
// let ["Mon" 1]::["Tue" 2]::["Wed" 3]::["Thu" 4]::["Fri" 5]::["Sat" 6]::["Sun" 7]::nil -> ldays in
let ["Jan" 1]::["Feb" 2]::["Mar" 3]::["Apr" 4]::["May" 5]::["Jun" 6]::["Jul" 7]::["Aug" 8]::["Sep" 9]::["Oct" 10]::["Nov" 11]::["Dec" 12]::nil -> lmonths in
let hd strextr date -> [dayname [monthname [day [hour [year _]]]]] in
let atoi (substr hour 0 2) -> hours in
let atoi (substr hour 3 2) -> minutes in
let atoi (substr hour 6 2) -> seconds in
[(atoi day) (switchstr lmonths monthname) (atoi year) hours minutes seconds];;
/*! @ingroup toolsdate
* \brief get the current date time
*
* Prototype: fun [I] [I I I I I I]
*
* \param I : 0 or nil for local time, 1 for GMT
*
* \return [I I I I I I] :
* \I : the day
* \I : the month
* \I : the year
* \I : the hours
* \I : the minutes
* \I : the seconds
**/
fun getCurrentDateTime(mode)=
let if (mode >= 1) then (gmtime time) else (localtime time) -> [seconds minutes hours day month year _ _] in
[day month year hours minutes seconds]
;;
/*! @ingroup toolsdate
* \brief get the current time
*
* Prototype: fun [I] [I I I]
*
* \param I : 0 or nil for local time, 1 for GMT
*
* \return [I I I] :
* \I : the hours
* \I : the minutes
* \I : the seconds
**/
fun getCurrentTime(mode)=
let if (mode >= 1) then (gmtime time) else (localtime time) -> [seconds minutes hours day month year _ _] in
[hours minutes seconds]
;;
/* ********************************************************************************************* /
CSV parser / writer
/ ********************************************************************************************* */
fun cbCSVstrip(s)=
stripChar s 34;;
/*! @ingroup csvtools
* \brief Write CSV format in string
*
* Prototype: fun [S [S r1] [[S r1] r1]] S
*
* \param S : separator
* \param [S r1] : list of column titles
* \param [[S r1] r1] : list of lines values
*
* \return S: formated string
**/
fun formatCSV(sep, ltitles, llinevalues)=
let if (sep == nil) then ";" else sep -> sep in
let "" -> out in
(
while (ltitles != nil) do
(
let hd ltitles -> title in
set out = strcatn out::title::sep::nil;
set ltitles = tl ltitles;
if (ltitles != nil) then nil else
set out = strcat out "\n";
);
while (llinevalues != nil) do
(
let hd llinevalues -> lvalues in
while (lvalues != nil) do
(
let hd lvalues -> val in
let if ((sizelist lineextr val) > 1) then (ctoa 34) else "" -> protect in
set out = strcatn out::protect::(addChar val 34 34)::protect::sep::nil;
set lvalues = tl lvalues;
if (lvalues != nil) then nil else
set out = strcat out "\n";
);
set llinevalues = tl llinevalues;
);
out;
);;
/*! @ingroup csvtools
* \brief Write CSV format in file
*
* Prototype: fun [S [S r1] [[S r1] r1]] S
*
* \param S : filepath
* \param S : separator
* \param [S r1] : list of column titles
* \param [[S r1] r1] : list of lines values
*
* \return 0
**/
fun writeCSV(filepath, sep, ltitles, llinevalues)=
let if (sep == nil) then ";" else sep -> sep in
let formatCSV sep ltitles llinevalues -> out in
_storepack out filepath;
0;;
/*! @ingroup csvtools
* \brief read CSV data with titles
*
* Prototype: fun [S S] [[S r1] [[S r1] r1]]
*
* \param S : data
* \param S : separator
*
* \return [[S r1] [[S r1] r1]] : list of title and list of values
**/
fun readCSVdataWithTitle(data, sep)=
let if (sep == nil) then ";" else sep -> sep in
let strToQuotedList data 34 -> ldata in
let nil -> ltitles in
let nil -> llinevalues in
(
let (hd ldata) -> titles in
set ltitles = strToListSepCb titles sep @cbCSVstrip;
set ldata = tl ldata;
while (ldata != nil) do
(
let hd ldata -> line in
let strToListSepCb line sep @cbCSVstrip -> lvalues in
set llinevalues = lvalues::llinevalues;
set ldata = tl ldata;
);
[ltitles (revertlist llinevalues)];
);;
/*! @ingroup csvtools
* \brief read CSV data
*
* Prototype: fun [S S] [[S r1] r1]
*
* \param S : data
* \param S : separator
*
* \return [[S r1] r1] : list of values
**/
fun readCSVdata(data, sep)=
let if (sep == nil) then ";" else sep -> sep in
let strToQuotedList data 34 -> ldata in
let nil -> llinevalues in
(
while (ldata != nil) do
(
let hd ldata -> line in
let strToListSepCb line sep @cbCSVstrip -> lvalues in
set llinevalues = lvalues::llinevalues;
set ldata = tl ldata;
);
revertlist llinevalues;
);;
/*! @ingroup csvtools
* \brief CSV data to array
*
* Prototype: fun [S S] [tab tab S]
*
* \param S : data
* \param S : separator
*
* \return [tab tab S] : array with datas
**/
fun readCSVdataToTab(data, sep)=
let if (sep == nil) then ";" else sep -> sep in
let strToQuotedList data 34 -> ldata in
let sizelist ldata -> nbrows in
let sizelist strToListSep (hd ldata) sep -> nbcols in
let mktab nbrows nil -> outtab in
(
let 0 -> t in
while (t < nbrows) do
(
set outtab.(t) = mktab nbcols "";
set t = t + 1;
);
let 0 -> i in
while (ldata != nil) do
(
let hd ldata -> line in
let strToListSepCb line sep @cbCSVstrip -> lvalues in
let outtab.(i) -> tval in
let 0 -> j in
while (lvalues != nil) do
(
if (j >= nbcols) then nil else
let hd lvalues -> value in
set tval.(j) = value;
set j = j + 1;
set lvalues = tl lvalues;
);
set ldata = tl ldata;
set i = i + 1;
);
outtab;
);;
/*! @ingroup csvtools
* \brief CSV data to array sized
*
* Prototype: fun [S S I I] [tab tab S]
*
* \param S : data
* \param S : separator
* \param I : Nb rows in tab
* \param I : Nb cols in tab
*
* \return [tab tab S] : array with datas
**/
fun readCSVdataToTabSized(data, sep, rows, cols)=
let if (sep == nil) then ";" else sep -> sep in
let strToQuotedList data 34 -> ldata in
let mktab rows nil -> outtab in
(
let 0 -> t in
while (t < rows) do
(
set outtab.(t) = mktab cols "";
set t = t + 1;
);
let 0 -> i in
while (ldata != nil) do
(
if (i >= rows) then nil else
(
let hd ldata -> line in
let strToListSepCb line sep @cbCSVstrip -> lvalues in
let outtab.(i) -> tval in
let 0 -> j in
while (lvalues != nil) do
(
if (j >= cols) then nil else
let hd lvalues -> value in
set tval.(j) = value;
set j = j + 1;
set lvalues = tl lvalues;
);
);
set ldata = tl ldata;
set i = i + 1;
);
outtab;
);;
/*! @ingroup csvtools
* \brief CSV tab to list
*
* Prototype: fun [[tab tab S] I I] [[S r1] r1]
*
* \param [tab tab S] : data in tab
* \param I : Nb rows
* \param I : Nb cols
*
* \return [[S r1] r1] : list of values
**/
fun readCSVTabToData(tdata, rows, cols)=
let nil -> out in
(
let 0 -> i in
while (i < rows) do
(
let tdata.(i) -> tval in
let 0 -> j in
let nil -> lines in
(
while (j < cols) do
(
let tval.(j) -> value in
set lines = value::lines;
set j = j + 1;
);
set out = (revertlist lines)::out;
);
set i = i + 1;
);
revertlist out;
);;
/*! @ingroup csvtools
* \brief CSV data to a single array row sized
*
* Prototype: fun [S S I [tab tab S] I I] [tab tab S]
*
* \param S : data
* \param S : separator
* \param I : row id
* \param [tab tab S] : input tab
* \param I : Nb rows in tab
* \param I : Nb cols in tab
*
* \return [tab tab S] : array with datas
**/
fun readCSVdataToTabRow(data, sep, rowid, srctab, rows, cols)=
let if (sep == nil) then ";" else sep -> sep in
let strToQuotedList data 34 -> ldata in
(
let rowid -> i in
while (ldata != nil) do
(
if (i >= rows) then nil else
(
let hd ldata -> line in
let strToListSepCb line sep @cbCSVstrip -> lvalues in
let srctab.(i) -> tval in
let 0 -> j in
while (lvalues != nil) do
(
if (j >= cols) then nil else
let hd lvalues -> value in
set tval.(j) = value;
set j = j + 1;
set lvalues = tl lvalues;
);
);
set ldata = tl ldata;
set i = i + 1;
);
srctab;
);;
/*! @ingroup csvtools
* \brief CSV data to a single array column sized
*
* Prototype: fun [S S I [tab tab S] I I] [tab tab S]
*
* \param S : data
* \param S : separator
* \param I : column id
* \param [tab tab S] : input tab
* \param I : Nb rows in tab
* \param I : Nb cols in tab
*
* \return [tab tab S] : array with datas
**/
fun readCSVdataToTabColumn(data, sep, colid, srctab, rows, cols)=
let if (sep == nil) then ";" else sep -> sep in
let strToQuotedList data 34 -> ldata in
(
let colid -> i in
while (ldata != nil) do
(
if (i >= cols) then nil else
(
let hd ldata -> line in
let strToListSepCb line sep @cbCSVstrip -> lvalues in
let 0 -> j in
while (lvalues != nil) do
(
if (j >= rows) then nil else
let srctab.(j) -> tval in
let hd lvalues -> value in
set tval.(i) = value;
set j = j + 1;
set lvalues = tl lvalues;
);
);
set ldata = tl ldata;
set i = i + 1;
);
srctab;
);;