home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
draco
/
draco-1.ark
/
DRUTIL.REF
< prev
next >
Wrap
Text File
|
1986-11-12
|
14KB
|
334 lines
XVII. Utility Routines
File "util.g" contains a number of declarations relevant to utility
routines provided in the Draco run-time system. Some of these
declarations are specific to the system in use (here CP/M), others are
more general. The types declared are as follows:
/* structure of a file name in a CP/M file control block: */
FILENAME = struct {
unsigned 16 fn_drive;
[8] char fn_name;
[3] char fn_type;
}
FILENAME reflects the stucture of a CP/M file name, and is used by some
of the utility routines specific to CP/M.
/* result from the string comparison routine: */
COMPARISON = enum {
EQUAL,
LESS,
GREATER
}
COMPARISON is returned by the 'chars' comparison routine explained below.
The 'IOerror' language construct returns an unsigned number which
indicates the nature of the first un-reset error which has occurred on
the channel given (or on the standard input channel if no channel is
given). The possible values are indicated below. 'IOerror' resets the
channel to a no-error state (CH_OK).
/* error codes returned by 'IOerror': */
ushort
CH_OK = 0, /* no error */
CH_EOF = 1, /* read past end-of-file indicator */
CH_CLOSED = 2, /* use after close */
CH_NONEXIS = 3, /* file doesn't exist */
CH_DISKFULL = 4, /* disk is full; write failed */
CH_MISSING = 5, /* no data on line */
CH_BADCHAR = 6, /* bad character for input conversion */
CH_OVERFLOW = 7; /* overflow on numeric conversion */
Draco does not contain a proper 'string' datatype. Such a type requires
that 'string' variables be initialized before use, and that all
dynamically allocated storage be cleared. Alternatively, a garbage
collector is needed to reclaim the storage occupied by 'lost' strings.
Neither alternative is in keeping with the nature of Draco as a systems
programming language. Thus Draco uses C-style strings (called 'chars'
values) in which a string is a pointer to a sequence of characters
terminated by the special character '\e'. The following utility
routines are provided to aid in the use of 'chars' values (whose type
is *char, pointer to character).
CharsLen(*char charsPtr)word
This routine, when passed a 'chars' value (a pointer to a row
of characters, such as a string constant enclosed in quotes),
will return the number of characters in that value, up to but
not including the terminating '\e'. Thus, the space needed to
hold a complete copy of the value is one greater than the
number returned.
CharsEqual(*char charsPtr1, charsPtr2)bool
This routine returns 'true' if the two chars values passed are
equal, else returns 'false'.
CharsCopy(*char destination, source)void
The chars value 'source' is copied into the buffer pointed to by
'destination'. It is assumed that the destination buffer is long
enough. The '\e' terminator is also copied.
CharsCmp(*char charsPtr1, charsPtr2)COMPARISON
The two chars values are compared, and the result (EQUAL, LESS or
GREATER) indicates the first with respect to the second. The
comparison uses the standard character set, thus, in ASCII, upper
case letters sort before lower case letters.
CharsConcat(*char destination, source)void
The source chars value is appended to the destination chars
value. Again, it is assumed that the destination buffer is long
enough.
CharsCopyN(*char destination, source; word count)void
This routine is the same as 'CharsCopy' except that at most
'count' characters (including the terminating '\e') will be
placed into the destination buffer.
CharsIndex(*char subject, object)int
The chars value 'object' is searched for in chars value
'subject'. The value returned is the 0-origin index of the object
in the subject, or is -1 if the object is not found in the
subject.
The following routines are of miscellaneous purposes:
exit(int errorCode)void
Many programs can encounter situations in which they simply
cannot continue executing. In such cases, a uniform method of
aborting the run is needed. In Draco, the standard routine
'exit' is available for this purpose. It returns to the host
operating system, indicating the nature of the error via
'errorCode'. By convention, errorCode = 0 indicates successful
execution. The errorCode is not usable from CP/M but the
facility is provided here to allow easy upgrading to other
systems.
BlockMove(*byte destination, source; word count)void
'count' bytes are copied from the source to the destination. This
routine will typically do the copy in the fasted way the CPU can
handle, and thus is preferred for large copies.
BlockMoveB(*byte destination, source; word count)void
'count' bytes are copied from the source to the destination. The
addresses are decremented, instead of incremented as in the
previous routine. Thus, the pointers should point to the last
byte in the two regions. This routine is used to move data up
in a buffer without destroying the data because of overlap.
BlockFill(*byte destination; word count; byte b)void
'count' bytes starting at 'destination' are filled with 'b'.
Again, for large fills, this routine will be faster than a loop
in Draco.
_getsp()*byte
This routine returns the current value of the CPU's stack
pointer. This can be used to check for stack overflow in routines
which are declared 'nonrec'.
The following routines are additional entries into the storage allocation
system used by the 'new' and 'free' language constructs.
Malloc(word length)*byte
A region of memory of size 'length' is allocated and a pointer to
it is returned. This routine is used when the size of the region
is not known at compile time, and 'new' cannot be used.
Mfree(*byte region; word length)void
This routine is used to free regions allocated by 'Malloc'. It
can also be used to free regions allocated by the 'new'
construct, but this is not recommended, for clarity's sake.
Mlist()void
This routine will list (on the standard output), the blocks that
are currently on the storage allocator's free list.
Mcheck(proc (*byte region; word length)void handler)void
This routine will call the passed handler routine once for each
region of memory that is still allocated. This can be used to
identify regions that are not being freed when they should. Note
that the storage allocator does not keep track of the individual
blocks that were requested - there will only be one call of the
handler for each contiguous block of storage that is NOT on the
free list. The call "Mcheck(Mfree)" can be used to free all
currently allocated storage, but this could be considered an
admission by the programmer that he/she is unable to keep track
of what is happening in his/her own program.
MerrorSet(bool newFlag)void
This routine allows the setting of the storage allocator's abort
enable flag. Normally, if the allocator cannot allocate a
requested region, it will abort the program. In some situations
this is not desireable. With a flag value of 'true', calls to
'Malloc' and the 'new' construct are allowed to return nil if
they cannot allocated storage. It is then the programmer's
responsibility to check ALL such results, and to handle them
appropriately. Passing a value of 'false' will re-enable the
automatic aborts if storage cannot be allocated.
MerrorGet()bool
This routine returns the current setting of the abort enable
flag. It can be used by a lower-level routine or package of
routines to restore the state expected by its caller.
The following routines are additional entries in the I/O system. They
perform various functions that are difficult or inefficient to perform
using Draco's I/O constructs. The description of operator types
describes further entry points used for I/O of operator types.
RawRead(channel input binary chin; *byte buffer; word len)word
Up to 'len' bytes are read from the given channel into the given
buffer. The actual number of bytes read is returned.
RawWrite(channel output binary chout; *byte buffer; word len)word
Up to 'len' bytes are written from the given buffer to the given
output channel. The actual number of bytes written is returned.
SeekIn(channel input binary chin; ushort posnHigh; word posn)bool
The given input channel is adjusted so that the next byte read
will come from position posnHigh << 16 + posn. If that position
is beyond the end of the file, no change is made and 'SeekIn'
returns 'false', else it returns 'true'. This routine can only
be used on channels attached to files.
GetIn(channel input binary chin; *ushort pPosnHigh)word
The position in the file of the next byte to be read is returned.
The high order 8 bits of the 24 bit position is returned through
'pPosnHigh' and the low order 16 bits is returned directly.
GetInMax(channel input binary chin; *ushort pPosnHigh)word
This routine returns the maximum seek position of the file, i.e.
the number of bytes in the file.
RandomOut(channel output binary chout)void
This routine enables random output on the attached file.
'SeekOut' cannot be used on a file for which it has not been
enabled. The reason for this is that of buffering - if random
output is enabled, the I/O system may have to read part of the
file into its buffer in order to insert written data at the
proper place. For normal, sequential I/O, this is never needed,
and the overhead can be avoided.
SeekOut(channel output binary chout; ushort posnHigh; word posn)bool
Sets the given output channel, which must be attached to a
file, so that the next byte written will be at the given position
in the file.
GetOut(channel output binary chout; *ushort pPosnHigh)word
Returns the position at which the next byte would be written.
GetOutMax(channel output binary chout; *ushort pPosnHigh)word
Returns the current size of the file.
FlushOut(channel output binary chout)void
Causes the output buffer for the file associated with the given
channel to be flushed to disk. This can be useful when writing
debugging information to a file from a program which may crash.
ReOpen(channel input binary chin; channel output binary chout)void
The input channel must be attached to a file. The output channel
must not yet have been opened. The output channel is attached to
the same file as the input channel, and is enabled for random
access. This call is used to set up channels to allow mixed
random reads and writes to/from the same file. This is needed
for things like database programs.
The following routines are specific to the CP/M version of Draco. The
parameters to a .COM file being executed are made available by CP/M to
the program. Unfortunately, these parameters are translated to upper
case. Also, the parameters are stored in a place which many programs
will overwrite. Draco provides routines to save and access these
parameters. Note that the source file containing these routines has an
initialization routine which is called automatically if either of these
is referenced.
GetPar()*char
The next CP/M command line parameter is returned as a chars
value, complete with terminating '\e'. If no parameters remain,
then 'nil' is returned. Leading blanks or tabs will have been
stripped off.
RescanPars()void
The saved copy of the CP/M command line parameters is modified
so that following calls to GetPar will return the parameters,
starting again with the first parameter.
The details of file names and of creating and destroying files varies
from system to system. The Draco run-time system contains the following
routines for dealing with CP/M files:
SetFileName(FILENAME fn; *char name)void
The 'chars' string 'name' is scanned as a CP/M filename,
complete with optional drive specification, and placed into
FILENAME fn. This FILENAME can then be used by the following
routines. 'SetFileName' will not put any illegal characters
into the FILENAME structure. In particular, asterisks and
question marks will be replaced by dollars signs. If ambiguous
file names are desired, the program must insert them by
directly accessing the parts of the FILENAME.
GetFileName(FILENAME fn; *char buffer)void
This routine is the inverse of 'SetFileName'. The name in the
passed FILENAME is placed into 'buffer' as a chars value. The
file extension, if present, is included, and blanks in the name
are removed.
FileCreate(FILENAME fn)bool
The specified file is created. If the creation attempt fails,
false will be returned, else true is returned. Note that CP/M
does not check for the named file already existing - it will
simply create another file by the same name.
FileDestroy(FILENAME fn)bool
The specified file is erased. If the erasure fails, false is
returned, else true is returned. Note that if the given
FILENAME is an ambiguous specification, CP/M will erase ALL
files which match it.
FileRename(FILENAME oldName, newName)bool
The file named by 'oldName' will be renamed to 'newName'. If
the attempt fails, false is returned, else true is returned. If
'oldName' is ambiguous, all matching files will be renamed to
the single new name.