Page 1 of 2

Problem with PeekS()

Posted: Sat Sep 21, 2024 2:09 pm
by Psychophanta
When I tried to assign an ascii string to a variable, not success using PeekS(), so I have to take the ugly way : CopyMemory()
Test yourself

Code: Select all

var$=PeekS(Ascii(#CRLF$),2,#PB_Ascii); <- Not Ok ??
debug peekB(@var$)
debug peekB(@var$+1)
debug "-----------"
CopyMemory(Ascii(#CRLF$),@var$,2); <- Ok
debug peekB(@var$)
debug peekB(@var$+1)

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 2:23 pm
by jacdelad
Is Peek officially allowed for constants?

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 2:36 pm
by the.weavster
*deleted... not useful :D

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 2:42 pm
by breeze4me

Code: Select all

var$=PeekS(Ascii(#CRLF$),2,#PB_Ascii)
As a result of the execution of the above line, a Unicode string is stored in the var$ variable. Therefore, it should be read with PeekC, not PeekB.

Code: Select all

var$=PeekS(Ascii(#CRLF$),2,#PB_Ascii)
Debug PeekC(@var$)
Debug PeekC(@var$+ SizeOf(Character))

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 3:27 pm
by Psychophanta
@breeze4me,

Code: Select all

var$=PeekS(Ascii(#CRLF$),2,#PB_Ascii)
should not store unicode, but ascii, isn't it?

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 3:40 pm
by breeze4me
Unless you're using an older version that supports ASCII compilation mode, strings are only stored in variables as Unicode.

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 6:18 pm
by AZJIO

Code: Select all

var$=PeekS(Ascii(#CRLF$), 1) ; -1
Debug PeekB(@var$)
Debug PeekB(@var$+1)
Psychophanta wrote: Sat Sep 21, 2024 3:27 pm should not store unicode, but ascii, isn't it?
Reads ascii, converts to unicode

There are 2 bytes here.

Code: Select all

Ascii(#CRLF$)
Read 2 bytes, treating each byte as #PB_Ascii. The output in Unicode will be 4 bytes.

Code: Select all

),2,#PB_Ascii
Reading 4 bytes with a +1 shift will not get the expected result.
If you use #PB_Unicode (default), you will get the same value of 2 bytes, but as one character.

Code: Select all

var$=PeekS(Ascii(#CRLF$),1) ; -1
Debug Asc(var$)
Debug Len(var$)
ShowMemoryViewer(@var$, 2)
Debug $0D
Debug $0A
Edit: corrected to the correct value 2->1

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 6:58 pm
by breeze4me
@AZJIO
The number of characters to read should be 1, not 2.
The buffer size allocated by Ascii(#CRLF$) is three bytes, so reading two characters in Unicode format is reading four bytes, which can cause problems.
13 10 (Unicode 1 chr) / 0 + x (Unicode 1 chr)
*Buffer = Ascii(String$)
......
The buffer includes a null-terminated character.

Code: Select all

;;var$=PeekS(Ascii(#CRLF$), 2)   ; Read 2 characters (=4 bytes) in Unicode format from that memory.
var$=PeekS(Ascii(#CRLF$), 1)   ; Read 1 character (=2 bytes) in Unicode format from that memory.
; var$=PeekS(Ascii(#CRLF$), 1, #PB_Unicode)  ; same
Debug PeekB(@var$)
Debug PeekB(@var$+1)

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 8:58 pm
by Mijikai
Sometimes i do something like this (ASM backend):

Code: Select all

EnableExplicit

Global str.s

str = PeekS(?hello,-1,#PB_Ascii)

Debug str

DataSection
  hello:
  !db 'Hello World',0
EndDataSection

Re: Problem with PeekS()

Posted: Sat Sep 21, 2024 9:22 pm
by STARGÅTE
A string variable like var$ stores its content always in unicode (UTF16) format.
The #PB_Ascii flag in PeekS is just for the source format.

Using CopyMemory is incorrect. It leads to IMAs, is the string was not allocated before in a sufficient length.

Re: Problem with PeekS()

Posted: Mon Sep 23, 2024 7:45 am
by Psychophanta
@Mijikai
Not good idea; to see it, please just replace 'Debug str' in your code by 'ShowMemoryViewer(@str,Len(str))'
STARGÅTE wrote: Sat Sep 21, 2024 9:22 pm Using CopyMemory is incorrect. It leads to IMAs, is the string was not allocated before in a sufficient length.
CopyMemory(Ascii(#CRLF$),@var$,Len(#CRLF$)+1); <- Ok

In general:
viewtopic.php?t=85410

Re: Problem with PeekS()

Posted: Mon Sep 23, 2024 5:21 pm
by Mijikai
Ok, give this a try (no CopyMemory):

Code: Select all

EnableExplicit

Global *test.String
Global *memory
Global length.i

Procedure.i AsciiAlloc(String.s);<- some black magic
  Protected *str.Integer
  Protected *eod.Ascii
  *str = Ascii(Space(SizeOf(Integer)) + String + ".")
  If *str
    *str\i = *str + SizeOf(Integer)
    *eod = *str + MemorySize(*str) - 2
    *eod\a = 0
    ProcedureReturn *str
  EndIf
  ProcedureReturn #Null
EndProcedure

Procedure.i AsciiDebug(*String.Integer);<- only for debugging
  ShowMemoryViewer(*String\i,MemorySize(*String) - SizeOf(Integer) - 1)
  ProcedureReturn #Null
EndProcedure

Procedure.i AsciiMemory(*String.Integer,*Length.Integer = #Null);<- get information about the memory
  If *Length
    *Length\i = MemorySize(*String) - SizeOf(Integer) - 2
  EndIf
  ProcedureReturn *String\i
EndProcedure

Procedure.i AsciiFree(*String)
  FreeMemory(*String)
  ProcedureReturn #Null
EndProcedure

*test = AsciiAlloc("Hello World")
*memory = AsciiMemory(*test,@length)

Debug *test\s ;<- assigned to string...
Debug *memory ;<- ascii string in memory
Debug length  ;<- ascii string length

AsciiDebug(*test) ;<- show ascii string in memory
AsciiFree(*test)  ;<- free ascii string

End

Re: Problem with PeekS()

Posted: Mon Sep 23, 2024 7:19 pm
by Psychophanta
@Mijikai
That's correct. Just it has to be stored in a string variable instead of pointer, like this one, which i think this is totally safe:

Code: Select all

Procedure$ AsignarCadenaAscii(cadena$)
  ;Carga una cadena de caracteres ascii extendido en una variable
  Protected size.i=2*Round((Len(cadena$)+1)/2,#PB_Round_Up)
  Protected *mem.byte=AllocateMemory(size,#PB_Memory_NoClear)
  *mem=Ascii(cadena$)
  ProcedureReturn PeekS(*mem,size)
EndProcedure
c$="Hello World !"
var$=AsignarCadenaAscii(c$)
debug var$
ShowMemoryViewer(@var$,2*Round((Len(c$)+1)/2,#PB_Round_Up))

Re: Problem with PeekS()

Posted: Mon Sep 23, 2024 8:25 pm
by Mijikai
@Psychophanta you leak *mem.
Due to the nature of the String representation in PB we should probably both still accomodate a 2nd zero (& alignment).
Also i think your version is still unsafe and only works because AllocateMemory internally reserves a bigger block.
PeekS will read 2 bytes per char regardless (not only 14 bytes).
Using var$/var.s (instead of a struct) may interfere with the internal memory management of Strings.

Btw. what will be the use for this Ascii.s thing?

Re: Problem with PeekS()

Posted: Mon Sep 23, 2024 10:54 pm
by Demivec
Psychophanta wrote: Mon Sep 23, 2024 7:19 pm @Mijikai
That's correct. Just it has to be stored in a string variable instead of pointer, like this one, which i think this is totally safe:

Code: Select all

Procedure$ AsignarCadenaAscii(cadena$)
  ;Carga una cadena de caracteres ascii extendido en una variable
  Protected size.i=2*Round((Len(cadena$)+1)/2,#PB_Round_Up)
  Protected *mem.byte=AllocateMemory(size,#PB_Memory_NoClear)
  *mem=Ascii(cadena$)
  ProcedureReturn PeekS(*mem,size)
EndProcedure
c$="Hello World !"
var$=AsignarCadenaAscii(c$)
debug var$
ShowMemoryViewer(@var$,2*Round((Len(c$)+1)/2,#PB_Round_Up))
The following code has a memory leak:

Code: Select all

Procedure$ AsignarCadenaAscii(cadena$)
  ;Carga una cadena de caracteres ascii extendido en una variable
  Protected size.i=2*Round((Len(cadena$)+1)/2,#PB_Round_Up)
  Protected *mem.byte=AllocateMemory(size,#PB_Memory_NoClear) ; <<<< this memory is never freed after the address is list on the next statement
  *mem=Ascii(cadena$) ;<<<< this memory is never freed, only copied
  ProcedureReturn PeekS(*mem,size)
EndProcedure