Jump to content

File pointers in CC65!


rje
 Share

Recommended Posts

So for some reason I only now started playing with CC65's file i/o.

And... it looks like it just works.  I haven't tried *real* things yet, but this opens up my horizons.

 

  • Like 1
Link to comment
Share on other sites

I'm going to need to either read a file byte by byte or else just pull pieces in at a time, so if cc65's fread () works right out of the box, that will be quite nice. I presume this code fails when using the host FS?

Link to comment
Share on other sites

Yes, only the load and save functions work on the emulator's filesystem.

Standard I/O and POSIX I/O work on the SD filesystem as the standards say that they should.  However, subdirectories don't exist in CBM DOS.  Therefore, those functions might not work in CMNDR DOS as you would expect.

Edited by Greg King
Link to comment
Share on other sites

Posted (edited)

R38

I've just attempted to write a file to the SD image... and I think it works.

Yes, it works.  Just don't mount the image on your computers file system at the same time you're running code on the X16 to modify that image.

 

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

Posted (edited)
4 hours ago, Greg King said:

Yes, only the load and save functions work on the emulator's filesystem.

Standard I/O and POSIX I/O work on the SD filesystem as the standards say that they should.  However, subdirectories don't exist in CBM DOS.  Therefore, those functions might not work in CMNDR DOS as you would expect.

I will be attempting directory reads next, so I'll find out what happens. 

I know it's no guarantee, but 16DOS knows to at least acknowledge the existence of dirs.

Screen Shot 2021-08-10 at 8.50.05 AM.png

Edited by rje
Link to comment
Share on other sites

Posted (edited)

How many files can a directory have?  Is it typical for the image filesystem?

I'll go check.

"CBM-DOS for FAT32 SD cards"

Well let's see what FAT32 can handle first.  (268 million files for 32kb clusters).

And now to see if we have any limitations on that.

Edited by rje
Link to comment
Share on other sites

FAT32 has a limit of 65536 files in a given directory, but!

Two are already used for the current and parent (. & ..) entries in subdirectories but not the root.

If a file has a simple 8.3 file name, then it only takes one entry. If a file has a long file name, it takes a variable number of entries (one extra entry per 13 characters in the LFN).

Link to comment
Share on other sites

Posted (edited)
45 minutes ago, Scott Robison said:

FAT32 has a limit of 65536 files in a given directory, but!

Two are already used for the current and parent (. & ..) entries in subdirectories but not the root.

If a file has a simple 8.3 file name, then it only takes one entry. If a file has a long file name, it takes a variable number of entries (one extra entry per 13 characters in the LFN).

Thank you for ALL of that.  The 8.3 AND the 2^16 - 3 limits.  That helps me plan.

So let's see.  The filenames I want to use will be larger than 8.3.  Call it two entries.

Maximum files per directory is therefore around 32,700.

Not a problem at all.

Edited by rje
Link to comment
Share on other sites

Note that the way FAT32 works is: Every file has an 8.3 entry. If it has a long file name, it also has additional entries per 13 character part.

For example, a file name x16emu.exe has a file named X16EMU.EXE (because traditional file names are all uppercase). Then it will have a single long name entry because x16emu.exe is under the 13 character limit. So if you are planning on say 16 character names, you'll use 3 entries: 1 for the short, 2 for the long.

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

Posted (edited)
3 hours ago, Scott Robison said:

Note that the way FAT32 works is: Every file has an 8.3 entry. If it has a long file name, it also has additional entries per 13 character part.

Ah OK.  Oh.... sure I remember seeing this back when we had DOS windows.  It would list the 8.3 name, complete with funny characters.  Windows would show the longname.  

 

Edited by rje
Link to comment
Share on other sites

Posted (edited)

Oh --- yeah I'll do that.

In the meantime, I can create files with content.  I don't know how to read them (yet).

NOTE: of course, you can't even COMPILE source with fgets(buf, 251, fp).  fgets won't accept anything above 250 bytes.  The docs do mention this.

 

Edited by rje
Link to comment
Share on other sites

In the meantime, I decided just to try a local directory read.

DIR* dp = opendir( "test1");  

dp is NULL.  I might need to phrase the directory differently... like ".//test" or something.  I seem to remember I had a thread here on 16DOS...

 

Link to comment
Share on other sites

Posted (edited)

Yeah ok, here's comments from cbm.h.

unsigned char __fastcall__ cbm_open (unsigned char lfn, unsigned char device,  unsigned char sec_addr, const char* name);
/* Opens a file. Works just like the BASIC command.
** Returns 0 if openning was successful, otherwise an error-code (see table)
*/

void __fastcall__ cbm_close (unsigned char lfn);
/* Closes a file */

int __fastcall__ cbm_read (unsigned char lfn, void* buffer, unsigned int size);
/* Reads up to "size" bytes from a file into "buffer".
** Returns the number of actually-read bytes, 0 if there are no bytes left.
** -1 in case of an error; then, _oserror contains an error-code (see table
** above).  (Remember:  0 means end-of-file; -1 means error.)
*/

int __fastcall__ cbm_write (unsigned char lfn, const void* buffer, unsigned int size);
/* Writes up to "size" bytes from "buffer" to a file.
** Returns the number of actually-written bytes, or -1 in case of an error;
** _oserror contains an error-code, then (see above table).
*/

Edited by rje
Link to comment
Share on other sites

Posted (edited)

The above commands appear to work.  I've tried them out with success, like so:

void readFile(const char *filename)
{
    char s[200];
    unsigned char lfn = 1;
    unsigned char dev = 8;
    unsigned char sec_addr = 0;
    unsigned char res = cbm_open(lfn, dev, sec_addr, filename);

    // read the first 200 bytes of the file.
    if (res == 0)
    {
        cbm_read(lfn, s, 200);
        cbm_close(lfn);
    }
    
    printf("data: %s\r\n", s);
}
 
	
Edited by rje
  • Like 1
Link to comment
Share on other sites

Posted (edited)
11 hours ago, Greg King said:

We use https://github.com/cc65/cc65/blob/master/targettest/dir-test.c to test our standard directory functions.

(Ignore the comment at the top of the file!  It describes the CBM library implementation, not the test program.)

@Greg King, would it be wrong for me to add timestamp fields to cbm_readdir?  I know most CBM devices don't read or write timestamp, but the directory entries have space for it, and it's used in the later drives, so....

...and I didn't see tests for cbm_opendir, _readdir, etc.  Where would I put "unit" tests for these?

And how do I make and submit document MRs?  

OK I'll start by cloning the repo and looking around.  Should I fork it?

Edited by rje
Link to comment
Share on other sites

Posted (edited)

This also seems to work fine:

void readFile2(const char *filename)
{
    char buf[200];
    FILE *fp = fopen( filename, "r" );
    if (fp)
    {
        fgets(buf, 100, fp);
        fclose(fp);
        printf("data: %s\n", buf);
    }
}
Edited by rje
Link to comment
Share on other sites

Posted (edited)
2 hours ago, Greg King said:

You should use
printf();
in an example about stdio code.

Updated.

It is messy, isn't it?  CC65 pushes conio to us, and yet stdio is... well, stdio.  The reality is that my code is always a work in progress.

Edited by rje
Link to comment
Share on other sites

Posted (edited)
On 8/11/2021 at 9:43 AM, rje said:

@Greg King, would it be wrong for me to add timestamp fields to cbm_readdir?  I know most CBM devices don't read or write timestamp, but the directory entries have space for it, and it's used in the later drives, so....

...and I've found the answer: no.  Reading $ means reading the "directory file" built by LOAD.  If that thing doesn't include timestamp, then this one won't ever see it.

Edited by rje
Link to comment
Share on other sites

29 minutes ago, rje said:

Updated.

It is messy, isn't it?  CC65 pushes conio to us, and yet stdio is... well, stdio.  The reality is that my code is always a work in progress.

It really depends on what you're trying to do. cprintf is not part of standard C, but it is offered by many platforms. And it doesn't have the potential overhead of processing data as a file stream, so it can be (not that it is guaranteed to be) faster when you *know* you want to write to the screen and not whatever is pretending to be the standard output stream.

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