mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-07-28 20:05:54 +00:00
90941fffa7
This moves the CONST replacement up before we turn the elements into a single string. The advantage is that we don't have to worry about splitting the string properly to find the CONST names as the elements are already split for us.t
613 lines
17 KiB
QBasic
613 lines
17 KiB
QBasic
|
|
FUNCTION getelement$ (a$, elenum)
|
|
DIM p AS LONG, n AS LONG, i AS LONG
|
|
|
|
IF a$ = "" THEN EXIT FUNCTION 'no elements!
|
|
|
|
n = 1
|
|
p = 1
|
|
getelementnext:
|
|
i = INSTR(p, a$, sp)
|
|
|
|
IF elenum = n THEN
|
|
IF i THEN
|
|
getelement$ = MID$(a$, p, i - p)
|
|
ELSE
|
|
getelement$ = RIGHT$(a$, LEN(a$) - p + 1)
|
|
END IF
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
IF i = 0 THEN EXIT FUNCTION 'no more elements!
|
|
n = n + 1
|
|
p = i + 1
|
|
GOTO getelementnext
|
|
END FUNCTION
|
|
|
|
' Used to iterate over all the elements in a$
|
|
'
|
|
' index returns the current element number. index = -1 after last element
|
|
' strIndex is string index of the start of the next element
|
|
'
|
|
' index and strIndex should start initialized to zero
|
|
FUNCTION getnextelement$ (a$, index AS LONG, strIndex AS LONG)
|
|
DIM i AS LONG
|
|
|
|
IF strIndex = 0 THEN strIndex = 1
|
|
|
|
i = INSTR(strIndex, a$, sp)
|
|
|
|
IF i THEN
|
|
getnextelement$ = MID$(a$, strIndex, i - strIndex)
|
|
strIndex = i + 1
|
|
index = index + 1
|
|
ELSEIF strIndex <> LEN(a$) + 1 THEN
|
|
getnextelement$ = MID$(a$, strIndex)
|
|
strIndex = LEN(a$) + 1
|
|
index = index + 1
|
|
ELSE
|
|
index = -1
|
|
END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION peeknextelement$ (a$, index AS LONG, strIndex AS LONG)
|
|
peeknextelement$ = getnextelement$(a$, (index), (strIndex))
|
|
END FUNCTION
|
|
|
|
SUB pushelement (a$, b$)
|
|
IF a$ <> "" THEN a$ = a$ + sp + b$ ELSE a$ = b$
|
|
END SUB
|
|
|
|
' Used to iterate over all the elements in a$ start with the last
|
|
'
|
|
' index returns the current element number. index = -1 after last element
|
|
' strIndex is string index of the start of the next element in the iteration
|
|
'
|
|
' index and strIndex should start initialized to zero, iteration will start at last element
|
|
FUNCTION getprevelement$ (a$, index AS LONG, strIndex AS LONG)
|
|
DIM i AS LONG
|
|
|
|
IF strIndex = 0 THEN strIndex = LEN(a$): Index = numelements(a$) + 1
|
|
IF strIndex = -1 THEN Index = -1: EXIT FUNCTION
|
|
|
|
IF strIndex > 0 THEN i = _INSTRREV(strIndex, a$, sp)
|
|
|
|
IF i THEN
|
|
getprevelement$ = MID$(a$, i + 1, strIndex - i)
|
|
strIndex = i - 1
|
|
index = index - 1
|
|
|
|
' Handle the case of an empty first element, strIndex would be zero
|
|
' which would trigger the starting logic again
|
|
IF strIndex = 0 THEN strIndex = -2
|
|
ELSEIF strIndex <> -1 THEN
|
|
getprevelement$ = MID$(a$, 1, strIndex)
|
|
strIndex = -1
|
|
index = index - 1
|
|
ELSE
|
|
index = -1
|
|
END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION getelements$ (a$, i1, i2)
|
|
DIM p AS LONG, n AS LONG, i AS LONG, i1pos AS LONG
|
|
|
|
IF i2 < i1 THEN getelements$ = "": EXIT FUNCTION
|
|
n = 1
|
|
p = 1
|
|
getelementsnext:
|
|
i = INSTR(p, a$, sp)
|
|
IF n = i1 THEN
|
|
i1pos = p
|
|
END IF
|
|
IF n = i2 THEN
|
|
IF i THEN
|
|
getelements$ = MID$(a$, i1pos, i - i1pos)
|
|
ELSE
|
|
getelements$ = RIGHT$(a$, LEN(a$) - i1pos + 1)
|
|
END IF
|
|
EXIT FUNCTION
|
|
END IF
|
|
n = n + 1
|
|
p = i + 1
|
|
GOTO getelementsnext
|
|
END FUNCTION
|
|
|
|
FUNCTION getelementsbefore$ (a$, i1)
|
|
getelementsbefore$ = getelements$(a$, 1, i1)
|
|
END FUNCTION
|
|
|
|
FUNCTION getelementsafter$ (a$, i1)
|
|
DIM p AS LONG, n AS LONG, i AS LONG, i1pos AS LONG
|
|
|
|
n = 1
|
|
p = 1
|
|
|
|
getelementsnext:
|
|
i = INSTR(p, a$, sp)
|
|
|
|
IF n = i1 THEN
|
|
getelementsafter$ = RIGHT$(a$, LEN(a$) - p + 1)
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
n = n + 1
|
|
p = i + 1
|
|
GOTO getelementsnext
|
|
END FUNCTION
|
|
|
|
SUB insertelements (a$, i, elements$)
|
|
DIM a2 AS STRING, n AS LONG, i2 AS LONG
|
|
|
|
IF i = 0 THEN
|
|
IF a$ = "" THEN
|
|
a$ = elements$
|
|
EXIT SUB
|
|
END IF
|
|
a$ = elements$ + sp + a$
|
|
EXIT SUB
|
|
END IF
|
|
|
|
a2$ = ""
|
|
n = numelements(a$)
|
|
|
|
FOR i2 = 1 TO n
|
|
IF i2 > 1 THEN a2$ = a2$ + sp
|
|
a2$ = a2$ + getelement$(a$, i2)
|
|
IF i = i2 THEN a2$ = a2$ + sp + elements$
|
|
NEXT
|
|
|
|
a$ = a2$
|
|
|
|
END SUB
|
|
|
|
FUNCTION numelements (a$)
|
|
DIM p AS LONG, n AS LONG, i AS LONG
|
|
|
|
IF a$ = "" THEN EXIT FUNCTION
|
|
n = 1
|
|
p = 1
|
|
numelementsnext:
|
|
i = INSTR(p, a$, sp)
|
|
IF i = 0 THEN numelements = n: EXIT FUNCTION
|
|
n = n + 1
|
|
p = i + 1
|
|
GOTO numelementsnext
|
|
END FUNCTION
|
|
|
|
SUB removeelements (a$, first, last, keepindexing)
|
|
DIM n AS LONG, i AS LONG, a2 AS STRING
|
|
|
|
a2$ = ""
|
|
'note: first and last MUST be valid
|
|
' keepindexing means the number of elements will stay the same
|
|
' but some elements will be equal to ""
|
|
|
|
n = numelements(a$)
|
|
FOR i = 1 TO n
|
|
IF i < first OR i > last THEN
|
|
a2$ = a2$ + sp + getelement(a$, i)
|
|
ELSE
|
|
IF keepindexing THEN a2$ = a2$ + sp
|
|
END IF
|
|
NEXT
|
|
IF LEFT$(a2$, 1) = sp THEN a2$ = RIGHT$(a2$, LEN(a2$) - 1)
|
|
|
|
a$ = a2$
|
|
|
|
END SUB
|
|
|
|
SUB removeelement (a$, i)
|
|
removeelements a$, i, i, 0
|
|
END SUB
|
|
|
|
' a$ should be a function argument list
|
|
' Returns number of function arguments (including empty ones) in the provided list
|
|
FUNCTION countFunctionElements (a$)
|
|
DIM count AS LONG, p AS LONG, lvl AS LONG, i AS LONG
|
|
p = 1
|
|
lvl = 1
|
|
i = 0
|
|
|
|
IF LEN(a$) = 0 THEN
|
|
countFunctionElements = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
DO
|
|
SELECT CASE ASC(a$, i + 1)
|
|
CASE ASC("("):
|
|
lvl = lvl + 1
|
|
|
|
CASE ASC(")"):
|
|
lvl = lvl - 1
|
|
|
|
CASE ASC(","):
|
|
IF lvl = 1 THEN
|
|
count = count + 1
|
|
END IF
|
|
|
|
END SELECT
|
|
|
|
i = INSTR(p, a$, sp)
|
|
IF i = 0 THEN
|
|
EXIT DO
|
|
END IF
|
|
|
|
p = i + 1
|
|
LOOP
|
|
|
|
' Make sure to count the argument after the last comma
|
|
countFunctionElements = count + 1
|
|
END FUNCTION
|
|
|
|
' a$ should be a function argument list
|
|
' Returns true if the argument was provided in the list
|
|
FUNCTION hasFunctionElement (a$, element)
|
|
DIM count AS LONG, p AS LONG, lvl AS LONG, i AS LONG, start AS LONG
|
|
start = 0
|
|
p = 1
|
|
lvl = 1
|
|
i = 1
|
|
|
|
IF LEN(a$) = 0 THEN
|
|
hasFunctionElement = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
' Special case for a single provided argument
|
|
IF INSTR(a$, sp) = 0 AND LEN(a$) <> 0 THEN
|
|
hasFunctionElement = element = 1
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
DO
|
|
IF i > LEN(a$) THEN
|
|
EXIT DO
|
|
END IF
|
|
|
|
SELECT CASE ASC(a$, i)
|
|
CASE ASC("("):
|
|
lvl = lvl + 1
|
|
|
|
CASE ASC(")"):
|
|
lvl = lvl - 1
|
|
|
|
CASE ASC(","):
|
|
IF lvl = 1 THEN
|
|
count = count + 1
|
|
|
|
IF element = count THEN
|
|
' We have a element here if there's any elements
|
|
' inbetween the previous comma and this one
|
|
hasFunctionElement = (i <> 1) AND (i - 2 <> start)
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
start = i
|
|
END IF
|
|
END SELECT
|
|
|
|
p = i
|
|
i = INSTR(i, a$, sp)
|
|
|
|
IF i = 0 THEN
|
|
EXIT DO
|
|
END IF
|
|
|
|
i = i + 1
|
|
LOOP
|
|
|
|
IF element > count + 1 THEN
|
|
hasFunctionElement = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
' Check if last argument was provided.
|
|
'
|
|
' Syntax '2,3' has two arguments, the '3' argument is what gets compared here
|
|
' Syntax '2,' has one argument, the comma is the last element so it fails this check.
|
|
IF p > 0 THEN
|
|
IF ASC(a$, p) <> ASC(",") THEN
|
|
hasFunctionElement = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
END IF
|
|
|
|
hasFunctionElement = 0
|
|
END FUNCTION
|
|
|
|
' Returns true if the provided arguments are a valid set for the given function format
|
|
' firstOptionalArgument returns the index of the first argument that is optional
|
|
FUNCTION isValidArgSet (format AS STRING, providedArgs() AS LONG, firstOptionalArgument AS LONG)
|
|
DIM maxArgument AS LONG, i AS LONG
|
|
DIM currentArg AS LONG, optionLvl AS LONG
|
|
DIM wasProvided(0 TO 10) AS LONG
|
|
DIM AS LONG ArgProvided, ArgNotProvided, ArgIgnored
|
|
|
|
ArgProvided = -1
|
|
ArgNotProvided = 0
|
|
ArgIgnored = -2
|
|
firstOptionalArgument = 0
|
|
|
|
wasProvided(0) = ArgIgnored
|
|
|
|
' Inside of each set of brackets, all arguments must either be provide or not provided, with no mixing.
|
|
' For nested brackets, if the argument(s) inside the nested brackets are
|
|
' provided, then the arguments inside the outer brackets also have to be
|
|
' provided. Ex:
|
|
'
|
|
' x[,y[,z]]
|
|
'
|
|
' When x is provided, y and z are optional, but when y is provided x is required.
|
|
' When z is provided both y and x are required.
|
|
|
|
maxArgument = UBOUND(providedArgs)
|
|
|
|
FOR i = 1 TO LEN(format)
|
|
SELECT CASE ASC(format, i)
|
|
CASE ASC("["):
|
|
optionLvl = optionLvl + 1
|
|
wasProvided(optionLvl) = ArgIgnored
|
|
|
|
CASE ASC("]"):
|
|
optionLvl = optionLvl - 1
|
|
|
|
IF wasProvided(optionLvl) = ArgIgnored THEN
|
|
' If not provided, then we stay in the ignored state
|
|
' because whether this arg set was provided does not matter
|
|
' for the rest of the parsing
|
|
IF wasProvided(optionLvl + 1) = ArgProvided THEN
|
|
wasProvided(optionLvl) = ArgProvided
|
|
END IF
|
|
ELSE
|
|
' If an arg at this level was already not provided, then
|
|
' this optional set can't be provided either
|
|
IF wasProvided(optionLvl) = ArgNotProvided AND wasProvided(optionLvl + 1) = ArgProvided THEN
|
|
isValidArgSet = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
END IF
|
|
|
|
CASE ASC("?"):
|
|
currentArg = currentArg + 1
|
|
IF optionLvl >= 1 AND firstOptionalArgument = 0 THEN firstOptionalArgument = currentArg
|
|
|
|
IF wasProvided(optionLvl) = ArgIgnored THEN
|
|
IF maxArgument >= currentArg THEN
|
|
wasProvided(optionLvl) = providedArgs(currentArg)
|
|
ELSE
|
|
wasProvided(optionLvl) = 0
|
|
END IF
|
|
ELSE
|
|
IF maxArgument < currentArg THEN
|
|
IF wasProvided(optionLvl) <> ArgNotProvided THEN
|
|
isValidArgSet = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
ELSEIF wasProvided(optionLvl) <> providedArgs(currentArg) THEN
|
|
isValidArgSet = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
END IF
|
|
END SELECT
|
|
NEXT
|
|
|
|
' The base level of arguments are required. They can be in the
|
|
' 'ignored' state though if all arguments are within brackets
|
|
IF currentArg < maxArgument OR wasProvided(0) = ArgNotProvided THEN
|
|
isValidArgSet = 0
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
isValidArgSet = -1
|
|
END FUNCTION
|
|
|
|
FUNCTION eleucase$ (a$)
|
|
DIM i AS LONG, i2 AS LONG, a2$, sp34$, i3 AS LONG
|
|
|
|
'this function upper-cases all elements except for quoted strings
|
|
'check first element
|
|
IF LEN(a$) = 0 THEN EXIT FUNCTION
|
|
i = 1
|
|
IF ASC(a$) = 34 THEN
|
|
i2 = INSTR(a$, sp)
|
|
IF i2 = 0 THEN eleucase$ = a$: EXIT FUNCTION
|
|
a2$ = LEFT$(a$, i2 - 1)
|
|
i = i2
|
|
END IF
|
|
'check other elements
|
|
sp34$ = sp + CHR$(34)
|
|
IF i < LEN(a$) THEN
|
|
DO WHILE INSTR(i, a$, sp34$)
|
|
i2 = INSTR(i, a$, sp34$)
|
|
a2$ = a2$ + UCASE$(MID$(a$, i, i2 - i + 1)) 'everything prior including spacer
|
|
i3 = INSTR(i2 + 1, a$, sp): IF i3 = 0 THEN i3 = LEN(a$) ELSE i3 = i3 - 1
|
|
a2$ = a2$ + MID$(a$, i2 + 1, i3 - (i2 + 1) + 1) 'everything from " to before next spacer or end
|
|
i = i3 + 1
|
|
IF i > LEN(a$) THEN EXIT DO
|
|
LOOP
|
|
END IF
|
|
a2$ = a2$ + UCASE$(MID$(a$, i, LEN(a$) - i + 1))
|
|
eleucase$ = a2$
|
|
END FUNCTION
|
|
|
|
'
|
|
' The natural type of the value is returned.
|
|
'
|
|
' The actual value is given back as floating point, integer, and unsigned integer.
|
|
'
|
|
FUNCTION elementGetNumericValue&(ele$, floating AS _FLOAT, integral AS _INTEGER64, uintegral AS _UNSIGNED _INTEGER64)
|
|
Dim num$, typ&, e$, x As Long
|
|
num$ = ele$
|
|
typ& = 0
|
|
|
|
' Cut off the hex/oct/bin representation if present
|
|
IF INSTR(num$, ",") THEN num$ = MID$(num$, 1, INSTR(num$, ",") - 1)
|
|
|
|
' integer suffixes
|
|
e$ = RIGHT$(num$, 3)
|
|
IF e$ = "~&&" THEN elementGetNumericValue& = UINTEGER64TYPE - ISPOINTER: GOTO handleInteger
|
|
IF e$ = "~%%" THEN elementGetNumericValue& = UBYTETYPE - ISPOINTER: GOTO handleInteger
|
|
e$ = RIGHT$(num$, 2)
|
|
IF e$ = "&&" THEN elementGetNumericValue& = INTEGER64TYPE - ISPOINTER: GOTO handleInteger
|
|
IF e$ = "%%" THEN elementGetNumericValue& = BYTETYPE - ISPOINTER: GOTO handleInteger
|
|
IF e$ = "~%" THEN elementGetNumericValue& = UINTEGERTYPE - ISPOINTER: GOTO handleInteger
|
|
IF e$ = "~&" THEN elementGetNumericValue& = ULONGTYPE - ISPOINTER: GOTO handleInteger
|
|
e$ = RIGHT$(num$, 1)
|
|
IF e$ = "%" THEN elementGetNumericValue& = INTEGERTYPE - ISPOINTER: GOTO handleInteger
|
|
IF e$ = "&" THEN elementGetNumericValue& = LONGTYPE - ISPOINTER: GOTO handleInteger
|
|
|
|
'ubit-type?
|
|
IF INSTR(num$, "~`") THEN
|
|
x = INSTR(num$, "~`")
|
|
elementGetNumericValue& = UBITTYPE - ISPOINTER - 1 + VAL(RIGHT$(num$, LEN(num$) - x - 1))
|
|
integral = VAL(LEFT$(num$, x - 1))
|
|
uintegral = integral
|
|
floating = integral
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
'bit-type?
|
|
IF INSTR(num$, "`") THEN
|
|
x = INSTR(num$, "`")
|
|
elementGetNumericValue& = BITTYPE - ISPOINTER - 1 + VAL(RIGHT$(num$, LEN(num$) - x))
|
|
integral = VAL(LEFT$(num$, x - 1))
|
|
uintegral = integral
|
|
floating = integral
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
'floats
|
|
IF INSTR(num$, "F") OR RIGHT$(num$, 2) = "##" THEN
|
|
floating = VAL(num$)
|
|
integral = floating
|
|
uintegral = floating
|
|
|
|
elementGetNumericValue& = FLOATTYPE - ISPOINTER
|
|
EXIT FUNCTION
|
|
END IF
|
|
IF INSTR(num$, "E") OR RIGHT$(num$, 1) = "!" THEN
|
|
floating = VAL(num$)
|
|
integral = floating
|
|
uintegral = floating
|
|
|
|
elementGetNumericValue& = SINGLETYPE - ISPOINTER
|
|
EXIT FUNCTION
|
|
END IF
|
|
IF INSTR(num$, "D") OR RIGHT$(num$, 1) = "#" OR INSTR(num$, ".") THEN
|
|
floating = VAL(num$)
|
|
integral = floating
|
|
uintegral = floating
|
|
|
|
elementGetNumericValue& = DOUBLETYPE - ISPOINTER
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
' No mentioned type, assume int64
|
|
elementGetNumericValue& = INTEGER64TYPE - ISPOINTER
|
|
e$ = ""
|
|
|
|
handleInteger:
|
|
num$ = LEFT$(num$, LEN(num$) - LEN(e$))
|
|
integral = VAL(num$)
|
|
uintegral = integral
|
|
floating = integral
|
|
|
|
END FUNCTION
|
|
|
|
' Returns whether the given element is a number
|
|
'
|
|
' Note that it allows numbers to have a negative sign.
|
|
FUNCTION elementIsNumber&(oele$)
|
|
DIM ele$, res&
|
|
IF oele$ = "" THEN EXIT FUNCTION
|
|
ele$ = oele$
|
|
|
|
' Skip the negative if present
|
|
IF ASC(ele$) = ASC("-") THEN ele$ = MID$(ele$, 2)
|
|
|
|
' Can start with a decimal point
|
|
res& = (ASC(ele$) >= ASC("0") AND ASC(ele$) <= ASC("9"))
|
|
IF NOT res& AND LEN(ele$) > 1 THEN res& = (ASC(ele$) = ASC(".") AND (ASC(ele$, 2) >= ASC("0") AND ASC(ele$, 2) <= ASC("9")))
|
|
|
|
elementIsNumber& = res&
|
|
END FUNCTION
|
|
|
|
FUNCTION elementIsString&(ele$)
|
|
' String elements are always surounded by quotes
|
|
elementIsString& = INSTR(ele$, CHR$(34))
|
|
END FUNCTION
|
|
|
|
FUNCTION elementGetStringValue&(ele$, value AS STRING)
|
|
Dim rawString$, res$, i AS LONG
|
|
' We have to invert the escaping done by createElementString
|
|
'
|
|
' Note this does not handle all possible C escaping, just the specific
|
|
' escaping done by createElementString
|
|
'
|
|
rawString$ = MID$(ele$, 2, INSTR(2, ele$, CHR$(34)) - 2)
|
|
res$ = ""
|
|
i = 1
|
|
|
|
WHILE INSTR(i, rawString$, "\")
|
|
res$ = res$ + MID$(rawString$, i, INSTR(i, rawString$, "\") - i)
|
|
i = INSTR(i, rawString$, "\") + 1
|
|
|
|
IF ASC(rawString$, i) = ASC("\") THEN
|
|
res$ = res$ + "\"
|
|
i = i + 1
|
|
ELSE
|
|
res$ = res$ + CHR$(VAL("&O" + MID$(rawString$, i, 3)))
|
|
i = i + 3
|
|
END IF
|
|
WEND
|
|
|
|
value = res$ + MID$(rawString$, i)
|
|
elementGetStringValue& = STRINGTYPE
|
|
END FUNCTION
|
|
|
|
' s$ should be all the data making up the string, with no quotes around it
|
|
'
|
|
' The string data will have C escape sequences in it if necessary
|
|
FUNCTION createElementString$(s$)
|
|
Dim ele$, o$, p1 As Long, c2 As Long, i As Long
|
|
ele$ = CHR$(34)
|
|
|
|
p1 = 1
|
|
FOR i = 1 TO LEN(s$)
|
|
c2 = ASC(s$, i)
|
|
|
|
IF c2 = 92 THEN '\
|
|
ele$ = ele$ + MID$(s$, p1, i - p1) + "\\"
|
|
p1 = i + 1
|
|
END IF
|
|
|
|
IF c2 < 32 OR c2 = 34 OR c2 > 126 THEN
|
|
o$ = OCT$(c2)
|
|
IF LEN(o$) < 3 THEN
|
|
o$ = "0" + o$
|
|
IF LEN(o$) < 3 THEN o$ = "0" + o$
|
|
END IF
|
|
ele$ = ele$ + MID$(s$, p1, i - p1) + "\" + o$
|
|
|
|
p1 = i + 1
|
|
END IF
|
|
NEXT
|
|
|
|
ele$ = ele$ + MID$(s$, p1) + CHR$(34) + "," + _TRIM$(STR$(LEN(s$)))
|
|
createElementString$ = ele$
|
|
END FUNCTION
|
|
|
|
FUNCTION elementStringConcat$(os1$, os2$)
|
|
DIM s1$, s2$, s1size AS LONG, s2size AS LONG
|
|
'concat strings
|
|
s1$ = MID$(os1$, 2, _INSTRREV(os1$, CHR$(34)) - 2)
|
|
s1size = VAL(RIGHT$(os1$, LEN(os1$) - LEN(s1$) - 3))
|
|
|
|
s2$ = MID$(os2$, 2, _INSTRREV(os2$, CHR$(34)) - 2)
|
|
s2size = VAL(RIGHT$(os2$, LEN(os2$) - LEN(s2$) - 3))
|
|
|
|
elementStringConcat$ = CHR$(34) + s1$ + s2$ + CHR$(34) + "," + _TRIM$(STR$(s1size + s2size))
|
|
END FUNCTION
|