April 30, 2024, 10:36:40 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


readMEM and writeMEM

Started by LarryMc, April 17, 2007, 07:28:13 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

Can anyone tell me why this isn't working?

I want to have an ISTRING variable of 1000 characters
I want to store the contents of up to 20 of the variables (which may contain 1 to 1000 characters)
I want to read the stored strings back.

Simple and straightforward.

autodefine "off"

memory buffer
istring k$[1000]
allocmem buffer,20,1000

k$=string$(80,"A")
print "["+k$+"]"
WRITEMEM buffer,1,k$
k$=""
readMEM buffer,1,k$
print "["+k$+"]"

print " Any key to end"
do:until inkey$<>""
freemem buffer
end


LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

found my problem:
changedWRITEMEM buffer,1,k$
k$=""
readMEM buffer,1,k$
to__WRITEMEM buffer,1,k$,1000
k$=""
__readMEM buffer,1,k$,1000


In the ebstd.incc there is:$command __READMEM(mptr as MEMORY,record as INT,var as POINTER,size as INT)
$command __WRITEMEM(mptr as MEMORY,record as INT,var as POINTER,size as INT)
and'{command}READMEM
'{command}WRITEMEM

Searching the rest of the incc files in my bin dir I don't find any other READMEM or WRITEMEM.

When I use READMEM/WRITEMEM without the size on the end(4th parameter)(and as indicated in the help file) I don't get an error. It just doesn't work.
If I add the 4th parameter I get an error.

When I use __READMEM/__WRITEMEM without the size on the end(4th parameter) I get an error.

I really don't understand what's going on here. ???
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

REDEBOLT

Larry,

Evidently, the length of readmem is constrained by the length of the receiving varable k$="".
Try k$=space$(1000)

autodefine "off"

int rtn
memory buffer
istring k$[1000]
rtn=allocmem buffer,20,1000
if rtn=0 then
print "allocmem succeeded"
else
print "allocmem failed"
goto endit
endif

k$=string$(80,"A")
print "["+k$+"]"
WRITEMEM buffer,1,k$
k$=space$(1000)
readMEM buffer,1,k$
print "["+k$+"]"
freemem buffer

label endit
print " Any key to end"
do:until inkey$<>""
end


Regards,
Bob

LarryMc

Quote from: REDEBOLT on April 17, 2007, 08:27:21 AM
Evidently, the length of readmem is constrained by the length of the receiving varable k$="".
Try k$=space$(1000)
Two points:
1. And most important, the program works exactly like I want it to when I made the changes as indicated in my last post.
2. k$=space$(1000) defeats what I'm trying to do.  That would mean that I would have to pad strings that I want to store to insure that were 1000 characters long. I shouldn't have to do that.  I don't have to pad an ISTRING  def as 1000 character's when I want to store a 5 character string in it.  So I shouldn't have to do it here.

After I "fixed" my program my confusion is:
Why is there __READMEM and __WRITEMEM in the pseudo "declares" in ebstd.incc with 4 parameters but there is no documentation for them?
Why is there READMEM and WRITEMEM in the documentation with 3 parameters but the pseudo "declares" for them in ebstd.incc don't show any parameters?

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

REDEBOLT

Point #1:
Quote1. And most important, the program works exactly like I want it to when I made the changes as indicated in my last post.
Something I learned many years ago is this: "Just because it works doesn't mean it is right."  You have to know the circumstances and reasons for its existence in order to use it correctly.  I am leery about using any function/statement with preceding underscores. These indicate to me that they may be internal to the operation of the compiler.  Further, they are undocumented, which lends credence to the above.

Point #2:
Quotek$=space$(1000) defeats what I'm trying to do.  That would mean that I would have to pad strings that I want to store to insure that were 1000 characters long. I shouldn't have to do that.  I don't have to pad an ISTRING  def as 1000 character's when I want to store a 5 character string in it.  So I shouldn't have to do it here.

You missed the context of using k$=space$(1000). This statement makes k$ 1000 bytes before you READMEM.  The contents of the allocated record contains only the 80 bytes you stored there with WRITEMEM.

Note, however, that when you allocated the buffer, you specified 20 records of 1000 bytes each.  Therefore, when you WRITEMEM buffer,1,k$ and you specified that len(k$) was 80 bytes by assignment, then you are wasting 920 bytes in the first record of the allocated space.

It sounds to me that you are trying to create a dynamic string space that holds a number of strings without wasting memory.  The STRING type in Ebasic is a static, fixed length, space in memory which occupies 255 bytes.  No matter what length of string (less than 255 bytes) you assign to it, it still occupies 255 bytes of memory.  ISTRING is not a data type, but rather a modification of the STRING type which allows you to specify a string size from 1 to the amount of available memory.  When you istring k$[1000], you have set aside enough space to hold 999 bytes of string data.  When you assign 80 bytes to this space, you still have 919 bytes of unused space in the string space.  ISTRING simply reserves a fixed amount of memory which never changes size.  It is the length of the assigned string which changes size.

I believe, and I hope Paul will correct me, that if you want dynamic strings, you will have two options:

Option #1:  Set aside enough space to hold all the strings, then use the mid$ command to store the strings.

Option #2:  <better> define an array of string pointers large enough to hold the maximum number of string pointers.  Then define a string with the length desired (+1) with the NEW command and store its pointer in the array.  Then you can access the string indirectly through its pointer by its index.  If you wish, I can try to conjure up an example.  If you don't know the size of the array, i.e., you can't predict the number of strings to keep track of, use a linked list.  An LL is much easier to work with when it comes to adding and deleting nodes.

Do you have an explicit example we could use for practice?

Incidentally, I was wrong about k$=space(1000). It should be k$=space(999) to allow for the terminating null character.

Regards,
Bob

LarryMc

Thanks for all the explaining.

What I'm doing is experimenting.

The 80 came from 80 columns in a console window.  It was just an arbitrary number that was less than 1000.

The 1000 was an arbitrary number greater than 255.
The whole point is the handling of variable len strings.

QuoteI am leery about using any function/statement with preceding underscores. These indicate to me that they may be internal to the operation of the compiler.  Further, they are undocumented, which lends credence to the above.
They're documented to the extent that Paul put them in the .incc and made them highlighted commands.  And they are written in EBasic. I can rewrite them and give them a name without the underscores. Your suggestion to 'initialize' k$ to 999 before using it to read is extra clock cycles.

As for wasting space, IF I was going to store 80 bytes in 1000 bytes I indeed would be wasting space; just like we do anytime we use string variables  We waste space all the time in dbase files. We trade the space for the functionality.

I use Mid$ all the time and am aware of it's functionallity.

I've used pointers before.  The program I wrote for Paul to use to generate the Aurora help files used them.  I understand how they work but they are NOT my FRIEND and never will be.  I'm just an old fogey who is a shadetree programmer and I'm not likely to change.

And since I won't be using pointers I'm not going to be using linked lists.

bottom line is:
I'll gladly waste a little memory as a trade off against ease of programming and understanding as long as my application(and potential users of it) don't noticeably suffer.

Since I'm a hobby programmer, when the tools available to do the application programming become the focal point of concentration as opposed to the application itself I believe in trying to find alternative tools.

Again, your posting is very informative and I do not dispute your statements.  I appreciate the time you spent in making it.  I know there are many people out there that will benefit much more than I from your comments.  But that's my fault, not yours.

Again thanks. :)
Larry

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

Bob,
Since you mentioned linked-list.
There are the commans to insert at the head of the list and insert at the end of the list.

What's the method/technique for inserting something in the middle of the list?

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

REDEBOLT

Apparently there is no way to insert a node into the middle of a simple linked list.  You can, however, delete a node in the middle of a list.  If you want this capability, you will need to roll your own bi-directional list.  Also called "double linked list," you can google on this phrase to find sites that show how they work.

This sounds like a good candidate for an object class.
Regards,
Bob

LarryMc

The "double linked list," would also allow us tp back 'up' a list also.


If I was an ace I write a class (but I ain't)........remember, shadetree! ;)

I always seem to know enough to be dangerous.  Maybe the next 60+ years will be better than the last ;D
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Rock Ridge Farm (Larry)

April 18, 2007, 05:51:14 AM #9 Last Edit: April 18, 2007, 05:52:56 AM by Rock Ridge Farm (Larry)
Another 60 - do not think I could do that - things hurt bad enough already.
Every morning I find a new pain - natures way of telling you 'you are still alive'.
Also - I do not think many people use double linked list anymore. That was a biggie in our generation.
Could be wrong - not the first time.

LarryMc

If I'm looking at it correctly, EBasic uses a double-linked list.

TYPE LINKEDLIST
DEF pNext as POINTER
DEF pPrev as POINTER
DEF pData as POINTER
ENDTYPE

and Aurora

//list classes
struct _linked_list
{
_linked_list *pNext;
_linked_list *pPrev;
pointer pData;
}


Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Rock Ridge Farm (Larry)

OK - What do I know - I am just a old moron. :)

LarryMc

Thing is, I just told you all I know but I don't always 'know' what I 'know'.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

REDEBOLT

Quote from: Larry McCaughn on April 18, 2007, 06:06:08 AM
If I'm looking at it correctly, EBasic uses a double-linked list.

TYPE LINKEDLIST
DEF pNext as POINTER
DEF pPrev as POINTER
DEF pData as POINTER
ENDTYPE

and Aurora

//list classes
struct _linked_list
{
_linked_list *pNext;
_linked_list *pPrev;
pointer pData;
}


Larry

Yes, it is defined in ebstd.incc.  But that is no gaurantee that it is used internally by the list statements.  You could use it though to roll your own double linked list.  It would be very handy to create an object class.
Regards,
Bob

REDEBOLT

Quote from: Larry McCaughn on April 17, 2007, 07:22:07 PM
I always seem to know enough to be dangerous.  Maybe the next 60+ years will be better than the last ;D

Well, I have 10 years up on you Larry.  ;D
I'll will be 71 this fall!  ;)
Regards,
Bob

LarryMc

Hang in there, gramps! :D

I'll be 62 in 3 months.
Does that put me in the category as a young fogey?
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

REDEBOLT

Better to be over the hill than under it  :D
Regards,
Bob

Rock Ridge Farm (Larry)

You old guys are making me feel young.

Parker

They are doubly linked but there are some missing functions. I think I had an EB linked list class around here that has a GetPrev and GetLast.

LarryMc

April 19, 2007, 05:35:12 PM #19 Last Edit: April 19, 2007, 05:38:01 PM by Larry McCaughn
Parker,
I'm just about through with a linklist class that has
create
deleteall
deletecurrent
getfirst
getnext
getprev
getlast
addhead
addend
addhere
getcount
getdata

I decided I could use linked list IF I had those extra functions plus it was a way to play with pointers some more.

I should have a static lib posted in a day or 2.

Larry

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Rock Ridge Farm (Larry)

If you are not writing a compiler - where would you use this?

REDEBOLT

April 19, 2007, 07:58:40 PM #21 Last Edit: April 19, 2007, 08:04:35 PM by REDEBOLT
There are a couple of illustrated articles on codingmonkeys that you may find interesting.  Look under "Latest uploads."
Regards,
Bob

LarryMc

I'm working with xml.

I found a free xml dll that had limited parsing functions.  Since I didn't have the source I couldn't add any.

Xml is very structured, as you may well know.
I'm not a C programmer and MSXML is not suitable for my needs on multiple levels.

I've written a XML parser that breaks lines into their individual components:
start tag name
attribute name
attribute data
tag data
end tag

Since I'm working with line based entries that are comprised of various numbers of fields of various lengths it appears that linklist will serve my purpose.

However, the functions currently available in EBasic don't allow me to manipulate the list the way I need to:
I need to be able to insert before and/or after a given point. (for the adding of xml comments and the nesting of tags.)

So, to answer you question (finally); I need the features to manipulate xml file entries.

Obvious next question; "why do you want to use xml files?"

They're much easier to deal with than .ini files and you can edit them with a regular text editor.

A program could use one xml file to store multiple application configuration parameters:
   Multiple languages for prompts comes to mind.
   Multiple screen size optimization also comes to mind.

You could easily store recent used files without getting into the registry.

One of the primary reasons for me is that one of the applications I use to maintain my family history and generate over 10,000 webpages is being converted over to use xml files for the storage of configuration information and user design preferences.

I've written some custom programs that use that information which saves me over 2 hoiurs everytime I regen my website.
If I want to continue to be able to do that AND take advantage of the new features in the 3rd party application then I need to adapt.

And, as Lily Tomlin would say; "And that's the truth!"

Larry

Plus I'm playing.

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

April 19, 2007, 08:43:28 PM #23 Last Edit: April 19, 2007, 08:50:46 PM by Larry McCaughn
Quote from: REDEBOLT on April 19, 2007, 07:58:40 PM
There are a couple of illustrated articles on codingmonkeys that you may find interesting.  Look under "Latest uploads."

I looked at that and I have even corresponded with the guy who wrote the articles.
He had code to read xml files but abandoned it with the collapse of Pyxia.  He was firm about not fooling with it anymore.

His articles don't even have the functionaly that Paul's LL have.

Also his article has other limitations.

He is using a UDT for his data.
That limits the number of fields to a fixed number and a fixed length on strings.
I need to be able to address strings greater than that.
I need to be able to handle an umlimited number of attributes.

I'll have a UDT but for strings the entry will point to a memoyr block.

For attributes my UDT will contain a pointer to another linked list who data is a UDT with pointers to attribute name in memory and attribute data in memory.

What his example is doing is holding a flat file in memory.  Nothing is nested.

Here's an extract of information for one person in my genealogy output using xml(my particular branch has over 50,000 of these)(and my total database has 47 branches):

<ppe>
  <pref id="9007">
   <name>(?) (?)</name>
   <gender>F</gender>
  </pref>
  <lifespan>b. between 1853 and 1873, d. between 1878 and 1957</lifespan>
  <tag type="birth" p="1" w="0" id="11104">
   <role>Spouse</role>
   <value type="label">Birth*</value>
   <value type="date">between 1853 and 1873</value>
  </tag>
  <tag type="marriage" p="1" w="0" id="45448">
   <role>Spouse</role>
   <value type="label">Marriage*</value>
   <value type="date">between 1874 and 1907</value>
   <pref p="1" id="8839">
    <name><![CDATA[<SPAN CLASS="ng">James Montgomery</SPAN> <SPAN CLASS="ns">Nunn</SPAN>]]></name>
    <href>p928.htm#i8839</href>
    <role>Spouse</role>
    <gender>M</gender>
   </pref>
  </tag>
  <tag type="death" p="1" w="0" id="11105">
   <role>Spouse</role>
   <value type="label">Death*</value>
   <value type="date">between 1878 and 1957</value>
  </tag>
  <tag type="name" p="0" w="0" id="38590">
   <value type="label">Married Name</value>
   <value type="name"><![CDATA[<SPAN CLASS="ng">(?)</SPAN> <SPAN CLASS="ns">Nunn</SPAN>]]></value>
  </tag>
  <family>
   <partner>
    <pref p="1" id="8839">
     <name><![CDATA[<SPAN CLASS="ng">James Montgomery</SPAN> <SPAN CLASS="ns">Nunn</SPAN>]]></name>
     <href>p928.htm#i8839</href>
     <gender>M</gender>
    </pref>
    <lifespan>b. 1857, d. between 1878 and 1947</lifespan>
   </partner>
   <child>
    <pref p="1" id="9008">
     <name><![CDATA[<SPAN CLASS="ng">Lura Lee</SPAN> <SPAN CLASS="ns">Nunn</SPAN>]]></name>
     <href>p929.htm#i9008</href>
     <gender>F</gender>
    </pref>
    <lifespan>b. bt 1878 - 1907, d. bt 1883 - 1989</lifespan>
   </child>
   <tag type="marriage" p="1" w="0" id="45448">
    <role>Spouse</role>
    <value type="label">Marriage*</value>
    <value type="date">between 1874 and 1907</value>
    <pref p="1" id="8839">
     <name><![CDATA[<SPAN CLASS="ng">James Montgomery</SPAN> <SPAN CLASS="ns">Nunn</SPAN>]]></name>
     <href>p928.htm#i8839</href>
     <role>Spouse</role>
     <gender>M</gender>
    </pref>
   </tag>
  </family>
</ppe>

The number of information items in this example is rather simple:
One person, one marriage; one kid;etc

One UDT does not fit all.

By outputing information in this manner I can use XLST and template files to generate html for web pages or by simply changing a template I can have it formated to print to a text file or to a MSWord doc.

anyway, enough of my babbling.

When I get it done (the LL class) as well as my XML parser I will post static libs and .inc files on the forum for those who might be interested.
I've got this many methods coded right now. declare Create(),INT
declare ClearAll(OPT DeleteData=0 as INT)
declare DelCurrent(OPT DeleteData=0 as INT)
declare AddEnd(pData as POINTER),POINTER
declare AddHead(pData as POINTER),POINTER
declare GetLast()
declare GetFirst()
declare GetPrev()
declare GetNext()
declare ReadData(),POINTER
declare Count(),int


I'm currently working on the AddBefore and AddAfter.

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

peterpuk

Keep up the good work, Larry Mc.

Linked lists, XML, etc. are all ways to store and manipulate data, and serve a purpose.

Over the last thirty years I have written many applications that output data to text files, sort the records, then read them back for further processing. Worked well then and still does now. Also, it was the only way to pass data from one application to another. :)

It will be good to see how your library develops.
Peter