Author Topic: UDT and String overlapping...  (Read 1355 times)

0 Members and 2 Guests are viewing this topic.

Brian Alvarez

  • Guest
UDT and String overlapping...
« on: May 05, 2019, 11:25:48 AM »
 Hello Charles, I am noticing something really weird and i am at the point that i am considering this a bug in oxygen... i cant find any other explanation.
I am converting the following code from PluriBASIC to Oxygen:



 I have a TYPE called ABC. As follows.

Code: [Select]
TYPE ABC
    CHAR astr[20]
    WCHAR wstr[20]
    CHAR ast2[20]
END TYPE

 Then, in a module i declare some variables as follow:

Code: [Select]
   DWORD ff
   ABC a
   CHAR b[20]
   INT c
   WSTRING inputstring

Let me explain the issue:
If i remark "GET #FF,,B" Everything works as expected, the code also displays the contents of a.astr, which are: *This is 1 ASCII* But when I execute the code, and PluriBASIC generates this macros:

   ¤GETSTR(bstring, ff, -1, b, ¤TMPV2, 20)
   ¤STRN(b, ¤TMPV2, 20)


 Then, the last byte of b gets written in the first byte of the a UDT, particularily at the beggining of a.astr, so, the null byte causes that STDOUT truncates the output to a null string.

In the ¤STRN macro, i explicitly limit the contents of b to its maximum size, as follows:

Code: [Select]
//Assigns a truncated null terminated string.
MACRO ¤STRN(v, c, l  b)   
    string b = c
    if len(b) > l then b = left(b, l)
    v = b           
END MACRO

And everything works as expected (except the loading of the b variable) if i remark the v = b part.

Everything works as expected also if i change the size of the b string to 10 characters, or 200. But if i specifically state 20 characters, Oxygen is allocating overlapped bytes.

 Im sorry if my error reports are long and hard to understand. Its the simplest way i have to explain it.

Brian Alvarez

  • Guest
Re: UDT and String overlapping...
« Reply #1 on: May 05, 2019, 11:31:59 AM »
By the way, before i forget, Oxygen also goes crazy if i save to file the string *It's an ascii str*, it seems like it doesnt like the ' character, it truncates everything in a weird way. Maybe the tokenizer is acting up again.

 Im going to test the newest version now.
« Last Edit: May 05, 2019, 11:40:41 AM by Brian Alvarez »

Brian Alvarez

  • Guest
Re: UDT and String overlapping...
« Reply #2 on: May 05, 2019, 11:48:17 AM »
Also... dont let this deceive you:

Code: [Select]
B = SPACE$(LOF(FF))
 Even though i am stating that the string should load more content that it is supposed to hold, i just did that to make sure it is not doing it. In fact LOF is out of service right now. The string only loads 20 bytes. Also, i was thinking that oxygen is creating a base 0 array for b[20], creating 21 bytes, but the problem occurs if i cut the string 1 byte in the ¤STRN() macro.

 Here is the code that pluribasic is generating, in case you want to play with it. It is probably a simple thing that i am overlooking:

Code: [Select]
'Generated with PluriBASIC 6.0.233801.0

$ filename "C:\Users\Diamante\Documents\PluriBASIC\projects\fulll_file_test.exe"

uses rtl32
uses console

Declare Function ¤MessageBoxa  Lib "user32.dll" Alias "MessageBoxA"
Declare Function ¤MessageBoxw  Lib "user32.dll" Alias "MessageBoxW"
STRING ¤TMPS = "" ' a temporary string.
DECLARE FUNCTION ¤GetAsyncKeyState    Lib "User32.dll"   Alias "GetAsyncKeyState" (ByVal vKey AS LONG) AS short
DECLARE SUB ¤Sleep                    lib "Kernel32.dll" alias "Sleep" (dword mSec)

function ¤QINI(int v1, v2) as quad
    quad qs=0x10000 : qs*=0x10000
    return qs*v1+v2
end function

DECLARE FUNCTION ¤OpenProcess         Lib "KERNEL32.DLL"  Alias "OpenProcess" (ByVal dwDesiredAccess AS DWORD, ByVal bInheritHandle AS LONG, ByVal dwProcessId AS SYS) AS SYS
DECLARE FUNCTION ¤TerminateProcess    Lib "KERNEL32.DLL"  Alias "TerminateProcess" ( ByVal hProcess AS SYS, ByVal uExitCode AS DWORD) AS LONG
DECLARE FUNCTION ¤CloseHandle         Lib "KERNEL32.DLL"  Alias "CloseHandle" (ByVal hObject AS SYS) AS LONG
DECLARE FUNCTION ¤GetCurrentProcessId Lib "KERNEL32.DLL"  Alias "GetCurrentProcessId" () AS SYS

MACRO ¤ONERR(l, e)
   Err.err = e
   IF (Err.err>0) THEN
      Err.ers = Err.erp
      Err.erl = l   
      IF Err.Oe1 THEN
         JMP Err.Oe1
      ELSEIF Err.Oe2 THEN
         CALL Err.Oe2
      END IF
   else
      Err.ers = ""
      Err.erl = 0   
   END IF
END MACRO

MACRO ERRCLEAR
    Err.err = 0
    Err.erl = 0
    Err.ers = ""
END MACRO

CLASS ¤SYSERR
    public sys Oe1 = 0
    public sys Oe2 = 0
    public int err = 0
    public int erl = 0
    public string erp = ""
    public string ers = ""
END CLASS
declare FUNCTION ¤CloseHandle LIB "KERNEL32.DLL" ALIAS "CloseHandle" (byval fHandle AS SYS) AS DWORD
DECLARE FUNCTION ¤CreateFileA LIB "KERNEL32.DLL" ALIAS "CreateFileA" ( _
                     ByVal lpFileName AS DWORD, _
                     ByVal dwDesiredAccess AS DWORD, _
                     ByVal dwShareMode AS DWORD, _
                     ByVal lpSecurityAttributes AS DWORD, _
                     ByVal dwCreationDisposition AS DWORD, _
                     ByVal dwFlagsAndAttributes AS DWORD, _
                     BYVAL hTemplateFile AS DWORD) AS DWORD
DECLARE FUNCTION ¤CreateFileW LIB "KERNEL32.DLL" ALIAS "CreateFileW" ( _
                     ByVal lpFileName AS DWORD, _
                     ByVal dwDesiredAccess AS DWORD, _
                     ByVal dwShareMode AS DWORD, _
                     ByVal lpSecurityAttributes AS DWORD, _
                     ByVal dwCreationDisposition AS DWORD, _
                     ByVal dwFlagsAndAttributes AS DWORD, _
                     BYVAL hTemplateFile AS DWORD) AS DWORD
DECLARE FUNCTION ¤SetFilePointerEx LIB "KERNEL32.DLL" ALIAS "SetFilePointerEx" ( _                   
                     BYVAL hFile AS SYS, _
                     BYVAL lDistanceToMove AS SYS, _
                     BYREF lpNewFilePointer AS SYS, _
                     BYVAL dwMoveMethod AS DWORD) AS INT
DECLARE FUNCTION ¤WriteFile LIB "Kernel32.dll" ALIAS "WriteFile" ( _
                     BYVAL hFile AS SYS, BYVAL lpBuffer AS SYS, _
                     BYVAL nNumberOfBytesToWrite AS DWORD, lpNumberOfBytesWritten AS DWORD, _
                     lpOverlapped AS DWORD) AS DWORD
DECLARE FUNCTION ¤ReadFile LIB "Kernel32.dll" ALIAS "ReadFile" ( _
                     BYVAL hFile AS SYS, BYVAL lpBuffer AS SYS, _
                     BYVAL nNumberOfBytesToRead AS DWORD, lpNumberOfBytesRead AS DWORD, _
                     lpOverlapped AS DWORD) AS DWORD                     
DECLARE FUNCTION ¤WriteConsole     LIB "KERNEL32.DLL" ALIAS "WriteFile" (BYVAL hFile AS DWORD, lpBuffer AS ANY, BYVAL nNumberOfBytesToWrite AS LONG, lpNumberOfBytesWritten AS LONG, lpOverlapped AS ANY) AS LONG
DECLARE FUNCTION ¤AllocConsole     LIB "KERNEL32.DLL" ALIAS "AllocConsole" () AS LONG
DECLARE FUNCTION ¤FlushFileBuffers LIB "KERNEL32.DLL" ALIAS "FlushFileBuffers" (BYVAL hFile AS DWORD) AS LONG
DECLARE FUNCTION ¤GetStdHandle     LIB "KERNEL32.DLL" Alias "GetStdHandle" (ByVal nStdHandle AS DWORD) AS DWORD

TYPE ¤HPROP
    long elem
    long dmode
    sys oldProc
    sys curProc
    'long user1
    'long user2   
END TYPE

Function ¤DEFAULT_CALLBACK_PROC(sys hwnd, wMsg, wParam, lParam) as sys callback
    sys retval = 0
   
    return retval
   
End Function


' STARTS PLURIBASIC_PREPARE.BIN
' This code is executed before anything else, if you want to do something after defining other things, see PLURIBASIC_INIT


' STARTS TERMINATE.BIN
' STARTS MSGBOX.BIN

FUNCTION MSGBOX(wstring wText, int mOptions, string aCaption) AS LONG
   wstring wCaption = mid(aCaption, 1)     
   FUNCTION = ¤MessageBoxw(0, wText, wCaption, mOptions)   
end function

FUNCTION MSGBOX(string aText, int mOptions, wstring wCaption) AS LONG
   wstring wText = mid(aText, 1)     
   FUNCTION = ¤MessageBoxw(0, wText, wCaption, mOptions)   
end function

FUNCTION MSGBOX(wstring wText, int mOptions, wstring wCaption) AS LONG
   FUNCTION = ¤MessageBoxw(0, wText, wCaption, mOptions)   
end function

FUNCTION MSGBOX(string aText, int mOptions, string aCaption) AS LONG
   FUNCTION = ¤MessageBoxa(0, aText, aCaption, mOptions)   
END FUNCTION

FUNCTION MSGBOX(string aText) AS LONG
   string aCaption = "PluriBASIC"
   int mOptions = 0
   FUNCTION = ¤MessageBoxa(0, aText, aCaption, mOptions)   
END FUNCTION

FUNCTION MSGBOX(wstring wText) AS LONG
   wString wCaption = "PluriBASIC"
   int mOptions = 0 
   FUNCTION = ¤MessageBoxw(0, wText, wCaption, mOptions)   
END FUNCTION

FUNCTION MSGBOX(string aText, int mOptions) AS LONG
   string aCaption = "PluriBASIC"
   FUNCTION = ¤MessageBoxa(0, aText, aCaption, mOptions)   
END FUNCTION

FUNCTION MSGBOX(wstring wText, int mOptions) AS LONG
   wString wCaption = "PluriBASIC"
   FUNCTION = ¤MessageBoxw(0, wText, wCaption, mOptions)   
END FUNCTION
' END OF MSGBOX.BIN
' CONTINUES (1) TERMINATE.BIN

FUNCTION _TERMINATE(string sText = "") as long

   if len(sText) then
       MSGBOX(sText, 64)
   end if
   
   sys hProcess = ¤OpenProcess(1, 0, ¤GetCurrentProcessId())
   
   If (hProcess<>0) And (hProcess <> 0xFFFFFFFF) Then
      ¤TerminateProcess(hProcess, 0)
      ¤CloseHandle(hProcess)
   End If   
   
END FUNCTION

' END OF TERMINATE.BIN
' CONTINUES (12) PLURIBASIC_PREPARE.BIN


#DEF HANDLE SYS






MACRO ¤SET_ERR(n)
    Err.err = n
    Err.erl = Err.erp
END MACRO


MACRO ¤UDTCOPY(s, u, n)
    copy u, n, s
END MACRO

macro ¤USETV(vu, ai, of, dt, nv, ln      a, c)
    sys a = ai + of
    dt c = nv
    copy a, @c, ln
end macro

macro ¤USETA(vu, ai, of, nv, ln  a, c)
    sys a = ai + of
    string c = left(nv, ln)
    c = (c + news(ln-len(c)))   
    copy(a, strptr(c), ln)
end macro

macro ¤USETW(vu, ai, of, nv, ln  a, c)
    sys a = ai + of
    wstring c = left(nv, ln)
    c = (c + news(ln-len(c)))   
    copy(a, strptr(c), ln*2)
end macro

macro ¤MSETV(vu, of, dt, nv, ln  c)
    dt c = nv
    copy @vu + of, @c, ln
end macro

macro ¤MSETA(vu, of, nv, ln  c)
    string c = left(nv, ln)
    c = (c + news(ln-len(c)))   
    copy(@vu + of, strptr(c), ln)
end macro

macro ¤MSETW(vu, of, nv, ln  c)
    wstring c = left(nv, ln)
    c = (c + news(ln-len(c)))
    copy(@vu + of, strptr(c), ln*2)
end macro

macro ¤MINCR(vu, of, dt, nv, ln  c, a)
    dt a = 0
    copy @, @vu + of, ln
    dt c = (a + (nv))
    copy @vu + of, @c, ln
end macro

macro ¤MDECR(vu, of, dt, nv, ln  c, a)
    dt a = 0
    copy @, @vu + of, ln
    dt c = (a - (nv))
    copy @vu + of, @c, ln
end macro

macro ¤SDT_VAL(nm, dt)
    function nm(sys hBuffer, of) as dt
        sys a = hBuffer + of       
        dt r
        copy @r, a, sizeof(dt)       
        return r
    end function
end macro

macro ¤SDT_STR(nm)
    function nm(sys hBuffer, offset, int ln) as string
        sys addr = (hBuffer + offset)
        string bb = space(ln+1)
        copy(strptr(bb), addr, ln)
        return bb
    end function
end macro

macro ¤SDT_WST(nm)
    function nm(sys hBuffer, of, int ln) as wstring
        sys addr = (hBuffer + of)
        wstring bb = news(ln) 
        copy(strptr(bb), addr, ln*2)
        return bb
    end function
end macro


TYPE ¤SYSNMHDR
    hwndFrom AS SYS
    idFrom   AS SYS
    Code     AS DWORD
END TYPE


' flags for internal file system.
% ·SYSFILE          = 1
% ·SYSTCP           = 2
% ·SYSUDP           = 4
% ·SYSCOMM          = 8
'% ·SYS??            = 16 ' RESERVED

% ·ASSIGN           = 32
% ·ASSIGNED         = 64
% ·HANDLE           = 128
'% ·?????            = 512 ' RESERVED

% ·BINARY           = 512
% ·RANDOM           = 1024
% ·INPUT            = 2048
% ·OUTPUT           = 4096
% ·APPEND           = 8192
% ·ANSI             = 16384
% ·WIDE             = 32768

% ·LOCK_WRITE       = 65536
% ·LOCK_READ        = 131072
% ·BASE_ZERO        = 262144
% ·BASE_ONE         = 524288


class ¤SYSF

    public int   CURHN
    public int   FHNDL[32767] ' File handle.
    public int   FFLAG[32767] ' Socket flags.
    public int   FRLEN[32767] ' Record length

    int LRNGN ' Last Random number generated.
    int LRNUB ' Last RND upper bound.
    int LRNLB ' Last RND lower bound.
   
    ' Default UDT member bounds...
    function m(int d1) as long {return d1}
    function m(int d1, d2) as long {return (d1 * d2)}
    function m(int d1, d2, d3) as long {return ((d1 * d2) + d3)}   
   
    ' Custom UDT member bounds...

                             
    ' UDT member readers.
    ¤SDT_VAL(byt, byte)   
    ¤SDT_VAL(wrd, word)
    ¤SDT_VAL(int, int)
    ¤SDT_VAL(lng, long)
    ¤SDT_VAL(sys, sys)
    ¤SDT_VAL(dwd, dword)
    ¤SDT_VAL(qud, quad)   
    ¤SDT_VAL(ext, extended)   
    ¤SDT_VAL(cur, extended)   
    ¤SDT_VAL(cux, extended)
    ¤SDT_VAL(sng, single)
    ¤SDT_VAL(dbl, double)
    ¤SDT_STR(asz) 
    ¤SDT_STR(chr)
    ¤SDT_WST(wsz)

    FUNCTION CONSTRUCTOR()
        this.CURHN = 1
    END FUNCTION       
           
END CLASS

new ¤SYSF EXE()
' END OF PLURIBASIC_PREPARE.BIN
' STARTS WSTRING.BIN
//assigns a truncated null terminated string.
MACRO ¤WSTR(v, c, l  b)   
    wstring b = c
    if len(b) > l then b = left(b, l)
    v = b       
END MACRO
' END OF WSTRING.BIN
' STARTS UDT_ASSIGNER.BIN
// copies binary data into a UDT
MACRO UDT_ASSIGNER(src, trg  buf, i)
   string buf
   int i = sizeof(src)
   buf = trg
   if i > len(buf) then i = len(buf)           
   copy @src, strptr(buf), i
END MACRO
' END OF UDT_ASSIGNER.BIN
' STARTS STRING.BIN
//Assigns a truncated null terminated string.
MACRO ¤STRN(v, c, l  b)   
    string b = c
    if len(b) > l then b = left(b, l)   
    v = b           
END MACRO


' END OF STRING.BIN
' STARTS STR$.BIN
' STARTS LTRIM$.BIN
// returns a trimed string
FUNCTION LTRIM(string src, long a = 0, string ch = " ") as string

    if len(src) = 0 then return ""
    if len(ch) = 0 then return ""
   
    byte srcchar at strptr(src)
    byte trichar at strptr(ch)
    long p1 = 1
    long index   
    long cha   
       
    if a then
        for index = 1 to len(src)       
            for cha = 1 to len(ch)       
                if srcchar[index] = trichar[cha] then
                    goto checknextchar                     
                end if
            next
            p1 = index
            exit for
            checknextchar:
        next
        return mid(src, p1)
    else       
        for index = 1 to len(src)
            for cha = 1 to len(ch)       
                if srcchar[index+cha-1] <> trichar[cha] then
                    goto nomorematches
                end if               
            next
            p1 += len(ch)             
        next
        nomorematches:       
        return mid(src, p1)
    end if
   
END FUNCTION
' END OF LTRIM$.BIN
' CONTINUES (1) STR$.BIN

FUNCTION ¤STR(double v, long d = 8) as string
    long d2 = d-1
    string ss = ""
    'int dp   ' DECIMAL PLACES
    'int trz  ' STRIP TRAILING ZEROS
    'int sn   ' SCIENTIFIC NOTATION BY DEFAULT
    'int sdp  ' INHIBIT ZERO BEFORE DECIMAL POINT
    'int sns  ' LEADING SPACE FOR NON NEGATIVE NUMBERS
    'int lps  ' LEAD PADDING SPACES

    'numberformat(8,0,0,0,1,0) 'default settings
   
    if v < 0 then
        ss = str(v, d2)
    else
        ss = str(v, d2)
        if instr(ss, ".") then
            ss = " " & LTRIM(ss, 0, "0")
        else
            ss = " " & ltrim(ss)
        end if
    end if
    'numberformat 'return to default   
    return ss
END FUNCTION

'FUNCTION ¤STR(quad v, long d = 16) as string
'    'PRINT " TWO " + V
'    long d2 = d-1
'    if v < 0 then
'        return str(v, d2)
'    else
'        string ss = str(v, d2)
'        return " " & ltrim(ss)
'    end if
'END FUNCTION


' END OF STR$.BIN
' STARTS PRINTR.BIN


SUB ¤INITCONSOLE()
    STATIC Allc    AS LONG
    IF Allc=0 THEN
        ¤AllocConsole()
        Allc = 1
    END IF   
END SUB

MACRO ¤STDOUT()
  LOCAL lWritten AS LONG     
  LOCAL hFile    AS DWORD
  LOCAL Btc      AS LONG
  LOCAL TTsnd    AS STRING

  ¤INITCONSOLE()   
 
  ¤Sleep(0)
 
  hFile = ¤GetStdHandle(-11)
  FOR Btc = 1 TO 50     
     IF ((Btc*32000)-31999) > len(s) THEN EXIT FOR
     TTsnd = MID$(s, ((Btc*32000)-31999), 32000)
     ¤WriteConsole(hFile, ByVal StrPtr(TTsnd), Len(TTsnd), lWritten, ByVal 0&)
  NEXT Btc
 
  ¤FlushFileBuffers(hFile)
END MACRO
               
SUB PRINTR(byval s AS WSTRING, byval b as string)               
    ¤STDOUT()
END SUB
   
SUB PRINTR(byval s AS STRING, byval b as string)
    ¤STDOUT()     
END SUB
' END OF PRINTR.BIN
' STARTS PLURIBASIC_INIT.BIN
' This code is executed before anything else, if you want to do something before nything else, see PLURIBASIC_PREPARE
' END OF PLURIBASIC_INIT.BIN
' STARTS OPEN.BIN

'h  = handle must be an open file handle.
'fn = filename.
'm  = input mode
'a  = access mode
'l  = lock mode
'ff = filenumber.
'ln = record lenght 
'bs = base address 
'ch = 1 = anso, 2 = WIDE

' Opens a file by its already opened handle.
SUB ¤OPENHANDLE(int h, int m, a, l, ff, ln, bs, ch, ¤SYSERR Err)

IF (ff < 1) OR (ff > 32767) THEN ¤SET_ERR(57) : EXIT FUNCTION
IF EXE.FFLAG[ff] <> ·ASSIGN THEN ¤SET_ERR(57) : EXIT FUNCTION

EXE.FFLAG[ff] = (EXE.FFLAG[ff] OR ·ASSIGNED OR ·SYSFILE OR ·HANDLE)
 

END SUB


'========================================================================================
' Opens a file by its filename.
SUB ¤OPENFILENM(string fn, int m, a, l, ff, ln, bs, ch, BYREF ¤SYSERR Err)

IF (ff < 1) OR (ff > 32767) THEN
    ¤SET_ERR(57)
    EXIT FUNCTION
END IF

IF EXE.FFLAG[ff] <> ·ASSIGN THEN
    ¤SET_ERR(57)
    EXIT FUNCTION
END IF

EXE.FFLAG[ff]    = 0

string fname     = fn + chr(0)
long   fAccess   = 0
long   fLock     = 0
long   fCreation = 0
long   fFlags    = 0

Select CASE m ' Mode
    CASE 2 ' output
        EXE.FFLAG[ff] = ·OUTPUT
        fCreation = 4 ' create
        fAccess   = 2
        if ((a and 1) = 1) THEN ' access READ??
            ¤SET_ERR(70)
            EXIT FUNCTION
        end if
       
    case 3 ' append
        EXE.FFLAG[ff] = ·APPEND
        fCreation = 4 ' create
        fAccess   = 2
        if ((a and 1) = 1) THEN ' access READ??
            ¤SET_ERR(70)
            EXIT FUNCTION
        end if
       
    case 4 ' binary
        EXE.FFLAG[ff] = ·BINARY       
        fCreation = 4 ' create
        if a = 0 then a = 3
               
    CASE ELSE
        fCreation = 3 ' open_existing
       
END SELECT

if ((a and 1) = 1) then fAccess = (fAccess or 0x80000000) ' access read
if ((a and 2) = 2) then fAccess = (fAccess or 0x40000000) ' access write

if (fLock <> 0) then
    if ((l and 1) <> 1) then fLock  = (fLock   or 0x80000000) ' lock read operations
    if ((l and 2) <> 2) then fLock  = (flock   or 0x40000000) ' lock write operations
end if       

IF ch = 1 THEN
    EXE.FHNDL[ff] = ¤CreateFileA(strptr(fName), fAccess, fLock, 0, fCreation, fFlags, 0)
    'PRINTR(¤STR(fAccess) + ¤STR(m) + ¤STR(fLock) + ¤STR(fCreation), chr(10, 13))
    IF EXE.FHNDL[ff] = -1 THEN
        ¤SET_ERR(70)
    ELSE
        '¤CloseHandle(EXE.FHNDL[ff])
        'EXE.FHNDL[ff] = ¤CreateFileA(strptr(fName), fAccess, fLock, 0, 3, fFlags, 0)
        EXE.FFLAG[ff] = (EXE.FFLAG[ff] OR ·ASSIGNED OR ·SYSFILE OR ·ANSI)   
    END IF   
ELSE
    EXE.FHNDL[ff] = ¤CreateFileW(StrPtr(fName), fAccess, fLock, 0, fCreation, fFlags, 0)
    IF EXE.FHNDL[ff] = -1 THEN
        ¤SET_ERR(70)
    ELSE
        '¤CloseHandle(EXE.FHNDL[ff])
        'EXE.FHNDL[ff] = ¤CreateFileA(strptr(fName), fAccess, fLock, 0, 3, fFlags, 0)   
        EXE.FFLAG[ff] = (EXE.FFLAG[ff] OR ·ASSIGNED OR ·SYSFILE OR ·WIDE)   
    END IF   
END IF

if m = 3 then
    ' set append position here.
    '¤SetFilePointer(EXE.FHNDL[ff], 0, byval 0, FILE_END)
end if


END SUB


' END OF OPEN.BIN
' STARTS LOF.BIN

'Returns the size of a file in bytes.
FUNCTION LOF(byval int fn) AS QUAD

END FUNCTION

' END OF LOF.BIN
' STARTS INP.BIN
'
FUNCTION INP( ) AS LONG

END FUNCTION

' END OF INP.BIN
' STARTS GET.BIN
' This file contains all the variations of use for the PUT statement.


' Writes a string to an open file.
SUB ¤ReadBinary(byval long fn, byval quad fp, byref string st, int sl, byref ¤SYSERR Err)
    IF ((EXE.FFLAG[fn] and ·BINARY) <> ·BINARY) AND ((EXE.FFLAG[fn] and ·RANDOM) <> ·RANDOM) THEN
        ¤SET_ERR(70)
        return
    END IF
    int w = 0
    IF (sl>0) THEN
        IF fp > -1 then       
            ¤SetFilePointerEx(EXE.FHNDL[fn], byval (fp-1), byval 0, byval 0)                     
        end if
        ¤ReadFile(EXE.FHNDL[fn], strptr(st), sl, w, null)
        IF w = 0 THEN
            ¤SET_ERR(70)       
        END IF
    END IF
END SUB

MACRO ¤GETUDT(vt, fn, fp, var, tv, ts   c, t)
    string tv = news(ts)
    ¤ReadBinary(fn, fp, tv, ts, Err)
END MACRO

MACRO ¤GETSTR(vt, fn, fp, var, tv, sl      ln, gg)
    int ln = sl
    IF sl < 1 THEN
        ln = len(var)
    END IF
    string tv = space(20)
    ¤ReadBinary(fn, fp, tv, ln, Err)
END MACRO

MACRO ¤GETVAR(vt, fn, fp, var, tv, ln   tt)
    string tt = news(ln)
    ¤ReadBinary(fn, fp, tt, ln, Err)
    vt tv
    copy @tv, tt, ln   
END MACRO
' END OF GET.BIN
' STARTS FREEFILE.BIN
' returns the next free handle.
FUNCTION FREEFILE() AS LONG

    int i = EXE.CURHN
   
    for i = i to 32767
        if EXE.FFLAG[i] = 0 then
            EXE.CURHN = i
            EXE.FFLAG[i] = ·ASSIGN
            EXE.FHNDL[i] = 0           
            EXE.FRLEN[i] = 0           
            return i
        end if
    next
   
    for i = 1 to EXE.CURHN
        if EXE.FFLAG[i] = 0 then
            EXE.CURHN = i
            EXE.FFLAG[i] = ·ASSIGN
            EXE.FHNDL[i] = 0           
            EXE.FRLEN[i] = 0           
            return i
        end if
    next
   
    return 0     

END FUNCTION
' END OF FREEFILE.BIN
' STARTS CLOSE.BIN
' Closes an opened file.
FUNCTION CLOSE(int ff, BYREF ¤SYSERR Err) AS LONG

IF (ff < 1) OR (ff > 32767) THEN
    ¤SET_ERR(57)
    EXIT FUNCTION
END IF

IF EXE.FFLAG[ff] = ·ASSIGN THEN
    ¤SET_ERR(57)
    EXIT FUNCTION
END IF

IF ((EXE.FFLAG[ff] and ·HANDLE) <> ·HANDLE) THEN
    if (¤CloseHandle(EXE.FHNDL[ff]) = 0) then
        ¤SET_ERR(70)
        EXIT FUNCTION   
    end if
END IF

EXE.FFLAG[ff] = 0
EXE.FHNDL[ff] = 0           
EXE.FRLEN[ff] = 0

END FUNCTION

' END OF CLOSE.BIN
' STARTS CALLBACKDATA.BIN
' END OF CALLBACKDATA.BIN

TYPE ABC
    CHAR astr[20]
    WCHAR wstr[20]
    CHAR ast2[20]
END TYPE

' SYSTEM DECLARES FOR ARRAYS


DECLARE FUNCTION PBMAIN() AS LONG


' Initializes various things in the script.
FUNCTION PluriBASIC_Initialize() AS LONG

END FUNCTION

FUNCTION PBMAIN() AS INT
   INT ¤RETVAL = 0
   ¤SYSERR Err
   DWORD ff
   ABC a
   CHAR b[20]
   INT c
   WSTRING inputstring
   ff = FREEFILE()
   ¤OPENFILENM("C:\Users\Diamante\Documents\Test.txt", 4, 0, 0, ff, 128, 1, 1, Err)
   IF Err.err THEN
      PRINTR("ERROR" + ¤STR(Err.err, byval 0) & " OPENING THE FILE.", chr(13, 10))
   ELSE
      PRINTR("SUCCES OPENING THE FILE.", chr(13, 10))
   END IF
   ¤GETUDT(abc, ff, 1, a, ¤TMPV1, 80)
   ¤UDTCOPY(80, @a, ¤TMPV1)
   ¤STRN(b, SPACE(LOF(ff)), 20)
   ¤GETSTR(bstring, ff, -1, b, ¤TMPV2, 20)
   ¤STRN(b, ¤TMPV2, 20)
   CLOSE(ff, Err)
   PRINTR("-----------" & chr(13,10), chr(13, 10))
   PRINTR("Done:" & chr(13,10), chr(13, 10))
   PRINTR(EXE.chr(@a, 0, 20) & chr(13,10), chr(13, 10))
   PRINTR(EXE.chr(@a, 60, 20) & chr(13,10), chr(13, 10))
   PRINTR(EXE.wsz(@a, 20, 20) & chr(13,10), chr(13, 10))
   PRINTR(b & chr(13,10), chr(13, 10))
   PRINTR(¤STR(c, byval 0) & chr(13,10), chr(13, 10))
   RETURN ¤RETVAL
END FUNCTION

PBMAIN() ' invoke entry point



Charles Pegge

  • Guest
Re: UDT and String overlapping...
« Reply #3 on: May 05, 2019, 12:58:19 PM »
Hi Brian,

Just a brief observation for now:

Each member in this structure  can hold a  max 19 character string + null terminator.

Overflows are possible with these fixed length strings.

Code: [Select]
TYPE ABC
    CHAR astr[20]
    WCHAR wstr[20]
    CHAR ast2[20]
END TYPE

Brian Alvarez

  • Guest
Re: UDT and String overlapping...
« Reply #4 on: May 05, 2019, 03:44:37 PM »
Hello Charles.

 I dont see the need for UDT members to store a null character at the end of strings when the length of the string is exactly the number of characters specified for the element other than when using it as a string parameter via its pointer. But that is up to you.

 Since i am not using Oxygen's internal mechanism to read UDT members that doesnt affect the code im generating (i made my own address and offset manager because of the udt dimensions). That said, the issue is not with UDT's. it is with stand-alone fixed-length strings writing in the space of (what should be) a completely unrelated udt (the memory space should not conflict). But i understand it. For now i will be fixing it by appending a couple extra characters to the fixed length strings. Hopefully that will fix it. I mean... i will do that if you have not yet fixed it in newer versions of Oxygen (i have yet to test).

 However, i suspect it could more likely have something to do with something not being freed correctly on Oxygen's macros. Hopefully im wrong, because that would affect a whole other lof of my code.

Brian Alvarez

  • Guest
Re: UDT and String overlapping...
« Reply #5 on: May 05, 2019, 03:49:53 PM »
I just tested the newest version of Oxygen, unfortunately it complains about something else that is not very clear:

Code: [Select]
; ASM ERR: _56!!  Unidentified instruction: _56
 ; AFTER:    .'
 ; LINE:    83

Line 83:


Brian Alvarez

  • Guest
Re: UDT and String overlapping...
« Reply #6 on: May 05, 2019, 03:57:46 PM »
Went back to the version i was using. Adding 2 extra bytes fixes everything. Confirming it is an overflow error by Oxygen's internals. :(

Charles Pegge

  • Guest
Re: UDT and String overlapping...
« Reply #7 on: May 06, 2019, 10:57:23 PM »
Hi Brian,

My preference is to stay with null-terminated chars without boundary checks, but I'll look into it.