Jump to content
IGNORED

Simple file IO disk operations question


Sinphaltimus

Recommended Posts

  • 5 weeks later...

So to follow up on this because it's something I haven't fully grasped.

This topic lead to the development of my console vs console number guessing game.

I am currently using (Yes I know how inefficient it is) one file per variable so when I need to know the value or change the value of a single variable, I know what file to open.

How do you handle this in a single file?

I have seen from the examples given that you can easily load and save ALL variables in a file but what if you only want to change one of those variables and then retrieve only one of those variables?

Do you really have to save them all (even if only one of their values changes) and then load them all later (if you need to retrieve only one value)?

 

Asked another way...

 

It's like a 1 dimensional array but you have no way to access and manipulate the single values in that array without reloading and then saving the entire array. Am I correct in that assumption?

 

If my assumption is wrong, then say I want to store a 2D array and then manipulate only a single value within it and reliably retrieve only a single value in it without loading and saving the entire array each time.

I'm going to guess that there is a lot of coding to take place in order to do such things and their is nothing "Built in" (DSR or otherwise) to help facilitate this.

 

I imagine you assembly coders approach this entirely differently and can probably store arrays to disk by dumping reallocated memory regions, let's try to keep this any answers grounded in BASIC, XB or RXB.

Because I'm no where near ready to start understanding assembly yet.

Edited by Sinphaltimus
  • Like 1
Link to comment
Share on other sites

Based on your question, I think you can do this with a relative file and get what you want. Especially since you are essentially using a number of sequential files to do what the relative file can do for you.

 

Assume you have 5 variables you want to keep track of and save in the file, A-E - this uses Extended BASIC syntax just for a couple of lines to make my example easier, but all of this can be do in exactly the same way with TI BASIC.

10 A,B,C,D,E=1
20 OPEN #1:"DSK1.VARS",UPDATE,RELATIVE,FIXED
25 REM PUT THE 5 RECORDS ON THE FILE
30 PRINT #1:A::PRINT #1:B::PRINT #1:C::PRINT #1:C::PRINT #1:D::PRINT #1:E
35 REM CODE RUNS AND NOW UPDATE RECORD 3
40 PRINT #1,REC 2:25
45 REM WHAT WAS IN RECORD 1?
50 INPUT #1,REC 0:X
55 REM X+E INTO RECORD 5
60 PRINT #1,REC 4:X+E
65 REM NOW LET'S SEE WHAT'S IN ALL THE RECORDS
70 RESTORE #1
80 FOR I=0 TO 4::INPUT #1:Y::PRINT Y::NEXT I
90 CLOSE #1

With a relative file, you must used fixed length records, so that the computer knows where the next record starts. But you can open a relative file in UPDATE mode, and then read and write any specific record in the file, or you can process them all just as if they were a sequential file. The record numbers start at 0, so the 3rd record in the file is referenced by using REC 2 on your PRINT and INPUT statements.

 

With just a little rework in your program, you can change from multiple files to multiple records in a single relative file fairly easily.

Edited by Casey
  • Like 1
Link to comment
Share on other sites

Id ask how many values we are talking about?

 

In my Werewolves Game, I pull 252 numeric variables from disk at the start of the game and populate a 2 dimensional array on the fly. I also pull 120 string variables from disk on each floor and populate a 2 dimensional string array on the fly. During any given point in the game, I can pull whatever value I need from either of these arrays and manipulate it. Then you can write a super small routine (3-4 lines of code) to break down the arrays in the same manner you built them and re-write your file to disk.

 

If youre maintaining 30-40 different variables with 30-40 different files, then I suggest using either Caseys method, or pulling the whole data set and then re-writing it once youve manipulated what you need. I can help you with this if youd like.

  • Like 2
Link to comment
Share on other sites

Id ask how many values we are talking about?

 

In my Werewolves Game, I pull 252 numeric variables from disk at the start of the game and populate a 2 dimensional array on the fly. I also pull 120 string variables from disk on each floor and populate a 2 dimensional string array on the fly. During any given point in the game, I can pull whatever value I need from either of these arrays and manipulate it. Then you can write a super small routine (3-4 lines of code) to break down the arrays in the same manner you built them and re-write your file to disk.

 

If youre maintaining 30-40 different variables with 30-40 different files, then I suggest using either Caseys method, or pulling the whole data set and then re-writing it once youve manipulated what you need. I can help you with this if youd like.

 

7. 7 total. My next game might be double that. :)

  • Like 1
Link to comment
Share on other sites

So let's start off with making your initial data file. We will need to populate it with all the starting values of your variables. The easiest way to do this is with a small, unrelated program (which is not part of your main game or variable handling routines). This stands alone, and you only need to use it once. After that, the main program will do all this for you.

 

 

 

Here we open a new file, we name it, we set it to be INTERNAL and then we proceed to populate it with numbers.

100 OPEN #1:"DSK1.TIPIDATA",INTERNAL
110 FOR X=1 TO 7
120 READ A
130 PRINT #1:A
140 NEXT A
150 CLOSE #1
1000 DATA 103,5,3,9,2,5,17

Thats it thats the whole program.

 

 

 

 

 

Now, for your game this code will have to be in there. You can determine where you want to put it, based on your needs.

10 DIM A(7)  ***at the top of the program
 
 
100 OPEN #1:"DSK1.TIPIDATA",INTERNAL
110 FOR LOOP=1 TO 7
120 INPUT #1:A(LOOP)
130 NEXT LOOP
140 CLOSE #1
 

 

What this does is opens your data file and populates the array with the data in your disk. You'll have 7 values in your array. You can then manipulate them using whatever method you choose.

 

**For instance**

550 REM IF PLAYER INPUTS "1", THEN CLEAR OUT VALUE 'A(3)' AND MAKE IT 'ZERO'
560 CALL KEY(0,K,S)
580 IF K=49 THEN A(3)=0

 

 

 

 

Once you've manipulated the data however you want, you need only save the manipulated

data to diskette. We do this by flipping the script from the initial method.

 

**NOTICE that the only difference here is that we PRINT instead of INPUT.

 

800 OPEN #1:"DSK1.TIPIDATA",INTERNAL
810 FOR LOOP=1 TO 7
820 PRINT #1:A(LOOP)
830 NEXT LOOP
840 CLOSE #1

And continue with your game. The only thing you will have to remember is which entry in your array does what. A simple comment in your code will help you keep track of that.

Edited by Opry99er
  • Like 2
Link to comment
Share on other sites

Thanks for this clear example. This will work well for the existing game. I also have to write a TIPI version that handles variables very differently but remarkably as well. I've been chatting with the Jedi privately on those details.

On a side note, I'm guessing this
810 FOR LOOP=1 TO 36
is supposed to be this

810 FOR LOOP=1 TO 7

so the examples are in tune with each other. Correct?

Link to comment
Share on other sites

  • 3 years later...

edit: NEVERMIND - Not sure what the differences are between dsk files but I am finding some that do not work in c99 (even if I check the V9T9 Reverse option). My fix? Create a new dsk image using TIDIR and copy files from non-working dsk to new dsk and POOF - Load works as expected. I figured this out because to spite TIDIR being able to open the files, I could not index them in classic99. I'm guessing they were made for a specific emulator or something that TIDIR supports.

 

Back to some disk I/O questions. 

I was under the impression that a disk with a file on it called "load" would automatically load the main program on it. So far I've come across two disks that do not. So my assumption must be incorrect. 

So my next question is, what's the difference between disks that actually do load straight into their program and disks that do not when "load" is listed in the cataloging?

 

I guess more to the point, how can I tell the difference ist my looking at the disk listings?

Link to comment
Share on other sites

1 minute ago, HOME AUTOMATION said:

I believe "Auto-load" is only an XB function.:ponder:

Yeah, I was using XB but my issue actually came down to something about the DSK image format. I just edited my initial question with an update.

 

"edit: NEVERMIND - Not sure what the differences are between dsk files but I am finding some that do not work in c99 (even if I check the V9T9 Reverse option). My fix? Create a new dsk image using TIDIR and copy files from non-working dsk to new dsk and POOF - Load works as expected. I figured this out because to spite TIDIR being able to open the files, I could not index them in classic99. I'm guessing they were made for a specific emulator or something that TIDIR supports."

Link to comment
Share on other sites

31 minutes ago, Sinphaltimus said:

(even if I check the V9T9 Reverse option)

DO NOT DO THIS. You are likely to corrupt the file. Despite documentation I saw twenty years ago that says some V9T9 disk images were like that, I've never come across one. This option will be going away.

 

If you have a file Classic99 can't open, send it to me. Classic99 is not a dead product with no support. If it's not something I need to fix, thus improving the experience for everyone, then I can at least tell you why.

  • Like 2
Link to comment
Share on other sites

7 minutes ago, Tursi said:

DO NOT DO THIS. You are likely to corrupt the file. Despite documentation I saw twenty years ago that says some V9T9 disk images were like that, I've never come across one. This option will be going away.

 

If you have a file Classic99 can't open, send it to me. Classic99 is not a dead product with no support. If it's not something I need to fix, thus improving the experience for everyone, then I can at least tell you why.

I've never used this until today to troubleshoot. But thanks for the heads up, I will never use that option again.

One of the DSK files I was having trouble with are attached. They came from whtech in some user group PC99 folder. I'm guessing pc99 files are different somehow.

 

EDIT: I wasn't blaming c99 because at least c99 was throwing disk i/o errors. Which pointed to an issue with the dsk file itself.

 

ENLARGER.DSK

  • Like 1
Link to comment
Share on other sites

Sure, but if it worked elsewhere, then it's likely Classic99 has a bug, right? Fixing bugs helps everyone. Ignoring them only causes me pain down the road.

 

Mind you, it IS Halloween season, maybe that's the goal? ;);):skull:

 

I'll take a peek at this.

 

 

  • Like 2
  • Haha 1
Link to comment
Share on other sites

So it's a PC99/track format disk image. 

 

The debug log says:

 

No DSK marker, assuming PC99 track-based image...
Can't find PC99 start of sector indicator - corrupt dsk?
Can't read sector 0 on D:\new\ENLARGER.DSK.

 

So it detected that much correctly (although it was really guessing). That message comes up when it can't find the 0xfe byte that indicates start of sector. The byte appears to be there. I don't have many PC99 images to test from, but the ones I have also fail.

 

Had to dig into the code... I had a bug where it was loading the sector into a signed char, then searching for 0xfe. While technically wrong (0xfe doesn't fit into a signed char), that used to work. The new compiler appears not to do that as expected. Changing the buffer to unsigned char, like it should have been anyway, fixed PC99 disks. So no PC99 disks were working for anyone since whenever that changed. ;)

 

I'll publish a new version with the fix in a few days.

 

  • Like 5
Link to comment
Share on other sites

1 hour ago, Tursi said:

So it's a PC99/track format disk image. 

 

The debug log says:

 

No DSK marker, assuming PC99 track-based image...
Can't find PC99 start of sector indicator - corrupt dsk?
Can't read sector 0 on D:\new\ENLARGER.DSK.

 

So it detected that much correctly (although it was really guessing). That message comes up when it can't find the 0xfe byte that indicates start of sector. The byte appears to be there. I don't have many PC99 images to test from, but the ones I have also fail.

 

Had to dig into the code... I had a bug where it was loading the sector into a signed char, then searching for 0xfe. While technically wrong (0xfe doesn't fit into a signed char), that used to work. The new compiler appears not to do that as expected. Changing the buffer to unsigned char, like it should have been anyway, fixed PC99 disks. So no PC99 disks were working for anyone since whenever that changed. ;)

 

I'll publish a new version with the fix in a few days.

 

Wow. I never suspected it being an issue with c99. I don't expect every emulator to support everything. I don't really use any others besides c99 except when running my retro pie. However, recently (my TI printer shenanigans) I found using Win994a to work with the print-ti994a printer emulator. it worked for testing prints before taking them to real iron but I could not figure it out in c99. I'm glad to have posted my question then. I'm humbled by your (and others here) expertise and skillsets. Who am I to inadvertently discover a bug? Glad to help make the improvement. Even if by accident.

 

EDIT: I guess what I mean is, I typically think I'm doing something wrong and not that it's the program.

  • Like 1
Link to comment
Share on other sites

2 hours ago, TheBF said:

Just curious about what compiler this is and could it be some kind of un-intended optimization bug?

Microsoft Visual Studio 2019, C++ compiler. Unlikely.

 

Code with buffer as signed char:

		if ((idx >= 256) || (buf[idx] != 0xfe)) {
00E3E051  cmp         dword ptr [ebp-10Ch],100h  
00E3E05B  jge         ImageDisk::VerifyFormat+1A3h (0E3E073h)  
00E3E05D  mov         eax,dword ptr [ebp-10Ch]  
00E3E063  movsx       ecx,byte ptr buf[eax]  
00E3E06B  cmp         ecx,0FEh  
00E3E071  je          ImageDisk::VerifyFormat+1B7h (0E3E087h)  

 

Code with buffer as unsigned char:

		if ((idx >= 256) || (buf[idx] != 0xfe)) {
0102E051  cmp         dword ptr [ebp-10Ch],100h  
0102E05B  jge         ImageDisk::VerifyFormat+1A3h (0102E073h)  
0102E05D  mov         eax,dword ptr [ebp-10Ch]  
0102E063  movzx       ecx,byte ptr buf[eax]  
0102E06B  cmp         ecx,0FEh  
0102E071  je          ImageDisk::VerifyFormat+1B7h (0102E087h)

So you can see it's almost the same code. The issue is coming from the movsx vs movzx. They are both copying the byte into a 32-bit int for the comparison, then comparing to a literal 0x000000fe. movsx does a sign extension, so the byte ends up being 0xfffffffe, which is not equal. (movzx does a zero fill instead). It's doing what it's supposed to... the old version probably compared the bytes as bytes.

 

I think those instructions came along in later CPUs, Pentium era, so likely when it worked I was still compiling for 486 (or even 386!)

 

  • Like 6
  • Thanks 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...