It happens when $ dollar signs appear in a string. It seems cut out the first appearances of $ with a few chars after that $, and then escape the following $ in the string like that: $ -> $$. But that is only my impression.
The Parsing happens "recursively" with ParseWildcards() / ParseWildcards_Back() and the argument exploder functions ExplodeArgString() and ExplodArgstring2().
Both those function pairs use the lookup functions to fill the wildcards/parameter arrays,
and the lookup functions use those functions too.
The "line input" procedures I wrote are not working 100% on linux, backspace and cursor keys aren't, and on Windows there might be glitches especially in the password input field. That's not the focus but you can simply hit return 3 times and you are through the test program.
On windows (all backends/x86/x64): no errors - the title/head is well drawn with - + | characters around the username
Linux x64: colors work, inputs work (tho yet incomplete), but the head/title is corrupted
I thought of "DangerousSmiley$" to be the problem but it isn't; it shows in all debug windows and even the Linux terminal; only windows (10) terminal prints an "undefined" symbol.
Code: Select all
; =====================================================
; = UnescapeString2.pb
; =====================================================
; Author: benubi
; Filename: UnescapeString2.pb
; Status: Secret
;
; Declare$ _UnescapeString(String$)
; Declare$ _UnescapeString2(String$, LookUp.UE_LookupProcedure, *udata)
; Declare.i _UnescapeString_Back(String$, *udataWriter, *udataLookup, Writer.UE_WriterProcedure, Lookup.UE_LookupProcedure)
;
; Declare ExplodeArgString(String$, Array Result.s(1))
; + a few little helpers
;
;
; \a: alarm Chr(7)
; \b: backspace Chr(8)
; \f: formfeed Chr(12)
; \n: newline Chr(10)
; \r: carriage return Chr(13)
; \t: horizontal tab Chr(9)
; \v: vertical tab Chr(11)
; \": double quote Chr(34)
; \\: backslash Chr(92)
;
;
;++ extended part ++
;
; \e: escape Chr(27)
; \xnn: ascii hex Chr(0-255)
; \unnnn: unicode hex Chr(0-65535)
; \nnn: octal digits[0-7] Chr(0-255)
; \0: octal null-byte Chr(0)
;
;
; Lookup: ${variable-name}
; ${var "name" 'value' some-thing}
; ${x}
; $[with brackets]
; $(with parenthesis)
; ${pretty}
; $short
;
; Lookup2: with AND without parenthesis:
; $varname_until_unfitting_char.
; The lookup strings remain escaped at lookup function call time
;
; to do/want:
;
;
; "maybe" (low probability of implementation)
; c++ 23 conventions
;
; \0{nnnnn,...}
; \x{nnnnn,...}
; \u{nnnnnn...}
;
;
EnableExplicit
; Like EplodeArgString() except that the results are parsed with a lookup procedure
; Prototype for lookup procedures
Prototype$ UE_LookupProcedure(*udata, key$, parenthesis, isWriter)
; Prototype for writer (output) procedures
Prototype UE_WriterProcedure(*udata, *buff, bytes) ; returns 0 to continue, other to abort
; Prototype for reader (input) procedures
Prototype UE_ReaderProcedure(*udata, *buff, bytes) ; returns 0 to continue, other to abort
Structure LookupStruct
*VT ; = @LookupStruct\LookUp
*LookupCookie
*WriterCookie
Lookup.UE_LookupProcedure
Writer.UE_WriterProcedure
EndStructure
; Extended UnescapeString procedure
Procedure$ _UnescapeString(String$)
Protected resultLength
Protected *C.Character = @String$
Protected octalvalue, i
If String$=#Null$
ProcedureReturn ""
EndIf
; \a: alarm Chr(7)
; \b: backspace Chr(8)
; \f: formfeed Chr(12)
; \n: newline Chr(10)
; \r: carriage return Chr(13)
; \t: horizontal tab Chr(9)
; \v: vertical tab Chr(11)
; \": double quote Chr(34)
; \\: backslash Chr(92)
;++
; \e: escape Chr(27)
; \0: null byte Chr(0)
; \nnn: octal 1-3 digits [0-7]
; \x##: ascii hex Chr(0-255)
; \u####: unicode hex Chr(0-65535)
;
While *C\c
If *C\c = '\'
*C + SizeOf(Character)
Select *C\c
Case '0' To '9'
i = 0
While i < 3 And *C\c >= '0' And *C\c <= '9'
i + 1
*C + SizeOf(character)
Wend
resultLength + 1
Case 'a', 'b', 'f', 'n', 'r', 't', 'v', 32, 39, 92, 'e'
resultLength + 1
Case 'x', 'X' ; ascii character (hex)
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
resultLength + 1
Case 'u', 'U' ; unicode character
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
resultLength + 1
Case 0
Break
Default
resultLength + 1
EndSelect
Else
resultLength + 1
EndIf
*C + SizeOf(Character)
Wend
Protected result$ = Space(resultLength)
Protected *Z.Character = @result$
Protected num.c
*C = @String$
While *C\c
If *C\c = '\'
*C + SizeOf(Character)
Select *C\c
Case '0' To '9' ; octal
octalvalue = 0
While *C\c >= '0' And *C\c <= '9' And i < 3
octalvalue * 8
octalvalue + *c\c - '0'
*C + SizeOf(character)
i + 1
Wend
*Z\c = octalvalue
Case 'a'
*Z\c = 7
Case 'b'
*Z\c = 8
Case 'f'
*Z\c = 12
Case 'n'
*Z\c = 10
Case 'r'
*Z\c = 13
Case 't'
*Z\c = 9
Case 'v'
*Z\c = 11
Case 32, 39, 92
*Z\c = *c\c
Case 'e'
*Z\c = 27
Case 'x', 'X' ; ascii character (hex)
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
Select *c\c
Case '0' To '9'
num = *c\c - '0'
Case 'a' To 'f'
num = *c\c - 'a' + 10
Case 'A' To 'F'
num = *c\c - 'A' + 10
EndSelect
num << 4
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
Select *c\c
Case '0' To '9'
num = num | (*c\c - '0')
Case 'a' To 'f'
num = num | (*c\c - 'a' + 10)
Case 'A' To 'F'
num = num | (*c\c - 'A' + 10)
EndSelect
*Z\c = num
Case 'u', 'U' ; unicode character
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
Select *c\c
Case '0' To '9'
num = *c\c - '0'
Case 'a' To 'f'
num = *c\c - 'a' + 10
Case 'A' To 'F'
num = *c\c - 'A' + 10
EndSelect
num << 4
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
Select *c\c
Case '0' To '9'
num = num | (*c\c - '0')
Case 'a' To 'f'
num = num | (*c\c - 'a' + 10)
Case 'A' To 'F'
num = num | (*c\c - 'A' + 10)
EndSelect
num << 4
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
Select *c\c
Case '0' To '9'
num = num | (*c\c - '0')
Case 'a' To 'f'
num = num | (*c\c - 'a' + 10)
Case 'A' To 'F'
num = num | (*c\c - 'A' + 10)
EndSelect
num << 4
*C + SizeOf(character):If *C\c = 0 : Break : EndIf
Select *c\c
Case '0' To '9'
num = num | (*c\c - '0')
Case 'a' To 'f'
num = num | (*c\c - 'a' + 10)
Case 'A' To 'F'
num = num | (*c\c - 'A' + 10)
EndSelect
*Z\c = num
Case 0
Break
Default
*Z\c = *c\c
EndSelect
Else
*Z\c = *C\c
EndIf
*C + SizeOf(Character)
*Z + SizeOf(Character)
Wend
ProcedureReturn result$
EndProcedure
; UnescapeString() with user-defined lookup function (searching for ${abcdefgh} variables)
Procedure$ ParseWildcards(String$, LookUp.UE_LookupProcedure, *udata, iswriter = #False)
Protected resultLength
Protected *C.Character = @String$
Protected t$, *s, enca, lims, lime
Protected tlen, i
Protected NewList token.s()
While *C\c
If *C\c = '$' ; dollar sign (will be omitted)
*C + SizeOf(Character)
Select *C\c
Case 'a' To 'z', 'A' To 'Z', '_'
tlen = 0
*S = *C
While *C\c
Select *C\c
Case 'a' To 'z', 'A' To 'Z', '_', '0' To '9'
tlen + 1
Default
Break
EndSelect
*C + SizeOf(character)
Wend
AddElement(Token())
t$ = LookUp(*udata, PeekS(*S, tlen), 0, isWriter)
Token() = t$
resultLength + Len(t$)
Continue
Case '{', '[', '('
lims = *c\c
If lims = '('
lime = lims + 1
Else
lime = lims + 2
EndIf
*C + SizeOf(character)
*S = *C
enca = 0
tlen = 0
While *C\c
If (*C\c = 34 Or *C\c = 39)
If enca = *C\c
enca = 0
ElseIf enca = 0
enca = *C\c
EndIf
ElseIf *C\c = '\'
resultLength + 1
*C + SizeOf(Character)
If Not *C\c
Break
EndIf
Continue
ElseIf *C\c = lime
If enca = 0
Break
EndIf
EndIf
tlen + 1
*C + SizeOf(Character)
Wend
If *C\c = lime
AddElement(Token())
t$ = LookUp(*udata, PeekS(*S, tlen), lims, isWriter)
Token() = t$
resultLength + Len(t$)
*C + SizeOf(Character)
Continue
Else
Break
EndIf
Default
EndSelect
EndIf
resultLength + 1 ; next character will be copied (no matter what it is) -> best choice $
*C + SizeOf(Character)
Wend
Protected result$ = Space(resultLength)
Protected *Z.Character = @result$
Protected num.c
*C = @String$
While *C\c
If *C\c = '$'
*C + SizeOf(Character)
Select *C\c
Case 'a' To 'z', 'A' To 'Z', '_'
While *C\c
Select *C\c
Case 'a' To 'z', 'A' To 'Z', '_', '0' To '9'
Default
Break
EndSelect
*C + SizeOf(character)
Wend
FirstElement(Token())
*Z + PokeS(*Z, token())
DeleteElement(token())
Continue
Case '{', '(', '['
lims = *C\c
If lims = '('
lime = lims + 1
Else
lime = lims + 2
EndIf
While *C\c
If (*C\c = 34 Or *C\c = 39)
If enca = *C\c
enca = 0
ElseIf enca = 0
enca = *C\c
EndIf
ElseIf *C\c = '\'
*Z\c = *C\c
*C + SizeOf(Character)
If Not *C\c
Break
EndIf
*Z\c = *C\c
*C + SizeOf(Character)
*S = *C
Continue
ElseIf *C\c = lime
If enca = 0
Break
EndIf
EndIf
*C + SizeOf(Character)
Wend
If *C\c = lime
FirstElement(Token())
*Z + PokeS(*Z, Token())
DeleteElement(token())
*c + SizeOf(Character)
Continue
EndIf
Break
Default
*Z\c = *C\c
EndSelect
Else
*Z\c = *C\c
EndIf
*C + SizeOf(Character)
*Z + SizeOf(Character)
Wend
ProcedureReturn result$
EndProcedure
; UnescapeString() with user-defined lookup and output/writer function
Procedure.i ParseWildcards_Back(String$, *udataWriter, *udataLookup, Writer.UE_WriterProcedure, Lookup.UE_LookupProcedure)
Structure UE_Token
Token.s
toklen.i
EndStructure
Protected *C.Character = @String$
Protected t$, *s, num.c
Protected result , enca, lims, lime
Protected toklen, ttlen, x$, c, *Z
Protected NewList token.UE_Token()
*S = *C
Macro WR(_X_)
AddElement(Token())
Token()\token = _X_
Token()\toklen = Len(_X_)
ttlen = ttlen + token()\toklen
toklen = 0
*S = *C + SizeOf(Character)
EndMacro
Macro WR1(_X_)
AddElement(Token())
Token()\token = _X_
Token()\toklen = 1
ttlen + 1
toklen = 0
*S = *C + SizeOf(Character)
EndMacro
Macro WRFLUSH()
c = 0
x$ = Space(ttlen + 2)
*z = @x$
ForEach token()
c + PokeS(*z + c, token()\token)
Next
ClearList(token())
ttlen = 0
toklen = 0
*S = *C + SizeOf(Character)
If c
result = Writer(*udataWriter, *z, c)
If result : ProcedureReturn result : EndIf
EndIf
EndMacro
While *C\c
If toklen = 0
*S = *C
EndIf
If *C\c = '$' ; dollar sign (will be omitted)
If toklen
WR(PeekS(*S, toklen))
EndIf
*C + SizeOf(Character)
Select *C\c
Case 'a' To 'z', 'A' To 'Z', '_'
WRFLUSH()
*S = *C
toklen = 0
While *C\c
Select *C\c
Case 'a' To 'z', 'A' To 'Z', '_', '0' To '9'
toklen + 1
Default
Break
EndSelect
*C + SizeOf(Character)
Wend
If toklen
t$ = Lookup(*udataLookup, PeekS(*S, toklen), 0, 1)
toklen = 0
WR(t$)
EndIf
*S = *C
toklen = 0
Continue
Case '{', '[', '(' ; look up procedure
WRFLUSH()
lims = *C\c
If lims = '(' : lime = lims + 1 : Else : lime = lims + 2 : EndIf
*C + SizeOf(character)
*S = *C ;+ SizeOf(Character)
enca = 0
While *C\c
If enca And enca = *C\c
enca = 0
ElseIf *c\c = 34 Or *C\c = 39 And enca = 0
enca = *C\c
ElseIf *C\c = '\'
*C + SizeOf(Character)
If Not *C\c
Break
EndIf
ElseIf enca = 0 And *C\c = lime
Break
EndIf
toklen + 1
*C + SizeOf(Character)
Wend
If *C\c = lime
t$ = LookUp(*udataLookup, PeekS(*S, toklen), lims, 1)
If t$ <> #Empty$ And T$ <> #Empty$
toklen = 0
WR(t$)
EndIf
toklen = 0
*C + SizeOf(Character)
*S = *C
Continue
Else
Break
EndIf
toklen = 0
*S = *C + SizeOf(Character)
Default
WR1(Chr(*C\c))
EndSelect
Else
toklen + 1
EndIf
*C + SizeOf(Character)
Wend
If toklen
; Debug #PB_Compiler_Procedure +" exit tail peek call"
WR(PeekS(*S, toklen))
EndIf
WRFLUSH()
; Debug #PB_Compiler_Procedure +" exit bottom"
ProcedureReturn 0
EndProcedure
; Explodes a string like if it was a command/batch line taking care of " ' parameter encapsulation
Procedure ExplodeArgString(String$, Array Result.s(1)) ;
Protected *C.Character
Protected count, c
Protected *argstart, slen, argend, *n.Character
*C = @String$
While *C\c
If (*C\c = 32 Or *C\c = #TAB) And *argstart
*argstart = 0
slen = 0
count + 1
EndIf
While *C\c = 32 Or *C\c = #TAB : *C + SizeOf(Character) : Wend
Select *C\c
Case 0, '#' ; commentary ; End of string
Break
Case '\'
If *argstart = 0
*argstart = *c
*C + SizeOf(Character)
If *c\c = 0
Break
EndIf
slen = 2
*C + SizeOf(Character)
Continue
Else
slen + 1
EndIf
Case 34, 39 ; Encapsulation
count + 1
argend = *C\c
*argstart = *C + SizeOf(Character)
slen = 0
*C + SizeOf(Character)
While *C\c
If *C\c = '\'
slen + 1
*C + SizeOf(Character)
If *C\c = 0
Break
EndIf
ElseIf *C\c = argend
;slen+1
Break
EndIf
slen + 1
*C + SizeOf(Character)
Wend
slen = 0
*argstart = 0
Default
If *argstart = 0
*argstart = *C
slen = 1
count = count + 1
Else
slen = slen + 1
EndIf
EndSelect
If *C\c
*C = *C + SizeOf(Character)
Else
Break
EndIf
Wend
If slen
count = count + 1
EndIf
ReDim Result.s(count)
*argstart = 0
*C = @String$
c = 0
While *C\c
If (*C\c = 32 Or *c\c = #TAB) And *argstart
If slen
result(c) = PeekS(*argstart, slen)
Else
result(c) = ""
EndIf
c = c + 1
slen = 0
*argstart = 0
EndIf
While *C\c = 32 Or *C\c = #TAB : *C + SizeOf(Character) : Wend
Select *C\c
Case 0, '#' ; commentary ; End of string
Break
Case '\'
If *argstart = 0
*argstart = *c
*C + SizeOf(Character)
If *c\c = 0
Break
EndIf
slen = 2
*C + SizeOf(Character)
Continue
Else
slen + 1
EndIf
Case 34, 39 ; Encapsulation
argend = *C\c
*argstart = *C + SizeOf(Character)
slen = 0
*C + SizeOf(Character)
While *c\c
If *c\c = '\'
*C = *c + SizeOf(Character)
slen = slen + 1
If *C\c = 0
Break
EndIf
ElseIf *C\c = argend
;slen+1
Break
EndIf
slen = slen + 1
*C + SizeOf(Character)
Wend
If slen
result(c) = PeekS(*argstart, slen)
Else
result(c) = ""
EndIf
*argstart = 0
slen = 0
c = c + 1
Default
If *argstart = 0
*argstart = *C
slen = 1
Else
slen = slen + 1
EndIf
EndSelect
If *C\c
*C + SizeOf(Character)
Else
Break
EndIf
Wend
If slen
result(c) = PeekS(*argstart, slen)
c = c + 1
EndIf
ReDim Result.s(c)
ProcedureReturn c
EndProcedure
; Like EplodeArgString() except that the results are parsed with a lookup procedure
Procedure ExplodeArgString2(String$, Array Result.s(1), LookUp.UE_LookupProcedure, *udata, isWriter) ;
Protected *C.Character
Protected count, c
Protected *argstart.character, slen, argend, *n.Character
;Protected old_show=show_it
;show_it=#True
*C = @String$
While *C\c
If (*C\c = 32 Or *C\c = #TAB) And *argstart
*argstart = 0
slen = 0
count + 1
EndIf
While *C\c = 32 Or *C\c = #TAB : *C + SizeOf(Character) : Wend
Select *C\c
Case 0, '#' ; commentary ; End of string
Break
Case '\'
If *argstart = 0
*argstart = *c
*C + SizeOf(Character)
If *c\c = 0
Break
EndIf
slen = 2
*C + SizeOf(Character)
Continue
Else
slen + 1
EndIf
Case 34, 39 ; Encapsulation
count + 1
argend = *C\c
*argstart = *C ;+ SizeOf(Character)
slen = 1
*C + SizeOf(Character)
While *C\c
If *C\c = '\'
slen + 1
*C + SizeOf(Character)
If *C\c = 0
Break
EndIf
ElseIf *C\c = argend
slen + 1
Break
EndIf
slen + 1
*C + SizeOf(Character)
Wend
slen = 0
*argstart = 0
Default
If *argstart = 0
*argstart = *C
slen = 1
count = count + 1
Else
slen = slen + 1
EndIf
EndSelect
If *C\c
*C = *C + SizeOf(Character)
Else
Break
EndIf
Wend
If slen
count = count + 1
EndIf
ReDim Result.s(count)
*argstart = 0
*C = @String$
c = 0
While *C\c
If (*C\c = 32 Or *c\c = #TAB) And *argstart
If slen
result(c) = PeekS(*argstart, slen)
Else
result(c) = ""
EndIf
c = c + 1
slen = 0
*argstart = 0
EndIf
While *C\c = 32 Or *C\c = #TAB : *C + SizeOf(Character) : Wend
Select *C\c
Case 0, '#' ; commentary ; End of string
Break
Case '\'
If *argstart = 0
*argstart = *c
*C + SizeOf(Character)
If *c\c = 0
Break
EndIf
slen = 2
*C + SizeOf(Character)
Continue
Else
slen + 1
EndIf
Case 34, 39 ; Encapsulation
argend = *C\c
*argstart = *C + SizeOf(Character)
slen = 0
*C + SizeOf(Character)
While *c\c
If *c\c = '\'
*C = *c + SizeOf(Character)
slen = slen + 1
If *C\c = 0
Break
EndIf
ElseIf *C\c = argend
;slen+1
Break
EndIf
slen = slen + 1
*C + SizeOf(Character)
Wend
If slen
If *argstart\c = 39
result(c) = ParseWildcards(PeekS(*argstart + SizeOf(Character), slen - (2*SizeOf(Character))), LookUp, *udata, isWriter)
ElseIf *argstart\c = 34
result(c) = ParseWildcards(PeekS(*argstart + SizeOf(Character), slen - (2*SizeOf(Character))), LookUp, *udata, isWriter)
Else
result(c) = ParseWildcards(PeekS(*argstart, slen), LookUp, *udata, isWriter)
EndIf
Else
result(c) = ""
EndIf
*argstart = 0
slen = 0
c = c + 1
Default
If *argstart = 0
*argstart = *C
slen = 1
Else
slen = slen + 1
EndIf
EndSelect
If *C\c
*C + SizeOf(Character)
Else
Break
EndIf
Wend
If slen
If *argstart\c = 39
result(c) = ParseWildcards(PeekS(*argstart + SizeOf(Character), slen - (2*SizeOf(Character))), LookUp, *udata, isWriter)
ElseIf *argstart\c = 34
result(c) = ParseWildcards(PeekS(*argstart + SizeOf(Character), slen - (2*SizeOf(Character))), LookUp, *udata, isWriter)
Else
result(c) = ParseWildcards(PeekS(*argstart, slen), LookUp, *udata, isWriter)
EndIf
c = c + 1
EndIf
ReDim Result.s(c)
ProcedureReturn c
EndProcedure
; returns the named flag's value (flag1:val1 flag2:val2) values are in decimal
Procedure.i StringFlag(String$, FlagList$)
Protected *S
Protected klen
Protected flag
Protected value
Protected *C.character = @flaglist$
While *C\c
While *C\c = #TAB Or *C\c = 32
*C + SizeOf(character)
Wend
*S = *C
klen = 0
While *C\c And *C\c <> 32 And *c\c <> #TAB
If *C\c = ':'
If PeekS(*S, klen) = String$
;Debug "found! "+String$
; continue
*C + SizeOf(Character)
While *C\c And *C\c <> 32 And *C\c <> #TAB
value * 10
value + (*C\c - '0')
*C + SizeOf(Character)
Wend
ProcedureReturn value
Else
; Debug "next... ("+PeekS(*S,klen)+")"
While *C\c And *c\c <> 32 And *C\c <> #TAB
*C + SizeOf(character)
Wend
*S = *C
If Not *C\c
;Debug "reached eol"
ProcedureReturn
EndIf
Break
EndIf
EndIf
klen + 1
*C + SizeOf(Character)
Wend
*C + SizeOf(Character)
Wend
;Debug "not found :("
ProcedureReturn flag
EndProcedure
; returns #true is string$ is in the memberlist
Procedure.i IsMember(String$, MemberList$)
Protected *Z1.Character
Protected *Z2.character = @MemberList$
While *Z2\c
While *Z2\c = #TAB Or *Z2\c = 32
*Z2 + SizeOf(Character)
Wend
*Z1 = @String$
While *Z1\c = *Z2\c And *Z1\c And *Z2\c
*Z1 + SizeOf(Character)
*Z2 + SizeOf(Character)
Wend
If *Z1\c = 0 And (*Z2\c = 0 Or *Z2\c = 32 Or *Z2\c = #TAB)
ProcedureReturn #True
EndIf
Wend
ProcedureReturn #False
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
; Examples
; --------------------------------------------------------------------------------------------------------
; How to make your own lookup function to return unescaped+filled strings
; Use helpfer functions like ExplodeArgString and StringFlag
;
; use StringFlag(String$,) with flaglists like these:
#INCLUDE_MSBOX = #True
#USE_CONSOLE = #True
Global msgboxflaglist$ ; pairs are name:value, pairs are separated by space(s) or tab(s)
msgboxflaglist$ = "cancel:" + Str(#PB_MessageRequester_Cancel)
msgboxflaglist$ + " error:" + Str(#PB_MessageRequester_Error)
msgboxflaglist$ + " info:" + Str(#PB_MessageRequester_Info)
msgboxflaglist$ + " no:" + Str(#PB_MessageRequester_No)
msgboxflaglist$ + " ok:" + Str(#PB_MessageRequester_Ok)
msgboxflaglist$ + " warning:" + Str(#PB_MessageRequester_Warning)
msgboxflaglist$ + " yes:" + Str(#PB_MessageRequester_Yes)
msgboxflaglist$ + " yes-no-cancel:" + Str(#PB_MessageRequester_YesNoCancel)
msgboxflaglist$ + " yes-no:" + Str(#PB_MessageRequester_YesNo)
; Example 1:
; look up procedures receive "CONTENT" key$ when found inside parsed/unescaped string "${CONTENT}"
NewMap _L.s()
Declare$ prime_lookup(*udata, key$, parenthesis, isWriter)
Procedure$ mylookup(*udata, key$, parenthesis, isWriter)
Shared _L()
Protected result$ = ""
Protected Dim p$(8)
; Protected pc = ExplodeArgString2(key$, p$(), @mylookup(), *udata, isWriter)
Protected pc = ExplodeArgString2(key$, p$(), @prime_lookup(), *udata, Bool(isWriter) * 2)
;Debug key$
If pc < 6
ReDim p$(6)
EndIf
If parenthesis = 0
Select LCase(p$(0))
Case "username"
result$ = UserName()
Case "computername"
result$ = ComputerName()
Default
result$ = GetRuntimeString(p$(0))
EndSelect
ProcedureReturn result$
ElseIf parenthesis = '['
; lang
result$ = _L(p$(0))
ProcedureReturn result$
EndIf
Select p$(0)
Case "n" ; CRLF 'Telnet' 'network-line' standard ${n} may be easier to type than \r\n for some !?
result$ = #CRLF$
Case "env"
If pc = 2
result$ = GetEnvironmentVariable(p$(1))
EndIf
Case "rts"
result$ = GetRuntimeString(p$(1))
Case "rti"
result$ = FormatNumber(GetRuntimeInteger(p$(1)), 0, "", p$(2))
Case "rtd"
result$ = FormatNumber(GetRuntimeDouble(p$(1)), Val(p$(2)), Left(p$(3) + ",", 1), Mid(p$(3), 2, 1))
Case "setrts"
SetRuntimeString(p$(1), p$(2))
Case "setrti"
SetRuntimeInteger(p$(1), Val(p$(2)))
Case "setrtd"
SetRuntimeDouble(p$(1), ValD(p$(2)))
Case "lset"
result$ = LSet(p$(1), Val(p$(2)), p$(3))
Case "rset"
result$ = RSet(p$(1), Val(p$(2)), p$(3))
Case "cset"
P$(1) = ParseWildcards(p$(1), @prime_lookup(), *udata, 0)
result$ = LSet(Space((Val(p$(2)) / 2) - (Len(p$(1)) / 2)), Val(p$(2)), P$(3))
Case "mid"
result$ = Mid(p$(1), Val(p$(2)), Val(p$(3)))
Case "rf"
Protected fh = ReadFile( - 1, p$(1))
Protected format, remove_eol, replace_eol
If fh
format = ReadStringFormat(fh)
result$ = ReadString(fh, format | #PB_File_IgnoreEOL)
CloseFile(fh)
Select p$(2)
Case ""
Case "remove-eol"
Repeat
Select Right(result$, 1)
Case #CR$, #LF$
result$ = Left(result$, Len(result$) - 1)
Default
Break
EndSelect
ForEver
Case "replace-eol"
result$ = ReplaceString(result$, #CRLF$, " ")
result$ = ReplaceString(result$, #LFCR$, " ")
result$ = ReplaceString(result$, #LF$, " ")
result$ = ReplaceString(result$, #CR$, " ")
result$ = ReplaceString(result$, #TAB$, LSet("", 8))
result$ = Trim(result$)
EndSelect
EndIf
CompilerIf #INCLUDE_MSBOX
Case "msgbox"
;Debug ">>"+key$
If pc => 4
Select MessageRequester(ParseWildcards(p$(1), @mylookup(), *udata), ParseWildcards(p$(2), @mylookup(), *udata), StringFlag(p$(3), msgboxflaglist$) | StringFlag(p$(4), msgboxflaglist$))
Case #PB_MessageRequester_Cancel
result$ = "cancel"
Case #PB_MessageRequester_No
result$ = "no"
Case #PB_MessageRequester_Yes
result$ = "yes"
EndSelect
ElseIf pc >= 3
MessageRequester(ParseWildcards(p$(1), @mylookup(), *udata), ParseWildcards(p$(2), @mylookup(), *udata))
ElseIf pc => 2
MessageRequester("Nested msgbox", ParseWildcards(p$(1), @mylookup(), *udata))
EndIf
CompilerEndIf
EndSelect
ProcedureReturn result$
EndProcedure
Procedure$ MyUnescapeString(String$)
EnableGraphicalConsole(0)
ProcedureReturn _UnescapeString(ParseWildcards(String$, @prime_lookup(), 0))
EndProcedure
; msgbox in mylookup() needs to be uncommented For it To work
;MessageRequester("Too much??", MyUnescapeString("Hello world\r\nSomething wrong?\r\n${msgbox 'Heh heh heh :)' 'A msgbox hiding in a msgbox!!' yes-no-cancel warning}!!!"), #PB_MessageRequester_YesNoCancel)
; --------------------------------------------------------------------------------------------------------
; How to make your own output writer
; How to make it work with the lookup function
; How to simply cascade lookup functions with select statements
Define CurrentConsoleINV
Define CurrentConsoleBG = 0, CurrentConsoleFG = 7
Declare _Print(String$)
Procedure$ Lang(id$)
Shared _L()
If FindMapElement(_L(), id$)
ProcedureReturn _L()
EndIf
ProcedureReturn ""
EndProcedure
Procedure$ PrimeParse(String$, isWriter = 0)
Protected result$ = ParseWildcards(String$, @prime_lookup(), 0, isWriter)
ProcedureReturn result$
EndProcedure
Procedure$ prime_lookup(*udata, key$, parenthesis, isWriter)
Shared CurrentConsoleFG
Shared CurrentConsoleBG
Shared CurrentConsoleINV
Protected Dim p$(0)
Protected pc = ExplodeArgString2(key$, p$(), @prime_lookup(), *udata, Bool(isWriter) * 2)
Protected result$ = Space(100)
Protected Raw
Protected inkey$
result$ = #Empty$
ReDim p$(8)
; Graphical console functions
Select LCase(P$(0))
Case "fg"
If isWriter = 1
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
CurrentConsoleFG = Val(p$(1))
If CurrentConsoleINV = 0
ConsoleColor(CurrentConsoleFG, CurrentConsoleBG)
Else
ConsoleColor(CurrentConsoleBG, CurrentConsoleFG)
EndIf
EnableGraphicalConsole(0)
CompilerEndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "bg"
If isWriter = 1
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
CurrentConsoleBG = Val(p$(1))
If CurrentConsoleINV = 0
ConsoleColor(CurrentConsoleFG, CurrentConsoleBG)
Else
ConsoleColor(CurrentConsoleBG, CurrentConsoleFG)
EndIf
EnableGraphicalConsole(0)
CompilerEndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "cls"
If isWriter = 1
;ClearConsole()
CurrentConsoleBG = 0
CurrentConsoleFG = 7
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
If CurrentConsoleINV = 0
ConsoleColor(CurrentConsoleFG, CurrentConsoleBG)
Else
ConsoleColor(CurrentConsoleBG, CurrentConsoleFG)
EndIf
EnableGraphicalConsole(0)
CompilerEndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "col"
If isWriter = 1
CurrentConsoleFG = Val(p$(1))
CurrentConsoleBG = Val(p$(2))
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
If CurrentConsoleINV = 0
ConsoleColor(CurrentConsoleFG, CurrentConsoleBG)
Else
ConsoleColor(CurrentConsoleBG, CurrentConsoleFG)
EndIf
EnableGraphicalConsole(0)
CompilerEndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "n"
result$ = #CRLF$
Case "h"
If isWriter = 1
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
ConsoleLocate(1, 1)
CompilerElse
ConsoleLocate(0, 0)
CompilerEndIf
EnableGraphicalConsole(0)
CompilerEndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "inv"
If isWriter = 1
CurrentConsoleINV ! 1
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
If CurrentConsoleINV = 0
ConsoleColor(CurrentConsoleFG, CurrentConsoleBG)
Else
ConsoleColor(CurrentConsoleBG, CurrentConsoleFG)
EndIf
EnableGraphicalConsole(0)
CompilerEndIf
EndIf
Case "cur"
If isWriter = 1
If pc = 1
CompilerIf #USE_CONSOLE
ConsoleCursor(Val(p$(1)))
CompilerEndIf
EndIf
EndIf
Case "loc"
If isWriter = 1
If pc = 2
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
ConsoleLocate(Val(p$(0)), Val(p$(1)))
CompilerElse
ConsoleLocate(Val(p$(0)), Val(p$(1)))
CompilerEndIf
EnableGraphicalConsole(0)
CompilerEndIf
EndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "rep"
result$ = LSet("", Val(p$(1)), p$(2))
Case "reset", "r"
If isWriter = 1
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(1)
CurrentConsoleBG = 0
CurrentConsoleFG = 7
CurrentConsoleINV = 0
ConsoleColor(7, 0)
EnableGraphicalConsole(0)
CompilerEndIf
ElseIf isWriter = 2
result$ = "${" + key$ + "}"
EndIf
Case "hd", "head"
Protected tt$ = ParseWildcards(p$(1), @prime_lookup(), 0, 0)
tt$ = Left(tt$, 76)
p$(1) = _UnescapeString(P$(1))
p$(2) = _UnescapeString(P$(2))
p$(3) = _UnescapeString(P$(3))
p$(4) = _UnescapeString(P$(4))
Protected ind$ = Space(Val(p$(4)))
Protected tlen = Len(tt$)
Protected horiz$ = Left(p$(2), 1)
If horiz$ = "" : horiz$ = "*" : EndIf
Protected vert$ = Mid(p$(2), 2, 1)
If vert$ = "" : vert$ = horiz$ : EndIf
Protected tl$ = Left(p$(3), 1)
If tl$ = "" : If vert$ = horiz$ : tl$ = horiz$:Else:tl$ = "+":EndIf :EndIf
Protected tr$ = Mid(p$(3), 2, 1)
If tr$ = "":tr$ = tl$:EndIf
Protected bl$ = Mid(p$(3), 3, 1)
If bl$ = "":bl$ = tl$:EndIf
Protected br$ = Mid(p$(3), 4, 1)
If br$ = "":br$ = tl$:EndIf
If isWriter = 0
result$ =ind$ + tl$ + LSet("", tlen + 2, horiz$) + tr$ + #CRLF$ + ind$ + vert$ + " " + tt$ + " " + vert$ + #CRLF$ + ind$ + bl$ + LSet("", tlen + 2, horiz$) + br$ + #CRLF$
ElseIf isWriter = 2
result$ = ind$ + tl$ + LSet("", tlen + 2, horiz$) + tr$ + #CRLF$ + ind$ + vert$ + " " + _UnescapeString(ParseWildcards(p$(1), @prime_lookup(), 0, 2)) + " " + vert$ + #CRLF$ +ind$ + bl$ + LSet("", tlen + 2, horiz$) + br$ + #CRLF$
Else
CompilerIf #USE_CONSOLE
_Print(ind$ + tl$ + LSet("", tlen + 2, horiz$) + tr$ + #CRLF$)
_Print(ind$ + vert$ + " " + p$(1) + " " + vert$ + #CRLF$)
_Print(ind$ + bl$ + LSet("", tlen + 2, horiz$) + br$ + #CRLF$)
CompilerEndIf
result$ = ""
EndIf
Case "inln"
CompilerIf #USE_CONSOLE
If isWriter = 1
Protected input_len = Val(p$(1))
Protected fill_char$ = Left(p$(3) + " ", 1)
Protected value$ = p$(2)
Protected inloc
Protected escape_sequence$
EnableGraphicalConsole(0)
Print(LSet(value$, input_len, fill_char$))
Print(LSet("", input_len - Len(value$), Chr(8)))
inloc = Len(value$)
Repeat
EnableGraphicalConsole(1)
inkey$ = Inkey()
raw = RawKey()
Select raw
Case 0
Delay(0)
Case 8, 127
If Len(value$) > 0 And inloc > 0
EnableGraphicalConsole(0)
value$ = Left(value$, inloc - 1) + Mid(value$, inloc + 1)
Print(Chr(8) + fill_char$ + Chr(8))
Print(Mid(value$, inloc) + fill_char$)
Print(LSet("", 2 + Len(value$) - inloc, Chr(8)))
inloc - 1
;
EndIf
Case 13, 10
result$ = value$
Break
Case 27
If Len(inkey$) < 2
While Len(value$)
value$ = Left(value$, Len(value$) - 1)
Print(Chr(8) + fill_char$ + Chr(8))
Wend
inloc = 0
EndIf
Case 37
; Debug "left"
If inloc > 0
inloc - 1
Print(Chr(8))
EndIf
Case 38
; Debug "up"
Case 39
; Debug "right"
If inloc < Len(value$)
inloc + 1
Print(Mid(value$, inloc, 1))
EndIf
Case 40
; Debug "down"
Case 46
; delete key
If Len(value$) > 0
If inloc < Len(value$)
value$ = Left(value$, inloc) + Mid(value$, inloc + 2)
Print(Mid(value$, inloc + 1) + fill_char$)
Print(LSet("", 1 + Len(Mid(value$, inloc + 1)), Chr(8)))
EndIf
EndIf
Default
Debug "default... raw: " + Raw
EndSelect
If raw >= 32 And Len(inkey$) = 1
If Len(value$) < input_len
value$ = Left(value$, inloc) + inkey$ + Mid(value$, inloc + 1)
inloc + 1
Print(Mid(value$, inloc))
Print(LSet("", Len(value$) - inloc, Chr(8)))
EndIf
ElseIf raw = 27
EndIf
ForEver
; Debug "value$="
; Debug value$
If IsRuntime(p$(4))
SetRuntimeString(p$(4), value$)
result$ = ""
Else
result$ = value$
EndIf
EndIf
CompilerEndIf
Case "inpw"
CompilerIf #USE_CONSOLE
If isWriter = 1
input_len = Val(p$(1))
fill_char$ = Left(p$(3) + " ", 1)
value$ = p$(2)
Protected pw_char$ = p$(4)
If pw_char$ = ""
pw_char$ = "*"
ElseIf pw_char$ = "no-char"
pw_char$ = ""
EndIf
inloc = Len(value$)
EnableGraphicalConsole(0)
If value$ <> "" And pw_char$ <> ""
Print(LSet(LSet("", Len(value$), pw_char$), input_len, fill_char$))
Print(LSet("", input_len - Len(value$), Chr(8)))
Else
Print(LSet("", input_len, fill_char$))
Print(LSet("", input_len, Chr(8)))
EndIf
Repeat
inkey$ = Inkey()
raw = RawKey()
Select raw
Case 0
Delay(0)
Case 10, 13
result$ = value$
Break
Case 27
If pw_char$ <> ""
While Len(value$)
value$ = Left(value$, Len(value$) - 1)
Print(Chr(8) + fill_char$ + Chr(8))
Wend
EndIf
inloc = 0
Case 37
If inloc > 0
inloc - 1
If pw_char$ <> ""
Print(Chr(8))
EndIf
EndIf
Case 38
Case 39
If inloc < Len(value$)
inloc + 1
Print(pw_char$)
EndIf
Case 40
EndSelect
If raw >= 32 And inkey$ <> ""
If Len(value$) < input_len
value$ = Left(value$, inloc) + inkey$ + Mid(value$, inloc + 1)
inloc + 1
If pw_char$ <> ""
Print(LSet("", 1 + Len(value$) - inloc, pw_char$))
Print(LSet("", Len(value$) - inloc, Chr(8)))
EndIf
EndIf
ElseIf raw = 8
If Len(value$) > 0 And inloc > 0
value$ = Left(value$, Len(value$) - 1)
If pw_char$ <> ""
Print(Chr(8) + fill_char$ + Chr(8))
EndIf
inloc - 1
If pw_char$ <> ""
Print(LSet("", 1 + Len(value$) - inloc, pw_char$))
Print(LSet("", Len(value$) - inloc, Chr(8)))
EndIf
EndIf
EndIf
ForEver
If IsRuntime(p$(5))
SetRuntimeString(p$(5), value$)
result$ = ""
Else
result$ = value$
EndIf
EndIf
CompilerEndIf
Case "waitkey"
Protected kl = Len(p$(1))
CompilerIf #USE_CONSOLE
If isWriter = 1
If kl = 0
Repeat
result$ = Inkey()
Raw = RawKey()
If Not Raw
Delay(0)
EndIf
Until result$ <> #Empty$ Or raw
result$ = result$ + ":" + Str(raw)
Else
Repeat
result$ = Inkey()
Raw = RawKey()
If result$ <> #Empty$
If Not FindString(result$, p$(1))
result$ = ""
EndIf
EndIf
If Not Raw
Delay(0)
EndIf
Until result$ <> ""
result$ = result$ + ":" + Str(raw)
EndIf
EndIf
If IsRuntime(p$(2))
SetRuntimeString(p$(2), result$)
result$ = ""
EndIf
CompilerEndIf
Default
ProcedureReturn mylookup(*udata, key$, parenthesis, isWriter) ; Cascading lookup-procedures
EndSelect
ProcedureReturn result$
EndProcedure
Procedure prime_writer(*udata, *buff, bytes)
;MessageRequester("Writer",string$)
CompilerIf #USE_CONSOLE
If *buff ; string$ <> #Null$
If bytes ; string$ <> #Empty$
EnableGraphicalConsole(0)
Print(PeekS(*buff, bytes))
EnableGraphicalConsole(1)
EndIf
EndIf
CompilerEndIf
ProcedureReturn 0
EndProcedure
Procedure$ PrimeUnescape(String$, isWriter = 0)
If isWriter
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(0)
CompilerEndIf
EndIf
ProcedureReturn _UnescapeString(PrimeParse(String$, IsWriter))
EndProcedure
Procedure _Print(String$)
CompilerIf #USE_CONSOLE
EnableGraphicalConsole(0)
ParseWildcards_Back(_UnescapeString(String$), 0, 0, @prime_writer(), @prime_lookup())
EnableGraphicalConsole(0)
CompilerEndIf
EndProcedure
Global myUsername.s
Global myPassword.s
Global Var1.d
Global Var2.d
Runtime myUsername, myPassword
Runtime Var1, Var2
Procedure Main()
Protected DangerousSmiley$ = "\uD83D\uDE0A" ; <--- is this the reason?
;Protected DangerousSmiley$ = "" ; <--- is this the reason?
Protected str$
Protected uname$
;
; this caused a bug on linux with the title/header frame $(hd ...)
; CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; uname$= "${env Username}$${fg 15}@$${fg 6}${env Computername}"
; CompilerElse
; uname$= "${env USER}@${rf '/etc/hostname' replace-eol}"
; CompilerEndIf
;
; directly setting virtual variables (returns result from UserName() and ComputerName())
uname$ = "$username$${fg 15}@$${fg 5}$computername$${r}"
myUsername = ParseWildcards(ParseWildcards(uname$, @prime_lookup(), 0, 0), @prime_lookup(), 0, 0)
;myUsername = ParseWildcards(uname$,@prime_lookup(),0,0)
str$ = "$(hd 'Hello $${fg 3}" + uname$
str$ = str$ + "$${fg 7}!' '-|' '+' 24)\r\n This message is \xA9 ${fg 10}free${fg 7} \U00A9.${n}" + DangerousSmiley$ + ""
str$ = str$ + "\r\n${lset 'Physical mem free' 20 '.'}: ${inv}${rset '${rtd var1 0 .,}' 24 ' '}${inv}"
str$ = str$ + "${n}${lset 'Total virtual' 20 '.'}: ${inv}${rset '${rtd var2 0 ,.}' 24 ' '}${inv}\r\n"
;str$ = str$ + "But now beware of $$ -> $$$$ $ $ $strange things can ${happen} if you don't consider ;)"
str$ = str$ + " \r\n"
str$ = str$ + "${lset 'Username ' 30 '.' } : ${inv}${inln 40 '$myUsername' '_' 'myUsername'}${inv}\r\n"
str$ = str$ + "${lset 'Password ' 30 '.' '*'} : ${inv}${inpw 40 '' '_' '*' 'myPassword'}${inv}\r\n"
;Define DangerousSmiley$="<no-smiley>" ; <--- is this the reason?
; Let's fill runtime variables that are accessible via the lookup procedure
Define log$ = "./testcoloroutput.txt"
CreateFile(0, log$, #PB_UTF8)
If Not ReadStringFormat(0)
WriteStringFormat(0, #PB_UTF8)
EndIf
WriteStringN(0, "String before parsing:")
WriteStringN(0, str$)
var1 = MemoryStatus(#PB_System_FreePhysical)
var2 = MemoryStatus(#PB_System_TotalVirtual)
CompilerIf #USE_CONSOLE
OpenConsole()
EnableGraphicalConsole(1)
Debug MyUnescapeString(str$)
Debug _UnescapeString(PrimeParse(str$))
_Print(str$)
PrintN("")
PrintN("")
PrintN("")
PrintN("")
PrintN("Entered Username=" + myUsername)
PrintN("Entered Password=" + myPassword)
EnableGraphicalConsole(0)
PrintN("The same without writer, using user-defined MyUnescape() procedure returning a string (therefor no color formatting inside)")
PrintN("")
Print(PrimeUnescape(str$))
; Print(MyUnescapeString(str$))
_Print("\r\nEnter ${inv}RETURN${inv} to exit\r\n")
EnableGraphicalConsole(0)
Input()
CloseConsole()
CompilerElse
WriteStringN(0, "Parsed:")
WriteStringN(0, PrimeParse(str$, 0))
CompilerEndIf
CloseFile(0)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
;RunProgram(log$)
CompilerElse
;RunProgram("gedit", log$, "")
CompilerEndIf
EndProcedure
main()
CompilerEndIf