MemFile System
#1
Can you open files to the drive and PRINT and LINE INPUT data to them?

If so, then you can now use _MEM, with these little routines which let you work with mem blocks the same way you'd read and write to the disk with PRINT and LINE INPUT!

Code: (Select All)
Type Mem_File_Type
    inUse As Integer
    EOF_Marker As _Offset
    Current_Pos As _Offset
    Content As _MEM
End Type

Dim Shared MemFile(1 To 100) As Mem_File_Type
'BI HEADER INFO BEFORE THIS








'first, let's showcase how to print and input some information to and from memory
handle = MemFileOpen '                            This is a combination FREEFILE + OPEN statement
MemPrint handle, "Hello World", 1 '              PRINT #filehandle, whatever$ + CRLF
MemPrint handle, "My name is Steve", 1 '          PRINT #filehandle, whatever$ + CRLF
For i = 1 To 10
    MemPrint handle, Str$(i) + ") Record #" + _Trim$(Str$(i)), 1
Next
MemSeek handle, 0 '                              SEEK #filehandle, byte

Do Until MemEOF(handle) '                        DO UNTIL EOF(filehandle)
    MemLineInput handle, temp$ '                    LINE INPUT #filehandle, temp$
    Print temp$ '                                    PRINT temp$
Loop '                                            LOOP

'I hope the above with the comments help to highlight how exactly similar the two syntaxes are here.
'With these mem routines, we're basically just using mem *exactly* as we'd do basic file access with PRINT and LINE INPUT



'And here I'll showcase how to save and load your memblock to disk -- both in compressed and uncompressed form

MemFileSave handle, "temp.txt", 0 '                  0 says save it in uncompressed format.  You can read the data in any old text editor!
MemFileSave handle, "temp_compressed.txt", -1 '      Anything else says to compress the data before saving it.  Not readable untl uncompressed.
Print
Print "Mem saved to disk in both compressed and uncompressed form."
Open "temp.txt" For Input As #1: LOF1 = LOF(1): Close
Open "temp_compressed.txt" For Input As #1: LOF2 = LOF(1): Close
Print "unCompressed file is "; LOF1; "bytes in size."
Print "Compressed file is "; LOF2; "bytes in size."
MemFileClose handle '                            CLOSE filehandle



_KeyClear
Print "Now to load back the file with the uncompressed data.  Press <ANY KEY>"
Sleep
newhandle = MemFileLoad("temp.txt", 0) 'load the uncompressed data file
Do Until MemEOF(newhandle) '                        DO UNTIL EOF(filehandle)
    MemLineInput newhandle, temp$ '                    LINE INPUT #filehandle, temp$
    Print temp$ '                                    PRINT temp$
Loop '                                            LOOP
MemFileClose newhandle

_KeyClear
Print "Now to load back the file with the compressed data.  Press <ANY KEY>"
Sleep
newhandle = MemFileLoad("temp_compressed.txt", -1) 'load the compressed data file
Do Until MemEOF(newhandle) '                        DO UNTIL EOF(filehandle)
    MemLineInput newhandle, temp$ '                    LINE INPUT #filehandle, temp$
    Print temp$ '                                    PRINT temp$
Loop '                                            LOOP
MemFileClose newhandle

Print
Print "And remember, the difference of the sizes of the files on disk were:"
Print "  compressed:"; LOF2
Print "uncompressed:"; LOF1

Print
Print "Press <ANY KEY> to compare speeds in loading an large file into an array in memory."
_KeyClear
Sleep

'And let's showcase a bit more of how this works, why don't we.
Dim As String wordlist(466544), wordlist2(466544), wordlist3(466544) 'arrays to hold the data

'MEM FILE INPUT
handle = MemFileLoad("466544 Word List.txt", 0) 'load a file directly into memory, and it's not compressed
t## = Timer '                                                        timer to see how long we take loading this data
Do Until MemEOF(handle) '                        Hopefully these lines will be intuitive enough.
    count = count + 1 '                          Especially when compared to the notes above
    MemLineInput handle, wordlist(count) '        and the preceeding lines after
Loop
Print count; Using " words loaded into memory from file, in ##.#### seconds."; Timer - t##
MemFileClose handle


'OPEN FILE FOR INPUT
Open "466544 Word List.txt" For Input As #1
t## = Timer
Do Until EOF(1)
    count2 = count2 + 1
    Line Input #1, wordlist2(count2)
Loop
Print count2; Using " words loaded from file OPEN FOR INPUT, in ##.#### seconds."; Timer - t##
Close handle

'OPEN FILE FOR BINARY
Open "466544 Word List.txt" For Binary As #1
t## = Timer
Do Until EOF(1)
    count3 = count3 + 1
    Line Input #1, wordlist3(count3)
Loop
Print count3; Using " words loaded from file OPEN FOR BINARY, in ##.#### seconds."; Timer - t##
Close handle

'and let's compare contents to be safe
For i = 1 To count
    If wordlist(i) <> wordlist2(i) Then Print "Wordlist does not match Wordlist2": failed = -1
    If wordlist(i) <> wordlist3(i) Then Print "Wordlist does not match Wordlist3": failed = -1
Next

If failed Then
    Print "Lists do not match"
Else
    Print "Lists match each other perfectly"
End If





'BM FOOTER AFTER THIS
Sub MemFileDump (memfile, file$, compressed) 'just one quick call to save to disk and free the memory all at once.
    MemFileSave memfile, file$, compressed
    MemFileClose memfile
End Sub

Sub MemFileSave (memfile, file$, compressed)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    temphandle = FreeFile
    Dim As _Offset length

    length = MemFile(memfile).EOF_Marker + 1
    temp$ = Space$(length)
    $Checking:Off
    _MemGet MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, temp$
    $Checking:On
    If compressed Then temp1$ = _Deflate$(temp$) Else temp1$ = temp$
    Open file$ For Output As temphandle: Close temphandle 'erase any existing file with the same name
    Open file$ For Binary As temphandle
    Put #temphandle, 1, temp1$
    Close
End Sub

Function MemFileLoad (file$, compressed)
    'Error codes for MemFileLoad
    '1: No mem files available.  (All 100 are in use!  Free some to use more!)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then MemFileLoad = 0: Exit Function 'can't open any more memfiles!
    If _FileExists(file$) = 0 Then Error 53: Exit Function 'file not found


    MemFileLoad = i
    temphandle = FreeFile
    Open file$ For Binary As #temphandle
    temp$ = Space$(LOF(temphandle))
    Get temphandle, 1, temp$
    Close temphandle
    If compressed Then temp$ = _Inflate$(temp$)
    length = Len(temp$)
    MemFile(i).Content = _MemNew(length)
    $Checking:Off
    _MemPut MemFile(i).Content, MemFile(i).Content.OFFSET, temp$
    $Checking:On
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = length - 1 'the end of the file is the length of the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
End Function


Sub MemFileClose (memfile)
    If memfile < 1 Or memfile > 100 Then Error 5: Exit Sub 'ILLEGAL FUNCTION CALL
    MemFile(memfile).inUse = 0 'no longer in sue
    MemFile(memfile).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(memfile).Current_Pos = 0 'and we're at the start of our nothing in the file
    _MemFree MemFile(memfile).Content 'free the memory we were using
End Sub


Function MemFileOpen
    'Error codes for MemFileOpen
    '1: No mem files available.  (All 100 are in use!  Free some to use more!)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then MemFileOpen = 0: Exit Function 'can't open any more memfiles!
    MemFileOpen = i
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
    MemFile(i).Content = _MemNew(1000000) '1mb memfile by default
    $Checking:Off
    _MemFill MemFile(i).Content, MemFile(i).Content.OFFSET, MemFile(i).Content.SIZE, 0 As _UNSIGNED _BYTE
    'make certain to blank the file when opening it for the first time so we don't have unwanted characters in it.
    $Checking:On
End Function

Function MemEOF (memfile)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Function 'File Not Found Error message
    If MemFile(memfile).Current_Pos >= MemFile(memfile).EOF_Marker Then MemEOF = -1
End Function


Sub MemSeek (memfile, position As _Offset)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    If position < 0 Then Error 5: Exit Sub 'Invalid Function Call
    If position > MemFile(memfile).EOF_Marker Then Error 5: Exit Sub 'Invalid Function Call
    MemFile(memfile).Current_Pos = position
End Sub

Sub MemLineInput (memfile, what$)
    'only valid line endings here are CHR$(10), chr$(13), and chr$(13) + chr$(10)

    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim As _Offset CP, EP, Size, L
    Dim tempM As _MEM, a1 As _Unsigned _Byte
    tempM = MemFile(memfile).Content 'it's just much shorter to type!

    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    If CP >= EP Then Error 62: Exit Sub 'INPUT PAST END OF FILE error
    Size = tempM.SIZE
    $Checking:Off
    Do
        a$ = _MemGet(tempM, tempM.OFFSET + CP, String * 1)
        Select Case a$
            Case Chr$(13)
                _MemGet tempM, tempM.OFFSET + CP + 1, a1
                If a1 = 10 Then CP = CP + 1 'move the Current Pointer past the 2nd character in a windows CRLF ending
                finished = -1
            Case Chr$(10)
                finished = -1
            Case Else
                temp$ = temp$ + a$
        End Select
        CP = CP + 1
        If CP >= EP Then finished = -1
    Loop Until finished
    $Checking:On
    MemFile(memfile).Current_Pos = CP
    what$ = temp$
End Sub



Sub MemPrint (memfile, what$, EOL_Type As Integer)
    'memfile is the memfile handle to print to
    'what$ is what we want to print
    'EOL_Type is the type of line ending we want after this print statement
    '1: This is a CHR$(10) line ending                  (Linux style line ending)
    '2: This is a CHR$(13) line ending                  (Old Mac style line ending)
    '3: This is a CHR$(13) + CHR$(10) line ending      (Old Windows style line ending)
    '4: This is a COMMA line ending.  Use this if writing continous CSV fields.
    '      (Think PRINT #1, stuff$, <-- see the comma there at the end of the print statement??)


    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim CRLF As String
    Dim As _Offset CP, EP, Size, L

    Select Case EOL_Type
        Case 1: CRLF = Chr$(10)
        Case 2: CRLF = Chr$(13)
        Case 3: CRLF = Chr$(13) + Chr$(10)
        Case 4: CRLF = ","
    End Select
    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    Size = MemFile(memfile).Content.SIZE
    L = Len(what$) + Len(CRLF)
    If CP + L > Size Then 'we're writing beyond the bounds of our reserved memory!
        Dim tempM As _MEM
        recheck:
        If Size <= 100000000 Then 'resize our memblock (to the limit) to save our data
            tempM = _MemNew(Size * 10)
            _MemCopy MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, Size To tempM, tempM.OFFSET
            _MemFree MemFile(memfile).Content
            MemFile(memfile).Content = tempM
            Size = Size * 10
            GoTo recheck 'just to make certain that our reserved memory is now large enough to hold our data
        Else
            Error 61 'DISK FULL ERROR MESSAGE
            Exit Sub 'I'm coding a hard size limit of 1GB for each memfile opened!
            '        Anything larger than that, and I'm tossing a Disk Full Error
        End If
    End If
    _MemPut MemFile(memfile).Content, MemFile(memfile).Content.OFFSET + CP, what$ + CRLF
    MemFile(memfile).Current_Pos = CP + L
    If CP + L > EP Then MemFile(memfile).EOF_Marker = CP + L
End Sub
 
Grab the necessary dictionary file from here:  https://staging.qb64phoenix.com/attachment.php?aid=760
(I didn't see any reason why the same file needed to be uploaded and attached to multiple posts when it was already here once. Wink )
Reply
#2
Very neat, Steve! I'll have to give this a try sometime!
Ask me about Windows API and maybe some Linux stuff
Reply
#3
(08-22-2022, 03:16 PM)Spriggsy Wrote: Very neat, Steve! I'll have to give this a try sometime!

Best part about these @Spriggsy is that they're about twice as fast as trying to OPEN file$ FOR BINARY and using LINE INPUT to read the data back into an array.  They definitely make a heck of a speed improvement with file access times for us -- at least from my testing, they do!  Wink
Reply
#4
I wonder how it compares to using GET or PUT in regards to getting or putting the whole data. Most of the time, rather than doing a LINE INPUT, I just do a GET and then split the filled string into an array to work with.
Ask me about Windows API and maybe some Linux stuff
Reply
#5
(08-22-2022, 03:29 PM)Spriggsy Wrote: I wonder how it compares to using GET or PUT in regards to getting or putting the whole data. Most of the time, rather than doing a LINE INPUT, I just do a GET and then split the filled string into an array to work with.

That's basically what we're doing here.  We load the whole file into a mem block (the old method which you're talking of would load the whole file into a string).  Then it parses that memblock looking for CRLF characters to split it apart into the lines to return with MemLineInput.  (Basically the same as the old method where we search with INSTR for the CRLF characters.)

I haven't ran any timed tests to compare yet, but I imagine the times wouldn't be extremely off.  This might be a little faster by checking for unsigned bytes rather than doing string compares like INSTR does, but I don't imagine it'd be a ton faster.  I'll give it a timed test soon and report back to you with exact figures.  Smile
Reply
#6
Just ran some timed tests and I'm a little surprised by the results!




[Image: image.png]

MemLineInput times is about 1.5 seconds.
OPEN FOR BINARY and then LINE INPUT is about 2.8 seconds.
OPEN FOR BINARY and then manually PARSE the data is about 0.05 seconds.

It's still a lot faster to load and parse than any other method, but I suppose it kind of makes sense after you think about it.  By writing a generic routine, we have to check for multiple things (are the line endings CHR$(10) or CHR$(13) or CHR$(13) + CHR$(10)??  We need to check and account for all of those, along with some basic error checks.)  Here, when I parse these, I'm already using 13+10 as the file endings and moving my pointer two spots for each CRLF.

I figured the times would be closer than that, but LOAD then PARSE is still the winner in terms of absolute time it takes to get something done.  Still though, I'm pretty happy with the results where we load and read the file from memory with LINE INPUT about twice as fast as we load and read from disk in BINARY mode.  We hold true to the syntax that a beginner quickly learns and uses, with a nice boost in speed and performance for them -- and we save our SSDs from repeated read/write calls to them.

Maybe I can tweak things here and close that gap for us with the speed somewhat.  Instead of checking constantly for various CRLF endings, I could read for the first one and then assign it as the default from there on out, and skip a whole bunch of the IF type decision checks for us. 

I'll dig into that later, after I find something around here to eat decent for lunch.  Wink


Edit:  Included code in case anyone wants to test on their own:

Code: (Select All)
Type Mem_File_Type
    inUse As Integer
    EOF_Marker As _Offset
    Current_Pos As _Offset
    Content As _MEM
End Type

Dim Shared MemFile(1 To 100) As Mem_File_Type
'BI HEADER INFO BEFORE THIS

Screen _NewImage(800, 600, 32)


Dim As String wordlist(466544), wordlist2(466544), wordlist3(466544), wordlist4(466545) 'arrays to hold the data

'MEM FILE INPUT
handle = MemFileLoad("466544 Word List.txt", 0) 'load a file directly into memory, and it's not compressed
t## = Timer '                                                        timer to see how long we take loading this data
Do Until MemEOF(handle) '                        Hopefully these lines will be intuitive enough.
    count = count + 1 '                          Especially when compared to the notes above
    MemLineInput handle, wordlist(count) '        and the preceeding lines after
Loop
Print count; Using " words loaded into memory from file, in ##.#### seconds."; Timer - t##
MemFileClose handle

'OPEN FILE FOR BINARY
Open "466544 Word List.txt" For Binary As #1
t## = Timer
Do Until EOF(1)
    count3 = count3 + 1
    Line Input #1, wordlist3(count3)
Loop
Print count3; Using " words loaded from file OPEN FOR BINARY with LINE INPUT, in ##.#### seconds."; Timer - t##
Close 1

'OPEN FILE FOR BINARY AND PARSE
Open "466544 Word List.txt" For Binary As #1
temp$ = Space$(LOF(1))
Get #1, 1, temp$
Close 1
t## = Timer
p = 1: CRLF$ = Chr$(13) + Chr$(10)
Do
    count4 = count4 + 1
    l = InStr(p, temp$, CRLF$)
    wordlist4(count4) = Mid$(temp$, p, l - p)
    p = l + 2 'move the pointer by the length and 2 more for windows CRLF data
Loop Until l = 0
Print count4; Using " words loaded from file OPEN FOR BINARY then PARSED, in ##.#### seconds."; Timer - t##




'and let's compare contents to be safe
For i = 1 To count
    If wordlist(i) <> wordlist4(i) Then Print "Wordlist does not match Wordlist4": failed = -1
    If wordlist(i) <> wordlist3(i) Then Print "Wordlist does not match Wordlist3": failed = -1
Next

If failed Then
    Print "Lists do not match"
Else
    Print "Lists match each other perfectly"
End If





'BM FOOTER AFTER THIS
Sub MemFileDump (memfile, file$, compressed) 'just one quick call to save to disk and free the memory all at once.
    MemFileSave memfile, file$, compressed
    MemFileClose memfile
End Sub

Sub MemFileSave (memfile, file$, compressed)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    temphandle = FreeFile
    Dim As _Offset length

    length = MemFile(memfile).EOF_Marker + 1
    temp$ = Space$(length)
    $Checking:Off
    _MemGet MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, temp$
    $Checking:On
    If compressed Then temp1$ = _Deflate$(temp$) Else temp1$ = temp$
    Open file$ For Output As temphandle: Close temphandle 'erase any existing file with the same name
    Open file$ For Binary As temphandle
    Put #temphandle, 1, temp1$
    Close
End Sub

Function MemFileLoad (file$, compressed)
    'Error codes for MemFileLoad
    '1: No mem files available.  (All 100 are in use!  Free some to use more!)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then MemFileLoad = 0: Exit Function 'can't open any more memfiles!
    If _FileExists(file$) = 0 Then Error 53: Exit Function 'file not found


    MemFileLoad = i
    temphandle = FreeFile
    Open file$ For Binary As #temphandle
    temp$ = Space$(LOF(temphandle))
    Get temphandle, 1, temp$
    Close temphandle
    If compressed Then temp$ = _Inflate$(temp$)
    length = Len(temp$)
    MemFile(i).Content = _MemNew(length)
    $Checking:Off
    _MemPut MemFile(i).Content, MemFile(i).Content.OFFSET, temp$
    $Checking:On
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = length - 1 'the end of the file is the length of the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
End Function


Sub MemFileClose (memfile)
    If memfile < 1 Or memfile > 100 Then Error 5: Exit Sub 'ILLEGAL FUNCTION CALL
    MemFile(memfile).inUse = 0 'no longer in sue
    MemFile(memfile).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(memfile).Current_Pos = 0 'and we're at the start of our nothing in the file
    _MemFree MemFile(memfile).Content 'free the memory we were using
End Sub


Function MemFileOpen
    'Error codes for MemFileOpen
    '1: No mem files available.  (All 100 are in use!  Free some to use more!)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then MemFileOpen = 0: Exit Function 'can't open any more memfiles!
    MemFileOpen = i
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
    MemFile(i).Content = _MemNew(1000000) '1mb memfile by default
    $Checking:Off
    _MemFill MemFile(i).Content, MemFile(i).Content.OFFSET, MemFile(i).Content.SIZE, 0 As _UNSIGNED _BYTE
    'make certain to blank the file when opening it for the first time so we don't have unwanted characters in it.
    $Checking:On
End Function

Function MemEOF (memfile)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Function 'File Not Found Error message
    If MemFile(memfile).Current_Pos >= MemFile(memfile).EOF_Marker Then MemEOF = -1
End Function


Sub MemSeek (memfile, position As _Offset)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    If position < 0 Then Error 5: Exit Sub 'Invalid Function Call
    If position > MemFile(memfile).EOF_Marker Then Error 5: Exit Sub 'Invalid Function Call
    MemFile(memfile).Current_Pos = position
End Sub

Sub MemLineInput (memfile, what$)
    'only valid line endings here are CHR$(10), chr$(13), and chr$(13) + chr$(10)

    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim As _Offset CP, EP, Size, L
    Dim tempM As _MEM, a1 As _Unsigned _Byte
    tempM = MemFile(memfile).Content 'it's just much shorter to type!

    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    If CP >= EP Then Error 62: Exit Sub 'INPUT PAST END OF FILE error
    Size = tempM.SIZE
    $Checking:Off
    Do
        a$ = _MemGet(tempM, tempM.OFFSET + CP, String * 1)
        Select Case a$
            Case Chr$(13)
                _MemGet tempM, tempM.OFFSET + CP + 1, a1
                If a1 = 10 Then CP = CP + 1 'move the Current Pointer past the 2nd character in a windows CRLF ending
                finished = -1
            Case Chr$(10)
                finished = -1
            Case Else
                temp$ = temp$ + a$
        End Select
        CP = CP + 1
        If CP >= EP Then finished = -1
    Loop Until finished
    $Checking:On
    MemFile(memfile).Current_Pos = CP
    what$ = temp$
End Sub



Sub MemPrint (memfile, what$, EOL_Type As Integer)
    'memfile is the memfile handle to print to
    'what$ is what we want to print
    'EOL_Type is the type of line ending we want after this print statement
    '1: This is a CHR$(10) line ending                  (Linux style line ending)
    '2: This is a CHR$(13) line ending                  (Old Mac style line ending)
    '3: This is a CHR$(13) + CHR$(10) line ending      (Old Windows style line ending)
    '4: This is a COMMA line ending.  Use this if writing continous CSV fields.
    '      (Think PRINT #1, stuff$, <-- see the comma there at the end of the print statement??)


    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim CRLF As String
    Dim As _Offset CP, EP, Size, L

    Select Case EOL_Type
        Case 1: CRLF = Chr$(10)
        Case 2: CRLF = Chr$(13)
        Case 3: CRLF = Chr$(13) + Chr$(10)
        Case 4: CRLF = ","
    End Select
    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    Size = MemFile(memfile).Content.SIZE
    L = Len(what$) + Len(CRLF)
    If CP + L > Size Then 'we're writing beyond the bounds of our reserved memory!
        Dim tempM As _MEM
        recheck:
        If Size <= 100000000 Then 'resize our memblock (to the limit) to save our data
            tempM = _MemNew(Size * 10)
            _MemCopy MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, Size To tempM, tempM.OFFSET
            _MemFree MemFile(memfile).Content
            MemFile(memfile).Content = tempM
            Size = Size * 10
            GoTo recheck 'just to make certain that our reserved memory is now large enough to hold our data
        Else
            Error 61 'DISK FULL ERROR MESSAGE
            Exit Sub 'I'm coding a hard size limit of 1GB for each memfile opened!
            '        Anything larger than that, and I'm tossing a Disk Full Error
        End If
    End If
    _MemPut MemFile(memfile).Content, MemFile(memfile).Content.OFFSET + CP, what$ + CRLF
    MemFile(memfile).Current_Pos = CP + L
    If CP + L > EP Then MemFile(memfile).EOF_Marker = CP + L
End Sub
Reply
#7
An update and an overhaul for the MemFile system here to make it both easier to use and more verstile.

Code: (Select All)
Type Mem_File_Type
    inUse As Integer
    CRLF As String
    EOF_Marker As _Offset
    Current_Pos As _Offset
    Content As _MEM
End Type

Dim Shared MemFile(1 To 100) As Mem_File_Type
'BI HEADER INFO BEFORE THIS

Screen _NewImage(800, 600, 32)


Dim As String wordlist(466549), wordlist3(466549) 'arrays to hold the data
$Color:32
Color Red, Yellow 'color so we can make certain that we're dealing with spaces properly
Open "test.txt" For Output As #1
Print #1, Chr$(34) + "New York, New York" + Chr$(34) + ",      New York      , New York" 'distinguish between in and out of quotes
Print #1, "Hello World, My name is " + Chr$(34) + "Steve The Awesome" + Chr$(34) + "!"
Close
Print "********** (testing INPUT)"
Open "test.txt" For Input As #1
Do Until EOF(1)
    Input #1, test$
    Print test$
Loop
Close
Print "********** (testing MemInput)"



'MEM FILE INPUT
handle = MemFileLoad("test.txt", 0) 'load a file directly into memory, and it's not compressed
t## = Timer '                                                        timer to see how long we take loading this data
Do Until MemEOF(handle) '                        Hopefully these lines will be intuitive enough.
    count = count + 1 '                          Especially when compared to the notes above
    MemInput handle, wordlist(count) '        and the preceeding lines after
    Print wordlist(count)
Loop
Print "**********"
MemFileClose handle

Color White, Black
count = 0
Print
Print "Now testing speed difference in loading a large file"

handle = MemFileLoad("466544 Word List.txt", 0) 'load a file directly into memory, and it's not compressed
t## = Timer '                                                        timer to see how long we take loading this data
Do Until MemEOF(handle) '                        Hopefully these lines will be intuitive enough.
    count = count + 1 '                          Especially when compared to the notes above
    MemInput handle, wordlist(count) '        and the preceeding lines after
Loop
Print count; Using " words loaded into memory from file with MemInput, in ##.#### seconds."; Timer - t##
MemFileClose handle
Print
Print "Now, go grab a soda or use the bathroom.  We're going to load the same list as a file FOR INPUT."
Print "Expect this to take several minutes -- we're not locking up your PC!  We're just sloooow!!"




Open "466544 Word List.txt" For Input As #1
t## = Timer
Do Until EOF(1)
    count3 = count3 + 1
    Input #1, wordlist3(count3)
Loop
Print count3; Using " words loaded from file OPEN FOR INPUT with INPUT, in ##.#### seconds."; Timer - t##
Close 1

'and let's compare contents to be safe
For i = 1 To count
    If wordlist(i) <> wordlist3(i) Then failed = -1: Print i, wordlist(i), wordlist3(i): Sleep
Next

If failed Then Print "Lists don't match" Else Print "Lists match perfectly"




'BM FOOTER AFTER THIS
Sub MemFileDump (memfile, file$, compressed) 'just one quick call to save to disk and free the memory all at once.
    MemFileSave memfile, file$, compressed
    MemFileClose memfile
End Sub

Sub MemFileSave (memfile, file$, compressed)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    temphandle = FreeFile
    Dim As _Offset length

    length = MemFile(memfile).EOF_Marker + 1
    temp$ = Space$(length)
    $Checking:Off
    _MemGet MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, temp$
    $Checking:On
    If compressed Then temp1$ = _Deflate$(temp$) Else temp1$ = temp$
    Open file$ For Output As temphandle: Close temphandle 'erase any existing file with the same name
    Open file$ For Binary As temphandle
    Put #temphandle, 1, temp1$
    Close
End Sub

Function MemFileLoad% (file$, compressed)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then Error 5: Exit Function 'can't open any more memfiles!
    If _FileExists(file$) = 0 Then Error 53: Exit Function 'file not found

    MemFileLoad% = i
    temphandle = FreeFile
    Open file$ For Binary As #temphandle
    temp$ = Space$(LOF(temphandle))
    Get temphandle, 1, temp$
    Close temphandle
    If compressed Then temp$ = _Inflate$(temp$)
    length = Len(temp$)
    MemFile(i).Content = _MemNew(length)
    $Checking:Off
    _MemPut MemFile(i).Content, MemFile(i).Content.OFFSET, temp$
    $Checking:On

    'we want to auto-detect our CRLF endings
    'as we have the file in temp$ at the moment, we'll just search for it via instr
    If InStr(temp$, Chr$(13) + Chr$(10)) Then
        MemFile(i).CRLF = Chr$(13) + Chr$(10)
    ElseIf InStr(temp$, Chr$(10)) Then
        MemFile(i).CRLF = Chr$(10)
    ElseIf InStr(temp$, Chr$(13)) Then
        MemFile(i).CRLF = Chr$(13)
    Else
        Error 5: Exit Function
    End If
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = length - 1 'the end of the file is the length of the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
End Function


Sub MemFileClose (memfile As Integer)
    If memfile < 1 Or memfile > 100 Then Error 5: Exit Sub 'ILLEGAL FUNCTION CALL
    MemFile(memfile).inUse = 0 'no longer in sue
    MemFile(memfile).CRLF = "" 'we have no file ending as we no longer have a file
    MemFile(memfile).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(memfile).Current_Pos = 0 'and we're at the start of our nothing in the file
    _MemFree MemFile(memfile).Content 'free the memory we were using
End Sub


Sub MemFileCRLF (memfile As Integer, CRLF As Integer)
    If memfile < 1 Or memfile > 100 Then Error 5: Exit Sub 'ILLEGAL FUNCTION CALL
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    Select Case CRLF
        Case 0: MemFile(i).CRLF = "" 'no file ending. Use this when you want text to continue on one line.  (Think PRINT with semicolon.)
        Case 1: MemFile(i).CRLF = Chr$(10) 'we default to CHR$(10) line endings
        Case 2: MemFile(i).CRLF = Chr$(13)
        Case 3: MemFile(i).CRLF = Chr$(13) + Chr$(10)
        Case Else: Error 5: Exit Sub
    End Select
End Sub


Function MemFileOpen%
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then Error 5: Exit Function 'can't open any more memfiles!
    If CRLF < 0 Or CRLF > 3 Then Error 5: Exit Function
    MemFileOpen% = i
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(i).CRLF = Chr$(10) 'we default to CHR$(10) line endings
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
    MemFile(i).Content = _MemNew(1000000) '1mb memfile by default
    $Checking:Off
    _MemFill MemFile(i).Content, MemFile(i).Content.OFFSET, MemFile(i).Content.SIZE, 0 As _UNSIGNED _BYTE
    'make certain to blank the file when opening it for the first time so we don't have unwanted characters in it.
    $Checking:On
End Function

Function MemEOF& (memfile As Integer)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Function 'File Not Found Error message
    If MemFile(memfile).Current_Pos >= MemFile(memfile).EOF_Marker Then MemEOF = -1
End Function

Function MemLOF& (memfile As Integer)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Function 'File Not Found Error message
    MemLOF = Val(Str$(MemFile(memfile).EOF_Marker))
End Function



Sub MemSeek (memfile As Integer, position As _Offset)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    If position < 0 Then Error 5: Exit Sub 'Invalid Function Call
    If position > MemFile(memfile).EOF_Marker Then Error 5: Exit Sub 'Invalid Function Call
    MemFile(memfile).Current_Pos = position
End Sub

Sub MemLineInput (memfile As Integer, what$)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    Dim As _Offset CP, EP, L, o
    Dim tempM As _MEM
    tempM = MemFile(memfile).Content 'it's just much shorter to type!
    CP = MemFile(memfile).Current_Pos
    CRLF$ = MemFile(memfile).CRLF: length = Len(CRLF$)
    a$ = CRLF$: o = tempM.OFFSET + CP: L = 0
    If length = 0 Then 'we have no CRLF to look for!
        what$ = Space$(MemFile(memfile).EOF_Marker - CP) 'return the whole string in memory as the result
        _MemGet MemFile(memfile).Content, o, what$
        Exit Sub
    End If
    EP = MemFile(memfile).EOF_Marker - length
    If CP >= EP Then Error 62: Exit Sub 'INPUT PAST END OF FILE error
    $Checking:Off
    Do
        _MemGet tempM, o + L, a$
        If a$ = CRLF$ Then Exit Do
        L = L + 1
    Loop Until CP + L > EP
    temp$ = Space$(L)
    _MemGet MemFile(memfile).Content, o, temp$
    $Checking:On
    CP = CP + L + length
    MemFile(memfile).Current_Pos = CP
    what$ = temp$
End Sub


Sub MemInput (memfile As Integer, what$)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    Dim As _Offset CP, EP, L, o
    Dim tempM As _MEM, a As _Unsigned _Byte
    tempM = MemFile(memfile).Content 'it's just much shorter to type!
    CP = MemFile(memfile).Current_Pos
    CRLF$ = MemFile(memfile).CRLF
    o = tempM.OFFSET + CP: L = 0
    EP = MemFile(memfile).EOF_Marker
    If CP >= EP Then Error 62: Exit Sub 'INPUT PAST END OF FILE error
    $Checking:Off
    Do
        _MemGet tempM, o + L, a
        Select Case a 'valid line seperators
            Case 10 'chr$(10)
                length = 1
                Exit Do
            Case 13 'chr$(13)
                If _MemGet(tempM, o + L + 1, _Unsigned _Byte) = 10 Then length = 2 Else length = 1
                Exit Do
            Case 32
                If L = 0 Then o = o + 1: L = L - 1: CP = CP + 1 'strip off leading spaces
            Case 34
                If L = 0 Then inquote = -1 Else inquote = 0
                If inquote Then stripQuotes = -1
            Case 44 'comma
                If Not inquote Then length = 1: Exit Do
        End Select
        L = L + 1
    Loop Until CP + L >= EP
    temp$ = Space$(L)
    _MemGet MemFile(memfile).Content, o, temp$
    $Checking:On
    CP = CP + L + length
    MemFile(memfile).Current_Pos = CP
    If stripQuotes Then 'we only count quotes as special when they start and stop a sequence?
        If Right$(temp$, 1) = Chr$(34) Then temp$ = Mid$(temp$, 2, Len(temp$) - 2)
    End If
    what$ = _Trim$(temp$)
End Sub





Sub MemPrint (memfile As Integer, what$)
    'memfile is the memfile handle to print to
    'what$ is what we want to print
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim As _Offset CP, EP, Size, L
    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    Size = MemFile(memfile).Content.SIZE
    L = Len(what$) + Len(MemFile(memfile).CRLF)
    If CP + L > Size Then 'we're writing beyond the bounds of our reserved memory!
        Dim tempM As _MEM
        recheck:
        If Size <= 100000000 Then 'resize our memblock (to the limit) to save our data
            tempM = _MemNew(Size * 10)
            _MemCopy MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, Size To tempM, tempM.OFFSET
            _MemFree MemFile(memfile).Content
            MemFile(memfile).Content = tempM
            Size = Size * 10
            GoTo recheck 'just to make certain that our reserved memory is now large enough to hold our data
        Else
            Error 61 'DISK FULL ERROR MESSAGE
            Exit Sub 'I'm coding a hard size limit of 1GB for each memfile opened!
            '        Anything larger than that, and I'm tossing a Disk Full Error
        End If
    End If
    _MemPut MemFile(memfile).Content, MemFile(memfile).Content.OFFSET + CP, what$ + MemFile(memfile).CRLF
    MemFile(memfile).Current_Pos = CP + L
    If CP + L > EP Then MemFile(memfile).EOF_Marker = CP + L
End Sub

The changes first:
You no longer have to specify a line ending for each MemPrint statement.  This brings our syntax in closer to what one would expect with a PRINT # statement.  Compare:

PRINT #1, stuff$
MemPrint handle, stuff$

If you want to change your line endings, you can do so via a call to MemFileCRLF and set them with it.  Default endings are CHR$(10) -- why use an extra byte of memory when it's not necessary? -- and MemFileOpen will search and detect the proper file endings automatically for any file it opens for you so you don't have to worry about it.  Truly, you should only need to change MemFileCRLF if you open a MemFileOpen and need it to have something other than the now standard CHR$(10) endings.

New additions:
MemLOF -- this is basically the same as LOF for a file, except it's for our mem file.  Everyone should know more or less what it'll do for us.

MemInput -- this allows us to do something which QB64 has been needing to do for quite a while -- have a speedier way to INPUT CSV files!  OPEN FOR INPUT is sloooooww....  and we can't OPEN FOR BINARY with INPUT (it only works with LINE INPUT)...  so we've either been stuck with doing things the slooow way, or else having to read and attempt to sort out and parse our data properly manually.  MemInput allows us to bypass this limitation now!

   


INPUT has a lot of little quirky behaviors to it, and I don't think I've ever seen a book that describes the behavior perfectly.  Items in quotes are supposed to stay in quotes, but the quotes themselves are sometimes removed from the items, and yet the quotes are always removed, and, and...  and who knows if QB64 is even perfectly mimicking how QB45 did this?!  INPUT with files is complex crap with all sorts of little exceptions and nuances.  I've did some testing and tried to replicate how QB64 does it, but there's probably a few tweaks that I'm just not aware of and so haven't coded any specific exceptions for.  If you guys do any testing and find an use case that doesn't behave as it should, post an example for me and I'll be happy to tweak things.  AFAIK, it's mimicking QB64 behavior, but I've never really used INPUT very much and thus feel like I'm just shooting blindly into the dark and hoping to hit close to the target in this case.

The difference in speed, however, means it's certainly worth implementing this little routine into your own programs, if you have to deal with large CSV datafiles.  Wink


(Note:  There's still a MemLineInput in here as well, which mimics LINE INPUT behavior.  You just have the choice now between which of the two functions you need for your usage.)
Reply
#8
I don't know of any single, thorough explainer of INPUT functionality, and I've never intentionally torture-tested INPUT before, so here goes:

I didn't try to re-create your tester input file, but used a text file which contains:

Quote:"New York, New York"111"New York, New York"
hi
one with no quotes, "two in quotes", "three with leading quote, four with trailing quote"
"stand-alone five with leading quote
stand-alone six with trailing quote"
toodles


This test program uses the simple INPUT statement (with just a taste of spaghetti for the TRS-80, which doesn't have fancy-pants features like WHILE...WEND or REPEAT...UNTIL):

Code: (Select All)
1 CLS
2 OPEN "I",1,"TEST.TXT"
3 IF NOT EOF(1) THEN INPUT #1, A$: PRINT A$: GOTO 3
4 CLOSE


What I expected based on experience:
Quotes embedded within an input string will be left unmolested.
A leading quote (and a matching trailing quote if there is one) will be stripped.


Tested on QB 4.5, GW Basic 3.23, Turbo Basic, Free Basic, and even TRS-80 Model III Disk Basic:
It's interesting that INPUT splits the first line after "New York, New York", but aside from the extra blank line that gets spit out, the rest is pretty much what I expected.


Output for all tested Basics except QB64:

Quote:New York, New York
111"New York
New York"
hi
one with no quotes
two in quotes
three with leading quote, four with trailing quote
stand-alone five with leading quote

stand-alone six with trailing quote"
toodles


Meanwhile, QB64 loses the 111"New York, and also the trailing quote on stand-alone six, so the output looks like this:

Quote:New York, New York
New York"
hi
one with no quotes
two in quotes
three with leading quote, four with trailing quote
stand-alone five with leading quote

stand-alone six with trailing quote
toodles


I thought that maybe the ANSI full BASIC spec (ANSI X.3113-1987) would give some specific requirements, but no, it only gives lots of words to wade through.

Speaking of ANSI requirements, I dunno if you thought of this:
If an input datum is an unquoted-string, leading and trailing spaces are ignored (cf. 4.1).  If it is a quoted-string, then all spaces between the quotation-marks are significant (cf. 6.11).
Reply
#9
(08-22-2022, 03:08 PM)SMcNeill Wrote: Can you open files to the drive and PRINT and LINE INPUT data to them?

If so, then you can now use _MEM, with these little routines which let you work with mem blocks the same way you'd read and write to the disk with PRINT and LINE INPUT!


Code: (Select All)
Type Mem_File_Type
    inUse As Integer
    EOF_Marker As _Offset
    Current_Pos As _Offset
    Content As _MEM
End Type

Dim Shared MemFile(1 To 100) As Mem_File_Type
'BI HEADER INFO BEFORE THIS








'first, let's showcase how to print and input some information to and from memory
handle = MemFileOpen '                            This is a combination FREEFILE + OPEN statement
MemPrint handle, "Hello World", 1 '              PRINT #filehandle, whatever$ + CRLF
MemPrint handle, "My name is Steve", 1 '          PRINT #filehandle, whatever$ + CRLF
For i = 1 To 10
    MemPrint handle, Str$(i) + ") Record #" + _Trim$(Str$(i)), 1
Next
MemSeek handle, 0 '                              SEEK #filehandle, byte

Do Until MemEOF(handle) '                        DO UNTIL EOF(filehandle)
    MemLineInput handle, temp$ '                    LINE INPUT #filehandle, temp$
    Print temp$ '                                    PRINT temp$
Loop '                                            LOOP

'I hope the above with the comments help to highlight how exactly similar the two syntaxes are here.
'With these mem routines, we're basically just using mem *exactly* as we'd do basic file access with PRINT and LINE INPUT



'And here I'll showcase how to save and load your memblock to disk -- both in compressed and uncompressed form

MemFileSave handle, "temp.txt", 0 '                  0 says save it in uncompressed format.  You can read the data in any old text editor!
MemFileSave handle, "temp_compressed.txt", -1 '      Anything else says to compress the data before saving it.  Not readable untl uncompressed.
Print
Print "Mem saved to disk in both compressed and uncompressed form."
Open "temp.txt" For Input As #1: LOF1 = LOF(1): Close
Open "temp_compressed.txt" For Input As #1: LOF2 = LOF(1): Close
Print "unCompressed file is "; LOF1; "bytes in size."
Print "Compressed file is "; LOF2; "bytes in size."
MemFileClose handle '                            CLOSE filehandle



_KeyClear
Print "Now to load back the file with the uncompressed data.  Press <ANY KEY>"
Sleep
newhandle = MemFileLoad("temp.txt", 0) 'load the uncompressed data file
Do Until MemEOF(newhandle) '                        DO UNTIL EOF(filehandle)
    MemLineInput newhandle, temp$ '                    LINE INPUT #filehandle, temp$
    Print temp$ '                                    PRINT temp$
Loop '                                            LOOP
MemFileClose newhandle

_KeyClear
Print "Now to load back the file with the compressed data.  Press <ANY KEY>"
Sleep
newhandle = MemFileLoad("temp_compressed.txt", -1) 'load the compressed data file
Do Until MemEOF(newhandle) '                        DO UNTIL EOF(filehandle)
    MemLineInput newhandle, temp$ '                    LINE INPUT #filehandle, temp$
    Print temp$ '                                    PRINT temp$
Loop '                                            LOOP
MemFileClose newhandle

Print
Print "And remember, the difference of the sizes of the files on disk were:"
Print "  compressed:"; LOF2
Print "uncompressed:"; LOF1

Print
Print "Press <ANY KEY> to compare speeds in loading an large file into an array in memory."
_KeyClear
Sleep

'And let's showcase a bit more of how this works, why don't we.
Dim As String wordlist(466544), wordlist2(466544), wordlist3(466544) 'arrays to hold the data

'MEM FILE INPUT
handle = MemFileLoad("466544 Word List.txt", 0) 'load a file directly into memory, and it's not compressed
t## = Timer '                                                        timer to see how long we take loading this data
Do Until MemEOF(handle) '                        Hopefully these lines will be intuitive enough.
    count = count + 1 '                          Especially when compared to the notes above
    MemLineInput handle, wordlist(count) '        and the preceeding lines after
Loop
Print count; Using " words loaded into memory from file, in ##.#### seconds."; Timer - t##
MemFileClose handle


'OPEN FILE FOR INPUT
Open "466544 Word List.txt" For Input As #1
t## = Timer
Do Until EOF(1)
    count2 = count2 + 1
    Line Input #1, wordlist2(count2)
Loop
Print count2; Using " words loaded from file OPEN FOR INPUT, in ##.#### seconds."; Timer - t##
Close handle

'OPEN FILE FOR BINARY
Open "466544 Word List.txt" For Binary As #1
t## = Timer
Do Until EOF(1)
    count3 = count3 + 1
    Line Input #1, wordlist3(count3)
Loop
Print count3; Using " words loaded from file OPEN FOR BINARY, in ##.#### seconds."; Timer - t##
Close handle

'and let's compare contents to be safe
For i = 1 To count
    If wordlist(i) <> wordlist2(i) Then Print "Wordlist does not match Wordlist2": failed = -1
    If wordlist(i) <> wordlist3(i) Then Print "Wordlist does not match Wordlist3": failed = -1
Next

If failed Then
    Print "Lists do not match"
Else
    Print "Lists match each other perfectly"
End If





'BM FOOTER AFTER THIS
Sub MemFileDump (memfile, file$, compressed) 'just one quick call to save to disk and free the memory all at once.
    MemFileSave memfile, file$, compressed
    MemFileClose memfile
End Sub

Sub MemFileSave (memfile, file$, compressed)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    temphandle = FreeFile
    Dim As _Offset length

    length = MemFile(memfile).EOF_Marker + 1
    temp$ = Space$(length)
    $Checking:Off
    _MemGet MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, temp$
    $Checking:On
    If compressed Then temp1$ = _Deflate$(temp$) Else temp1$ = temp$
    Open file$ For Output As temphandle: Close temphandle 'erase any existing file with the same name
    Open file$ For Binary As temphandle
    Put #temphandle, 1, temp1$
    Close
End Sub

Function MemFileLoad (file$, compressed)
    'Error codes for MemFileLoad
    '1: No mem files available.  (All 100 are in use!  Free some to use more!)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then MemFileLoad = 0: Exit Function 'can't open any more memfiles!
    If _FileExists(file$) = 0 Then Error 53: Exit Function 'file not found


    MemFileLoad = i
    temphandle = FreeFile
    Open file$ For Binary As #temphandle
    temp$ = Space$(LOF(temphandle))
    Get temphandle, 1, temp$
    Close temphandle
    If compressed Then temp$ = _Inflate$(temp$)
    length = Len(temp$)
    MemFile(i).Content = _MemNew(length)
    $Checking:Off
    _MemPut MemFile(i).Content, MemFile(i).Content.OFFSET, temp$
    $Checking:On
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = length - 1 'the end of the file is the length of the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
End Function


Sub MemFileClose (memfile)
    If memfile < 1 Or memfile > 100 Then Error 5: Exit Sub 'ILLEGAL FUNCTION CALL
    MemFile(memfile).inUse = 0 'no longer in sue
    MemFile(memfile).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(memfile).Current_Pos = 0 'and we're at the start of our nothing in the file
    _MemFree MemFile(memfile).Content 'free the memory we were using
End Sub


Function MemFileOpen
    'Error codes for MemFileOpen
    '1: No mem files available.  (All 100 are in use!  Free some to use more!)
    For i = 1 To 100
        If MemFile(i).inUse = 0 Then Exit For
    Next
    If i > 100 Then MemFileOpen = 0: Exit Function 'can't open any more memfiles!
    MemFileOpen = i
    MemFile(i).inUse = -1 'TRUE
    MemFile(i).EOF_Marker = 0 'nothing is written in the file to begin with
    MemFile(i).Current_Pos = 0 'and we're at the start of our nothing in the file
    MemFile(i).Content = _MemNew(1000000) '1mb memfile by default
    $Checking:Off
    _MemFill MemFile(i).Content, MemFile(i).Content.OFFSET, MemFile(i).Content.SIZE, 0 As _UNSIGNED _BYTE
    'make certain to blank the file when opening it for the first time so we don't have unwanted characters in it.
    $Checking:On
End Function

Function MemEOF (memfile)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Function 'File Not Found Error message
    If MemFile(memfile).Current_Pos >= MemFile(memfile).EOF_Marker Then MemEOF = -1
End Function


Sub MemSeek (memfile, position As _Offset)
    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message
    If position < 0 Then Error 5: Exit Sub 'Invalid Function Call
    If position > MemFile(memfile).EOF_Marker Then Error 5: Exit Sub 'Invalid Function Call
    MemFile(memfile).Current_Pos = position
End Sub

Sub MemLineInput (memfile, what$)
    'only valid line endings here are CHR$(10), chr$(13), and chr$(13) + chr$(10)

    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim As _Offset CP, EP, Size, L
    Dim tempM As _MEM, a1 As _Unsigned _Byte
    tempM = MemFile(memfile).Content 'it's just much shorter to type!

    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    If CP >= EP Then Error 62: Exit Sub 'INPUT PAST END OF FILE error
    Size = tempM.SIZE
    $Checking:Off
    Do
        a$ = _MemGet(tempM, tempM.OFFSET + CP, String * 1)
        Select Case a$
            Case Chr$(13)
                _MemGet tempM, tempM.OFFSET + CP + 1, a1
                If a1 = 10 Then CP = CP + 1 'move the Current Pointer past the 2nd character in a windows CRLF ending
                finished = -1
            Case Chr$(10)
                finished = -1
            Case Else
                temp$ = temp$ + a$
        End Select
        CP = CP + 1
        If CP >= EP Then finished = -1
    Loop Until finished
    $Checking:On
    MemFile(memfile).Current_Pos = CP
    what$ = temp$
End Sub



Sub MemPrint (memfile, what$, EOL_Type As Integer)
    'memfile is the memfile handle to print to
    'what$ is what we want to print
    'EOL_Type is the type of line ending we want after this print statement
    '1: This is a CHR$(10) line ending                  (Linux style line ending)
    '2: This is a CHR$(13) line ending                  (Old Mac style line ending)
    '3: This is a CHR$(13) + CHR$(10) line ending      (Old Windows style line ending)
    '4: This is a COMMA line ending.  Use this if writing continous CSV fields.
    '      (Think PRINT #1, stuff$, <-- see the comma there at the end of the print statement??)


    If MemFile(memfile).inUse = 0 Then Error 53: Exit Sub 'File Not Found Error message

    Dim CRLF As String
    Dim As _Offset CP, EP, Size, L

    Select Case EOL_Type
        Case 1: CRLF = Chr$(10)
        Case 2: CRLF = Chr$(13)
        Case 3: CRLF = Chr$(13) + Chr$(10)
        Case 4: CRLF = ","
    End Select
    CP = MemFile(memfile).Current_Pos
    EP = MemFile(memfile).EOF_Marker
    Size = MemFile(memfile).Content.SIZE
    L = Len(what$) + Len(CRLF)
    If CP + L > Size Then 'we're writing beyond the bounds of our reserved memory!
        Dim tempM As _MEM
        recheck:
        If Size <= 100000000 Then 'resize our memblock (to the limit) to save our data
            tempM = _MemNew(Size * 10)
            _MemCopy MemFile(memfile).Content, MemFile(memfile).Content.OFFSET, Size To tempM, tempM.OFFSET
            _MemFree MemFile(memfile).Content
            MemFile(memfile).Content = tempM
            Size = Size * 10
            GoTo recheck 'just to make certain that our reserved memory is now large enough to hold our data
        Else
            Error 61 'DISK FULL ERROR MESSAGE
            Exit Sub 'I'm coding a hard size limit of 1GB for each memfile opened!
            '        Anything larger than that, and I'm tossing a Disk Full Error
        End If
    End If
    _MemPut MemFile(memfile).Content, MemFile(memfile).Content.OFFSET + CP, what$ + CRLF
    MemFile(memfile).Current_Pos = CP + L
    If CP + L > EP Then MemFile(memfile).EOF_Marker = CP + L
End Sub
 
Grab the necessary dictionary file from here:  https://staging.qb64phoenix.com/attachment.php?aid=760
(I didn't see any reason why the same file needed to be uploaded and attached to multiple posts when it was already here once. Wink )
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#10
I've just been up to the link you posted for the word list, and found it a bit disappointing. It has about half a million words, but many of these seem to be numerics (unless I'm opening it wrong and they're control codes etc.) and many more are hyphenated or include non-alpha chars: dashes, colons etc.
I've weeded these out and now have what, to me anyway, seems a lot more useful word list, which has all the full-alpha words from that file, a total of 466467 words. 
It still includes a whole heap of acronyms - like "AAAAAA" which I intend to remove also, as I don't have a use for these.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply




Users browsing this thread: 6 Guest(s)