The only logical difference between FCBs and handle mechanisms is
where are the actual FCBs stored. A handle mechanism assigns space
in the OS for them, which facilitates keeping track of their
status, but eats up memory and limits the number of files that can
be open. The cost of an FCB system is basically that any FCB must
be initialized properly. With handles that is done at the time of
the creation of the space in the OS.
With the memory protection levels of CP/M (and MsDos) there is
never any guarantee that the status defining bits in an FCB are
valid.
--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
> looking at the Aztec C runtime it appeared they allocated some memory
> for FCBs and when the program ended they went through those FCBs and
> closed them all. Should we adopt a similar strategy?
Probably. Definitely the open modified files must be closed to flush
the writes to disk.
DRI C allocates the FILES structues at compile time. See STDIO.H
#include <portab.h> /* Portability Definitions */
/* */
/****************************************************************************
* Stream I/O File Definitions
*****************************************************************************/
#define BUFSIZ 512 /* Standard (ascii) buf size */
#define MAXFILES 16 /* Max # open files ( < 32 ) */
struct _iobuf { /* */
WORD _fd; /* file descriptor for low level io */
WORD _flag; /* stream info flags */
BYTE *_base; /* base of buffer */
BYTE *_ptr; /* current r/w pointer */
WORD _cnt; /* # chars to be read/have been wrt */
}; /* */
#ifndef FILE /* conditionally include: */
extern struct _iobuf _iob[MAXFILES]; /* an array of this info */
#define FILE struct _iobuf /* stream definition */
#endif /************************************/
/* flag byte definition */
#define _IOREAD 0x01 /* readable file */
#define _IOWRT 0x02 /* writeable file */
#define _IOABUF 0x04 /* alloc'd buffer */
#define _IONBUF 0x08 /* no buffer */
#define _IOERR 0x10 /* error has occurred */
#define _IOEOF 0x20 /* EOF has occurred */
#define _IOLBUF 0x40 /* handle as line buffer */
#define _IOSTRI 0x80 /* this stream is really a string */
#define _IOASCI 0x100 /* this was opened as an ascii file */
/************************************/
#define stdin (&_iob[0]) /* standard input stream */
#define stdout (&_iob[1]) /* " output " */
#define stderr (&_iob[2]) /* " error " */
/************************************/
#define clearerr(p) ((p)->_flag &= ~_IOERR) /* clear error flag */
#define feof(p) ((p)->_flag & _IOEOF) /* EOF encountered on stream
*/
#define ferror(p) ((p)->_flag & _IOERR) /* error encountered on stream
*/
#define fileno(p) ((p)->_fd) /* get stream's file descriptor */
#define getchar() getc(stdin) /* get char from stdin */
#define putchar(c) putc(c,stdout) /* put char to stdout */
#define putc fputc
#define getc fgetc
The FILE handle is an index number into an array of _iobuf structure.
The implementing code is locked up in the library, but looks guessable
since the functions mostly resolve to getc & putc.
> My suspicion is that mapping FCBs to file handles and treating CON:
and
> KBD: like files will probably be our 2 biggest translation hurdles.
> If you've got ideas on file handling speak up!
I think this file handling seems reasonable, perhaps adding a
#define _MUSTFLUSH 0x200 /* record changed must update */
to check .ATEXIT. I don't know if this functionality is already
covered
in the library, it should be.
Steve
IIRC my PascalP, when installed under CP/M, used the disk field of
the FCB to identify the device. After allowing for user values in
the upper 3 bits (0 to 7) there could be 32 device ids. 0 was
reserved for the null file, while 1 through a small number
described devices (con, kbd, aux, lst, etc.) conin and conout
could be redirected on the command line. The result was a small
set of tables in the system:
devnames
fopentbl
fclosetbl
fwritetbl
freadtbl
fstatustbl
where everything except the names table pointed to routines to
handle the calls. The system included a fileinit function, which
was automatically called when a file type was declared, and
initialized the FCB (and some auxiliary fields added to it). Since
the compiler knew when a file type was declared it could generate
the call to fileinit, and it could also call the fclose operation
when the file (and thus the FCB storage) went out of scope.
The kbd device file was used for non-echoing input. A different
device could use the interrupt system, and fileopen started it up.
The exception to this simplicity was when arrays of files were
declared, or files were components of records (struct in C).
It all worked cleanly. My embedded systems included such devices
as LANs, AtoD and DtoA converters, etc. I suspect I have omitted
some critical details above.
It was all done by about 1981, but some improvements were made in
the next few years. Things started about 1977 or so. The primary
purpose was embedded machinery in the medical world. Unfortunately
almost everything go lost in a disk crash a few years ago. You can
find remnants on my site (see the organization header of this
message) including a compiler port, and enough to run things on
CP/M emulators. The source of the three back ends is gone, which
created code for the 8080, for a P-machine, or for the HP3000. The
port to the 8086 was never finished. I still have printouts of the
source to the 8080 p-machine interpreter, which includes the file
system.