PureBasic Docs- Ideas/Help needed for a "We start" chapter!?

Everything else that doesn't fall into one of the other PB categories.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

spikey wrote:@Andre:
Oh OK. I was assuming that's what you meant when you put "Compiler commands" in your proposed table of contents! What did you have in mind then?
I don't think, there is anything *very important* for beginners in this chapter.
So I will prabably remove the Compiler commands, if you don't have more ideas for this...


@IdeasVacuum: thanks for the example! I think this is more something for the related command description (CatchImage) in the manual, if you don't have in mind writing some more explanation important for this chapter ("Beginning with PureBasic" for beginners).
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Reading and Writing Files item

Post by spikey »

I ran out of inspiration with this one - if anyone else has any better ideas?!

This example will write 100 random records each containing a byte, a floating point number, a long integer and a string. It then reads all the records back and displays them in the debug window.

It demonstrates the GetTemporaryDirectory, CreateFile, OpenFile, EOF and a number of Read and Write data instructions too.

It works fine as far as it goes, but has a drawback. As the string value has a variable length - you can't randomly access the records because you can't predict where each new record will start in the file. They must be all be read back in the same sequence as they were written. This isn't a problem with the small number of records created here but this could be an inconvenience with a larger file. PureBasic offers a way to handle this situation too - but an example would be too complex for this topic. See the "Database" sections of the help file or reference manual to see how it could be done.

Code: Select all

; Define some variables.
Define.F fltFloat
Define.L lngCount, lngFile
Define.S strFolder, strFile, strString

; Create a temporary file name.
strFolder = GetTemporaryDirectory()
strFile = strFolder + "test.data"

; Create the temporary file.
; If #PB_Any is used, CreateFile returns the file's number.  
; Useful if you may have more than one file open simultaneously.
lngFile = CreateFile(#PB_Any, strFile)

If lngFile
  ; If this was successful - write 100 random records.
  For lngCount = 1 To 100
    
    ; Write a random byte (0 - 255).
    WriteByte(lngFile, Random(#MAXBYTE))
    
    ; Create and write a random float.
    ; This calculation is there to make the number have a floating point component (probably).
    fltFloat = Random(#MAXLONG) / ((Random(7) + 2) * 5000)
    WriteFloat(lngFile, fltFloat)
    
    ; Write a random long.
    WriteLong(lngFile, Random(#MAXLONG))
    
    ; Create and write a random string in Unicode format.
    ; Note the use of WriteStringN to delimit the string with an end of line marker.
    strString = "String " + StrU(Random(#MAXLONG))
    WriteStringN(lngFile, strString, #PB_Unicode)
    
  Next lngCount
  
  ; Close the file.
  CloseFile(lngFile)
  
Else
  ; If this was unsuccessful.
  Debug "Could not create the file: " + strFile 
  
EndIf

; Open the file for reading this time.
lngFile = ReadFile(#PB_Any, strFile)

If lngFile
  ; If this was successful - read and display records from the file.

  ; Reset the counter.
  lngCount = 1
  
  ; Loop until the 'end of file' is reached.
  ; This will read all of the records regardless of how many there are.
  While Eof(lngFile) = 0
    
    ; Print a header line.
    Debug "------------------------------------------------------------------------------------------------"
    
    Debug "[" + StrU(lngCount) + "]"
    lngCount + 1
    ; Read a byte value and print it.
    Debug StrU(ReadByte(lngFile), #PB_Byte)
    
    ; Read a float value..
    Debug StrF(ReadFloat(lngFile))
    
    ; Read a long value.
    Debug StrU(ReadLong(lngFile), #PB_Long)
    
    ; Read a string value.
    Debug ReadString(lngFile, #PB_Unicode)
    
  Wend
  
  ; Print the trailing line.
  Debug "------------------------------------------------------------------------------------------------"
    
  ; Close the file.
  CloseFile(lngFile)
  
  ; Tidy up.
  DeleteFile(strFile)
  
Else
  ; If this was unsuccessful.
  Debug "Could not open the file: " + strFile 
  
EndIf
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: Reading and Writing Files item

Post by Andre »

spikey wrote: I ran out of inspiration with this one - if anyone else has any better ideas?!
Thanks anyway. I like it and it shouldn't be more than a start, including links to further documentation in the manual at the named commands... So I've included it in first post! :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
GeBonet
Enthusiast
Enthusiast
Posts: 135
Joined: Fri Apr 04, 2008 6:20 pm
Location: Belgium

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by GeBonet »

Hi !
@spikey

Each record is written after the other! At the time of writing the next one Lof (# File) tell you what address to write (the end). We retain this position that we place in an index. Reading after each record is from the index ...

The recording "X" file "direct" primary is given by the address used in the index (X). And if the index is organized so as to always be in alphanumeric order (dichotomic insertion) with a key and a pointer to "X" then we have a line system ordered.
The only trouble is that you have two files ... A main content and variable length, and an Index with Access key and a pointer to the record. With this system you have an indexed sequential file with variable reccord length.
Note: The index can be loaded and kept him in memory and even be used for multiple files (example: "FileName.SpecifiqueKey).

The procedure of creation:
Writing or there is room in the direct address is retained, then insert the key into the index with the address in the direct file.
The procedure for reading:
From the key of the index, it takes the address and read the record in the file directly.
Advantage ... No limit!
But hey, it's just an idea ... :wink:
Other Note: This type of file, need, with the time, reorganisation... (Like defragmentation)....
Sorry for my english :wink: ! (Windows Xp, Vista and Windows 7, Windows 10)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by spikey »

@GeBonet:

Yes I know, but as it's for inclusion in a beginner's primer I had several concerns in mind at the same time, namely, not introducing too many new concepts at one time, not using any concepts and jargon that haven't already been introduced, keeping the article as short as possible, keeping it suitable for someone with potentially no programming experience and not giving false or misleading information...

My main objective with that item is to look at the file read and write commands. That particular paragraph is to draw attention to the fact that there is a problem with the example as shown and it's not really intended for real-world applications.

I did say that you can't predict where each new record will begin. I didn't say that you couldn't record it.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

spikey wrote: Yes I know, but as it's for inclusion in a beginner's primer I had several concerns in mind at the same time, namely, not introducing too many new concepts at one time, not using any concepts and jargon that haven't already been introduced, keeping the article as short as possible, keeping it suitable for someone with potentially no programming experience and not giving false or misleading information...
That's the right goal! :D

This chapter should be "only" a start, something for beginners, linking directly to further command descriptions, etc.
But it should be in no way a competitor to other tutorials like blueznl's website or Kale's PureBasic book. :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
GeBonet
Enthusiast
Enthusiast
Posts: 135
Joined: Fri Apr 04, 2008 6:20 pm
Location: Belgium

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by GeBonet »

Ok, I understand your point of view.
In fact it is a pity that there have not at least one form of direct-access style "Get (# file, NoRecord). And of course the Field (# file, size) or ability to save a structure at once. We can create a library that does, but it would be better if it existed.
Sincerely,
Gerhard
Sorry for my english :wink: ! (Windows Xp, Vista and Windows 7, Windows 10)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by spikey »

If you did construct an index the way that you described then the FileSeek instruction would allow access any record directly using the offset from the index, and it wouldn't be difficult to write a procedure to serialize a particular structure to a file.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

About the first post in this thread:

I've revised the "Overview" (of available topics in the beginners chapter) and have added some ideas at each topic, which doesn't contain further content until now.

Many thanks for any contribution until now! :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Memory Access item

Post by spikey »

Some PureBasic instructions, for example those from the Cipher library and many operating system API calls, require a pointer to a memory buffer as an argument rather than the data directly itself. PureBasic provides a number of instructions to manipulate memory buffers to facilitate this.

This example uses a buffer to read a file from disk into memory. It then converts the buffer content into a hexadecimal and text display in a List Icon Gadget as a simple hex viewer application.

An Explorer List Gadget is used to display the contents of the user's home directory, initially, and to allow selection of a file. Two buttons are provided, one to display a file and another to clear the display.

The List Icon Gadget is divided into nine columns, the first shows the base offset of each line in the list, the next show eight byte values offset from the base value and the ninth shows the string equivalent of these eight values.

Two pointers are used - the first (*Buffer) contains the memory address of the complete file. The second (*Byte), in the procedure "FileDisplay", demonstrates the use of pointer arithmetic and the "Peek" instruction to obtain individual values from within the buffer.

Finally, the "FileClose" procedure demonstrates the use of the "FillMemory" instruction to overwrite the buffer's contents and "FreeMemory" to de-allocate the memory buffer.

Code: Select all

;- Compiler Directives
EnableExplicit

;- Constants
; Window
Enumeration
  #wdwHex
EndEnumeration

; Gadgets
Enumeration
  #xlsFiles
  #btnOpen
  #btnClose
  #lsiHex
EndEnumeration

;- Variables
Define.L Event, EventWindow, EventGadget, EventType, EventMenu
Define.L lngLength
Define.S strFile
Define *Buffer

;- Declarations
Declare WindowCreate()
Declare WindowResize()
Declare FileClose()
Declare FileDisplay()
Declare FileRead()

;- Implementation
Procedure WindowCreate()  
  ; Create the window.
  
  Protected.L lngCol
  Protected.S strLabel
  
  If OpenWindow(#wdwHex, 50, 50, 440, 400, "Hex View", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
    
    ; Set minimum window size.
    WindowBounds(#wdwHex, 175, 175, #PB_Ignore, #PB_Ignore)
    
    ; Create Explorer List and set to user's home directory.
    ExplorerListGadget(#xlsFiles, 5, 5, 430, 175, GetHomeDirectory())
    
    ; Buttons.
    ButtonGadget(#btnOpen, 5, 185, 80, 25, "Open")
    ButtonGadget(#btnClose, 90, 185, 80, 25, "Close")
    
    ; List Icon Gadget.
    ListIconGadget(#lsiHex, 5, 215, 430, 180, "Offset", 80, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
    
    ; Column Headings.
    For lngCol = 0 To 7
      strLabel = RSet(Hex(lngCol, #PB_Byte), 2, "0")
      AddGadgetColumn(#lsiHex, lngCol + 1, strLabel, 30)
    Next lngCol
    AddGadgetColumn(#lsiHex, 9, "Text", 80)
    
  EndIf
  
EndProcedure

Procedure WindowResize()
  ; Resize gadgets to new window size.
  
  Protected.L lngX, lngY, lngW, lngH
  
  ; Explorer List
  lngW = WindowWidth(#wdwHex) - 10
  lngH = (WindowHeight(#wdwHex) - 35) / 2
  ResizeGadget(#xlsFiles, #PB_Ignore, #PB_Ignore, lngW, lngH)
  
  ; Buttons
  lngY = GadgetHeight(#xlsFiles) + 10
  ResizeGadget(#btnOpen, #PB_Ignore, lngY, #PB_Ignore, #PB_Ignore)
  ResizeGadget(#btnClose, #PB_Ignore, lngY, #PB_Ignore, #PB_Ignore)
  
  ; List Icon View
  lngY = (WindowHeight(#wdwHex) / 2) + 23
  lngW = WindowWidth(#wdwHex) - 10
  lngH = WindowHeight(#wdwHex) - (lngY + 5)
  ResizeGadget(#lsiHex, #PB_Ignore, lngY, lngW, lngH)
  
EndProcedure

Procedure FileClose()
  ; Clear the list view and release the memory buffer.
  
  Shared lngLength, *Buffer
  
  ClearGadgetItems(#lsiHex)
  FillMemory(*Buffer, lngLength)
  FreeMemory(*Buffer)
  
EndProcedure

Procedure FileDisplay()
  ; Display the file buffer in the list view.
  
  Shared lngLength, *Buffer
  
  Protected *Byte
  Protected bytPeek
  Protected.L lngRows, lngCols, lngOffset
  Protected.S strOffset, strRow, strString
  
  ; Clear current contents.
  ClearGadgetItems(#lsiHex)
  
  ; Loop through rows.
  For lngRows = 0 To lngLength - 1 Step 8
    
    ; Clear the text value for each row.
    strString = ""
    
    ; Convert the offset value to a fixed length string.
    strRow = RSet(Hex(lngRows, #PB_Long), 6, "0") + Chr(10)
    
    ; Loop through columns.
    For lngCols = 0 To 7
      
      ; Calculate the offset for the current column.
      lngOffset = lngRows + lngCols
      
      ; Compare the offset with the file length.
      If lngOffset < lngLength
        ; The offset is less than the length of the file.
        
        ; Obtain the byte from the buffer.
        *Byte = *Buffer + lngOffset
        bytPeek = PeekB(*Byte)
        
        ; Convert the byte to text.
        strRow + RSet(Hex(bytPeek, #PB_Byte), 2, "0") + Chr(10)
        
        ; Add the character to the text version.
        Select bytPeek
            
          Case 0 To 31, 127
            ; Unprintable characters.
            strString + Chr(129)   
            
          Default
            ; Printable characters.
            strString + Chr(bytPeek)
            
        EndSelect
        
      Else
        ; The offset is greater than the length of the file.
        
        ; Add an empty column.
        strRow + Chr(10)
        
      EndIf
      
    Next lngCols
    
    ; Add the text version at the end of the hex columns.
    strRow + strString
    
    ; Add the completed row to the list view.
    AddGadgetItem(#lsiHex, -1, strRow)
    
  Next lngRows
  
EndProcedure

Procedure FileRead()
  ; Read the file into the memory buffer.
  
  Shared lngLength, strFile, *Buffer
  
  Protected.B bytRead
  Protected.L lngFile, lngRead, lngSize
  
  ; Stop if file is empty.
  If strFile = ""
    ProcedureReturn
  EndIf
  
  ; Stop if file size is invalid.
  lngSize = FileSize(strFile)
  If lngSize < 1
    ProcedureReturn 
  EndIf
  
  ; Open the file.
  lngFile = OpenFile(#PB_Any, strFile)
  lngLength = Lof(lngFile)
  
  If lngFile And lngLength
    
    ; Allocate a memory buffer to hold the file.
    *Buffer = AllocateMemory(lngLength)
    
    ; Read the file into the buffer.
    lngLength = ReadData(lngFile, *Buffer, lngLength)
    
  EndIf
  
  ; Close the file.
  CloseFile(lngFile)
  
EndProcedure

;- Main
WindowCreate()

;- Event Loop
Repeat
  
  ; Obtain event parameters.
  Event = WaitWindowEvent()
  EventGadget = EventGadget()
  EventType = EventType()
  EventWindow = EventWindow()
  
  ; Handle events.
  Select Event
      
    Case #PB_Event_Gadget
      If EventGadget = #xlsFiles
        ; Do nothing.

      ElseIf EventGadget = #btnOpen
        strFile = GetGadgetText(#xlsFiles) + GetGadgetItemText(#xlsFiles, GetGadgetState(#xlsFiles))
        If FileSize(strFile) > 0
          FileRead()  
          FileDisplay()
        EndIf
        
      ElseIf EventGadget = #btnClose
        FileClose()
        
      ElseIf EventGadget = #lsiHex
        ; Do nothing.
        
      EndIf
      
    Case #PB_Event_CloseWindow
      If EventWindow = #wdwHex
        CloseWindow(#wdwHex)
        Break
      EndIf
      
    Case #PB_Event_SizeWindow
      WindowResize()
      
  EndSelect
  
ForEver
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

...as the first post is becoming too big now (one post is restricted to 60000 chars in the forum!), we are continueing the first post here:

Last edited: 12th-June-2011
We start programming...

Part 2 for first post see here


Memory access
spikey wrote:Some PureBasic instructions, for example those from the Cipher library and many operating system API calls, require a pointer to a memory buffer as an argument rather than the data directly itself. PureBasic provides a number of instructions to manipulate memory buffers to facilitate this.

This example uses a buffer to read a file from disk into memory. It then converts the buffer content into a hexadecimal and text display in a List Icon Gadget as a simple hex viewer application.

An Explorer List Gadget is used to display the contents of the user's home directory, initially, and to allow selection of a file. Two buttons are provided, one to display a file and another to clear the display.

The List Icon Gadget is divided into nine columns, the first shows the base offset of each line in the list, the next show eight byte values offset from the base value and the ninth shows the string equivalent of these eight values.

Two pointers are used - the first (*Buffer) contains the memory address of the complete file. The second (*Byte), in the procedure "FileDisplay", demonstrates the use of pointer arithmetic and the "Peek" instruction to obtain individual values from within the buffer.

Finally, the "FileClose" procedure demonstrates the use of the "FillMemory" instruction to overwrite the buffer's contents and "FreeMemory" to de-allocate the memory buffer.

Code: Select all

;- Compiler Directives
EnableExplicit

;- Constants
; Window
Enumeration
  #wdwHex
EndEnumeration

; Gadgets
Enumeration
  #xlsFiles
  #btnOpen
  #btnClose
  #lsiHex
EndEnumeration

;- Variables
Define.L Event, EventWindow, EventGadget, EventType, EventMenu
Define.L lngLength
Define.S strFile
Define *Buffer

;- Declarations
Declare WindowCreate()
Declare WindowResize()
Declare FileClose()
Declare FileDisplay()
Declare FileRead()

;- Implementation
Procedure WindowCreate()  
  ; Create the window.
  
  Protected.L lngCol
  Protected.S strLabel
  
  If OpenWindow(#wdwHex, 50, 50, 440, 400, "Hex View", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
    
    ; Set minimum window size.
    WindowBounds(#wdwHex, 175, 175, #PB_Ignore, #PB_Ignore)
    
    ; Create Explorer List and set to user's home directory.
    ExplorerListGadget(#xlsFiles, 5, 5, 430, 175, GetHomeDirectory())
    
    ; Buttons.
    ButtonGadget(#btnOpen, 5, 185, 80, 25, "Open")
    ButtonGadget(#btnClose, 90, 185, 80, 25, "Close")
    
    ; List Icon Gadget.
    ListIconGadget(#lsiHex, 5, 215, 430, 180, "Offset", 80, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
    
    ; Column Headings.
    For lngCol = 0 To 7
      strLabel = RSet(Hex(lngCol, #PB_Byte), 2, "0")
      AddGadgetColumn(#lsiHex, lngCol + 1, strLabel, 30)
    Next lngCol
    AddGadgetColumn(#lsiHex, 9, "Text", 80)
    
  EndIf
  
EndProcedure

Procedure WindowResize()
  ; Resize gadgets to new window size.
  
  Protected.L lngX, lngY, lngW, lngH
  
  ; Explorer List
  lngW = WindowWidth(#wdwHex) - 10
  lngH = (WindowHeight(#wdwHex) - 35) / 2
  ResizeGadget(#xlsFiles, #PB_Ignore, #PB_Ignore, lngW, lngH)
  
  ; Buttons
  lngY = GadgetHeight(#xlsFiles) + 10
  ResizeGadget(#btnOpen, #PB_Ignore, lngY, #PB_Ignore, #PB_Ignore)
  ResizeGadget(#btnClose, #PB_Ignore, lngY, #PB_Ignore, #PB_Ignore)
  
  ; List Icon View
  lngY = (WindowHeight(#wdwHex) / 2) + 23
  lngW = WindowWidth(#wdwHex) - 10
  lngH = WindowHeight(#wdwHex) - (lngY + 5)
  ResizeGadget(#lsiHex, #PB_Ignore, lngY, lngW, lngH)
  
EndProcedure

Procedure FileClose()
  ; Clear the list view and release the memory buffer.
  
  Shared lngLength, *Buffer
  
  ClearGadgetItems(#lsiHex)
  FillMemory(*Buffer, lngLength)
  FreeMemory(*Buffer)
  
EndProcedure

Procedure FileDisplay()
  ; Display the file buffer in the list view.
  
  Shared lngLength, *Buffer
  
  Protected *Byte
  Protected bytPeek
  Protected.L lngRows, lngCols, lngOffset
  Protected.S strOffset, strRow, strString
  
  ; Clear current contents.
  ClearGadgetItems(#lsiHex)
  
  ; Loop through rows.
  For lngRows = 0 To lngLength - 1 Step 8
    
    ; Clear the text value for each row.
    strString = ""
    
    ; Convert the offset value to a fixed length string.
    strRow = RSet(Hex(lngRows, #PB_Long), 6, "0") + Chr(10)
    
    ; Loop through columns.
    For lngCols = 0 To 7
      
      ; Calculate the offset for the current column.
      lngOffset = lngRows + lngCols
      
      ; Compare the offset with the file length.
      If lngOffset < lngLength
        ; The offset is less than the length of the file.
        
        ; Obtain the byte from the buffer.
        *Byte = *Buffer + lngOffset
        bytPeek = PeekB(*Byte)
        
        ; Convert the byte to text.
        strRow + RSet(Hex(bytPeek, #PB_Byte), 2, "0") + Chr(10)
        
        ; Add the character to the text version.
        Select bytPeek
            
          Case 0 To 31, 127
            ; Unprintable characters.
            strString + Chr(129)   
            
          Default
            ; Printable characters.
            strString + Chr(bytPeek)
            
        EndSelect
        
      Else
        ; The offset is greater than the length of the file.
        
        ; Add an empty column.
        strRow + Chr(10)
        
      EndIf
      
    Next lngCols
    
    ; Add the text version at the end of the hex columns.
    strRow + strString
    
    ; Add the completed row to the list view.
    AddGadgetItem(#lsiHex, -1, strRow)
    
  Next lngRows
  
EndProcedure

Procedure FileRead()
  ; Read the file into the memory buffer.
  
  Shared lngLength, strFile, *Buffer
  
  Protected.B bytRead
  Protected.L lngFile, lngRead, lngSize
  
  ; Stop if file is empty.
  If strFile = ""
    ProcedureReturn
  EndIf
  
  ; Stop if file size is invalid.
  lngSize = FileSize(strFile)
  If lngSize < 1
    ProcedureReturn 
  EndIf
  
  ; Open the file.
  lngFile = OpenFile(#PB_Any, strFile)
  lngLength = Lof(lngFile)
  
  If lngFile And lngLength
    
    ; Allocate a memory buffer to hold the file.
    *Buffer = AllocateMemory(lngLength)
    
    ; Read the file into the buffer.
    lngLength = ReadData(lngFile, *Buffer, lngLength)
    
  EndIf
  
  ; Close the file.
  CloseFile(lngFile)
  
EndProcedure

;- Main
WindowCreate()

;- Event Loop
Repeat
  
  ; Obtain event parameters.
  Event = WaitWindowEvent()
  EventGadget = EventGadget()
  EventType = EventType()
  EventWindow = EventWindow()
  
  ; Handle events.
  Select Event
      
    Case #PB_Event_Gadget
      If EventGadget = #xlsFiles
        ; Do nothing.

      ElseIf EventGadget = #btnOpen
        strFile = GetGadgetText(#xlsFiles) + GetGadgetItemText(#xlsFiles, GetGadgetState(#xlsFiles))
        If FileSize(strFile) > 0
          FileRead()  
          FileDisplay()
        EndIf
        
      ElseIf EventGadget = #btnClose
        FileClose()
        
      ElseIf EventGadget = #lsiHex
        ; Do nothing.
        
      EndIf
      
    Case #PB_Event_CloseWindow
      If EventWindow = #wdwHex
        CloseWindow(#wdwHex)
        Break
      EndIf
      
    Case #PB_Event_SizeWindow
      WindowResize()
      
  EndSelect
  
ForEver

Other Compiler keywords
...
idea: some more infos about keywords not mentioned before in this chapter, maybe even without further description / example, just guiding the user to the related chapters of the manual

Other Library functions
...
idea: some more infos about Libraries/Commands (e.g. Sound, 3D,...) not mentioned before in this chapter, maybe even without further description / example, just guiding the user to the related chapters of the manual

Advanced functions
...
- pointers and how to pass by reference to procedures
...
idea: maybe such a topic is already too much for a beginners chapter, but if anything should be included here, which isn't mentioned until now, then place it here!

Some Tipps & Tricks
...
idea: some things the user (beginner) should be aware of?
spikey wrote: Tip: Using a Map to index a Linked List

Linked lists provide a powerful way to build a structured storage system - however they have a disadvantage. If you aren't sure exactly where in the list a particular item is, you must examine each entry in the list to find the right one.

Maps also provide a similar function but are indexed by a key value instead - however they too have a disadvantage, they don't maintain the order elements are inserted into the list.

However by using a combination of the two, you can neatly avoid both of these issues...

This example loads a structured linked list of book data and builds an index of ISBN numbers using a map. It then demonstrates how to access the linked list using the index in the map.

Code: Select all

EnableExplicit

; A book catalog structure.
Structure BOOK
  Title.S
  Author.S
  ISBN13.S
  Price.D
EndStructure

; Create a list to hold the catalog entries.
NewList lstCatalog.BOOK()
; Create a map to hold the ISBN index.
NewMap mapISBN13.L()
; Working variables.
Define.L lngCount, lngIndex
Define.S strISBN

; Add an empty element at the top of the list.
; The first element in a linked list is numbered zero, however the map will return zero if a requested entry isn't present.
; This empty element avoids a potential problem with an incorrect reference to the first catalog item being returned.
AddElement(lstCatalog())

For lngCount = 1 To 5
 
  ; Read the data from the table into the list.
  AddElement(lstCatalog())
  Read.S lstCatalog()\Title
  Read.S lstCatalog()\Author
  Read.S lstCatalog()\ISBN13
  Read.D lstCatalog()\Price
 
  ; Index the ISBN to the map.
  mapISBN13(lstCatalog()\ISBN13) = ListIndex(lstCatalog())
 
Next lngCount

; Find an entry.
strISBN = "978-0340896983"
lngIndex = mapISBN13(strISBN)

If lngIndex > 0
  Debug "Book with ISBN13 " + strISBN + " is at list index " + StrU(lngIndex) + "."
  Debug ""
 
  ; We can now directly select the right list element without having to perform a search.
  SelectElement(lstCatalog(), lngIndex)
  Debug "'" + lstCatalog()\Title + "' by " + lstCatalog()\Author
  Debug "ISBN: " + lstCatalog()\ISBN13
  Debug "Price: " + StrD(lstCatalog()\Price, 2)
 
Else
  Debug "No book with that ISBN in the catalog."
 
EndIf

End

; Some test data.
DataSection
 
  BookData:
 
  Data.S "Carte Blanche", "Jeffery Deaver", "978-1444716474"
  Data.D 19.99
 
  Data.S "One Day", "David Nicholls", "978-0340896983"
  Data.D 7.99
 
  Data.S "Madeleine", "Kate McCann", "978-0593067918"
  Data.D 20.00
 
  Data.S "The Dukan Diet", "Dr Pierre Dukan", "978-1444710335"
  Data.D 8.99
 
  Data.S "A Game of Thrones", "George R. R. Martin", "978-0006479888"
  Data.D 9.99
 
  Data.S "The Help", "Kathryn Stockett", "978-0141039282"
  Data.D 8.99
 
EndDataSection
......
...

...
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
akee
Enthusiast
Enthusiast
Posts: 475
Joined: Wed Aug 18, 2004 9:52 am
Location: Penang, Malaysia

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by akee »

Good job Andre...

- I would like to see some information on pointers and how to pass by reference to procedures.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Docs- Ideas/Help needed for a "We start" chapt

Post by Andre »

akee wrote:Good job Andre...

- I would like to see some information on pointers and how to pass by reference to procedures.
Thanks akee, also when the "thank you" mostly goes to spikey for his help! :mrgreen:

I will add your suggestion to the "To Do". Probably the topic is a bit too advanced for a "beginners" chapter... We will see! 8)
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Tip - Using a Map to index a Linked List

Post by spikey »

Linked lists provide a powerful way to build a structured storage system - however they have a disadvantage. If you aren't sure exactly where in the list a particular item is, you must examine each entry in the list to find the right one.

Maps also provide a similar function but are indexed by a key value instead - however they too have a disadvantage, they don't maintain the order elements are inserted into the list.

However by using a combination of the two, you can neatly avoid both of these issues...

This example loads a structured linked list of book data and builds an index of ISBN numbers using a map. It then demonstrates how to access the linked list using the index in the map.

Code: Select all

EnableExplicit

; A book catalog structure.
Structure BOOK
  Title.S
  Author.S
  ISBN13.S
  Price.D
EndStructure

; Create a list to hold the catalog entries.
NewList lstCatalog.BOOK()
; Create a map to hold the ISBN index.
NewMap mapISBN13.L()
; Working variables.
Define.L lngCount, lngIndex
Define.S strISBN

; Add an empty element at the top of the list.
; The first element in a linked list is numbered zero, however the map will return zero if a requested entry isn't present.
; This empty element avoids a potential problem with an incorrect reference to the first catalog item being returned.
AddElement(lstCatalog())

For lngCount = 1 To 5
 
  ; Read the data from the table into the list.
  AddElement(lstCatalog())
  Read.S lstCatalog()\Title
  Read.S lstCatalog()\Author
  Read.S lstCatalog()\ISBN13
  Read.D lstCatalog()\Price
 
  ; Index the ISBN to the map.
  mapISBN13(lstCatalog()\ISBN13) = ListIndex(lstCatalog())
 
Next lngCount

; Find an entry.
strISBN = "978-0340896983"
lngIndex = mapISBN13(strISBN)

If lngIndex > 0
  Debug "Book with ISBN13 " + strISBN + " is at list index " + StrU(lngIndex) + "."
  Debug ""
 
  ; We can now directly select the right list element without having to perform a search.
  SelectElement(lstCatalog(), lngIndex)
  Debug "'" + lstCatalog()\Title + "' by " + lstCatalog()\Author
  Debug "ISBN: " + lstCatalog()\ISBN13
  Debug "Price: " + StrD(lstCatalog()\Price, 2)
 
Else
  Debug "No book with that ISBN in the catalog."
 
EndIf

End

; Some test data.
DataSection
 
  BookData:
 
  Data.S "Carte Blanche", "Jeffery Deaver", "978-1444716474"
  Data.D 19.99
 
  Data.S "One Day", "David Nicholls", "978-0340896983"
  Data.D 7.99
 
  Data.S "Madeleine", "Kate McCann", "978-0593067918"
  Data.D 20.00
 
  Data.S "The Dukan Diet", "Dr Pierre Dukan", "978-1444710335"
  Data.D 8.99
 
  Data.S "A Game of Thrones", "George R. R. Martin", "978-0006479888"
  Data.D 9.99
 
  Data.S "The Help", "Kathryn Stockett", "978-0141039282"
  Data.D 8.99
 
EndDataSection
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: Tip - Using a Map to index a Linked List

Post by Andre »

spikey wrote:Linked lists provide a powerful way to build a structured storage system...
I'm back from holidays :D

Thanks spikey for this new contribution! Have added it to the Tipps & Tricks section in part 2 of the beginners chapter.

By the way I asked freak about some suggestions, before including this stuff / code examples into the help (because there should be a continious style/convention through the whole help...).

So I need to change all code examples a bit, according to the following "rules":
- avoid hungarian notation like "strString", just "String$" or a (longer) meaningful name should do it
- use String variables always with $ (instead of .s)
- type suffix at Define in lower chars, like "Define.l" (instead of "Define.L")
- Integer variables without type suffix (because the standard .i type should be used instead of long .l)
- define Floats with .f or .d, then normally use them
- examples for meaningful (variable) names: 'CamelCase': "FileName", "EventType", etc.

This are things which should make things easier for the beginner, because he will find this convention through the complete help (command names, variables name, code examples in general)...

I will start including this chapter into the PB help as soon I've completed the german translation of all new/changed PB4.60 docs + error corrections / improvements to the english docs too... :)
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
Post Reply