			   ====================
			   Z80 HI-TECH C UPDATE
			   ====================
				Jon Saxton
				2014-05-03

This volume contains a substantial update to the Hi-Tech C 3.09A compiler
suite for Z80 CP/M.  It is built upon the excellent foundation provided by
John Elliott's PIPEMGR patches which can be found at:

	http://www.seasip.demon.co.uk/Cpm/software/Pipemgr/index.html

John's changes comprise the more significant portion of this update.  My own
contributions are more modest.  Some of my changes have been posted earlier
(see Tesseract volume 88) and are included in this update, albeit with further
enhancements.

1.  Packaging
    ---------

    Everything has been repackaged as .ARC files for ease of transport
    between CP/M and other operating systems (linux, Windows, etc.).

2.  Bug in memset()
    ---------------

    The memset() bug has been fixed.  This was part of my earlier Hi-Tech C
    updates and has been carried forward without change.

3.  Wildcard expansion
    ------------------

    Programs compiled with this update get wildcard expansion of the CP/M
    command line automatically.  There is no longer any need to call
    _getargs() explicitly.

    Enclosing an argument in quote marks (' or ") supresses expansion.
    This can be useful for programs like grep which may use ? and/or * in
    text search patterns or for program options containing a question mark:

	grep 'a.*end' *.h 2d:*.c
	grep "-?"

    The -R option passed to the Hi-Tech C compiler is no longer useful.  (It
    didn't work anyway.)

    Implementing automatic argument expansion meant altering the order of
    modules in LIBC.LIB.  That entailed rebuilding the entire library from
    scratch.  A script to do that is supplied.

4.  Single bdos() function
    ----------------------

    All versions of CP/M 80 return from BDOS calls with BA = HL regardless of
    whether the function is returning an 8-bit or 16-bit result.  Hi-Tech C
    provided a bdos() call for 8-bit results and a bdoshl() call for 16-bit
    results.  John Elliott added a third, bdose(), for disk functions which
    could return extended error codes in H (and B) when running on CP/M 3.

    There is now a single bdos() function.  It always returns a 16-bit result
    in HL.  The bdoshl() routine still exists for compatibility with older
    source files but it is simply an alias for bdos().  John Elliott's
    bdose() routine no longer exists; bdos() also performs its functions.

    Some BDOS functions return 255 as an error flag.  The old bdos() code
    would sign-extend that to -1 (16 bit) but that is no longer done.

	if (bdos(fn, data) == -1)		/* This won't work */

	if (bdos(fn, data) == 255)		/* This works sometimes */

	if ((bdos(fn, data) & 0xFF) == 255)	/* This always works */

    Under CP/M Plus several functions return extended error information in
    the upper 8 bits of the return value.  (Those functions also set the
    standard errno global item.)  Always use the third form when checking
    for an error result.  The compiler is quite clever and doesn't make your
    program work harder ... it just uses the L register.

    John's documentation describes a way to implement a password callback
    function to deal with incorrect or missing passwords on protected files.
    For the moment this is disabled.  I have never found password protection
    worthwhile on CP/M 3 anyway and it is fairly easy to defeat.

5.  User number in file name prefix
    -------------------------------

    The format of file name prefixes indicating drive letter and/or user
    number is now much more liberal.  If a file "sample.txt" is on drive
    E: in user area 12 then depending on the current drive/user the file
    may be accessed as:

	sample.txt		if current DU: is E12:
	12:sample.txt		if current disk is E:
	e:sample.txt		if current user is 12
	e12:sample.txt
	12e:sample.txt
	12:e:sample.txt		(Hi-Tech C format)

    Note that any of these forms is acceptable for program arguments, even
    those containng wildcard characters (?, *).

    (This is all from John Elliott.)

6.  Exact file sizes (CP/M Plus)
    ----------------------------

    Exact file sizes are supported on CP/M 3.  Under CP/M 2.2 file sizes are
    always a multiple of 128 bytes but some versions of CP/M allow setting
    and reading a "last sector byte count" field in the FCB.  The concept was
    carried forward from CP/M's ancestor, ISIS, but DRI did not document the
    precise meaning of the count for CP/M so two distinct interpretations were
    possible:

    a.	LSBC represents the number of UNUSED bytes in the last sector;

    b.	LSBC contains the number of USED bytes but 0 means 128.

    Both usages have appeared in the small number of CP/M 3 utilities which
    support exact file lengths.  My own tools use the first interpretation;
    John Elliott's utilities use the second.

    The first interpretation is slightly simpler to implement because it
    avoids any special-case handling.  It is also historically correct.
    Neither of these considerations is particularly significant but we do need
    to have programs which work together and interpret the last sector byte
    count the same way.  After a lifetime in software development I have
    learned to avoid handling special cases as far as possible.  Accordingly
    I have modified John Elliott's routines to interpret the last sector byte
    count as the number of unused bytes in the last sector.

    With this interpretation the formula for calculating the number of bytes
    in a file is always (sectors * 128) - lsbc.

    (When running on CP/M 2 lsbc is always zero.)

7.  bios() function fixed for CP/M 3 and 2.2
    ----------------------------------------

    The original bios() routine used the function number to construct an offset
    into the BIOS jump vector and from that calculated the address of the
    appropriate BDOS routine.  Except for some character I/O routines, that
    method of calling the BIOS is guaranteed to crash CP/M 3.

    A new bios() function has been implemented which checks for CP/M 3 and if
    that is the current operating system then it accesses the BIOS via the
    sanctioned method, i.e. by invoking bdos(50) with an appropriately filled-
    out parameter block.

    The standard bios() routine takes 1, 2 or 3 parameters:

	short bios(int func, int bc, int de)

    and that is good enough for CP/M 2.2.  However CP/M 3 has functions which
    also take inputs in A and/or HL.  The routine is smart enough to figure
    out where to put the parameters.  All the C programmer needs to do is to
    supply the requisite arguments in the right order.

    A bug in the 2.2 bios() routine has been fixed.  The original code would
    always return an 8-bit result even though there are some functions which
    return 16-bit results.
