Jump to content

Create a SEQ file in BASIC


rje
 Share

Recommended Posts

In order to do this, you need to boot with an SD image.  For example

 

~/commanderx16/x16emu_mac-r38/x16emu -sdcard ~/git/x16-a1-sd.img

Now you can get things done.  Here's a BASIC program that creates a new SEQ file.

You'll probably want to write several separate pieces of data.  The comma will separate data for you in a way that INPUT# knows how to read back in.  

100 OPEN 2,8,2,"0:MY-NEW-FILE,SEQ,W"
105 CO$ = "," 
110 PRINT#2, "ROB"; CO$; "10"; CO$; "2020"; CO$; "TEXAS"
120 CLOSE 2

The CO$ inserts actual commas into the SEQ file, so we can read them back in individually.  Otherwise INPUT# would treat the thing as one long line.

To read the SEQ file:

100 OPEN 2,8,2,"0:MY-NEW-FILE,SEQ,R"
110 INPUT#2, N$, M, YR, S$
120 CLOSE 2

 

Edited by rje
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

9 hours ago, rje said:

Here's a BASIC program that creates a new SEQ file.
(You'll probably want to write several separate pieces of data.  The comma will separate data for you in a way that INPUT# knows how to read back in.)


100 OPEN 2,8,2,"N0:MY-NEW-FILE,SEQ,W"
110 PRINT#2, "ROB", 10, 2020, "TEXAS"
120 CLOSE 2

 

That "N" in the "N0:" will be ignored; don't put it in the string.  And, don't bother to spell out the "SEQ".  Just use the initial letter:

100 OPEN 2,8,2,"0:MY-NEW-FILE,S,W"
Edited by Greg King
  • Thanks 1
Link to comment
Share on other sites

Quote

That "N" in the "N0:" will be ignored; don't put it in the string.

Thanks for the "N" bit... a holdover to the Bad Olde Days!

Quote

And, don't bother to spell out the "SEQ".  Just use the initial letter:

Because it's a clarification ("SEQ" is more obvious than "S") rather than a confusion (the "N" prefix is a confusion), I'd recommend always keeping this bit of syntactic sugar... especially when you've got the extra two bytes to spend.

Edited by rje
Link to comment
Share on other sites

  • 5 months later...

Yeah, putting a comma in a PRINT statement inserts a tab into the output. So the first program actually printed

ROB<tab>10<tab>2020<tab>TEXAS

If you're trying to create a list of comma delimited values, for example  to read back in for later use, then Scott's solution is correct: print a literal comma to the file. Or just print one item per line, like so:
PRINT#2, "ROB"
PRINT#2, "10"
and so on.

 

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

Thanks Rob for the correction of your code in the original post. The code works as expected. 

Quote

You'll probably want to write several separate pieces of data.  The comma will separate data for you in a way that INPUT# knows how to read back in.  


100 OPEN 2,8,2,"0:MY-NEW-FILE,SEQ,W"
105 CO$ = "," 
110 PRINT#2, "ROB"; CO$; "10"; CO$; "2020"; CO$; "TEXAS"
120 CLOSE 2

The CO$ inserts actual commas into the SEQ file, so we can read them back in individually.  Otherwise INPUT# would treat the thing as one long line.

 

Yes that worked correctly:

1918564284_ScreenShot2021-08-31at3_56_21PM.png.81262c248b01a8b5eb95a0d77312c676.png

Likewise the read code worked once I gave it the proper SEQ file name. 🙂

regards,

Edmond

 

Link to comment
Share on other sites

You're welcome.

And thank you review team!  It's been decades since I did any file ops on Commodore equipment.

 

Note that there's an "input pattern" required if you're expecting to have null values in the data stream -- I can't quite remember it, but I think it involves injecting a chr$(0) into the input to safeguard against it.

 

Edited by rje
  • Thanks 1
Link to comment
Share on other sites

1 hour ago, rje said:

You're welcome.

And thank you review team!  It's been decades since I did any file ops on Commodore equipment.

 

Note that there's an "input pattern" required if you're expecting to have null values in the data stream -- I can't quite remember it, but I think it involves injecting a chr$(0) into the input to safeguard against it.

So the issue with CHR$(0) and NULL is a problematic one. 

Writing a zero out to disk works fine: PRINT#8, CHR$(0);

However, reading a Zero byte from disk with the GET command will actually return a Zero Length String, aka "". So, because we obviously need file I/O in BASIC to be even slower, you have to check every read against "" when reading binary data. So the pattern goes like this:

100 OPEN 8,8,8,"MyFile,S,R"
110 A=0
120 GET#8, A$
130 IF A$<>"" THEN A=ASC(A$)
140 IF ST <> 0 THEN 200
150 do things 
160 GOTO 110
200 check command channel for errors
250 CLOSE 8

The critical part is lines 110-130. This starts A with a value of zero, so when we get to the IF statement, we already have the null value handled. The IF sets A to the value of the character read for non-null values, and then we get to to the core of the program at 150. 

Line 140 is just the standard EOF check, which diverts to 200 to check the disk status and close the file. You really want to read the command channel in line 200 to make sure that you didn't get some sort of error on the last GET before closing the file. 

I feel like this might be a good time to sit down and do some proper tutorials for disk I/O, covering basic I/O, error handling, and the Position (or seek) command. 

 

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, TomXP411 said:

I feel like this might be a good time to sit down and do some proper tutorials for disk I/O, covering basic I/O, error handling, and the Position (or seek) command.

I plan on making one for assembly development as soon as that kernal code is stable and fully functioning in the emulator. Unfortunately, progress on that has been stalled for many months.

Link to comment
Share on other sites

I could swear I saw an easier way to handle those nulls.  Ah something like this:

...
120 GET#8, A$
130 A=ASC(A$ + CHR$(0))        :REM NULL PROTECTION PATTERN
140 IF ST <> 0 THEN 200
...

Here's where I found it, this time around.  I think I've also seen it on the "C64 Programming" Facebook page.

https://www.lemon64.com/forum/viewtopic.php?p=181978&sid=5e9b35d1a6b8e77a89c45bb383be70cf#181978

Quote:

30 print asc(t$): rem display the byte in ASCII code

Make that

Code:
30 print asc(t$+chr$(0))

so it won't barf when it encounters chr$(0) which get# returns as empty string.

=====================================================================================================

* Upside: terser code.

* Downside: string cat is probably slower.

* Downside: might encourage the garbage collector to run.

 

^ So, good for small files, bad for big files?

 

 

Edited by rje
Link to comment
Share on other sites

42 minutes ago, rje said:

* Upside: terser code.
* Downside: string cat is probably slower.
* Downside: might encourage the garbage collector to run.
^ So, good for small files, bad for big files?

Yeah, you're trading an IF statement for some string concatenation. I'll go run both and see what we get.

 

Link to comment
Share on other sites

A quick test shows my version is slightly faster...

writing 25K to disk (CHR$(0)-CHR$(255) 100 times) took about 28 seconds.

Reading back using the IF took 53 seconds

Reading back using ASC(A$+CHR$(0)) took 54 seconds.

And since it's not spawning 25,600 tiny strings, I'm going to say that the IF version is a better choice in any situation I can think of where you need binary data.

	10 REM CREATE TEST FILE
15 TI$="000000":PRINT "WRITING TEST FILE"
20 OPEN 8,8,8,"@0:TESTFILE,S,W"
30 FOR I=1 TO 100
40 FOR C=0 TO 255
50 PRINT#8,CHR$(C);
60 NEXT C,I
70 CLOSE 8
80 PRINT TI$
100 OPEN 8,8,8,"TESTFILE,S,R"
105 PRINT "READ TEST 1":TI$="000000"
110 A=0
120 GET#8,A$
130 IF ST<>0 GOTO 200
140 IF A$<>""THEN A=ASC(A$)
150 GOTO 120
200 CLOSE 8
210 PRINT TI$
300 OPEN 8,8,8,"TESTFILE,S,R"
305 PRINT "READ TEST 2":TI$="000000"
320 GET#8,A$
330 IF ST<>0 GOTO 360
340 A=ASC(A$+CHR$(0))
350 GOTO 320
360 CLOSE 8
370 PRINT TI$
	


 

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

1 hour ago, SlithyMatt said:

I plan on making one for assembly development as soon as that kernal code is stable and fully functioning in the emulator. Unfortunately, progress on that has been stalled for many months.

I'm waiting for similar reasons; there are promised changes coming to the emulator and the ROMs, but they have not actually been happening.... and with the emulator in this weird, quantum "released but not released" state, I don't want to write any code for the current iteration.

I don't think the guys realize how much not having a binary release is holding the community back right now.

 

  • Like 1
Link to comment
Share on other sites

With me, it's a kind of reluctance to write VERA sprite code in C.  That's my next project.

We've got examples.  It's not like there isn't any code.

But there's something about it that just makes me wince.

 

Link to comment
Share on other sites

I always overcomplicated things!  

 

My approach back in the day was to do it all in one line for the read, null handling, and conversion to a number:

20 GET#8, A$: A=1+(A$=""):IF A THEN A=ASC(A$)

 

 

Funny how there are so many different ways.   

BTW, I have no idea how mine performed, it never mattered when you knew you were waiting on the 1541! 

 

 

Edited by Snickers11001001
Link to comment
Share on other sites

1 hour ago, rje said:

I guess we could fix GET#.

Meh, probably not.

I seem to recall through the haze of history that there was a relatively simple patch for BASIC published in Compute's Gazette or similar that fixed ASC to return 0 for an empty string. That would probably be simple to integrate, and it would be compatible with v2, just one less error case to check. People who already check for empty string would not see a difference, and the rest would have it easier.

  • Thanks 1
Link to comment
Share on other sites

1 hour ago, rje said:

I guess we could fix GET#.

Meh, probably not.

 

 

53 minutes ago, Scott Robison said:

I seem to recall through the haze of history that there was a relatively simple patch for BASIC published in Compute's Gazette or similar that fixed ASC to return 0 for an empty string. That would probably be simple to integrate, and it would be compatible with v2, just one less error case to check. People who already check for empty string would not see a difference, and the rest would have it easier.

IMO, both should be done. GET# should return a 0 when the data on the channel is a zero. And ASC should not choke on a zero length string. 

 

  • Like 1
Link to comment
Share on other sites


EDITED:   Well, I tried both the Plus/4 and C128 emulators and, on both, the following worked fine:

10: A$=""
20 A=ASC(A$)
30 PRINT A

So, just a matter of tracing the assembly code for ASC() and seeing where the difference is.  ('just' hahaha)

Edited by Snickers11001001
  • Like 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.

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.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use