Jump to content
IGNORED

New Atari BBS software.


tschak909

Recommended Posts

To expand on the thought process:

 

I need to be able to load modules into memory to provide the various BBS functions.

 

As it turns out, CC65's linker can do a LOT of funky, flexible things in this department, making files that are of any shape, size, file format imaginable.

 

And if I play my cards right, and define a clean enough API, this means that anyone will be able to make a new cc65 project that can be a module for this BBS.

 

Since I don't have the foggiest clue on how to do this well, I'm just going to have to play around, until I come up with something that's sane.

 

The overlay examples that I posted above, depend on a linker config that generates overlay files.

 

Here's the standard Atari linker config:

 

FEATURES {
    STARTADDRESS: default = $2000;
}
SYMBOLS {
    __EXEHDR__:          type = import;
    __SYSTEM_CHECK__:    type = import;  # force inclusion of "system check" load chunk
    __AUTOSTART__:       type = import;  # force inclusion of autostart "trailer"
    __STACKSIZE__:       type = weak, value = $0800; # 2k stack
    __STARTADDRESS__:    type = export, value = %S;
    __RESERVED_MEMORY__: type = weak, value = $0000;
}
MEMORY {
    ZP:            file = "", define = yes, start = $0082, size = $007E;

# file header, just $FFFF
    HEADER:        file = %O,               start = $0000, size = $0002;

# "system check" load chunk
    SYSCHKHDR:     file = %O,               start = $0000, size = $0004;
    SYSCHKCHNK:    file = %O,               start = $2E00, size = $0300;
    SYSCHKTRL:     file = %O,               start = $0000, size = $0006;

# "main program" load chunk
    MAINHDR:       file = %O,               start = $0000, size = $0004;
    RAM:           file = %O, define = yes, start = %S,    size = $BC20 - __STACKSIZE__ - __RESERVED_MEMORY__ - %S;
    TRAILER:       file = %O,               start = $0000, size = $0006;
}
SEGMENTS {
    EXEHDR:    load = HEADER,     type = ro;
    SYSCHKHDR: load = SYSCHKHDR,  type = ro,                optional = yes;
    SYSCHK:    load = SYSCHKCHNK, type = rw,  define = yes, optional = yes;
    SYSCHKTRL: load = SYSCHKTRL,  type = ro,                optional = yes;
    MAINHDR:   load = MAINHDR,    type = ro;
    STARTUP:   load = RAM,        type = ro,  define = yes;
    LOWCODE:   load = RAM,        type = ro,  define = yes, optional = yes;
    INIT:      load = RAM,        type = ro,                optional = yes;
    CODE:      load = RAM,        type = ro,  define = yes;
    RODATA:    load = RAM,        type = ro;
    DATA:      load = RAM,        type = rw;
    BSS:       load = RAM,        type = bss, define = yes;
    ZEROPAGE:  load = ZP,         type = zp;
    EXTZP:     load = ZP,         type = zp,                optional = yes;
    AUTOSTRT:  load = TRAILER,    type = ro;
}
Versus, an example config for having up to 10 "overlay" segments:

 

FEATURES {
    STARTADDRESS: default = $2000;
}
SYMBOLS {
    __EXEHDR__:          type = import;
    __SYSTEM_CHECK__:    type = import;  # force inclusion of "system check" load chunk
    __AUTOSTART__:       type = import;  # force inclusion of autostart "trailer"
    __STACKSIZE__:       type = weak, value = $0800; # 2k stack
    __OVERLAYSIZE__:     type = weak, value = $1000; # 4k overlay
    __STARTADDRESS__:    type = export, value = %S;
    __RESERVED_MEMORY__: type = weak, value = $0000;
}
MEMORY {
    ZP:            file = "", define = yes, start = $0082, size = $007E;

# file header, just $FFFF
    HEADER:        file = %O,               start = $0000, size = $0002;

# "system check" load chunk
    SYSCHKHDR:     file = %O,               start = $0000, size = $0004;
    SYSCHKCHNK:    file = %O,               start = $2E00, size = $0300;
    SYSCHKTRL:     file = %O,               start = $0000, size = $0006;

# "main program" load chunk
    MAINHDR:       file = %O,               start = $0000, size = $0004;
    RAM:           file = %O, define = yes, start = %S + __OVERLAYSIZE__,
                                                           size = $BC20 - __OVERLAYSIZE__ - __STACKSIZE__ - __RESERVED_MEMORY__ - %S;
    TRAILER:       file = %O,               start = $0000, size = $0006;

    OVL1:          file = "%O.1",           start = %S,    size = __OVERLAYSIZE__;
    OVL2:          file = "%O.2",           start = %S,    size = __OVERLAYSIZE__;
    OVL3:          file = "%O.3",           start = %S,    size = __OVERLAYSIZE__;
    OVL4:          file = "%O.4",           start = %S,    size = __OVERLAYSIZE__;
    OVL5:          file = "%O.5",           start = %S,    size = __OVERLAYSIZE__;
    OVL6:          file = "%O.6",           start = %S,    size = __OVERLAYSIZE__;
    OVL7:          file = "%O.7",           start = %S,    size = __OVERLAYSIZE__;
    OVL8:          file = "%O.8",           start = %S,    size = __OVERLAYSIZE__;
    OVL9:          file = "%O.9",           start = %S,    size = __OVERLAYSIZE__;
}
SEGMENTS {
    EXEHDR:    load = HEADER,     type = ro;
    SYSCHKHDR: load = SYSCHKHDR,  type = ro,                optional = yes;
    SYSCHK:    load = SYSCHKCHNK, type = rw,  define = yes, optional = yes;
    SYSCHKTRL: load = SYSCHKTRL,  type = ro,                optional = yes;
    MAINHDR:   load = MAINHDR,    type = ro;
    STARTUP:   load = RAM,        type = ro,  define = yes;
    LOWCODE:   load = RAM,        type = ro,  define = yes, optional = yes;
    INIT:      load = RAM,        type = ro,                optional = yes;
    CODE:      load = RAM,        type = ro,  define = yes;
    RODATA:    load = RAM,        type = ro;
    DATA:      load = RAM,        type = rw;
    BSS:       load = RAM,        type = bss, define = yes;
    ZEROPAGE:  load = ZP,         type = zp;
    EXTZP:     load = ZP,         type = zp,                optional = yes;
    AUTOSTRT:  load = TRAILER,    type = ro;
    OVERLAY1:  load = OVL1,       type = ro,  define = yes, optional = yes;
    OVERLAY2:  load = OVL2,       type = ro,  define = yes, optional = yes;
    OVERLAY3:  load = OVL3,       type = ro,  define = yes, optional = yes;
    OVERLAY4:  load = OVL4,       type = ro,  define = yes, optional = yes;
    OVERLAY5:  load = OVL5,       type = ro,  define = yes, optional = yes;
    OVERLAY6:  load = OVL6,       type = ro,  define = yes, optional = yes;
    OVERLAY7:  load = OVL7,       type = ro,  define = yes, optional = yes;
    OVERLAY8:  load = OVL8,       type = ro,  define = yes, optional = yes;
    OVERLAY9:  load = OVL9,       type = ro,  define = yes, optional = yes;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = INIT;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}
Oh, but this gets even more interesting, there are memory profiles which allow for the use of OSRAM:

 

FEATURES {
    STARTADDRESS: default = $2400;
}

SYMBOLS {
    __EXEHDR__:          type = import;
    __SYSTEM_CHECK__:    type = import;  # force inclusion of "system check" load chunk
    __AUTOSTART__:       type = import;  # force inclusion of autostart "trailer"
    __STACKSIZE__:       type = weak, value = $0800; # 2k stack
    __OVERLAYSIZE__:     type = weak, value = $1000; # 4k overlay
    __STARTADDRESS__:    type = export, value = %S;
}

MEMORY {
    ZP:            file = "", define = yes, start = $0082,                  size = $007E;

# just $FFFF
    HEADER:        file = %O,               start = $0000,                  size = $0002;

# "system check" load chunk
    SYSCHKHDR:     file = %O,               start = $0000,                  size = $0004;
    SYSCHKCHNK:    file = %O,               start = $2E00,                  size = $0300;
    SYSCHKTRL:     file = %O,               start = $0000,                  size = $0006;

# "shadow RAM preparation" load chunk
    SRPREPHDR:     file = %O,               start = $0000,                  size = $0004;
    SRPREPCHNK:    file = %O, define = yes, start = %S + __OVERLAYSIZE__,   size = $7C20 - %S - __OVERLAYSIZE__ - $07FF;  # $07FF: space for temp. chargen buffer, 1K aligned
    SRPREPTRL:     file = %O,               start = $0000,                  size = $0006;

# "main program" load chunk
    MAINHDR:       file = %O,               start = $0000,                  size = $0004;
    RAM:           file = %O, define = yes, start = %S +
                                                    __OVERLAYSIZE__ +
                                                    __LOWBSS_SIZE__,        size = $D000 -
                                                                                   __STACKSIZE__ -
                                                                                   %S -
                                                                                   __OVERLAYSIZE__ -
                                                                                   __LOWBSS_SIZE__;

# defines entry point into program
    TRAILER:       file = %O,               start = $0000, size = $0006;

# memory beneath the ROM preceeding the character generator
    HIDDEN_RAM2:   file = "", define = yes, start = $D800, size = $0800;

# address of relocated character generator (same addess as ROM version)
    CHARGEN:       file = "", define = yes, start = $E000, size = $0400;

# memory beneath the ROM
    HIDDEN_RAM:    file = "", define = yes, start = $E400, size = $FFFA - $E400;

# overlays
    OVL1:          file = "%O.1",           start = %S,                     size = __OVERLAYSIZE__;
    OVL2:          file = "%O.2",           start = %S,                     size = __OVERLAYSIZE__;
    OVL3:          file = "%O.3",           start = %S,                     size = __OVERLAYSIZE__;
    OVL4:          file = "%O.4",           start = %S,                     size = __OVERLAYSIZE__;
    OVL5:          file = "%O.5",           start = %S,                     size = __OVERLAYSIZE__;
    OVL6:          file = "%O.6",           start = %S,                     size = __OVERLAYSIZE__;
    OVL7:          file = "%O.7",           start = %S,                     size = __OVERLAYSIZE__;
    OVL8:          file = "%O.8",           start = %S,                     size = __OVERLAYSIZE__;
    OVL9:          file = "%O.9",           start = %S,                     size = __OVERLAYSIZE__;
}

SEGMENTS {
    EXEHDR:      load = HEADER,                        type = ro;

    SYSCHKHDR:   load = SYSCHKHDR,                     type = ro,                optional = yes;
    SYSCHK:      load = SYSCHKCHNK,                    type = rw,  define = yes, optional = yes;
    SYSCHKTRL:   load = SYSCHKTRL,                     type = ro,                optional = yes;

    SRPREPHDR:   load = SRPREPHDR,                     type = ro;
    LOWBSS:      load = SRPREPCHNK,                    type = bss, define = yes;  # shared btw. SRPREPCHNK and RAM, not zero initialized
    SRPREP:      load = SRPREPCHNK,                    type = rw,  define = yes;
    SHADOW_RAM:  load = SRPREPCHNK, run = HIDDEN_RAM,  type = rw,  define = yes, optional = yes;
    SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM2, type = rw,  define = yes, optional = yes;
    SRPREPTRL:   load = SRPREPTRL,                     type = ro;

    MAINHDR:     load = MAINHDR,                       type = ro;
    STARTUP:     load = RAM,                           type = ro,  define = yes;
    LOWCODE:     load = RAM,                           type = ro,  define = yes, optional = yes;
    INIT:        load = RAM,                           type = ro,                optional = yes;
    CODE:        load = RAM,                           type = ro,  define = yes;
    RODATA:      load = RAM,                           type = ro;
    DATA:        load = RAM,                           type = rw;
    BSS:         load = RAM,                           type = bss, define = yes;
    ZEROPAGE:    load = ZP,                            type = zp;
    EXTZP:       load = ZP,                            type = zp,                optional = yes;
    AUTOSTRT:    load = TRAILER,                       type = ro;

    OVERLAY1:    load = OVL1,                          type = ro,  define = yes, optional = yes;
    OVERLAY2:    load = OVL2,                          type = ro,  define = yes, optional = yes;
    OVERLAY3:    load = OVL3,                          type = ro,  define = yes, optional = yes;
    OVERLAY4:    load = OVL4,                          type = ro,  define = yes, optional = yes;
    OVERLAY5:    load = OVL5,                          type = ro,  define = yes, optional = yes;
    OVERLAY6:    load = OVL6,                          type = ro,  define = yes, optional = yes;
    OVERLAY7:    load = OVL7,                          type = ro,  define = yes, optional = yes;
    OVERLAY8:    load = OVL8,                          type = ro,  define = yes, optional = yes;
    OVERLAY9:    load = OVL9,                          type = ro,  define = yes, optional = yes;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = INIT;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}
Notice in this one, the memory under the OS ram is presented, along with a few little switches passed into the runtime library to relocate the font out of the system area...

 

The flexibility is amazing, but it is making my head spin...

 

In the end, my target is literally a 1088K RAMBO XL, where I want to be able to load overlays into for various system functions. I know i'll get there, it's just going to take some serious experimentation and learning. whee. :) Why don't I ever pick easy things to do? ;)

 

-Thom

  • Like 1
Link to comment
Share on other sites

...and Fixed. I peeled away the union from the config typedefs that I was using to serialize the bitfields...

 

Turns out it really wasn't needed and was just overcomplicating things. Config file saving and subsequent reloading works, once again.

 

Now I'm going to start experimenting with BBS functionality. First up, a user module.

 

-Thom

  • Like 1
Link to comment
Share on other sites

Hmm.. Am finding myself needing to come up with a set of routines for a key/value database, particularly for user storage.

 

I am trying to think on how best to implement something that wouldn't be a total dog on the 6502, would using a 16 bit CRC as a hash of the user id work effectively, as an index?

 

How would any of you do it?

 

-Thom

Link to comment
Share on other sites

Status report:

 

I have committed a new 'user' module, where I am developing code to do the user database and its lookups...

 

The 16 bit CRC seems to work ok as a hash.

 

For now, When a new user is added, a corresponding user index record is added, which is essentially a pair of values: a hash generated by the username, and a 32-bit value meaning the byte offset within the file.

 

The byte level seek is only supported by SpartaDOS, but it is very much needed for this.

 

On a user lookup, the index is read sequentially until a matching hash is found. Then the dat file is read from offset. At some point, I will want to optimize this...a B tree lookup here? hmm not sure... but for now, this should work, once i've debugged the lookup code.

 

Onward...

 

-Thom

  • Like 1
Link to comment
Share on other sites

New Status report, The user module is starting to breathe, I can add users, and look them up. Still need to add an update function.

 

The algorithm at moment is very simple, a linearly accessed index containing a hash of the username and the 32-bit file offset. The index is read sequentially and matched against calculated hash. If a match is found, the dat file is seeked, and the record returned. Nothing special yet.

 

But I've made a video taking you into it, and the code.

 

Sorry, I made this at 2am in the morning, I was half asleep..so.. ;)

 

 

Enjoy, more to come,

-Thom

  • Like 1
Link to comment
Share on other sites

I am getting _very_ concerned that I am already running into memory issues.

 

I can't run the current BBS core under SpartaDOS X, for one reason or another, I need to figure out why.

 

Also, I am having issues with repeated opening and closing of files with the fopen/close/read/write commands. This is becoming quite maddening.

 

But I forge on...

 

-Thom

Link to comment
Share on other sites

There are only 8 IOCB's in the entire system:

 

(1) is used by the keyboard/screen (editor)

(1) is used by the printer

 

and I am trying to conserve the rest, as best as I can. Certain files only need to be open for a moment, to look up information, and shouldn't have their IOCBs being held.

 

-Thom

  • Like 1
Link to comment
Share on other sites

Hey guys, have posted this in a few other places including cc65 list, but I figured i'd put it here, too...

 

I'm thinking through a particular problem that I will eventually need to solve.

 

I want people to have the ability to implement loadable modules for my BBS engine. They shouldn't need to have to build the code with the knowledge that particular modules will be used in a specific order. Maybe this is possible, maybe it isn't...but....

 

Based on what I see with the overlay and multi demos, you can indeed specify different code and variable segments be written out into seperate files and/or memory spaces, a consequence of the flexibility of the linker...

 

Could we have a situation where you could spit out executables that load themselves into a bank of extended memory e.g. on the Atari there is a 16KB window set aside for bank switching in the most common extended memory configuration (the second PIA does the requisite bank switching), and loading an executable would load itself into high memory, and leave a little chunk of memory just below MEMHI as a sort of vector table that the main engine and other modules can bolt onto to call functions?

 

The idea would be to have a known API that anything could include and call for functions like:

 

user_get()

last_menu_selection()

 

etc...

 

These would be abstract functions that the different modules (a user module, a menu module, a display module, a message board module) would implement, and could be swapped out for other modules, while still adhering to this basic framework, this would allow for a certain amount of modularity and flexibility when building a BBS.

 

In the end, I don't care if it's an executable (it would be nice, as e.g. a SpartaDOS batch file would load the requisite modules in place, and start the BBS), or if its some sort of binary blob that gets loaded into place, I'm just trying to think of a way forward, after I write all these little functions to be able to have a parser read through a map of the BBS and load/unload/reload specific modules in response to things happening...

 

-Thom

Link to comment
Share on other sites

I have sent the following to the cc65 list:

 

Ok guys,

 

I am at the end...of my fucking rope...

 

I have managed to side-step this for weeks now, but I need to either

figure out if:

 

(1) this is a problem I am doing, not using something correctly, OR

(2) this is a problem that someone (myself included) needs to fix in

the standard libs for atari.

 

If I use fopen and fclose enough times, I eventually get an EMFILE

error. No way around it, I've written several pieces of different code

that exhibit this behavior.

 

I am working on functions for a user database for a BBS, and it has a

test harness that is failing.

 

The error is shown here: http://i.imgur.com/z4lvizT.png

 

The code is here:

https://github.com/tschak909/ataribbs/blob/master/user/src/user.c

https://github.com/tschak909/ataribbs/blob/master/user/src/user.h

 

This is me as a result of this bug:

http://themortgagenerd.net/wp-content/uploads/2011/06/bigstock_Man_Screaming_In_Pain_And_Agon_2270461.jpg

 

 

The files it is accessing are:

 

* NUMUSERS, a simple counter.

* USER.DAT, the user database

* USER.IDX, the index file.

 

Once any of these files are done being used, I fclose them. I am

trying to conserve IOCBs as much as I can, because they are so few on

the Atari.

 

Can anyone help?

 

Thanks,

-Thom

Link to comment
Share on other sites

A breakthrough.

 

On a whim, I wrote a test program using the POSIX calls (open/read/write/close) as opposed to the ANSI C (fopen/fread/fwrite/fclose) calls. The program was able to open and close a test file 255 times, writing to it in the middle of that process.

 

So I changed the user code entirely to use the POSIX calls, and what do you know? It passes now.

.

The moral here? The ANSI C file operations are BUH_ROKEN, as far as the atari target, is concerned. I will no longer use them, as they in the end just call the underlying functions I am now using, anyway. Basically it seems the f* functions don't take the reference counting in findfreeiocb and friends into account...

 

Moving on, now. But first...BED.

 

Rtp0iwT.png

  • Like 2
Link to comment
Share on other sites

CC65 is a very good compiler, its unusual to find significant issues but you may have found one. IT's very good at compiling ANSI C but the mapping of the standard libraries to target machines sometimes need some work. You could always investigate the library in question yourself, and suggest fixes. You can get the source code for the entire system, do your own fixes, and then send them patches for approval.

 

You will probably run into memory issues if you write the entire thing in C. You should adjust your linker config to maximize memory, there's some simple things you can do. For instance, cut your parameter stack down from 2k, the default is way too large. Stay away from large complicated structs and stuff like that, its best to have everything flat and to prefer arrays of scalars over arrays of structs. Keep your function parameters down to a minimum. Use a lot of globals. Consider linking as little of the libraries as possible, and writing your own calls to SIO and CIO. For instance, using the FILE * stuff is a 9k hit, and you can write your own specialized stuff in much less. Learn to use the embedded assembly capability, you will gain speed and save memory. When I write a large program in CC65, I usually wind up using the C language as just kind of a structural glue around a lot of embedded assembler.

 

You can use extended memory banks to hold code and data. You will probably have to mostly roll your own ability to do that...it's not particularly hard once you figure out a calling and parameter passing methodology. It usually involves copying things a bit back and forth. CC65 does have some libraries to do extended memory, but I'm not sure what the status on that is for the Atari target, last time I looked at it it wasn't viable, but that was a while ago. Don't forget you can swap out the OS on some machines, too. I would also get a second emulator running, say the atariwin800 one, so that you can weed out things that are problems of the emulators rather than actual problems in your code.

  • Like 2
Link to comment
Share on other sites

The moral here? The ANSI C file operations are BUH_ROKEN, as far as the atari target, is concerned. I will no longer use them, as they in the end just call the underlying functions I am now using, anyway. Basically it seems the f* functions don't take the reference counting in findfreeiocb and friends into account...

I can't reproduce your problem here. I have a test program that opens a file, writes to it, closes it, five different file names. Then it read each file, prints the contents and closes the file. It runs this forever... no crashes, no problems, all the data is read fine.

 

Is the problem having multiple files open at the same time? IOCB reuse doesn't seem to be an issue, at least with the version of cc65 and Atari runtime I'm on.

 

Test code I ran:

 

#include <atari.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>

char r_data[80];
char w_data[80];


int main()
{
  FILE *fp;
  unsigned char f;
  int i;

  i = 0;

  while(1) {
    i = i + 1;
    for(f=0;f<6;++f) {
      sprintf(w_data, "fp%d: %d", f, i);
      printf("%s\n", w_data);

      sprintf(r_data, "d:test%d.dat", f);
      fp = fopen(r_data, "wb"); 
      if (!fp) return(0);
      fwrite(&w_data, 80, 1, fp); 
      fclose(fp);
    }

    fflush(fp);

    strcpy(w_data, "");
    strcpy(r_data, "");

    for(f=0;f<6;++f) {
      sprintf(w_data, "d:test%d.dat", f);
      fp = fopen(w_data, "rb"); 
      if (!fp) return(0);
      fread(&r_data, 80, 1, fp); 
      printf("%s\n", r_data);
      fclose(fp);
    }
  }

  return(0);
}
note: that fflush is probably redundant, I edited a test program I already had.

 

PS. This program only compiles to slightly over 5k, not 9k, but the file functions and the heap memory allocation functions definitely will eat up some ram. Get the linker to generate a map file, and you can see how much space each module is using, and your overall segment RAM use too. printf and friends take quite a lot of RAM too.

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

I can't reproduce your problem here. I have a test program that opens a file, writes to it, closes it, five different file names. Then it read each file, prints the contents and closes the file. It runs this forever... no crashes, no problems, all the data is read fine.

 

Is the problem having multiple files open at the same time? IOCB reuse doesn't seem to be an issue, at least with the version of cc65 and Atari runtime I'm on.

 

Test code I ran:

 

#include <atari.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>

char r_data[80];
char w_data[80];


int main()
{
  FILE *fp;
  unsigned char f;
  int i;

  i = 0;

  while(1) {
    i = i + 1;
    for(f=0;f<6;++f) {
      sprintf(w_data, "fp%d: %d", f, i);
      printf("%s\n", w_data);

      sprintf(r_data, "d:test%d.dat", f);
      fp = fopen(r_data, "wb"); 
      if (!fp) return(0);
      fwrite(&w_data, 80, 1, fp); 
      fclose(fp);
    }

    fflush(fp);

    strcpy(w_data, "");
    strcpy(r_data, "");

    for(f=0;f<6;++f) {
      sprintf(w_data, "d:test%d.dat", f);
      fp = fopen(w_data, "rb"); 
      if (!fp) return(0);
      fread(&r_data, 80, 1, fp); 
      printf("%s\n", r_data);
      fclose(fp);
    }
  }

  return(0);
}
note: that fflush is probably redundant, I edited a test program I already had.

 

No sooner you said that, than I've run into the problem here.. It's something in my code, I'll find it.

 

In the mean time, I'm working on the user code, and making it as atomic as I possibly can (I try not to hold onto any file descriptors for any longer than I need them.)

 

I'm going to have to be very lean with my error checking, as it seems me checking each and every file operation adds quite a bit to the resulting binary...

 

My end goal with anything that works with database files is to:

 

(1) make a temporary copy

(2) open

(3) do file operation

(4) close

(5) move temporary copy over original.

 

Yes, it will slow things down, but it will ensure against corruption of the database, and a requirement of this BBS is that it be run on a HARD DRIVE (or some emulated facsimile of one).

 

-Thom

Link to comment
Share on other sites

Glad you are tracking it down, and it doesn't seem to be a problem in the library.

 

Did you see my message on the cc65 mailing list about modules? I should have just responded here, but I saw it there first.

 

Yeah, I did.. It's going to take me a lot of experimenting and stumbling around to find a workable solution.

 

What I'm hoping is that I can have the lion's share of the core in main memory, linking back to standard libs/whatever, and have the different overlays only call functions that are in the main program... I dunno...maybe each overlay blob plops a pointer to a struct of function pointers in main memory...

 

Still thinking... slowly going insane... :)

 

p.s. Shawn, have you looked @ at my code?:

 

http://github.com/tschak909/ataribbs/

 

-Thom

Link to comment
Share on other sites

Ok guys, I need some help. Have really hit a wall.

Can somebody run this binary through debugger emulation under SpartaDOS X and help me figure out why the hell this thing is failing to load? It works perfectly under SD3.2, but it doesn't load under SDX, with either OSRAM or BANKED. I'm _really_ confused.

-Thom

bbs.zip

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...