Full Code of agn453/HI-TECH-Z80-C for AI

master fab74859c039 cached
518 files
1.2 MB
417.9k tokens
350 symbols
1 requests
Download .txt
Showing preview only (1,337K chars total). Download the full file or copy to clipboard to get everything.
Repository: agn453/HI-TECH-Z80-C
Branch: master
Commit: fab74859c039
Files: 518
Total size: 1.2 MB

Directory structure:
gitextract_om_jot2q/

├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── cpm/
│   ├── ABORT.C
│   ├── BDOS.AS
│   ├── BIOS.AS
│   ├── BUILD-C.LOG
│   ├── BUILD-C.SUB
│   ├── BUILDCPM.SUB
│   ├── BUILDCRT.SUB
│   ├── C-ORIG.C
│   ├── C309-20.C
│   ├── CHMOD.C
│   ├── CLEANUP.C
│   ├── CLOSE.C
│   ├── CONVTIME.C
│   ├── CREAT.C
│   ├── CSV.AS
│   ├── DUP.C
│   ├── EXEC-BLD.SUB
│   ├── EXEC.AS
│   ├── EXECL.AS
│   ├── EXIT.AS
│   ├── FAKECLEA.AS
│   ├── FAKECPCL.AS
│   ├── FCBNAME.C
│   ├── GETCH.C
│   ├── GETFCB.C
│   ├── GETUID.AS
│   ├── ISATTY.C
│   ├── MAKEFILE
│   ├── MKTIME.C
│   ├── OPEN.C
│   ├── READ.C
│   ├── RELIBCPM.SUB
│   ├── RENAME.C
│   ├── SEEK.C
│   ├── SIGNAL.C
│   ├── SRAND.AS
│   ├── SRAND1.C
│   ├── START1.AS
│   ├── START2.AS
│   ├── STAT.C
│   ├── SYS_ERR.C
│   ├── TIME.C
│   ├── TIMEZONE.C
│   ├── UNLINK.C
│   ├── WRITE.C
│   ├── ZC280CPM.AS
│   ├── ZCRTCPM.AS
│   ├── ZD280CPM.AS
│   ├── ZDRTCPM.AS
│   ├── ZN280CPM.AS
│   ├── ZNRTCPM.AS
│   ├── ZR280CPM.AS
│   ├── ZRRTCPM.AS
│   └── _EXIT.AS
├── dist/
│   ├── $EXEC.COM
│   ├── ASSERT.H
│   ├── C-ORIG.COM
│   ├── C309-20.COM
│   ├── C309.COM
│   ├── CGEN.COM
│   ├── CONIO.H
│   ├── CPM.H
│   ├── CPM.HUF
│   ├── CPP.COM
│   ├── CREF.COM
│   ├── CRTCPM.OBJ
│   ├── CTYPE.H
│   ├── DEBUG.COM
│   ├── DEHUFF.COM
│   ├── DRTCPM.OBJ
│   ├── EXEC.H
│   ├── FLOAT.H
│   ├── FLOAT.HUF
│   ├── GEN.HUF
│   ├── HITECH.H
│   ├── HUFF.HUF
│   ├── HUFFORIG.HUF
│   ├── LIBC.LIB
│   ├── LIBCORIG.LIB
│   ├── LIBF.LIB
│   ├── LIBFORIG.LIB
│   ├── LIBOVR.LIB
│   ├── LIBR.COM
│   ├── LIMITS.H
│   ├── LINQ.COM
│   ├── MATH.H
│   ├── NRTCPM.OBJ
│   ├── OBJTOHEX.COM
│   ├── OPTIM.COM
│   ├── OPTIONS
│   ├── OVERLAY.H
│   ├── P1.COM
│   ├── RRTCPM.OBJ
│   ├── SETJMP.H
│   ├── SIGNAL.H
│   ├── STAT.H
│   ├── STDARG.H
│   ├── STDDEF.H
│   ├── STDINT.H
│   ├── STDIO.H
│   ├── STDIO.HUF
│   ├── STDLIB.H
│   ├── STRING.H
│   ├── SYMTOAS.COM
│   ├── SYS.H
│   ├── TIME.H
│   ├── UNIXIO.H
│   └── ZAS.COM
├── doc/
│   ├── DEBUGMAN.TXT
│   ├── HTCZ80.TXT
│   ├── OBJCODE.TXT
│   └── SYMFILE.TXT
├── float/
│   ├── ACOS.C
│   ├── ASFLOAT.AS
│   ├── ASIN.C
│   ├── ATAN.C
│   ├── ATAN2.C
│   ├── ATOF.C
│   ├── CEIL.C
│   ├── COS.C
│   ├── COSH.C
│   ├── DOPRNT.C
│   ├── DOSCAN.C
│   ├── EVALPOLY.C
│   ├── EXP.C
│   ├── FABS.C
│   ├── FBCD.AS
│   ├── FINC.AS
│   ├── FLOAT.AS
│   ├── FLOOR.C
│   ├── FNUM.C
│   ├── FPRINTF.C
│   ├── FREXP.AS
│   ├── FRNDINT.AS
│   ├── FSCANF.C
│   ├── FTOL.AS
│   ├── LIBFVER.C
│   ├── LOG.C
│   ├── LTOF.AS
│   ├── M280LIBF.LOG
│   ├── M280LIBF.SUB
│   ├── MAKEFILE
│   ├── MAKELIBF.LOG
│   ├── MAKELIBF.SUB
│   ├── PRINTF.C
│   ├── SCANF.C
│   ├── SIN.C
│   ├── SINH.C
│   ├── SPRINTF.C
│   ├── SQRT.C
│   ├── SSCANF.C
│   ├── TAN.C
│   └── TANH.C
├── gen/
│   ├── ABS.AS
│   ├── ALLSH.AS
│   ├── ALRSH.AS
│   ├── ASALLSH.AS
│   ├── ASALRSH.AS
│   ├── ASAR.AS
│   ├── ASDIV.AS
│   ├── ASLADD.AS
│   ├── ASLAND.AS
│   ├── ASLL.AS
│   ├── ASLLRSH.AS
│   ├── ASLMUL.AS
│   ├── ASLOR.AS
│   ├── ASLR.AS
│   ├── ASLSUB.AS
│   ├── ASLXOR.AS
│   ├── ASMOD.AS
│   ├── ASMUL.AS
│   ├── ATOI.AS
│   ├── ATOL.C
│   ├── BITFIELD.AS
│   ├── BLKCLR.AS
│   ├── BLKCPY.C
│   ├── BMOVE.AS
│   ├── BRELOP.AS
│   ├── BUILDGEN.SUB
│   ├── CALLOC.C
│   ├── CSV.AS
│   ├── CTYPE.C
│   ├── CTYPE_.C
│   ├── FRELOP.AS
│   ├── GETSP.AS
│   ├── IDIV.AS
│   ├── IMUL.AS
│   ├── INDEX.AS
│   ├── INOUT.AS
│   ├── IREGSET.AS
│   ├── ISALPHA.AS
│   ├── ISDIGIT.AS
│   ├── ISLOWER.AS
│   ├── ISSPACE.AS
│   ├── ISUPPER.AS
│   ├── LADD.AS
│   ├── LAND.AS
│   ├── LDIV.AS
│   ├── LIBCVER.C
│   ├── LINC.AS
│   ├── LLRSH.AS
│   ├── LMUL.AS
│   ├── LONGJMP.AS
│   ├── LOR.AS
│   ├── LRELOP.AS
│   ├── LSUB.AS
│   ├── LXOR.AS
│   ├── MAKEFILE
│   ├── MALLOC.C
│   ├── MAX.AS
│   ├── MEMCMP.C
│   ├── MEMCPY.C
│   ├── MEMSET.C
│   ├── PNUM.C
│   ├── QSORT.C
│   ├── RAND.C
│   ├── RCSV.AS
│   ├── RINDEX.AS
│   ├── SBRK.AS
│   ├── SHAR.AS
│   ├── SHLL.AS
│   ├── SHLR.AS
│   ├── STRCAT.AS
│   ├── STRCHR.AS
│   ├── STRCMP.AS
│   ├── STRCPY.AS
│   ├── STRDUP.C
│   ├── STRFTIME.C
│   ├── STRICMP.AS
│   ├── STRISTR.C
│   ├── STRLEN.AS
│   ├── STRNCAT.AS
│   ├── STRNCMP.AS
│   ├── STRNCPY.AS
│   ├── STRNICMP.AS
│   ├── STRNISTR.C
│   ├── STRNSTR.C
│   ├── STRRCHR.AS
│   ├── STRSTR.C
│   ├── STRTOK.C
│   ├── SWAP.AS
│   ├── TOLOWER.AS
│   ├── TOUPPER.AS
│   ├── WRELOP.AS
│   └── XTOI.AS
├── historical/
│   ├── HTC13.LBR
│   └── Z80V309.LBR
├── htc-bin.lbr
├── huff/
│   ├── DECODE.C
│   ├── DEHUF.C
│   ├── DEHUFF.C
│   ├── DEHUFF.COM
│   ├── ENCODE.C
│   ├── ENHUFF.C
│   ├── ENHUFF.COM
│   ├── HUFF.H
│   ├── MAKEFILE
│   └── MISC.C
├── msx2dist/
│   ├── cc_01/
│   │   ├── CC.C
│   │   ├── CC.COM
│   │   ├── CC.TXT
│   │   ├── LIBDOS2.LIB
│   │   ├── MAKEFILE
│   │   ├── REDIR.AS
│   │   ├── REDIR.OBJ
│   │   ├── VSH.TXT
│   │   ├── VSH1.O
│   │   ├── VSH2.O
│   │   ├── VSH3.O
│   │   └── VSHRT.AS
│   ├── ldos2_04/
│   │   ├── ACT_FILE.AS
│   │   ├── ASSERT.C
│   │   ├── BUF.C
│   │   ├── CGETS.C
│   │   ├── CHANGES
│   │   ├── CHDIR.C
│   │   ├── CHMOD.C
│   │   ├── CLOSE.C
│   │   ├── CLOSEDIR.AS
│   │   ├── CPUTS.C
│   │   ├── CREAT.C
│   │   ├── DIRENT.H
│   │   ├── DOPRNT.C
│   │   ├── DOSCAN.C
│   │   ├── DUP.C
│   │   ├── ERRNO.C
│   │   ├── EXIT.AS
│   │   ├── FAKECPCL.AS
│   │   ├── FCLOSE.C
│   │   ├── FFLUSH.C
│   │   ├── FGETC.AS
│   │   ├── FILBUF.C
│   │   ├── FLSBUF.C
│   │   ├── FOPEN.C
│   │   ├── FPRINTF.C
│   │   ├── FREAD.C
│   │   ├── FREOPEN.C
│   │   ├── FSCANF.C
│   │   ├── FSEEK.C
│   │   ├── FWRITE.C
│   │   ├── GETARGS.C
│   │   ├── GETCWD.AS
│   │   ├── GETENV.AS
│   │   ├── GETS.C
│   │   ├── GETW.C
│   │   ├── ISATTY.C
│   │   ├── LIBDOS2.LIB
│   │   ├── LIBDOS2.TXT
│   │   ├── MAKEFILE
│   │   ├── MKDIR.C
│   │   ├── OPEN.C
│   │   ├── OPENDIR.AS
│   │   ├── PERROR.C
│   │   ├── PRINTF.C
│   │   ├── PUTCHAR.C
│   │   ├── PUTS.C
│   │   ├── READ.C
│   │   ├── READDIR.AS
│   │   ├── REMOVE.C
│   │   ├── RENAME.C
│   │   ├── REWIND.C
│   │   ├── REWNDDIR.AS
│   │   ├── RMDIR.C
│   │   ├── SCANF.C
│   │   ├── SEEK.C
│   │   ├── SETBUF.C
│   │   ├── SETENV.AS
│   │   ├── SPRINTF.C
│   │   ├── SSCANF.C
│   │   ├── START1.AS
│   │   ├── START2.AS
│   │   ├── STAT.C
│   │   ├── STAT.H
│   │   ├── STDCLEAN.C
│   │   ├── UNGETC.C
│   │   ├── UNIXIO.H
│   │   ├── UNLINK.C
│   │   ├── UTIME.C
│   │   └── WRITE.C
│   ├── libfix01/
│   │   ├── CONVTIME.C
│   │   ├── DOPRNT.C
│   │   ├── FBCD.OBJ
│   │   ├── FDOPRNT.C
│   │   ├── FIXES.TXT
│   │   ├── FRELOP.AS
│   │   ├── GETCH.AS
│   │   ├── INOUT.AS
│   │   ├── LIBC.LIB
│   │   ├── LIBF.LIB
│   │   ├── MAKEFILE
│   │   ├── MEMCHR.AS
│   │   ├── MEMCMP.AS
│   │   ├── MEMCPY.AS
│   │   ├── MEMMOVE.AS
│   │   ├── MEMSET.AS
│   │   ├── MSXTIME.AS
│   │   ├── PEEKPOKE.AS
│   │   ├── RCSV.AS
│   │   ├── SIGNAL.AS
│   │   ├── SLEEP.C
│   │   ├── STRCHR.AS
│   │   ├── STRDUP.C
│   │   ├── STRFTIME.C
│   │   ├── STRICMP.AS
│   │   ├── STRING.H
│   │   ├── STRISTR.C
│   │   ├── STRNICMP.AS
│   │   ├── STRNISTR.C
│   │   ├── STRNSTR.C
│   │   ├── STRRCHR.AS
│   │   ├── STRSTR.C
│   │   ├── STRTOK.C
│   │   ├── TIME.C
│   │   └── TIME.H
│   ├── make_004/
│   │   ├── FILE.C
│   │   ├── MACRO.C
│   │   ├── MAKE.C
│   │   ├── MAKE.COM
│   │   ├── MAKE.H
│   │   ├── MAKE.MAN
│   │   ├── MAKEFILE
│   │   ├── MSPAWN.C
│   │   ├── PARSEDIR.C
│   │   ├── PATH.C
│   │   ├── README
│   │   ├── TOKEN.C
│   │   ├── UTILS.C
│   │   ├── XARGS.C
│   │   └── XARGS.COM
│   └── original/
│       ├── CC.LZH
│       ├── CC_01.LZH
│       ├── LDOS2_03.LZH
│       ├── LDOS2_04.LZH
│       ├── LIBFIX01.LZH
│       ├── MAKE_003.LZH
│       └── MAKE_004.LZH
├── overlays/
│   ├── B280OVR.SUB
│   ├── BUILDOVR.SUB
│   ├── LIBOVR.LIB
│   ├── LIBOVR.SUB
│   ├── M280LIBV.SUB
│   ├── OVERLAY.H
│   ├── OVRBGN.AS
│   ├── OVREADME.TXT
│   ├── OVRLOAD.C
│   └── SYMTOAS.C
├── pipemgr/
│   ├── MKRSX.SUB
│   ├── PIPEMGR.ARC
│   ├── PIPEMGR.C
│   ├── PIPEMGR.DOC
│   ├── PIPEMGR.H
│   ├── PIPEMGR.LBR
│   ├── PIPEMGR.RSX
│   ├── PIPEMGR.TXT
│   ├── PIPEMGR.Z80
│   ├── TEE.C
│   └── TEE.COM
├── stdio/
│   ├── ASSERT.C
│   ├── BUF.C
│   ├── BUILDSTD.SUB
│   ├── C280LIBC.LOG
│   ├── C280LIBC.SUB
│   ├── CGETS.C
│   ├── COMPLIBC.LOG
│   ├── COMPLIBC.SUB
│   ├── CPUTS.C
│   ├── CTIME.C
│   ├── DOPRNT.C
│   ├── DOSCAN.C
│   ├── EXIT.C
│   ├── FAKECLEA.C
│   ├── FCLOSE.C
│   ├── FFLUSH.C
│   ├── FGETC.C
│   ├── FILBUF.C
│   ├── FLSBUF.C
│   ├── FOPEN.C
│   ├── FPRINTF.C
│   ├── FPUTC.C
│   ├── FREAD.C
│   ├── FREOPEN.C
│   ├── FSCANF.C
│   ├── FSEEK.C
│   ├── FWRITE.C
│   ├── GETARGS.C
│   ├── GETENV.C
│   ├── GETS.C
│   ├── GETW.C
│   ├── LISTMODC.SUB
│   ├── M280LIBC.LOG
│   ├── M280LIBC.SUB
│   ├── M280LIBV.SUB
│   ├── MAKEFILE
│   ├── MAKELIBC.LOG
│   ├── MAKELIBC.SUB
│   ├── PERROR.C
│   ├── PRINTF.C
│   ├── PUTCHAR.C
│   ├── PUTS.C
│   ├── PUTW.C
│   ├── RELIBCPM.SUB
│   ├── RELIBGEN.SUB
│   ├── RELIBSTD.SUB
│   ├── REMOVE.C
│   ├── REWIND.C
│   ├── SCANF.C
│   ├── SETBUF.C
│   ├── SPRINTF.C
│   ├── SSCANF.C
│   ├── STDCLEAN.C
│   ├── STDIO.I
│   └── UNGETC.C
├── test/
│   ├── TEST-OPT.AS
│   ├── TEST-OPT.AS2
│   ├── TEST-OPT.AS3
│   ├── TEST.LOG
│   ├── TEST.SUB
│   ├── TEST280.LOG
│   ├── TEST280.SUB
│   ├── TESTAES.C
│   ├── TESTARGS.C
│   ├── TESTBDOS.C
│   ├── TESTBIOS.C
│   ├── TESTFILE.C
│   ├── TESTFTIM.C
│   ├── TESTHELL.C
│   ├── TESTIO.C
│   ├── TESTOVR.C
│   ├── TESTOVR1.C
│   ├── TESTOVR2.C
│   ├── TESTPR.C
│   ├── TESTPWD.C
│   ├── TESTRC.C
│   ├── TESTREL.C
│   ├── TESTSTR.C
│   ├── TESTTRIG.C
│   ├── TESTUID.C
│   ├── TESTVER.C
│   ├── TESTVER.SUB
│   ├── TESTVIEW.C
│   └── TESTWILD.C
├── z280bin.lbr
└── z280dist/
    ├── C280-20.COM
    ├── C280CPM.OBJ
    ├── C280OPTS
    ├── C280ORIG.COM
    ├── D280CPM.OBJ
    ├── LIB280C.LIB
    ├── LIB280F.LIB
    ├── LIB280OV.LIB
    ├── N280CPM.OBJ
    ├── OPTIMH.C
    ├── OPTIMH.COM
    └── R280CPM.OBJ

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Default is to keep crlf line endings
text=auto

README.md text eol=crlf
LICENSE text eol=crlf
MAKEFILE text eol=crlf
*.DOC text eof=crlf
*.AS text eol=crlf linguist-language=Assembly
*.AS2 text eol=crlf linguist-language=Assembly
*.AS3 text eol=crlf linguist-language=Assembly
*.Z80 text eol=crlf linguist-language=Assembly
*.C text eol=crlf linguist-language=C
*.COM binary
*.H text eol=crlf linguist-language=C
*.HUF binary
*.LIB binary
*.LOG text eol=crlf
*.LZH binary
*.MAN text eol=crlf
*.OBJ binary
*.SUB text eol=crlf
*.TXT text eol=crlf
*.lbr binary
*.LBR binary
*.ARC binary
*.RSX binary
*.pdf binary
OPTIONS text eol=crlf
C280OPTS text eol=crlf


================================================
FILE: .gitignore
================================================
**/.*.swp
**/.DS_Store


================================================
FILE: LICENSE
================================================
The HI-TECH Z80 CP/M C compiler V3.09 is provided free of charge for
any use, private or commercial, strictly as-is.  No warranty or product
support is offered or implied.

You may use this software for whatever you like, providing you
acknowledge that the copyright to this software remains with
HI-TECH Software.

--
From the HI-TECH Software web site (now defunct) - a copy of which
is on the Wayback Machine at

https://web.archive.org/web/20000301031041/http://www.hitech.com.au/


================================================
FILE: README.md
================================================
# HI-TECH Z80 C Compiler for CP/M

## Introduction

This repository contains the HI-TECH C Compiler for Z80 v3.09 along with
updates and enhancements.  It runs natively on a Zilog Z80/Z180/Z280
processor under the CP/M operating system or under emulation on your
Windows/Linux/macOS system using RunCPM[^1], SIMH AltairZ80[^2] or
ZXCC[^3].

Each release is a consolidated milestone with various updates and
patches applied.  You should read this README.md file for details.

The latest release is V3.09-20 (see Modification History below).

If you only wish to download the latest binary distribution, download
it from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/htc-bin.lbr

and optionally the Z280 binary distribution (if you need it) from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/z280bin.lbr

I welcome bug reports/fixes and additional commentry and discussion.

You can raise an issue here on GitHub or contact me directly via e-mail
at <tony.nicholson@computer.org> or by posting to the USENET newsgroup
forum at comp.os.cpm in the "Consolidating Updates for HI-TECH C for
Z80 CP/M v3.09" discussion thread[^4].

The first release is a slightly modified (see below) v3.09.

## Background

The HI-TECH Z80 CP/M C compiler v3.09 is provided free of charge for any
use, private or commercial, strictly as-is. No warranty or product
support is offered or implied.

You may use this software for whatever you like, providing you acknowledge
that the copyright to this software remains with HI-TECH Software.

The *dist* folder contains the entire compiler including the original
distributed library source-code in Huffman-encoded archive files (CPM.HUF,
GEN.HUF, FLOAT.HUF and STDIO.HUF). NB: I have not rebuilt the .HUF files -
so please use updated run-time library source files in the following folders.

The *cpm*, *gen*, *float* and *stdio* folders contain the library
source-code that has been extracted from the .HUF archive files
using DEHUFF.COM and the updated/modified files.

The *doc* folder contains the documentation in ASCII text as HTCZ80.TXT.


## Modification History

In chronological order - so be sure to check the latest updates at the
end of this README file.

## Release v3.09
<!-- Mar 3, 2020 -->

The original HI-TECH C linker (LINK.COM) has been renamed as LINQ.COM
and the main compiler front-end (C.COM) has been patched to reflect
this name change.  This was done to avoid a name clash with the Digital
Research supplied CP/M linker.  The original version is kept as C-ORIG.COM
and the patched version is dist/C309.COM

I've edited the documentation to remove the underlining and bolding of
text by over-printing and fixed some layout issues and typos.


## Release v3.09-1
<!-- Mar 4, 2020 -->

As supplied in v3.09, the LIBF.LIB produces inaccurate floating point
trigonometry results - as reported by "Ed" in his posting to the
comp.os.cpm USENET Newsgroup.

```
Since we're on the topic of Hitech-C for CP/M, below is a problem I
discovered with the freeware release.

LIBF.LIB supplied with the freeware Hitech-C v3.09 produces inaccurate trig
results.  I found that by simply recompiling the library with the existing
source files from FLOAT.HUF, it fixed the problem.  Absolutely no changes
to the sources were required.
```

The re-compiled LIBF.LIB from the FLOAT.HUF library sources in *float*
has been copied to the distribution files in *dist*.  A CP/M submit file to
rebuild LIBF.LIB has been added to *float*.

A *test* folder has been created.  In it is a TESTTRIG.C program for testing
this release.


## Release v3.09-2
<!-- Mar 3, 2020 -->

The late Jon Saxton (former SYSOP of the Australian Tesseract RCPM)
collected together a number of patches and updates - See Tesseract
volume 091.

These include contributions from John Elliott via
http://www.seasip.info/Cpm/software/index.html - in particular
for PIPEMGR which is a CP/M 3 RSX that implements piping and redirection.

John's contributions will be implemented in a later release.

This release includes updates to memset(), bios() and bdos() library
routines.  In addition the stat(), close() and sys_err() routines
are updated to remove references to bdoshl() and to include CP/M 3
error messages.

```
memset()

     The Hi-Tech C implementation of memset() is seriously broken and is
     almost guaranteed to give trouble in any program which uses it.

     The original implementation simply does not agree with the function
     declaration.  It now does.

         void memset(void s, char c, size_t n)

     Sets n bytes of memory starting at the location pointed to by s with
     the character c.

bios()

    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.

    Under CP/M 3 the calling of the BIOS SELMEM (function 27) is intercepted
    by the BDOS (to prevent you selecting a memory bank that could change the
    memory bank that you are executing from).  Also, if you're using the
    Digital Research banked BDOS then when it invokes a direct BIOS call
    (BDOS function 50) it makes a call to the BIOS MOVE routine to copy the
    parameter block into common memory.  This means you cannot cascade a
    bios() call to XMOVE (function 29) and MOVE (function 25) without
    corrupting memory.  Simeon Cran's ZPM3 banked BDOS replacement does not
    have this restriction.

bdos()

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


## Release v3.09-3
<!-- Mar 4, 2020 -->

These are the Jon Saxton modified versions of John Elliott's patches.

```
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 "-?"

    _getargs() also recognises piping of stdin and stdout using the
    Unix-style >filename (redirect stdout to filename) >>filename
    (append stdout to file) and <filename (read stdin from file).

    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.

Filename drive and user number prefixes

    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 (?, *).

Exact file sizes (CP/M 3 and DOS+ v2.5)

    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.  Jon Saxton's 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.)

NB: This change is now detected automatically for releases v3.09-14 (and
    later) by the start-up module (CRTCPM.OBJ) - see below.

strcasecmp()

    The case-insensitive string comparison function strcasecmp() has been
    implemented.  Its function prototype is in string.h.  It works just like
    strcmp() except that upper- and lower-case letters are treated as 
    identical.  There is also a strncasecmp() analogue of strncmp() which
    allows one to limit the comparison to a certain number of characters.

toupper() and tolower()

    The functions toupper() and tolower() were implemented as macros which
    added a case-shift value to the character parameter without checking to
    see if the parameter was a letter.  To use these routines correctly it was
    necessary to do a range check, e.g.

        if (isupper(c))
            c = tolower(c);

    These operations now invoke the correspondingly named routines in LIBC.LIB
    and it is no longer necessary to pre-test the character.

Support for read/write files

    The stdio functions now allow files to be opened in modes "r+" and "w+" - 
    ie, reading and writing are supported on the same file.
    Remember to fflush() or fseek() between a read and a write.
    This code is experimental.

PIPEMGR support (CP/M 3)

    Programs automatically check for PIPEMGR when they load, and if it
    is present the C streams stdin, stdout and stderr are routed to their
    PIPEMGR counterparts - no modification of the source is required.

    The special device files (CON: LST: PUN: and RDR:) are joined by RSX: 
    (PIPEMGR stdin/stdout streams) and ERR: (PIPEMGR stderr stream). If
    PIPEMGR is not present, these files behave like CON:

    The variable:

        extern char _piped;

    is nonzero if PIPEMGR is present.

    The command 

        FOO <CON:

    will behave differently if PIPEMGR is present. If it is not present,
    then you get line-based input from the Hi-Tech C library. If PIPEMGR
    is present then you get character-based input from PIPEMGR.

    The line-based input in the library will now return EOF if a control-Z
    is typed on a line by itself. Previously it would never return EOF on 
    line-based input.

    Unfortunately if you're using Simeon Cran's replacement ZPM3 then it
    does not allow control-Z to be typed on an input line.
    I'm not yet sure how to get round this.
  
    Remember that when PIPEMGR has parsed the command line, you may have a 
    number of blank (zero-length) arguments.

CP/M 3 extended error support

    To enable CP/M 3 extended error support, put the line

        bdos(0x2D,0xFF);

    near the beginning of your program. Then errors such as read-only files 
    will not cause the program to terminate abruptly; instead the call which
    caused the error will fail, and perror() will explain the reason. The 
    variable:

        extern int errno;

    will contain (16+x) for CP/M 3 extended error x.

File passwords (CP/M 3)

    NB: This feature is disabled.  You will need to change the
        PWDREC definition in the file BDOS.AS to true and rebuild
        and replace the module in LIBC.LIB to enable it.

    There is partial support for file passwords. To enable it, declare a 
    function:

        #include <cpm.h>

        char *mypass(struct FCB *fcb)
        {
        /* For the file specified by "fcb", a password needs to be entered.
           Return a pointer to it (8 characters, uppercase, packed with
           spaces) 
         */
        }

    and insert a line near the beginning of your program:

        _passwd = mypass;

    Then your routine ("mypass" in this example) will be called when
    CP/M reports a password error; it will be called repeatedly until
    the user enters the correct password or a it returns a NULL pointer
    (ie, the user has given up).

Checks for a ZCPR3 environment

    The variable

        extern void *_z3env;

    is 0 if one is not present, or its address if one is. It also passes it
    as a third parameter to main():

        int main(int argc, char **argv, void *z3env);

    The Z3 environment address must be passed to the program in HL.

Graceful exits

    Compiled programs exit gracefully if run on an 8080 or 8086 processor,
    or if there is not enough memory for the program and its static data.
    This is done in the CRTCPM.OBJ module.

CP/M 3 compatible error system

    exit(0) and _exit(0) set the CP/M 3 error code to 0.
    exit(n) and _exit(n) for non-zero n set the error code to 0xFF00 | (n&0x7F).

    The practical upshot is that exit(0) translates as "OK"; other values 
    translate as "error". You can use this in conjunction with CP/M 3's
    SUBMIT features.  If the next command in a .SUB file is preceded by
    a : character, it will be ignored:

        CPROG 
        :OTHER

    will only execute OTHER if CPROG exited with the value 0.

Extended getenv()

    Under CP/M 3, getenv() uses the search path set by SETDEF to locate the
    ENVIRON file. So if you like to keep ENVIRON on a drive that isn't A:, 
    programs will still find it.
```


## Release v3.09-3b
<!-- Mar 5, 2020 -->

Updated the previous release to adjust the ordering of modules in LIBC.LIB -
programs should now link correctly.  Also added the missing documentation for
the debugger in doc/DEBUGMAN.TXT (this was previously available from the
now defunct hitech.com.au web site) and scanned PDFs of the 1989
vintage documentation.


## Release v3.09-4
<!-- Mar 8, 2020 -->

Some of the string related function prototypes in STRING.H are missing from
the LIBC.LIB library.  Most of these are from an update to the MSX flavour
of HI-TECH C by Arnold Metsalaar.  I've cherry-picked the following routines
which are applicable to generic CP/M as well as MSX.

```
STRING.H
    The header file has been changed to reflect the available
    functions in LIBC.LIB.  There are still missing routines -
    namely strcoll() strcspn() strpbrk() and strspn() and these
    have been commented out for now.

strchr() and strrchr()
        char *strchr(char *s, int c)
        char *strrchr(char *s, int c)
    These functions - as well as index() and rindex() (which are identical)
    previously returned a NULL for no match.  The functions now return
    a pointer to the character string's ending NUL character.

stricmp() and strnicmp()
        char stricmp(char *s1, char *s2)
        char strnicmp(char *s1, char *s2, size_t n)
    Case-insensitive versions of strcmp() and strncmp() comparison routines.
    Can also be referenced as strcasecmp() and strncasecmp().

strstr(), strnstr(), stristr() and strnistr()
        char *strstr(char *t, char *s)
        char *strnstr(char *t, char *s, unsigned int n)
        char *strcasestr(char *t, char *s)
        char *strncasestr(char *t, char *s, unsigned int n)
    These extra functions locate the first occurrence of string s in
    string t.  The functions strnstr() and strcasestr() read at most
    n characters from the string t.  The functions strcasestr() and
    strncasestr() use case insensitive comparisons.
    All these functions return a pointer to the first character of
    the first occurence of string s in string t if found, and NULL
    otherwise.

strdup()
        char *strdup(char *s)
    Allocates a new buffer for and copies the string pointed to
    by s to it.  Returns a pointer to the copy of the string or NULL
    if the memory allocation failed. The memory block can be released
    using free().

strtok()
        char *strtok(char *s, char *tok, size_t toklen, char *brk)
    Copies characters from s to tok until it encounters one of the
    characters in brk or until toklen-1 characters have been copied
    (whichever comes first).  It then adds a NUL character to the
    end of the string.  This is a non-conforming POSIX function.

TIME.H
    Now includes a prototype for strftime() - see below.

strftime()
        size_t strftime(char *s, size_t maxs, char *f, struct tm *t)
    Converts a time value t to a string using the format string f
    into the string s of size maxs (including a terminating NUL).
    It acts as a sprintf() function for date/time values. The
    following are valid in the format string -

             %A      full weekday name (Monday)
             %a      abbreviated weekday name (Mon)
             %B      full month name (January)
             %b      abbreviated month name (Jan)
             %c      standard date and time representation
             %d      day-of-month (01-31)
             %H      hour (24 hour clock) (00-23)
             %I      hour (12 hour clock) (01-12)
             %j      day-of-year (001-366)
             %M      minute (00-59)
             %m      month (01-12)
             %p      local equivalent of AM or PM
             %S      second (00-59)
             %U      week-of-year, first day sunday (00-53)
             %W      week-of-year, first day monday (00-53)
             %w      weekday (0-6, sunday is 0)
             %X      standard time representation
             %x      standard date representation
             %Y      year with century
             %y      year without century (00-99)
             %Z      timezone name
             %%      percent sign

    the standard date string is equivalent to:

        %a %b %d %Y

    the standard time string is equivalent to:

        %H:%M:%S

    the standard date and time string is equivalent to:

        %a %b %d %H:%M:%S %Y

    strftime() returns the number of characters placed in the
    buffer, not including the terminating NUL, or zero if more
    than maxs characters were produced.
```

## Release v3.09-4-Z280
<!-- Mar 8, 2020 -->

This is the first experimental release of the libraries that have been
built for a Zilog Z280 MPU.  Most of this work was retrieved from a
distribution of the UZI-280 operating system for the CPU280 system.
It was written by Stefan Nitschke and Alexander Schmid.

To use this on a system with a Zilog Z280 MPU, merge the files from the
*dist* folder (i.e. the Z80 version) with those from the *z280dist*
folder onto a drive in the search path (usually drive A in user area 0).
On CP/M 3 the *.COM, *.H, CRTCPM.OBJ and the *.LIB files should be
set with the system file attribute so they can be found from all user
areas.

The *z280dist* folder contains the following files -

```
C280.COM
    The compiler front-end for driving the HI-TECH Z80 C compiler
    for CP/M to produce code to run on a Zilog Z280 MPU.  It accepts
    command lines similar to the C.COM front-end from the *dist*
    folder - with a modified command-line switch to perform optimisation
    of generated assembly language to use the enhanced Z280 instructions.
    You can optimise for size (-O2) or speed (-OF2). For example,

        c280 -of2 ...

    will cause the OPTIMH.COM pass to perform speed optimisation.

OPTIMH.COM and OPTIMH.C
    This is the Z280 assembly language optimiser (with source-code).
    The following instructions are optimised -

        call amul        -> multw hl,de

        call lmul        -> multuw hl,de

        call csv         -> push iy, push ix, lda ix,(sp+0)  (+6 bytes)

        jp cret          -> ld sp,ix pop ix pop iy ret (+6 bytes)

        ld  (hl),c
        inc hl           -> ldw (hl),bc
        ld  (hl),b       -> inc hl

        ld  (hl),e
        inc hl           -> ldw (hl),de
        ld  (hl),d       -> inc hl

        ld  c,(hl)
        inc hl           -> ldw bc,(hl)
        ld  b,(hl)       -> inc hl

        ld  e,(hl)
        inc hl           -> ldw de,(hl)
        ld  d,(hl)       -> inc hl

        ld  c,(ix+n)     or iy
        ld  b,(ix+n+1)   -> ldw bc,(ix+n)    (2 byte)

        ld  e,(ix+n)     or iy
        ld  d,(ix+n+1)   -> ldw de,(ix+n)    (2 byte)

        ld  l,(ix+n)     or iy
        ld  h,(ix+n+1)   -> ldw hl,(ix+n)    (2 byte)

        ld  (ix+n),c     or iy
        ld  (ix+n+1),b   -> ldw (ix+n),bc    (2 byte)

        ld  (ix+n),e     or iy
        ld  (ix+n+1),d   -> ldw (ix+n),de    (2 byte)

        ld  (ix+n),l     or iy
        ld  (ix+n+1),h   -> ldw (ix+n),hl    (2 byte)

        or  a
        sbc hl,bc        -> subw hl,bc       (1 byte)

        or  a
        sbc hl,de        -> subw hl,de       (1 byte)

        push  ix
        pop   de
        ld    hl,nn
        add   hl,de      -> lda hl,(ix+nn)   (3 byte)

        push  ix         -> ld  e,ixl
        pop   de         -> ld  d,ixh

        push  ix
        pop   hl         -> lda hl,(ix+0)

    In addition memory addressing with large offset -

        push  ix
        pop   de
        ld    hl,nn
        add   hl,de      -> lda hl,(ix+nn)   (3 byte)

        push	iy
        pop	de
        ld	hl,nn
        add	hl,de	-> lda	hl,(iy+nn)  (3 byte)

LIB280C.LIB and LIB280F.LIB
    These are the library modules for the Z280 C run-time library
    and floating point library that contain optimised Z280 routines.
    These will only execute on a Z280 MPU - and not on a Z80!
    They have been built from sources of the v3.09-4 release.

```

## Not actually a release - but including MSX-DOS 2 distribution
<!-- Apr 17, 2020 -->

I'm making available the raw updates for MSX-DOS 2 for those interested in
the last known updates to run HI-TECH C for Z80 under MSX2.  You'll
find the individual files in the msx2dist folder and its sub-folders.

These were extracted from files produced by Arnold Metselaar in 2013 and
distributed as LZH archives on the MSX Banzai web site at
http://msxbanzai.tni.nl/dev/software.html

One of these archive files is known to be damaged - the one containing the
I/O library for MSX-DOS 2 (LDOS2_04.LZH) and I have replaced the source
code for only one of the modules with that from an earlier version obtained
from the Wayback machine at archive.org.  There's still 
a missing (_UTIME.AS) that I'll try to re-assemble from the binary
in the cc_01/LIBDOS2.LIB library. 

The msx2dist/original folder contains the as-downloaded .LZH archives
(including the previous versions from archive.org).

Also note that Yeongman Seo is currently working on a toolchain for developing
MSX-DOS/DOS 2 applications using the HI-TECH Z80 C compiler under a
Windows Win32 environment.  This is available on GitHub at

https://github.com/sharksym/CPMEMU_HI-TECH_C


## Fix to getenv()
<!-- May 24, 2020 -->

The getenv() function was not correctly looking up the location of
the environment file under CP/M 3 for the "default" entry in the drive
search chain.  It will now locate the ENVIRON file if you have set-up
the default search chain with a default entry. For example

```
; Set search chain to current drive, RAMdisk, C: then A:
setdef * m: c: a:
```

in your CP/M 3 PROFILE.SUB file (or manually entered on the command line).

Updated dist/LIBC.LIB and z280dist/LIBC280.LIB too.


## General tidy-up and Overlay capability
<!-- Jun 3, 2020 -->

Updates merged from @tsupplis

Ron Murray's overlay capabilities have been added, along with some
miscellaneous fixes - mainly to the CP/M BDOS definitions in CPM.H
and to fix an incompatibility with conflicting _TIME macros in both
TIME.H and CPM.H


## Release V3.09-5
<!-- Jun 3, 2020 -->

Rebuilt libraries LIBC.LIB and LIBF.LIB (as well as LIB280C.LIB and
LIB280F.LIB for the Z280).  New snapshot as Release V3.09-5.


## Fix CRTCPM.OBJ start-up module
<!-- Jun 12, 2020 -->

The CP/M start-up module CRTCPM.OBJ was not checking the CP/M version
prior to checking for the existence of the PIPEMGR RSX.  This caused
compiled programs under CP/M 2.2 to fail to initialise correctly.

A new version of CRTCPM.OBJ is available (and the source-code in
ZCRTCPM.AS has been updated to correct this).


## Add source for DEHUFF and ENHUFF
<!-- Dec 13, 2020 -->

Andrey Nikitin has contributed the sources for the DEHUFF and ENHUFF
programs that were used by HI-TECH Software to distribute the library
source files.  I've placed the extracted source files and the resulting
binary produced by the latest compiler in the *huff* folder. Also,
the Huffman-encoded archive containing these sources has been placed
in the *dist* folder as HUFF.HUF.  There's also an original version
that produces some diagnostic errors in HUFFORIG.HUF.

These sources may be built using the HI-TECH C compiler or using the
gcc compiler under Linux or macOS.  I built them natively under CP/M
using -

```
c -O -v enhuff.c encode.c misc.c
c -O -v dehuff.c decode.c misc.c
```

(If you're using a Z280 use 'c280 -of2 -v ...')


## Change supported string length in printf() routine
<!-- Jan 5, 2021 -->

Merged a minor change into stdio/DOPRNT.C from @tupplis so that various
printf() routines can now output strings greater than 255 characters.

Updated the dist/LIBC.LIB and z280dist/LIB280C.LIB libraries too
and created a new v3.09-6 release to consolidate the recent updates.


## Release V3.09-6
<!-- Jan 6, 2021 -->

Updated the cpm/C.C source to include the V3.09-6 identifier and
supply a pre-compiled version in dist/C309-6.COM that can be copied
to the CP/M system path (usually drive A in user area 0) as C.COM

Also included a version of the start-up code for the Z280 under CP/M
as z280dist/CRTCPM.OBJ 
(with source-code in z280dist/Z280CPM.AS).  This checks whether
the compiled binary is running on a Z280 MPU.


## PIPEMGR sources
<!-- Jan 8, 2021 -->

I've included Jon Saxton's version of the PIPEMGR RSX for handling
pipes under CP/M 3.

This is a modified version of the original by John Elliott that's
detected and used by each of the releases of HI-TECH C available
from this repository.

You'll find the original PIPEMGR.ARC distribution from Tesseract
volume 089, a PIPEMGR.LBR containing the same files and individual
extracted files in the *pipemgr* folder.

Also included is the source and executable for TEE which has the
PIPEMGR RSX attached and behaves like its namesake in the Unix world,
along with missing files from the original Van Nuys tools
(PIPEMGR.H and PIPEMGR.C).

The rest of the Van Nuys tools are available from John Elliott's
original PIPEMGR page at

http://www.seasip.info/Cpm/software/Pipemgr/index.html


## Self-relocating .COM program PIPEMGR integration
<!-- Jan 8, 2021 -->

@tsupplis provided updates to the self-relocating image start-up module
to support the improvements from the standard CP/M start-up (in CRTCPM.OBJ).
The source changes are in cpm/ZRRTCPM.AS and the compiled object replaces
dist/RRTCPM.OBJ

To build a self-relocating image, use the -A compile option.


## Minor issues
<!-- Jan 10, 2021 -->

* Declaration for rename() missing from dist/UNIXIO.H

* Make CPU check in the start-up modules consistent.  Output
message for Z80 (or Z280 MPU) if the incorrect processor is
detected. For example -
```
This CP/M program requires a Z80 CPU.
```

* Include the modified floating-point version of float/DOPRNT.AS
to support outputting strings greater than 255 characters by the
various printf() routines.

* With @tsupplis provided fix for the compiler front-end dist/C309-7.COM
now handles input correctly from submit files - resolving issue #9.
Updated dist/SIGNAL.H, cpm/SIGNAL.C, cpm/C.C and stdio/GETARGS.C
(a mix of input from and output to the console device stream was
previously discarding input from CP/M 3 submit files). 

* The start-up modules have been corrected to properly
report an error when run under MS-DOS. (Previously the assembly language
routine was incorrectly being optimised - and an absolute jump was
changed to a relative branch).

* Updated both dist/LIBC.LIB and dist/LIBF.LIB object libraries
and the Z280 ones in z280dist/LIB280C.LIB and z280dist/LIB280F.LIB.

* Include dist/STDINT.H for some standard type definitions (and referenced
by the overlay support routine).


## MS-DOS cross-compiler available
<!-- Jan 13, 2021 -->

Recently Microchip Technology Inc. (the current owners of the HI-TECH
intellectual property) also released the MS-DOS version of the HI-TECH
C Compiler v4.11 - a cross-compiler for building CP/M and ROM-able
programs for the Z80 using MS-DOS.  I've uploaded this version to
GitHub at

https://github.com/agn453/HI-TECH-Z80-C-Cross-Compiler


## Release v3.09-7
<!-- Jan 14, 2021 -->

Thanks to @tsupplis, the following enhancements are now available
in the latest release v3.09-7.

* The compiler front end now supports building CP/M programs using overlays.
Just copy the dist/C309-7.COM to your system directory as C.COM, along
with the symbol table builder dist/SYMTOAS.COM and overlay support library
dist/LIBOVR.LIB.

To build a program with overlays, specify the -F option when compiling
the resident part of the main program (which writes a symbol file) and -Lovr
to use the ovrload() routine; and for each of the overlay segments compile
using the -Y option and specify the symbol file on the
command line.  For example (these files are in the *test* folder too) --

```
Firstly the simple main program

A>type TESTOVR.C
#include <cpm.h>
#include <stdio.h>
#include <overlay.h>

int main(int argc, char ** argv)
{
    intptr_t i;
    printf("overlay test\n");
    i=ovrload("testovr1",0);
    printf("overlay return is %d\n",i);
    i=ovrload("testovr1",0);
    printf("overlay return is %d\n",i);
    i=ovrload("testovr2",0);
    printf("overlay return is %d\n",i);
    i=ovrload("testovr1",0);
    printf("overlay return is %d\n",i);
    return 0;
}

A>type testovr1.c
void * yop(void *a) {
    printf("hello from overlay 01\n");
    return 0;
}

A>type testovr2.c
void * yop(void *a) {
    printf("hello from overlay 02\n");
    return 0;
}

A>c -ftestovrx.sym -o testovr.c -lovr                                         
A:C        COM  (User 0)                                                        
Hi-Tech C Compiler (CP/M-80) V3.09-7                                            
Copyright (C) 1984-87 HI-TECH SOFTWARE                                          
Updated from https://github.com/agn453/HI-TECH-Z80-C                            
                                                                                
A>c -y -o testovr1.c testovrx.sym                                             
A:C        COM  (User 0)                                                        
Hi-Tech C Compiler (CP/M-80) V3.09-7                                            
Copyright (C) 1984-87 HI-TECH SOFTWARE                                          
Updated from https://github.com/agn453/HI-TECH-Z80-C                            
TESTOVR1.C                                                                      
TESTOVRX.SYM

A>>c -y -o testovr2.c testovrx.sym                                             
A:C        COM  (User 0)                                                        
Hi-Tech C Compiler (CP/M-80) V3.09-7                                            
Copyright (C) 1984-87 HI-TECH SOFTWARE                                          
Updated from https://github.com/agn453/HI-TECH-Z80-C                            
TESTOVR2.C                                                                      
TESTOVRX.SYM                                                                    
                                                                                
A>testovr                                                                     
A:TESTOVR  COM                                                                  
overlay test                                                                    
hello from overlay 01                                                           
overlay return is 0                                                             
hello from overlay 01                                                           
overlay return is 0                                                             
hello from overlay 02                                                           
overlay return is 0                                                             
hello from overlay 01                                                           
overlay return is 0                                                             
                                                                                
A>
```

* There are additional testing programs added to the *test* folder along
with the output of a testing run in test/TEST.LOG that was generated on
a CP/M 3 system.

* Since wildcard expansion using _getargs() has been supported since
v3.09-3, it is no longer necessary to use the -R option.  This is now
deprecated and ignored if you use it on the command line.

* A new -H option may be specified to obtain help with the command-line
options.  It types out the system's OPTIONS file - so be sure this is
copied from the dist folder to the system directory (usually drive A:
in user area 0, and marked with the SYS and RO attributes).


## Minor Updates
<!-- Jan 15, 2021 -->

Addressing some minor changes from issue #18 -

* A description of the -E option was missing from the dist/OPTIONS help
message file.

* For CP/M emulators the options emitted by the compiler front-end have
been adjusted to be consistently in uppercase.

* Report an error if the OPTIONS file can't be found (for the -H help text).

I've re-issued this as a revised v3.09-7b release too.


## Release v3.09-8 (support for Z280 MPU)
<!-- Jan 15, 2021 -->

The compiler front-end source in cpm/C.C has been updated so that it
can be compiled to produce a Z280 MPU version.  Co-existence with the Z80
version is now also possible due to the renaming of the various Z280 versions
start-up modules to C280CPM.OBJ, D280CPM.OBJ and R280CPM.OBJ.

The original source-code to the C280 front-end is lost (not included with the
UZI-280 distribution files) - so now Z280 users (like me) have the updated
version supporting overlays etc.  The original binary from the UZI-280
distribution is in the file z280dist/C280ORIG.COM

You'll find updated Z280 files in the *z280dist* folder.  The
z280dist/C280-8.COM is the new front-end and can be copied to the system
drive as C280.COM.  It tests for, and will only run on a Z280 MPU.
Be sure to copy the start-up object modules (?280CPM.OBJ files) and
the z280dist/LIB280*.LIB libraries to the system drive too.

This is also a new release milestone at v3.09-8.


## Minor fixes
<!-- Jan 15, 2021 -->

* Minor change to allow size optimization (-O2 switch) for Z280.


## Easy binary download
<!-- Jan 17, 2021 -->

Include an easy-download CP/M library file containing the binary
distribution (all the files you need from the *dist* folder to get it
running under CP/M).

Download this from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/htc-bin.lbr

and extract the files using one of the CP/M .LBR extraction tools, e.g.
[NULU.COM](https://raw.githubusercontent.com/agn453/Z280RC/master/utilities/NULU.COM).


## Minor update
<!-- Jan 17, 2021 -->

* Revert change defining "Z80" symbol back to the lowercase form "z80"
in the main driver.  There are some inconsistencies with how this is used
in the other compiler modules - and in the library sourcefiles.


## Z280 optimizer speed/size
<!-- Jan 18, 2021 -->

* Modify z280/OPTIMH.C and the front-end driver to select between size
and speed optimisations.  Previously some additional code was added to
unroll calls to the csv() routine and jumps to cret() into inline-code.
OPTIMH now accepts a -F option to include them (for faster code), else
it omits them for reduced code-size.  This is selected by using the -OF2
and -O2 option to the C280 front-end.


## Old files removed
<!-- Jan 19, 2021 -->

Up until now, I've kept various replaced files in this repository
by renaming them to include a hash (or octothorpe) "#" character
in their names.  They have now been removed to avoid confusion.
GitHub is already tracking changes for us - and comparing commits
will show them from now on!  If you need to refer to them you can
download one of the previous releases.


## Decompilation of CGEN.COM
<!-- Feb 5, 2021 -->

Andrey Nikitin has made available a decompilation of the HI-TECH C V3.09
code generation program CGEN.COM based on work by himself and
a group of Russian enthusiasts.

You'll find this at

https://github.com/nikitinprior/dcgen


## bios() routine restrictions
<!-- Mar 18, 2021 -->

Issue #24 raised a limitation with calling the bios() function to perform
inter-bank memory moves using the CP/M 3 BIOS XMOVE and MOVE routines
(function 29 and 25).  I've updated the description for bios() above to
document this and the SELMEM (function 27) restriction.


## Incomplete prototype definitions in TIME.H
<!-- Mar 20, 2021 -->

As per issue #25 - corrected the function prototype definitions in
dist/TIME.H for ctime(), gmtime() and localtime().  Updated the
htc-bin.lbr binary distribution library archive file too.


## More work on decompiling CPP.COM
<!-- Mar 29, 2021 -->

Andrea Nikitin has posted some more decompiled source-code for the
C pre-processor (CPP.COM) and a revised pre-processor for the compiler
that supports C++ style comments.  You can get this from his GitHub
repository at

https://github.com/nikitinprior/dcpp


## Historical version 1.3 added
<!-- Jun 7, 2021 -->

I've added a CP/M library format file containing the HI-TECH C COMPILER V1.3
for Z80 CP/M in the *historical* folder.  The files in
[historical/HTC13.LBR](https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/historical/HTC13.LBR)
can be extracted using one of the CP/M library utilities like
[NULU.COM](https://raw.githubusercontent.com/agn453/Z280RC/master/utilities/NULU.COM),
and are from the original
eight-inch floppy disk distribution media that I purchased in 1984.

Andrey Nikitin noticed that this version has an object file dump utility that
can decode the HI-TECH C Z80 object file format.  He's done a disassembly
and reconstruction of this utility that you can get from his GitHub
repository at

https://github.com/nikitinprior/ddump


## Object librarian source-code reconstructed
<!-- Aug 4, 2021 -->

Andrey Nikitin has managed to reconstruct the C language source for the
object-code librarian program LIBR.COM by disassembling the program.  You'll
find this in his repository at

https://github.com/nikitinprior/dlibr


## v3.09-9 update release
<!-- Aug 16, 2021 -->

I've added a mktime() routine to the C library (LIBC.LIB and LIB280C.LIB)
and consolidated the recent updates as a release v3.09-9.


```
mktime()

        time_t mktime(struct tm *)

    A routine to convert the broken out time (in the structure pointed
    to by the parameter) into a time value representing the number
    of seconds since the Unix epoch (since CP/M has no knowledge of the
    local timezone - the time is assumed to be respresenting Universal
    Coordinated Time or UTC).  The value returned is the number of
    seconds since midnight 01-Jan-1970.

    This can be used (for example) to manipulate a file's time-stamp
    or for computing time differences.

    External declarations, as well as the tm structure definition, are
    contained in the TIME.H include file.  The tm structure includes
    at least the following fields:

           int tm_sec;     /* seconds (0 - 60) */
           int tm_min;     /* minutes (0 - 59) */
           int tm_hour;    /* hours (0 - 23) */
           int tm_mday;    /* day of month (1 - 31) */
           int tm_mon;     /* month of year (0 - 11) */
           int tm_year;    /* year - 1900 */
           int tm_wday;    /* day of week (Sunday = 0) */
           int tm_yday;    /* day of year (0 - 365) */
           int tm_isdst;   /* is summer time in effect? */
```


## CPM.H header file update
<!-- Aug 16, 2021 -->

* Added a few missing bdos() function constants for CP/M 3, MP/M, ZSDOS
and ZPM3.

* I forgot to include the testing logs (in the *test* folder)

* Add -Y description to dist/OPTIONS file.


## Reconstructed source for OPTIM.COM
<!-- Nov 12, 2021 -->

Andrey Nikitin and Mark Ogden have been busy.  They've reconstructed the
C source-code for the Z80 code optimiser.  You'll find it at

https://github.com/nikitinprior/doptim


## Fix to fgets routine
<!-- Dec 19, 2021 -->

Reported by Mark Ogden, the fgets() library routine (in LIBC.LIB and
LIB280C.LIB) has been updated to prevent a character string
terminator (NULL) from being written to outside the buffer bounds.

You can update just the object library file, or fetch and extract the
files from the updated binary distribution from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/htc-bin.lbr


## Bundle up the Z280 distribution
<!-- Dec 28, 2021 -->

I've added a binary Z280 distribution library file too.  Get it from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/z280bin.lbr

Just extract the contents to your system drive (A:) and set them
with the SYS file attribute (so they are accessible from all user
areas and via the CP/M 3 search path).


## C front-end fixes and new V3.09-10 update release
<!-- Dec 30, 2021 -->

Mark Ogden has supplied some fixes to the C front-end so that it can process
long command lines (particularly when wildcard expanded filename are
specified).  I've also added a minor change to the Z280 front-end to use
the C280OPTS file when help (-H) is requested from the C280 command.

The new release V3.09-10 consolidates all the changes since V3.09-9.  As
usual, updated binary distribution libraries are available too.


## Fix to pre-processor assembly language output
<!-- Jan 3, 2022 -->

A long-standing bug with the generation of Z80 assembly
language output containing the C source-code as comments
(when using the -S command-line option without optimisation)
has been fixed.  A replacement C309-10.COM (and C280-10.COM)
is available - and the source-code in cpm/C390-10.C has been
updated.  Thanks to Andrey Nikitin for reporting this.


## Inclusion of object-code and symbol-table documentation
<!-- Jan 4, 2022 -->

On the Internet archive WayBackMachine, I found some documentation
describing the HI-TECH object-code (.OBJ) and symbol-table (.SYM) file
formats in the ZIP archive
[symfiles.zip](https://web.archive.org/web/19980205193245fw_/http://www.hitech.com.au/software/tech_docs.html).

I've extracted the old MS-Word format files and converted them to ASCII text
in the
[doc/OBJCODE.TXT](https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/doc/OBJCODE.TXT)
and
[doc/SYMFILE.TXT](https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/doc/SYMFILE.TXT)
files.


## Work-around compiler bug
<!-- Jan 5, 2022 -->

Passing a pointer to a function parameter can give rise to a warning
or compilation failure (with both ```operation: arguments redeclared```
and ```argument list conflicts with prototype``` error messages).  One
such example is the ```qsort()``` routine which needs a pointer to a
comparison routine as one of its arguments.

The bug can be worked around by using a typedef'ed parameter.  The
header library prototype for ```qsort()``` in STDLIB.H has been updated.
Thanks to Andrey Nikitin for the heads up on this bug.


## Redirection of error message output work-around
<!-- Jan 6, 2022 -->

NB: This issue has been resolved with the V3.09-11 release (see below).

The re-direction of error message output (from the C or C280 command)
is currently broken.  This is a side-effect of the fix to the
pre-processor assembly language output.  I've temporarily added
a workaround to discard the error message redirect and only send
error messages to the console device CON:.  This works under CP/M
and ZXCC emulation until I find a fix.


## Sourcecode reconstruction for the HI-TECH C linker
<!-- Jan 8, 2022 -->

Both Andrey Nikitin and Mark Ogden have reconstructed the source
code to the HI-TECH object code linker.  You'll find it at

https://github.com/nikitinprior/dlink

and it can be compiled using gcc under Linux or CLANG under macOS
to produce a executable that doesn't require Z80 emulation for
cross-compilation.


## Code-generation issue with casting char to long
<!-- Jan 8, 2022 -->

Mark Ogden supplied the following detail regarding an issue with
code generation when casting a ```char```/```unsigned char``` to a
```long```.  The current compiler emits incorrect Z80 instructions.

The following snippet of code shows the problem and work-arounds.

```
void func(char *pia, unsigned char *pib) {
    long a;
    unsigned long b;
 
    a = pia[1]; /* ok */
    a = pib[1]; /* bad sets a = 0 */
    b = pia[1]; /* bad sets b = 0 */
    b = pib[1]; /* bad sets b = 0 */

    /* work arounds */

    /* for the simple assignment case use
     * (int)pia[1], (unsigned)pia[1] or (unsigned)pib[1]
     * dependent on whether you need sign extension
     *
     * for example -
     */

    a = (unsigned) pib[1];
    b = (int) pia[1];
    b = (unsigned) pib[1];

    /* if used in an expression you may also need to add
     * another cast to (long) or (unsigned long)
     * e.g. (unsigned long)(unsigned)
     */

}
```

For the three failing cases, the code generated is
```
      ld    l,(hl)      ; picks up the char from the array
      ld    hl,0
      ld    d,l
      ld    e,l
```

whereas the correct optimised code should be

```
      ld    e,(hl)
      ld    hl,0
      ld    d,l
```


## Fix I/O redirection start-up and V3.09-11 release
<!-- Jan 11, 2022 -->

When the PIPEMGR I/O redirection is not detected, the standard files
for stdin, stdout and stderr now default to use the console ```CON:```
device for compiler output.  With I/O redirection, these use the
PIPEMGR pseudo device names ```RSX:``` and ```ERR:```.  This fixes the
issue with the compiler front-end error message output - so the temporary
work-around I made a few days ago has been removed.

This fix has changed the start-up modules ```CRTCPM.OBJ``` and
```RRTCPM.OBJ``` to use a new ```_initrsx()``` routine when PIPEMGR is
detected (the source is in the cpm/CLEANUP.C module of LIBC).

To indicate this fix is included, I've bumped the release to V3.09-11
and updated the binary distribution library files.


## Re-order library file modules and V3.09-12 release
<!-- Jan 11, 2022 -->

Fixed the order of modules in the C library (LIBC.LIB and LIB280C.LIB)
to prevent an ```undefined symbol:``` error during linking.

Also added a new feature to the main front-end driver (C.COM) to accept
an ```-N``` switch.  This causes the resulting CP/M program to be
linked with a new start-up module ```NRTCPM.OBJ```.  This provides a
minimal version of _getargs() instead of the standard enhanced default
version of_getargs().  Using ```-N``` can significantly reduce
the size of the generated CP/M binary .COM file at the expense of
wild-card argument processing and command-line file redirection of
stdout and stdin (using the ```>file```, ```>>file``` and ```<file```
modifiers).

## Backport more-accurate floating point library routines
<!-- Feb 2, 2022 -->

Phillip Stevens has submited updates to the floating point library
routines for ```acos()```, ```asin()```, ```atan()```, ```atan2()```,
```cos()```, ```eval_poly()```, ```exp()```, ```float()```, ```log()```,
```sin()``` and ```sinh()```.  These are from a backport of the
routines from the HI-TECH Z80 cross compiler V7.80pl2.

These fix -

* some typos in the ```atan()``` coefficients - affecting ```acos()```
and ```asin()```;

* improved accuracy of the polynomial estimation for ```asin()``` and
```acos()``` by restricting the range of the polynomial in use;

* correct the sign of ```atan2()``` to reflect the standard usage;

* allow integer powers of negative bases; and

* fixes to the intrinsic ```float.as``` floating point arithmetic
functions.

These changes seem to provide more accurate results.

I've rebuilt the floating-point libraries (LIBF.LIB and LIB280F.LIB).

Please let me know if you notice any issues.


## More back-porting of library source-code
<!-- Feb 3, 2022 -->

Phillip Stevens has back-ported some more of the V7.80pl2 library source.

A summary of the updates are -

* float/LTOF.AS - ```lbtof()``` and ```abtof()``` loaded wrong registers,
and ```lltof()``` improved conversion of long to float accuracy by up
to 7 bits.

* gen/ATOL.C - recognise a ```+``` in a number constant (e.g. ```+123456L```).

* gen/BRELOP.AS, gen/FRELOP.AS, gen/LRELOP.AS - avoid the use of
an ```ex af af'``` op-code (some CP/M systems use the alternate 
accumulator and flags register for interrupts without doing a push/pop
to save it).

* gen/LONGJMP.AS - fixes.

* gen/IDIV.AS - fixes.

* plus add miscellaneous type casts and fix typos in cpm/ABORT.C,
gen/RAND.C, gen/STRFTIME.C, stdio/FILBUF.C, stdio/GETW.C and stdio/UNGETC.C

Updated libraries (LIBC.LIB/LIBF.LIB and LIB280C.LIB/LIB280F.LIB) are
in the dist folder and the binary distribution libraries.


## Z280 assembly language optimisation
<!-- Feb 7, 2022 -->

The Z280 front-end ```C280.COM``` has been modified to allow optimisation
of Z80 assembly language input files when either the ```-O2``` or ```-OF2```
options are specified.  This uses the same ```OPTIMH``` optimisation
rules as it uses when ```C280``` compiles C programs.

This means a command like ```C280 -O2 -C MODULE.AS``` will firstly
perform a source-code optimisation pass before invoking the assember
```ZAS```.  Testing this on the library build procedures squeezes
a few bytes from some of the modules.

If you wish to examine the result of the ```OPTIMH``` pass, you can use
the ```-S``` option to retain the optimised source in a file with
the ```.AS2``` file type.

For example -

```
10E>c280 -s -o2 -v execl.as                                                     
A:C280     COM  (User 0)                                                        
Hi-Tech Z280 C Compiler (CP/M-80) V3.09-13                                      
Copyright (C) 1984-87 HI-TECH SOFTWARE                                          
Updated from https://github.com/agn453/HI-TECH-Z80-C                            
0:A:OPTIMH EXECL.AS EXECL.AS2                                                   
 71 bytes optimized away                                                        
 122 bytes replaced                                                             
0:A:ZAS -J -OEXECL.OBJ EXECL.AS2                                                
ERA M:$$EXEC.$$$                                                                
                                                                                
10E>
```

There's newly optimised Z280 object libraries (LIB280C.LIB and LIB280F.LIB)
and CP/M COM  files in the *z280dist* folder, including the new V3.09-13
compiler front-end as ```C280-13.COM``` (which you should copy and rename to
```C280.COM``` on the drive where you install the rest of the compiler files).

The Z280 binary distribution library has been updated too. Get it from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/z280bin.lbr

(If you're wondering - there's been no changes that affect the V3.09-12
Z80 release files).


## Interpretation of exact file sizes reverted
<!-- Mar 17, 2022 -->

Following on from Mark Ogden's consultations with John Elliott (the author
of the ZXCC emulator and PIPEMGR),  I have accepted a proposal from Mark
Ogden to revert the interpretation of exact file sizes back to John
Elliott's original DOS Plus interpretation.

As mentioned in the release v3.09-3 notes (above), there are two common
conventions that can be used to record exact file sizes in CP/M 3 and
DOS Plus.

* Record the number of bytes USED in the last sector (as used by DOS Plus)

or

* Record the number of UNUSED bytes in the last sector (used by ISX for
ISIS emulation)

NB: The compiler release V3.09-13 was set to select this via
an ```EXACT``` environment variable (defined in the 0:A:ENVIRON file).
This feature has been removed from the current release V3.09-14 (and
subsequent versions) and replaced with the following.

The start-up module (CRTCPM.OBJ) detects whether you are running the
compiler under CP/M 2 or CP/M 3 (or DOS Plus) and defaults a global
variable ```_exact``` to enable DOS Plus interpretation of exact file
size.

To allow you to continue with the alternative ISX/ISIS interpretation,
you can override the value of the global variable as follows -

```
#include <stdio.h>
extern char _exact;
..
int main(int argc, char ** argv)
{
    _exact = 'I';  /* Enable ISIS exact file size */
..
}
```

The values of ```_exact``` can also be only one of the following -

```
    _exact = 'C';  /* No exact file size - like CP/M 2.2 uses */
or
    _exact = 'D';  /* DOS Plus convention for exact file size */
```

The C library close() routine uses the selected exact file size mode
to write the last record USED (DOS Plus) or UNUSED (ISIS) byte value
to the directory entry.

Note: You need to take extra care if you're using an emulator like ZXCC
which has been updated to only support the DOS Plus
convention or the CP/M 2.2 interpretation (as per the original version
by John Elliott).  Using the wrong mode will cause the file to be
extended or truncated in the last sector.  The CP/M 2.2 mode causes
```Ctrl-Z``` to be written at the end of text files (as per the CP/M
convention).

The PIPEMGR source code has also been reverted to support only the
DOS plus and CP/M 2.2 file size convention.  Piping a text concatenation
(using the ```>>``` operator) will now write the extra text to the end
of the file (and before the ```Ctrl-Z``` marker if the file has this in
the last sector).  Files written to by PIPEMGR will use the DOS Plus
exact file size convention.


## Fixes to longjmp() and detect underflow in floating point division
<!-- May 24, 2022 -->

Mark Ogden has supplied a couple of fixes.

The first was a result of an incorrect assumption about a compiler
optimisation from later versions of the HI-TECH Z80 cross-compiler.
V3.09-x does not pass an initial function argument in the DE register.
Only the longjmp() routine (in gen/LONGJMP.AS) is affected.

The second concerns a floating point division not detecting an underflow
condition.  The fldiv() routine (in float/FLOAT.AS) now detects this
and returns a zero result.

Updated LIBC.LIB and LIBF.LIB contain the fixes (as well as the Z280
versions LIB280C.LIB and LIB280F.LIB), and I've bumped the release
to V3.09-15.


## Fixes to the compiler driver
<!-- Aug 9, 2022 -->

As reported by Mark Ogden, there are a couple of bugs in the compiler
driver program.

* The first is regarding the use of the self-relocating (-A) option,
where the code compiled for the linker should use the ```cpm``` psect 
segment (as per the relocatable start-up module RRTCPM.OBJ); and

* If you specify a .SYM file on the command line without specifying
the overlay (-Y) option, the compiler driver tries to assemble a
non-existing temporary file.

The latest compiler driver (in cpm/C309-16.C) addresses both by passing
the ```cpm``` psect to the linker and ignores .SYM files unless the
overlay (-Y) option is specified.

The binaries for the compiler driver (in dist//C309-16.COM and
z280dist/C280-16.COM) have been updated as well as the binary distribution
library files to be release V3.09-16 (download link at the top of
this README file).

## Minor LIBC ordering fix
<!-- Feb 6, 2023 -->

The C library has had the ordering of modules adjusted to resolve
an undefined symbol error (thanks to Mark Ogden for bringing this 
to my attention).

## Remove temporary file
<!-- Mar 22, 2023 -->

When the compiler driver was executed without producing an output file, it
left behind a stray ```$$EXEC.$$$``` file on the current drive (or on the
temporary drive if you specified a TMP environment variable in your
```0:A:ENVIRON.``` file).  This now fixed.

I've also bumped the version number to be release V3.09-17.


## Library containing distribution files for unmodified V3.09 release
<!-- Mar 24, 2023 -->

I've added a CP/M library format (.LBR) file containing the unmodified
HI-TECH C COMPILER V3.09 for Z80 CP/M to the *historical* folder.
The files in
[historical/Z80V309.LBR](https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/historical/Z80V309.LBR)
can be extracted using one of the CP/M library utilities like
[NULU.COM](https://raw.githubusercontent.com/agn453/Z280RC/master/utilities/NULU.COM),
or a Unix tool like lar,


## Z280 optimiser (OPTIMH) fixes/enhancements
<!-- Nov 1, 2023 -->

The following updates have been made to the Z280 assembly language
optimiser (OPTIMH.COM) -

* Comments in the OPTIMH.C source file have been translated from German
into English;

* The counters for the additional byte and replaced counts are now more
accurate;

* The processing summary output now includes "speed" or "size";

* The default filetype for the output file has been changed from .ASO to .AS2
to be consistent with the compiler behaviour when it optimises and saves
the output assembler source (i.e compilation using the ```-O2``` or
```-OF2``` with the ```-S``` option);

* Some ```call csv``` and ```jp cret``` speed optimisations were not being
detected; and

* Assembly language statement labels on optimised code were being omitted
in the output file.  Processing now detects them and outputs them
on a separate line prior to performing optimisation.

I've rebuilt the Z280 optimised libraries (LIB280C.LIB, LIB280F.LIB) and
compiler frontend C280-17.COM using the updated optimiser - and these files
are now available in both the *z280dist* folder and updated Z280 binary
distribution at

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/z280bin.lbr

Please raise an issue if you have any problems with them.

## Update missing exact file length code in the C Library for stat() and open() routines, and fix fseek() bug.
<!-- May 6, 2025 -->

When the exact file length code was reverted back in V3.09-13 I missed
updating a couple of the C library routines to use the ```_exact```
global variable to correctly handle the selected mode for handing
DOS Plus mode (the DEFAULT).  The ```stat()``` and ```open()``` library
routines have now been updated.   These were found when looking for the
resolution to issue #49. The ```fseek()``` routine was returning with an
offset of the buffer size (512 bytes) for files opened in read and write ("r+b")
mode.  The ```ftell()``` routine was the culprit in the FSEEK.C library
module and the offset is no longer added for a file opened in this mode.
(This bug appears to be a long standing one that is in the C library
at least as far back as HI-TECH C V1.3).

The C libraries (LIBC.LIB and LIB280C.LIB) have been updated and the
compiler front-end processor have been updated to include the corrected
modules.  I've also bumped the version to V3.09-18 so you
know you're using the corrected modules.

## OCR version of scanned manual added
<!-- May 29, 2025 -->

Thanks to Martin Homuth-Rosemann for contributing an OCR enhanced copy of
the scanned October 1989 "HI-TECH SOFTWARE C COMPILER (Z80) User's Manual".
You'll find this in the
[doc/Hi-Tech-Z80-1989-october_ocr.pdf](https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/doc/Hi-Tech-Z80-1989-october_ocr.pdf)
file.  This allows you to search the document for content using your PDF
reader/web browser.

## Backported V4.11 STDIO routines
<!-- June 3, 2025 -->

In order to resolve issue #50 concerning incorrect handling of file position
and failure to flush buffers when a file is accessed for updating (in
```r+b``` mode),  I have backported the stdio routines from the HI-TECH
C Z80 Cross-compiler V4.11 into the C Library (LIBC.LIB and LIB280C.LIB).
The original V3.09 routines had convoluted code that was not properly
handling a file read followed by a seek and write.

When examining the HI-TECH stdio routines from the V4.11 cross-compiler
it became obvious that the problem was known and corrected using a
different combination of file flag status bytes.  The update adds a
word to the ```FILE``` structure that permits a different file buffer size
to be selected (using a newly added ```setvbuf()``` routine) whilst
maintaining the old default of 512 bytes; and replaces the old
```_IOWROTE``` flag status bit with an ```_IOSEEKED``` flag to indicate
that a file seek has occurred since the last file write.

```
setvbuf() and setbuf()

     The setvbuf() function allows the buffering behaviour of a STDIO
     stream to be altered. It supersedes the function setbuf() which is
     retained for backwards compatibility.

     #include <stdio.h>

     int setvbuf(FILE * stream, char * buf, int mode, size_t size);

     void setbuf(FILE * stream, char * buf)

     The arguments to setvbuf() are as follows:

     stream designates the STDIO stream to be affected; buf is a pointer
     to a buffer which will be used for all subsequent I/O operations on
     this stream. If buf is null, then the routine will allocate a buffer
     from the heap if necessary, of size BUFSIZ as defined in ```<stdio.h>```.
     mode may take the values _IONBF, to turn buffering off completely,
     _IOFBF, for full buffering, or _IOLBF for line buffering. Full
     buffering means that the associated buffer will only be flushed when
     full, while line buffering means that the buffer will be flushed at
     the end of each line or when input is requested from another STDIO
     stream. size is the size of the buffer supplied. For example -

     setvbuf(stdout, my_buf, _IOLBF, sizeof my_buf);

     If a buffer is supplied by the caller, that buffer will remain
     associated with that stream even over fclose(), fopen() calls until
     another setvbuf() changes it.
```

The updated binaries, libraries and header files have been included in
the *dist* and *z280dist* folders, along with source-code and build files
in the *stdio*, *float* and *cpm* folders.

I've also bumped the version to V3.09-19 so you know you're using the
latest library modules.  Library version information is also now included
in the ```STDIO.H``` file as

```
#define _HTC_VERSION    "3.09-19"
#define _HTC_MAJOR      3
#define _HTC_MINOR      9
#define _HTC_REV        19
```

and a global string can be accessed from the C libraries. This can be
referenced and printed using

```
extern char * _libcver; /* or _libfver for LIBF.LIB */
..
fprintf(stdout,"C library version %s\n",_libcver);
```

Grab the updated V3.09-19 distribution binary .LBR file for Z80 CP/M from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/htc-bin.lbr

and optionally the Z280 binary distribution (if you need it) from

https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/z280bin.lbr


## Z280 assembly optimiser minor update
<!-- June 5, 2025 -->

A minor issue has been corrected with the Z280 optimiser ```OPTIMH.COM```
where it was failing to process assembly language source files where a
statement label has no white-space (a space or tab) between the colon
and the opcode.  e.g.

```
label1:ld hl,0
```

was incorrectly output as

```
label1:
        d hl,0
```

to the Z280 assembler ```.AS2``` output file.

This did not trigger with the normal compiler processing of assembler
intermediate files - since all labels that the compiler produces have
a space after them.

The updated source ```OPTIMH.C``` and binary ```OPTIMH.COM``` are in the
*z280dist* folder and the 
[z280bin.lbr](https://raw.githubusercontent.com/agn453/HI-TECH-Z80-C/master/z280bin.lbr)
Z280 binary distribution library.


## Update to support binaries running under Digital Research MP/M-II
<!-- September 5, 2025 -->

NB:  There is insufficient memory to run the compiler modules under
MP/M due to the reduced transient program area.

The binaries produced by the compiler now run under MP/M-II following
a correction to the
various start-up modules (CRTCPM.OBJ C280CPM.OBJ etc) to check for MP/M
after doing a BDOS function 12 Get Version call.  Previously it was
following the CP/M 3 path and trying un-implemented BDOS calls to check
for the presence of the PIPEMGR RSX and making all the wrong configuration
choices.  (As an aside -- one of the main differences
between MP/M and CP/M is that it returns a HL=0xFFFF error code for
unimplemented BDOS calls whereas CP/M returns HL=0).  Hopefully I have
reviewed all the places the C Library routines do a BDOS Check Version call.

Also, I have modified the code in the ```signal()``` library routine that
detects a SIGINT to use a Direct Console I/O (BDOS function 6) call to check
for a CTRL-C while processing a stdio call.  Previously it was checking
if a character had been struck using the Console Status (BDOS function 11)
and fetching it using the Console Input with Echo (BDOS function 1) call.
The old way did not work correctly under MP/M since it was already
intercepting the CTRL-C internally and prompting to abort the running
program.  A side-effect of this is that now when you SIGINT a HI-TECH C
program using CTRL-C via ```signal()```, the ```^C``` will no longer be
echoed back to the console.  MP/M does not intercept characters using
the Direct Console I/O call.  HI-TECH C produced binaries will recognise
and act on it though.

The version number for HI-TECH C has been bumped to V3.09-20 to reflect
these changes (in the libraries and main driver).  I've done all my testing
under MP/M V2.1 and it should work with older versions.  If not, please
raise an issue on GitHub.


[^1]: RunCPM is a multi-platform, portable, Z80 CP/M 2.2 emulator.  It is
actively maintained and available from https://github.com/MockbaTheBorg/RunCPM

[^2]: SIMH AltairZ80 is one of many computer system simulators from the
Open SIMH Project (https://opensimh.org).  It emulates 8080/Z80/8085 and
MC68000 S-100 bus computers (like the MITS Altair with various interface
cards and peripherals).  You can obtain source-code for over 70 different
systems from https://github.com/open-simh/simh or just the AltairZ80
specific simulator and various prebuilt CP/M operating system kits from
Peter Schorn's site at https://schorn.ch/altair.html

[^3]: ZXCC is a CP/M 2/3 emulator for cross compiling and running most
CP/M binary command files under Linux/Unix/macOS and Microsoft Windows.
It was authored by John Elliott and with various updates may be obtained
from https://github.com/agn453/ZXCC

[^4]: The newsgroup comp.os.cpm can be accessed via a USENET
provider like www.eternal-september.org using newsreader software like
Mozilla Thunderbird.  An archived copy of the original thread can be
read via Google Groups at
https://groups.google.com/forum/#!topic/comp.os.cpm/V9Qwoc3--Ak - but
since February 2024 you will need to access comp.os.cpm via a USENET
provider to be able to post messages. 

--

Tony Nicholson, Friday 05-Sep-2025


================================================
FILE: cpm/ABORT.C
================================================
#include <cpm.h>

static char	mess[] = "Fatal error - program aborted\r\n$";

void
abort()
{
	bdos(CPMWCOB, mess);
	exit(-1);
}


================================================
FILE: cpm/BDOS.AS
================================================
;-----------------------------------------------------------------------------
;
; All BDOS calls on all versions of CP/M 80 return with B = H and A = L.
; Furthermore, when an 8-bit result is all that is returned then B = H = 0.
;
; This is a documented feature of CP/M but it seems to have been overlooked
; by most programmers.  Compiler vendors in particular seem to have felt
; compelled to provide two versions of the bdos() function, one for 8-bit
; results and one for 16-bit results.  There is simply no need for that.
;
; This is a replacement for the bdos() and bdoshl() functions in the Hi-Tech
; C runtime library.
;
; How to patch your library:
;
;	zas bdos.as
;	libr d libc.lib bdoshl.obj
;	libr r libc.lib bdos.obj
;
; Jon Saxton
; September 2012
;
;-----------------------------------------------------------------------------
;
; There is one caveat attached to all this.  The Hi-Tech C bdos() function
; did a sign extension of the 8-bit result to convert it to a 16-bit result.
; That is no longer done.  It is only going to be a problem if your code
; checks 8-bit return codes for negative numbers, e.g. -1 instead of 0xFF.
; The function prototype is:
;
;	short bdos(short func, ...);
;
; instead of:
;
;	char bdos(short func, ...);
;	short bdoshl(short func, ...);
;
; When running under CP/M 3 there are several functions which can return
; extended error codes.  For those functions, the error signal is A=L=0xFF
; and the extended error is in B and H.  For consistency across all versions
; of CP/M it is correct to test the low-order byte of the return value where
; appropriate; for example:
;
;	short	rc;
;	...
;	rc = bdos(fn, arg);
;	if ((rc & 0xFF) == 0xFF)
;	    [deal with error];
;	else
;	    [normal processing];
;
; Note that finding 0xFF in the low-order 8 bits of the return value does not
; always indicate an error.  For example, functions such as 25 (return login
; vector) and 31 (get DPB address) could legitimately return such a value.
; When calling the BDOS one always has to be aware of the context and the
; possible return value.  The prior implementation with separate calls for
; for 8-bit and 16-bit results was already an expression of context awareness.
;
; Also be aware that an error is not always flagged by 0xFF in the low-order
; byte of the return value.  For some functions any non-zero return value is
; an error.
;
;-----------------------------------------------------------------------------
;
; 10 Apr 2014
;
; This module has been updated to incorporate John Elliott's code to set
; _errno on a failed BDOS call.
;
; This is only possible on CP/M Plus and only meaningful for the subset of
; BDOS functions which return an extended error code.  These functions can
; now set errno.
;
; John's version of this routine is bdose() and is part of the PIPEMGR suite
; found on his web site:
;
;	http://www.seasip.demon.co.uk/Cpm/software/Pipemgr/index.html
;
; There is no need to call bdose(); bdos() does everything.
;
;-----------------------------------------------------------------------------
;
; The password handler mechanism documented in John's LIBCNEW.DOC has been
; disabled for the time being because it seems to be ineffective and I have
; not yet discovered why.  It is possible that the problem lies with CP/M 3
; rather than John's code.  Opening a password-protected file generates a
; password error but entering a null password is sufficient to bypass the
; protection!
;
; Passwords are probably useless anyway.  They are also easily bypassed.
;
; Jon Saxton [20 Apr 2014]
;
;-----------------------------------------------------------------------------

	global	csv,cret

false	equ	0
true	equ	.not. false

PWDREC	equ	false		; Password recovery mechanism (off)

entry	equ	5		; CP/M entry point

arg	equ	8		;argument to call
func	equ	6		;desired function

	global	_bdos, _errno

	cond	PWDREC
	global	__passwd, __dpass
	endc

	psect	data

	cond	PWDREC
__passwd:
	defw	__dpass
	endc

;-----------------------------------------------------------------------------
; The following table is a bit map.  Each bit represents a BDOS function
; which, under CP/M Plus, can return an extended error code.  The functions
; identified in the bit map are also the ones which can set errno.
;
; The extended errors are consistent over all the relevant functions:
;
;	Error		Meaning
;
;	  1		Disk I/O error
;	  2		Read-only disk
;	  3		Read-only file
;	  4		Invalid drive
;	  5
;	  6
;	  7		Password error
;	  8		File exists
;	  9		? in file name
;
; These are the functions flagged in the bitmap.
;
;	BDOS function			Possible errors 
;
;	14 Select disk			1, 4
;	15 Open file			1, 4, 7, 9
;	16 Close file			1, 2, 4
;	17 Search for first		1, 4
;	18 Search for next		1, 4
;	19 Delete file			1, 2, 3, 4, 7
;	20 Sequential read		1, 4
;	21 Sequential write		1, 2, 3, 4
;	22 Create file			1, 2, 4, 8, 9
;	23 Rename file			1, 2, 3, 4, 7, 8, 9
;	30 Set file attributes		1, 2, 4, 7, 9
;	33 Random read			1, 4
;	34 Random write			1, 2, 3, 4
;	35 Compute file size		1, 4
;	40 Random write with zero fill	1, 2, 3, 4
;	46 Get disk free space		1, 4
;	48 Flush buffers		1, 2, 4
;	59 Load overlay			1, 4
;	60 Call RSX			depends on RSX
;	98 Free blocks			4
;	99 Truncate file		1, 2, 3, 4, 7, 9
;      100 Set directory label		1, 2, 4, 7
;      101 Return directory label data	1, 4
;      102 File datestamps/pwd mode	1, 4, 9
;      103 Write file XFCB		1, 2, 4, 7, 9
;-----------------------------------------------------------------------------
 
funcmap:
	defb	00000000B	;   0
	defb	11000000B	;   8		14,15
	defb	11111111B	;  16		16-23
	defb	01000000B	;  24		30
	defb	00001110B	;  32		33-35
	defb	01000001B	;  40		40,46
	defb	00000001B	;  48		48
	defb	00011000B	;  56		59,60
	defb	00000000B	;  64
	defb	00000000B	;  72
	defb	00000000B	;  80
	defb	00000000B	;  88
	defb	11111100B	;  96		98-103
	defb	00000000B	; 104
	defb	00000000B	; 112
	defb	00000000B	; 120
	defb	00000000B	; 128
	defb	00000000B	; 136
	defb	00000000B	; 144
	defb	00000000B	; 152

	psect	text

	cond	PWDREC
__dpass:
	ld	hl,0
	ret
	endc

_bdos:
	call	csv		; Establish pointer to parameters
retry:
	ld	e,(ix+arg)
	ld	d,(ix+arg+1)
	ld	c,(ix+func)
	push	iy		; Save IY for caller
	push	ix		; Save stack pointer over BDOS call
	call	entry		; Call BDOS
	pop	ix		; Recover stack pointer
	ld	a,(ix+func)	; Get BDOS function number
	cp	160		; Check range
	jr	nc,2f		; Skip extended processing if out of range
	push	hl		; Save BDOS return code
	ld	c,12		; Get CP/M version
	call	entry
	dec	l		; set Z bit if MP/M
	pop	hl		; Restore BDOS result before checking version
	jr	z,2f		; No return codes for MP/M
	cp	30h		; Need at least 3.x
	jr	c,2f		; No extended error processing if not CP/M+
	ld	iy,instruction	; Prepare to modify code
	ld	a,(ix+func)	; Get function number again
	push	af		; Save it for a moment
	and	7		; Isolate bit number
	add	a,a		; Shift left 3 positions
	add	a,a		;  /
	add	a,a		; /
	or	46h		; Form BIT sub-instruction
	ld	(iy+3),a	; Store it
	pop	af		; Recover function number
	srl	a		; Shift right 3 positions to form byte index
	srl	a		;  /
	srl	a		; /
	ld	(iy+2),a	; Store offset
	ld	iy,funcmap	; Point at function bitmap
instruction:
	bit	0,(iy+0)	; This gets modified by foregoing code
	jr	z,2f		; Not a function returning an extended error
	ld	a,l		; Check for error
	inc	a		; Only 0xFF indicates an extended error
	ld	a,-16		; Pre-condition for a zero
	jr	nz,0f		; Skip if extended error is not possible
	ld	a,h		; Get extended error code

;-----------------------------------------------------------------------------
; The following code exists to support a user-supplied password routine.

	cond	PWDREC
	cp	7		; Password error?
	jr	nz,0f		; If not then just set _errno and exit
	ld	bc,pwret
	push	bc		; Set return address
	ld	hl,(__passwd)	; Possible user-supplied password handler
	jp	(hl)		; Execute default or user-supplied handler
pwret:
	ld	a,h		; Check to see if a password came back
	or	l
	ld	a,7		; Prepare a password error code
	jr	z,0f		; Exit with errno=23 if no password
	ex	de,hl		; DE = password address
	ld	c,26		; Set DMA
	push	ix
	call	entry		; Point DMA at the password
	pop	ix
	pop	iy
	jp	retry		; DE is still on the stack!
	endc
;-----------------------------------------------------------------------------

0:
	add	a,16
	ld	(_errno),a
2:
	pop	iy
	jp	cret


================================================
FILE: cpm/BIOS.AS
================================================
;------------------------------------------------------------------------------
;
; Modified bios() function for Hi-Tech C.
;
; The original code simply acessed the jump table at the start of the CP/M
; BIOS.  That is unsupported (and potentially dangerous) under CP/M 3.x with
; banked memory.
;
; The sanctioned method on CP/M 3.x is to use BDOS function 50.  Since that
; won't work on CP/M 2.2 this version of bios() tests the operating system
; version and acts according to the answer it receives.
;
; But that is not all.  CP/M 2.2 BIOS calls take 0, 1 or 2 inputs.  Single
; inputs go in BC or C, double inputs go in BC and DE.  CP/M 3.x has BDOS
; functions which take inputs in other registers.  The bios() function is
; smart enough to figure out where the arguments go.
;
; Since some functions return 16-bit results, mask the return when expecting
; an 8-bit result.
;
; Examples:
;	rc = bios(2) & 0xFF;		/* Get console input status */
;	bios(4,'K');			/* Write a K to the console */
;	rc = bios(16, sector, trntbl);	/* Get translated sector number */
;	bios(len, src, dst);		/* Copy len bytes from src to dst */s
;
; There was a problem with bios() calls under CP/M 2.2.  The original code
; always returned the A register contents.  In other words it NEVER returned
; a 16-bit result.  That has been fixed.k
;
; Jon Saxton
; (ex-)sysop of the long-defunct Tesseract RCPM+
; 2010-01-30
;
;------------------------------------------------------------------------------

	psect	text

	global	_bios, csv, cret
	global	exit22

cpm	equ	 5			;bdos entry point
CPMVERS	equ	12			; Get Version function
CPMBIOS	equ	50			; CP/M+ Call BIOS function

arg	equ	 6			;offset of 1st arg on stack

SELDSK	equ	 9
SECTRN	equ	16
DEVTBL	equ	20
DRVTBL	equ	22
MOVE	equ	25
USERF	equ	30

_bios:
	call	csv
	ld	c,CPMVERS
	call	cpm
	dec	h			; if running under MP/M
	jr	z,1f			;  treat it like CP/M 2.2
	cp	30h
	jr	nc,30f

;==============================================================================
;			   BIOS call for CP/M 2.2
;==============================================================================

1:	ld	hl,21f			;set up return address
	push	hl
	ld	l,(ix+arg+0)		;get bios index
	dec	l			;adjust
	ld	e,l
	ld	h,0
	ld	d,0
	add	hl,hl			;triple it
	add	hl,de
	ld	de,(1)			;get warm boot address
	add	hl,de			;now have transfer address
	push	hl			;put on stack
	ld	c,(ix+arg+2)		;get 1st arg
	ld	b,(ix+arg+3)
	ld	e,(ix+arg+4)		;get 2nd arg
	ld	d,(ix+arg+5)
	ret				;do bios call
21:
	; Check for 16-bit or 8-bit result.  For CP/M 2.2 the only functions
	; which return 16-bit results are SELDSK (9) and SECTRAN (16).
	; This code is shared with CP/M 3 and that operating system has a few
	; more calls which may return a 16-bit result.
exit22:
	ld	c,a			; Save possible 8-bit return code
	ld	a,(ix+arg+0)		; Get function
	cp	SELDSK			; Test for 16-bit return
	jr	z,23f
	cp	SECTRN
	jr	z,23f
	cp	DEVTBL
	jr	z,23f
	cp	DRVTBL
	jr	z,23f
	cp	MOVE
	jr	z,23f
	cp	USERF
	jr	nc,23f
	ld	l,c			;return value in a (copied to C)
	ld	h,0
23:
	jp	cret

;==============================================================================
;			    BIOS call for CP/M 3.x
;==============================================================================

30:
	push	iy
	ld	iy,biospb		; Point at BIOS parameter block
	ld	e,(ix+arg+0)		; Get function number
	ld	(iy+0),e		; Store in BPB
	ld	hl,rutable		; Point at table
	ld	d,0
	srl	e			; Halve the index, low order bit to CF
	push	af			; Save carry
	add	hl,de			; Point at function bits
	pop	af			; Restore carry flag
	ld	a,(hl)			; Get register usage flags
	jr	nc,31f			; Skip if index was even
	rrca				; Index was odd, move high nybble down
	rrca
	rrca
	rrca
31:
	push	ix			; Stack frame to HL
	pop	hl
	ld	de,arg+2		; Point at first argument
	add	hl,de
	ld	e,(hl)			; Load first argument
	inc	hl
	ld	d,(hl)
	inc	hl
	rra				; Low bit of register flags to carry
	jr	nc,34f			; Skip if A register not used
	ld	(iy+1),e		; Store argument in BPB.A
	ld	e,(hl)			; Get next argument
	inc	hl
	ld	d,(hl)
	inc	hl
34:
	ld	b,3			; Shift counter
35:
	inc	iy			; Step the BPB to the next register
	inc	iy			;  slot
	rra				; Register usage bit to carry
	jr	nc,36f			; Skip if unused
	ld	(iy+0),e		; Store argument in BPB.XX
	ld	(iy+1),d		;  where XX is BC, DE or HL
	ld	e,(hl)			; Get next argument
	inc	hl
	ld	d,(hl)
	inc	hl
36:
	djnz	35b

	pop	iy			; Restore caller's IY
	ld	de,biospb		; Recover BPB address
	ld	c,CPMBIOS		; BIOS call via BDOS
	call	cpm
	jr	21b			; Exit with 8- or 16-bit result

;==============================================================================

	psect	data
biospb:
	defs	8			; BIOS parameter block

;------------------------------------------------------------------------------
; The following table defines input register usage for BIOS functions.
;
;	Bit 0 is set if A is used
;	Bit 1 is set if BC is used
;	Bit 2 is set if DE is used
;	Bit 3 is set if HL is used
;
; Each entry in the table represents two functions.  The lower nybble holds
; the register usage bits for an even-numbered function and the upper nybble
; holds the bits for the next (odd-numbered) function.
;------------------------------------------------------------------------------

rutable:
	defb	00h			;  0 - Cold boot
					;  1 - Warm boot
	defb	00h			;  2 - Console input status
					;  3 - Console input
	defb	22h			;  4 - Console output
					;  5 - List device output
	defb	02h			;  6 - Auxiliary device output
					;  7 - Auxiliary device input
	defb	60h			;  8 - Home disk
					;  9 - Select disk
	defb	22h			; 10 - Set track
					; 11 - Set sector
	defb	02h			; 12 - Set DMA
					; 13 - Read
	defb	02h			; 14 - Write
					; 15 - List device status
	defb	06h			; 16 - Sector translate
					; 17 - Console output status
	defb	00h			; 18 - Auxiliary input status
					; 19 - Auxiliary output status
	defb	20h			; 20 - Get device table address
					; 21 - Initialise device
	defb	20h			; 22 - Drive table
					; 23 - Multi sector I/O
	defb	0E0h			; 24 - Flush buffers
					; 25 - Move
	defb	12h			; 26 - Time
					; 27 - Select memory bank
	defb	21h			; 28 - Set bank for I/O
					; 29 - XMove
	defb	0FFh			; 30 - UserF
					; 31 - Reserved 1
	defb	0Fh			; 32 - Reserved 2

;==============================================================================
;	BIOS call summary for C programs
;==============================================================================
;
;	bios(0);			Cold boot
;	bios(1);			Warm boot
;	rc = bios(2);			Console input status
;	rc = bios(3);			Console input
;	bios(4, chr);			Console output
;	bios(5,	chr);			List device output
;	bios(6, chr);			Auxiliary device output (PUN)
;	rc = bios(7);			Auxiliary device input (RDR)
;	bios(8);			Home disk
;	rc = bios(9, drv, init);	Select disk
;	bios(10, track);		Set track
;	bios(11, sector);		Set sector
;	bios(12, pDMA);			Set DMA
;	rc = bios(13);			Read
;	rc = bios(14, deblock);		Write
;	rc = bios(15);			List device status
;	rc = bios(16, sector, txtbl);	Sector translate
;
;-------------------------- CP/M 2.2 - 3.1 boundary ---------------------------
;
;	rc = bios(17);			Console output status
;	rc = bios(18);			Auxiliary input status
;	rc = bios(19);			Auxiliary output status
;	rc = bios(20);			Get device table address
;	rc = bios(21, devno);		Initialise device
;	rc = bios(22);			Drive table
;	bios(23, sectors);		Multi sector I/O
;	rc = bios(24);			Flush buffers
;	bios(25, len, src, dest);	Move
;	bios(26, getorset);		Time
;	bios(27, bank);			Select memory bank
;	bios(28, iobank);		Set bank for I/O
;	bios(29, srcBank+destBank*256);	XMove
;	rc = bios(30, a, bc, de, hl);	UserF (implementor defined)
;	rc = bios(31, a, bc, de, hl);	Reserved
;	rc = bios(32, a, bc, de, hl);	Reserved
;==============================================================================


================================================
FILE: cpm/BUILD-C.LOG
================================================

10E>;
10E>date
A:DATE     COM  (User 0)

Fri 05/09/2025 13:20:24
10E>;
10E>; Build Z80 version
10E>c -o -v c309-20.c
A:C        COM  (User 0)
Hi-Tech Z80 C Compiler (CP/M-80) V3.09-20
Copyright (C) 1984-87 HI-TECH SOFTWARE
Updated from https://github.com/agn453/HI-TECH-Z80-C
0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: C309-20.C M:$CTMP1.$$$
0:A:P1 M:$CTMP1.$$$ M:$CTMP2.$$$ M:$CTMP3.$$$
0:A:CGEN M:$CTMP2.$$$ M:$CTMP1.$$$
0:A:OPTIM M:$CTMP1.$$$ M:$CTMP2.$$$
0:A:ZAS -J -N -OC309-20.OBJ M:$CTMP2.$$$
ERA M:$CTMP1.$$$
ERA M:$CTMP2.$$$
ERA M:$CTMP3.$$$
ERA M:$CTMP5.$$$
0:A:LINQ -Z -Ptext=0,data,bss -C100H -OC309-20.COM 0:A:CRTCPM.OBJ C309-20.OBJ 0:A:LIBC.LIB
ERA C309-20.OBJ
ERA M:$$EXEC.$$$

10E>;
10E>; Now build Z280 version
10E>;
10E>; First a Z280 version using the Z80 LIBC.LIB (runs on Z80)
10E>c309-20 -o -v -ec280z80.com -dZ280 c309-20.c
E:C309-20  COM
Hi-Tech Z80 C Compiler (CP/M-80) V3.09-20
Copyright (C) 1984-87 HI-TECH SOFTWARE
Updated from https://github.com/agn453/HI-TECH-Z80-C
0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: C309-20.C M:$CTMP1.$$$
0:A:P1 M:$CTMP1.$$$ M:$CTMP2.$$$ M:$CTMP3.$$$
0:A:CGEN M:$CTMP2.$$$ M:$CTMP1.$$$
0:A:OPTIM M:$CTMP1.$$$ M:$CTMP2.$$$
0:A:ZAS -J -N -OC309-20.OBJ M:$CTMP2.$$$
ERA M:$CTMP1.$$$
ERA M:$CTMP2.$$$
ERA M:$CTMP3.$$$
ERA M:$CTMP5.$$$
0:A:LINQ -Z -Ptext=0,data,bss -C100H -OC280Z80.COM 0:A:CRTCPM.OBJ C309-20.OBJ 0:A:LIBC.LIB
ERA C309-20.OBJ
ERA M:$$EXEC.$$$

10E>;
10E>; and the Z280 optimized version from it (only runs on a Z280)
10E>c280z80 -of2 -v -ec280-20.com c309-20.c
E:C280Z80  COM
Hi-Tech Z280 C Compiler (CP/M-80) V3.09-20
Copyright (C) 1984-87 HI-TECH SOFTWARE
Updated from https://github.com/agn453/HI-TECH-Z80-C
0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: C309-20.C M:$CTMP1.$$$
0:A:P1 M:$CTMP1.$$$ M:$CTMP2.$$$ M:$CTMP3.$$$
0:A:CGEN M:$CTMP2.$$$ M:$CTMP1.$$$
0:A:OPTIM -F M:$CTMP1.$$$ M:$CTMP2.$$$
0:A:OPTIMH -F M:$CTMP2.$$$ M:$CTMP5.$$$
 496 bytes speed optimised away
 1643 bytes replaced
0:A:ZAS -N -OC309-20.OBJ M:$CTMP5.$$$
ERA M:$CTMP1.$$$
ERA M:$CTMP2.$$$
ERA M:$CTMP3.$$$
ERA M:$CTMP5.$$$
0:A:LINQ -Z -Ptext=0,data,bss -C100H -OC280-20.COM 0:A:C280CPM.OBJ C309-20.OBJ 0:A:LIB280C.LIB
ERA C309-20.OBJ
ERA M:$$EXEC.$$$

10E>;
10E>; plus a Z80 version of the Z280 optimisation program in case
10E>; we need to bootstrap a new LIB280C.LIB using the Z80 C280Z80
10E>; compiler front end on a Z80
10E>c280z80 -o2 -v -eoptimh80.com optimh.c
E:C280Z80  COM
Hi-Tech Z280 C Compiler (CP/M-80) V3.09-20
Copyright (C) 1984-87 HI-TECH SOFTWARE
Updated from https://github.com/agn453/HI-TECH-Z80-C
0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: OPTIMH.C M:$CTMP1.$$$
0:A:P1 M:$CTMP1.$$$ M:$CTMP2.$$$ M:$CTMP3.$$$
0:A:CGEN M:$CTMP2.$$$ M:$CTMP1.$$$
0:A:OPTIM M:$CTMP1.$$$ M:$CTMP2.$$$
0:A:OPTIMH M:$CTMP2.$$$ M:$CTMP5.$$$
 244 bytes size optimised away
 442 bytes replaced
0:A:ZAS -J -N -OOPTIMH.OBJ M:$CTMP5.$$$
ERA M:$CTMP1.$$$
ERA M:$CTMP2.$$$
ERA M:$CTMP3.$$$
ERA M:$CTMP5.$$$
0:A:LINQ -Z -Ptext=0,data,bss -C100H -OOPTIMH80.COM 0:A:C280CPM.OBJ OPTIMH.OBJ 0:A:LIB280C.LIB
ERA OPTIMH.OBJ
ERA M:$$EXEC.$$$

10E>;
10E>; Build the optimiser with the Z280 compiler front-end (may fail
10E>; if the LIB280C.LIB library is not present or compatible with
10E>; the latest updates - use C280Z80 and OPTIMH80 instead.
10E>c280-20 -o2 -v optimh.c
E:C280-20  COM
Hi-Tech Z280 C Compiler (CP/M-80) V3.09-20
Copyright (C) 1984-87 HI-TECH SOFTWARE
Updated from https://github.com/agn453/HI-TECH-Z80-C
0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: OPTIMH.C M:$CTMP1.$$$
0:A:P1 M:$CTMP1.$$$ M:$CTMP2.$$$ M:$CTMP3.$$$
0:A:CGEN M:$CTMP2.$$$ M:$CTMP1.$$$
0:A:OPTIM M:$CTMP1.$$$ M:$CTMP2.$$$
0:A:OPTIMH M:$CTMP2.$$$ M:$CTMP5.$$$
 244 bytes size optimised away
 442 bytes replaced
0:A:ZAS -J -N -OOPTIMH.OBJ M:$CTMP5.$$$
ERA M:$CTMP1.$$$
ERA M:$CTMP2.$$$
ERA M:$CTMP3.$$$
ERA M:$CTMP5.$$$
0:A:LINQ -Z -Ptext=0,data,bss -C100H -OOPTIMH.COM 0:A:C280CPM.OBJ OPTIMH.OBJ 0:A:LIB280C.LIB
ERA OPTIMH.OBJ
ERA M:$$EXEC.$$$

10E>;
10E>dir c*.com [fu
A:DIR      COM  (User 0)

Scanning Directory...

Sorting  Directory...

Directory For Drive E:  User 10

    Name     Bytes   Recs   Attributes   Prot      Update          Create    
------------ ------ ------ ------------ ------ --------------  --------------

C280-20  COM    28k    198 Dir RW       None   05/09/25 13:30  05/09/25 13:30
C280Z80  COM    28k    215 Dir RW       None   05/09/25 13:26  05/09/25 13:26
C309-20  COM    28k    209 Dir RW       None   05/09/25 13:23  05/09/25 13:23

Total Bytes     =     84k  Total Records =     622  Files Found =    3
Total 1k Blocks =     79   Used/Max Dir Entries For Drive E: 1129/2048

10E>dir optimh.com [fu
A:DIR      COM  (User 0)

Scanning Directory...

Directory For Drive E:  User 10

    Name     Bytes   Recs   Attributes   Prot      Update          Create    
------------ ------ ------ ------------ ------ --------------  --------------

OPTIMH   COM    20k    151 Dir RW       None   05/09/25 13:36  05/09/25 13:36

Total Bytes     =     20k  Total Records =     151  Files Found =    1
Total 1k Blocks =     19   Used/Max Dir Entries For Drive E: 1129/2048

10E>;
10E>; Done
10E>put console to console
A:PUT      COM  (User 0)


================================================
FILE: cpm/BUILD-C.SUB
================================================
era build-c.log
put console output to file build-c.log [system]
;
date
;
; Build Z80 version
c -o -v c309-20.c
;
; Now build Z280 version
;
; First a Z280 version using the Z80 LIBC.LIB (runs on Z80)
c309-20 -o -v -ec280z80.com -dZ280 c309-20.c
;
; and the Z280 optimized version from it (only runs on a Z280)
c280z80 -of2 -v -ec280-20.com c309-20.c
;
; plus a Z80 version of the Z280 optimisation program in case
; we need to bootstrap a new LIB280C.LIB using the Z80 C280Z80
; compiler front end on a Z80
c280z80 -o2 -v -eoptimh80.com optimh.c
;
; Build the optimiser with the Z280 compiler front-end (may fail
; if the LIB280C.LIB library is not present or compatible with
; the latest updates - use C280Z80 and OPTIMH80 instead.
c280-20 -o2 -v optimh.c
;
dir c*.com [fu
dir optimh.com [fu
;
; Done
put console to console


================================================
FILE: cpm/BUILDCPM.SUB
================================================
c
<-c -o start1.as open.c read.c write.c chmod.c seek.c \
<fcbname.c rename.c creat.c time.c convtime.c timezone.c \
<stat.c isatty.c cleanup.c close.c unlink.c dup.c getfcb.c \
<srand1.c getch.c signal.c getuid.as abort.c execl.as bdos.as \
<bios.as _exit.as exit.as fakeclea.as fakecpcl.as sys_err.c \
<mktime.c



================================================
FILE: cpm/BUILDCRT.SUB
================================================
;
; Build the start-up modules
;
c -c -o zcrtcpm.as zdrtcpm.as zrrtcpm.as znrtcpm.as
c280 -c -o zc280cpm.as zd280cpm.as zr280cpm.as zn280cpm.as


================================================
FILE: cpm/C-ORIG.C
================================================
/*
 *	Copyright (C) 1984-1897 HI-TECH SOFTWARE
 *
 *	This software remains the property of HI-TECH SOFTWARE and is
 *	supplied under licence only. The use of this software is
 *	permitted under the terms of that licence only. Copying of
 *	this software except for the purpose of making backup or
 *	working copies for the use of the licensee on a single
 *	processor is prohibited.
 */
#include	<stdio.h>
#include	<ctype.h>
#include	<cpm.h>
#include	<exec.h>
#include	<stat.h>

/*
 *	C command
 *	CP/M-80 version
 *
 *	C [-C] [-O] [-I] [-F] [-U] [-D] [-S] [-X] [-P] [-W] [-M] files {-Llib}
 */

#define	DFCB	((struct fcb *)0x5C)

#define	MAXLIST	60		/* max arg list */
#define	BIGLIST	120		/* room for much more */

#define	HITECH	"HITECH"
#define	PROMPT	"c"
#define	TEMP	"TMP"
#define	DEFPATH	"0:A:"
#define	DEFTMP	""

#define	LIBSUFF	".LIB"		/* library suffix */

#define	LFLAGS		"-Z"
#define	STDLIB		"C"
#define	GETARGS		"-U__getargs"

static char	keep,		/* retain .obj files, don't link */
		keepas,		/* retain .as files, don't assemble */
		verbose,	/* verbose - echo all commands */
		optimize,	/* invoke optimizer */
		speed,		/* optimize for speed */
		reloc,		/* auto-relocate program at run time */
		xref,		/* generate cross reference listing */
		nolocal;	/* strip local symbols */

static char *	iuds[MAXLIST],	/* -[IUD] args to preprocessor */
	    *	objs[MAXLIST],	/* .obj files and others for linker */
	    *	flgs[BIGLIST],	/* flags etc for linker */
	    *	libs[MAXLIST],	/* .lib files for linker */
	    *	c_as[MAXLIST];	/* .c files to compile or .as to assemble */

static uchar	iud_idx,	/* index into uids[] */
		obj_idx,	/*   "     "  objs[] */
		flg_idx,	/*   "     "  flgs[] */
		lib_idx,	/*   "     "  libs[] */
		c_as_idx;	/*   "     "  c_as[] */
static char *	paths[] =
{
	"LINQ",
	"OBJTOHEX",
	"CGEN",
	"OPTIM",
	"CPP",
	"ZAS",
	"LIB",
	"P1",
	"CRTCPM.OBJ",
	"$EXEC",
	"CREF",
};

#define	linker	paths[0]
#define	objto	paths[1]
#define	cgen	paths[2]
#define	optim	paths[3]
#define	cpp	paths[4]
#define	assem	paths[5]
#define	libpath	paths[6]
#define	pass1	paths[7]
#define	strtoff	paths[8]
#define	execprg	paths[9]
#define	cref	paths[10]

#define	RELSTRT	strtoff[plen]

static char *	temps[] =
{
	"$CTMP1.$$$",
	"$CTMP2.$$$",
	"$CTMP3.$$$",
	"$CTMP4.$$$",
	"L.OBJ",
	"$$EXEC.$$$",
	"CREF.TMP",
};

#define	tmpf1	temps[0]
#define	tmpf2	temps[1]
#define	tmpf3	temps[2]
#define	redname	temps[3]
#define	l_dot_obj	temps[4]
#define	execmd	temps[5]
#define	crtmp	temps[6]

static char *	cppdef[] = { "-DCPM", "-DHI_TECH_C", "-Dz80" };
static char *	cpppath = "-I";


static char	tmpbuf[128];	/* gen. purpose buffer */
static char	single[40];	/* single object file to be deleted */
static short	nfiles;		/* number of source or object files seen */
static char *	outfile;	/* output file name for objtohex */
static FILE *	cmdfile;	/* command file */
static short	plen;		/* length of path */
static char	ebuf[22];	/* error listing file */
static char *	xrname;
static struct stat	statbuf;

extern char *	malloc(),
	    *	getenv(),
	    *	fcbname(),
	    *	rindex(),
	    *	strcat(),
	    *	strcpy();
extern char **	_getargs();
extern int	strlen(),
		strcmp(),
		dup();

static char *	xalloc();

main(argc, argv)
char **	argv;
{
	register char *	cp, * xp;
	short		i;

	fprintf(stderr, "HI-TECH C COMPILER (CP/M-80) V3.09\n");
	fprintf(stderr, "Copyright (C) 1984-87 HI-TECH SOFTWARE\n");
#if	EDUC
	fprintf(stderr, "Licensed for Educational purposes only\n");
#endif	EDUC
	if(argc == 1)
		argv = _getargs((char *)0, PROMPT);
	setup();
	while(*++argv) {
		if((argv)[0][0] == '-') {
			if(islower(i = argv[0][1]))
				argv[0][1] = i = toupper(i);
			switch(i) {

			case 'A':
				reloc = 1;
				RELSTRT = 'R';
				flgs[flg_idx++] = "-L";
				break;

			case 'R':
				flgs[flg_idx++] = GETARGS;
				break;

			case 'V':
				verbose = 1;
				break;

			case 'S':
				keepas = 1;

			case 'C':
				if(argv[0][2] == 'r' || argv[0][2] == 'R') {
					xref = 1;
					if(argv[0][3]) {
						xrname = &argv[0][1];
						xrname[0] = '-';
						xrname[1] = 'o';
					} else
						xrname = (char *)0;
				} else
					keep = 1;
				break;

			case 'O':
				optimize = 1;
				if(argv[0][2] == 'F' || argv[0][2] == 'f')
					speed = 1;
				break;

			case 'I':
			case 'U':
			case 'D':
				iuds[iud_idx++] = argv[0];
				break;

			case 'L':
				addlib(&argv[0][2]);
				break;

			case 'F':
				argv[0][1] = 'D';
				flgs[flg_idx++] = argv[0];
				break;

			case 'X':
				nolocal = 1;

			case 'P':
			case 'M':
			case 'W':
				flgs[flg_idx++] = argv[0];
				break;

			default:
				fprintf(stderr, "Unknown flag %s\n", argv[0]);
				exit(1);
			}
			continue;
		}
		nfiles++;
		cp = argv[0];
		while(*cp) {
			if(islower(*cp))
				*cp = toupper(*cp);
			cp++;
		}
		cp = rindex(argv[0], '.');
		if(cp && (strcmp(cp, ".C") == 0 || strcmp(cp, ".AS") == 0)) {
			c_as[c_as_idx++] = argv[0];
			if(xp = rindex(argv[0], ':'))
				xp++;
			else
				xp = argv[0];
			*cp = 0;
			strcat(strcpy(tmpbuf, xp), ".OBJ");
			addobj(tmpbuf);
			strcpy(single, tmpbuf);
			*cp = '.';
		} else
			addobj(argv[0]);
	}
	doit();
}

setup()
{
	register char *	cp;
	short		i, len;

	if(!(cp = getenv(HITECH)))
		if(stat("P1.COM", &statbuf) >= 0)
			cp = "";
		else
			cp = DEFPATH;
	plen = strlen(cp);
	cpppath = strcat(strcpy(xalloc(plen+strlen(cpppath)+1), cpppath), cp);
	for(i = 0 ; i < sizeof paths/sizeof paths[0] ; i++)
		paths[i] = strcat(strcpy(xalloc(plen+strlen(paths[i])+1), cp), paths[i]);
	if(cp = getenv(TEMP)) {
		len = strlen(cp);
		for(i = 0 ; i < sizeof temps/sizeof temps[0] ; i++)
			temps[i] = strcat(strcpy(xalloc(len+strlen(temps[i])+1), cp), temps[i]);
	}
	if(strcmp(fcbname(fileno(stdout)), "CON:")) {	/* redirect errors */
		strcat(strcpy(ebuf, "-E"), fcbname(fileno(stdout)));
		close(fileno(stdout));
		stdout->_file = dup(fileno(stderr));
	}
	objs[0] = strtoff;
	obj_idx = 1;
	flgs[0] = LFLAGS;
	flg_idx = 1;
	for(i = 0 ; i < sizeof cppdef/sizeof cppdef[0] ; i++)
		iuds[i] = cppdef[i];
	iud_idx = i;
}

doit()
{
	register char *	cp;
	register uchar	i;

	if(xref)
		close(creat(crtmp, 0600));
	iuds[iud_idx++] = cpppath;
	if(!(cmdfile = fopen(execmd, "wb")))
		error("Can't create temporary file %s", execmd);
	put_cmd(SKP_ERR);
	if(verbose)
		put_cmd(ECHO);
	for(i = 0 ; i < c_as_idx ; i++) {
		cp = rindex(c_as[i], '.');
		if(strcmp(cp, ".C") == 0)
			compile(c_as[i]);
		else
			assemble(c_as[i]);
		put_cmd(TRAP);
	}
	rm(RM_FILE, tmpf1);
	rm(RM_FILE, tmpf2);
	rm(RM_FILE, tmpf3);
	if(!keep) {
		flgs[flg_idx++] = "-Ptext=0,data,bss";
		if(reloc)
			flgs[flg_idx++] = strcat(strcpy(xalloc(strlen(l_dot_obj)+3), "-o"), l_dot_obj);
		else {
			flgs[flg_idx++] = "-C100H";
			flgs[flg_idx++] = strcat(strcpy(xalloc(strlen(outfile)+3), "-O"), outfile);
		}
		for(i = 0 ; i < obj_idx ; i++)
			flgs[flg_idx++] = objs[i];
		addlib(STDLIB);
		for(i = 0 ; i < lib_idx ; i++)
			flgs[flg_idx++] = libs[i];
		flgs[flg_idx] = 0;
		put_cmd(IF_NERR);
		doexec(linker, flgs);
		if(reloc) {
			flgs[0] = "-R";
			flgs[1] = "-B100H";
			flgs[2] = l_dot_obj;
			flgs[3] = outfile;
			flgs[4] = (char *)0;
			doexec(objto, flgs);
			rm(RM_FILE, l_dot_obj);
		}
		if(c_as_idx == 1 && nfiles == 1)
			rm(RM_FILE, single);
	}
	if(xref)
		if(xrname) {
			flgs[0] = xrname;
			strcat(strcpy(tmpbuf, "-h"), outfile);
			if(cp = rindex(tmpbuf, '.'))
				strcpy(cp, ".CRF");
			else
				strcat(tmpbuf, ".CRF");
			flgs[1] = tmpbuf;
			flgs[2] = crtmp;
			flgs[3] = 0;
			put_cmd(IF_NERR);
			doexec(cref, flgs);
			rm(RM_FILE, crtmp);
		} else {
			sprintf(tmpbuf, "Cross reference info left in %s: run CREF to produce listing\n", crtmp);
			print(tmpbuf);
		}
	put_cmd(TRAP);
	rm(RM_EXIT, execmd);
	fclose(cmdfile);
	fclose(stdout);
	fclose(stdin);
	setfcb(DFCB, execmd);
	execl(execprg, execprg, execmd, (char *)0);
	error("Can't execute %s", execprg);
}

rm(type, file)
char *	file;
{
	char	buf[40];

	if(verbose) {
		strcat(strcpy(buf, "ERA "), file);
		print(buf);
	}
	setfcb(DFCB, file);
	putc(type, cmdfile);
	putc(16, cmdfile);
	fwrite(DFCB, 1, 16, cmdfile);
}

print(s)
char *	s;
{
	putc(PRINT, cmdfile);
	putc(strlen(s), cmdfile);
	fputs(s, cmdfile);
}

put_cmd(i)
{
	putc(i, cmdfile);
	putc(0, cmdfile);
}

addobj(s)
char *	s;
{
	char *	cp;
	uchar	len;
	static char	oname;

	if(oname == 0) {
		oname = 1;
		if(cp = rindex(s, '.'))
			len = cp - s;
		else
			len = strlen(s);
		cp = xalloc(len + strlen("-O.COM") + 1);
		strncat(strcpy(cp, "-O"), s, len);
		strcpy(cp+len+2, ".COM");
		outfile = cp+2;
	}
	cp = xalloc(strlen(s)+1);
	strcpy(cp, s);
	objs[obj_idx++] = cp;
}

addlib(s)
char *	s;
{
	char *	cp;

	strcpy(tmpbuf, libpath);
	strcat(strcat(tmpbuf, s), LIBSUFF);
	cp = xalloc(strlen(tmpbuf)+1);
	strcpy(cp, tmpbuf);
	libs[lib_idx++] = cp;
}

error(s, a)
char *	s;
{
	fprintf(stderr, s, a);
	exit(1);
}

static char *
xalloc(s)
short	s;
{
	register char *	cp;

	if(!(cp = malloc(s)))
		error("Out of memory");
	return cp;
}

upcase(s)
register char *	s;
{
	while(*s) {
		if(*s >= 'a' && *s <= 'z')
			*s -= 'a'-'A';
		s++;
	}
}

doexec(name, vec)
char *	name;
char **	vec;
{
	uchar	len;
	char **	pvec;
	char *	redir[2];
	char	redbuf[20];
	FILE *	cfile;
	static short	redno;
	char	xbuf[130];

	pvec = vec;
	len = 0;
	redbuf[0] = 0;
	while(*pvec)
		len += strlen(*pvec++)+1;
	if(len > 124) {
		sprintf(xbuf, redname, ++redno);
		if(!(cfile = fopen(xbuf, "w")))
			error("Can't create %s", xbuf);
		len = 0;
		while(*vec) {
			len += strlen(*vec);
			fprintf(cfile, "%s ", *vec++);
			if(len > 126) {
				len = 0;
				fprintf(cfile, "\\\n");
			}
		}
		fputc('\n', cfile);
		fclose(cfile);
		redir[1] = (char *)0;
		sprintf(redbuf, "<%s", xbuf);
		redir[0] = redbuf;
		vec = redir;
	}
	xbuf[0] = 0;
	while(*vec)
		strcat(strcat(xbuf, " "), *vec++);
	len = strlen(xbuf);
	putc(EXEC, cmdfile);
	putc(len+50, cmdfile);
	setfcb(DFCB, name);
	strcpy(DFCB->ft, "COM");
	DFCB->nr = 0;
	putc(DFCB->uid, cmdfile);
	fwrite(DFCB, 1, 16, cmdfile);
	setfcb(DFCB, &xbuf[1]);
	DFCB->nr = 0;
	fwrite(DFCB, 1, 32, cmdfile);
	putc(len, cmdfile);
	fwrite(xbuf, 1, len, cmdfile);
	if(redbuf[0])
		rm(RM_FILE, &redbuf[1]);
}

assemble(s)
char *	s;
{
	char *	vec[5];
	char	buf[80];
	char *	cp;
	uchar	i;

	if(c_as_idx > 1)
		print(s);
	i = 0;
	if(optimize && !speed)
		vec[i++] = "-J";
	if(nolocal)
		vec[i++] = "-X";
	if(cp = rindex(s, ':'))
		cp++;
	else
		cp = s;
	strcat(strcpy(buf, "-O"), cp);
	if(rindex(buf, '.'))
		*rindex(buf, '.') = 0;
	strcat(buf, ".OBJ");
	vec[i++] = buf;
	vec[i++] = s;
	vec[i] = (char *)0;
	doexec(assem, vec);
}

compile(s)
char *	s;
{
	register char *	cp;
	uchar	i, j;
	char *	vec[MAXLIST];
	char	cbuf[50];

	if(c_as_idx > 1)
		print(s);
	for(j = 0; j < iud_idx ; j++)
		vec[j] = iuds[j];
	vec[j++] = s;
	vec[j++] = tmpf1;
	vec[j] = (char *)0;
	doexec(cpp, vec);
	if(cp = rindex(s, ':'))
		s = cp+1;
	*rindex(s, '.') = 0;
	i = 0;
	if(keepas && !optimize)
		vec[i++] = "-S";
	if(xref)
		vec[i++] = strcat(strcpy(cbuf, "-c"), crtmp);
	if(ebuf[0])		/* error redirection */
		vec[i++] = ebuf;
	vec[i++] = tmpf1;
	vec[i++] = tmpf2;
	vec[i++] = tmpf3;
	vec[i++] = (char *)0;
	doexec(pass1, vec);
	vec[0] = tmpf2;
	vec[1] = keepas && !optimize ? strcat(strcpy(tmpbuf, s), ".AS") : tmpf1;
	vec[2] = (char *)0;
	doexec(cgen, vec);
	if(keepas && !optimize)
		return;
	cp = tmpf1;
	if(optimize) {
		i = 0;
		if(speed)
			vec[i++] = "-F";
		vec[i++] = tmpf1;
		if(keepas)
			vec[i++] = strcat(strcpy(tmpbuf, s), ".AS");
		else
			vec[i++] = tmpf2;
		vec[i] = (char *)0;
		doexec(optim, vec);
		if(keepas)
			return;
		cp = tmpf2;
	}
	i = 0;
	if(nolocal)
		vec[i++] = "-X";
	if(optimize && !speed)
		vec[i++] = "-J";
	vec[i++] = "-N";
	vec[i++] = strcat(strcat(strcpy(tmpbuf, "-o"), s), ".OBJ");
	vec[i++] = cp;
	vec[i] = (char *)0;
	doexec(assem, vec);
}


================================================
FILE: cpm/C309-20.C
================================================
/*
 *  Copyright (C) 1984-1987 HI-TECH SOFTWARE
 *
 *  This software remains the property of HI-TECH SOFTWARE and is
 *  supplied under licence only. The use of this software is
 *  permitted under the terms of that licence only. Copying of
 *  this software except for the purpose of making backup or
 *  working copies for the use of the licensee on a single
 *  processor is prohibited.
 */

/*----------------------------------------------------------------------*\
 | Note by Jon Saxton, 3 May 2014.					|
 |									|
 | It appears that the source file C.C distributed with Hi-Tech C 3.09	|
 | for CP/M-80 does not quite match the C.COM in the same distribution.	|
 |									|
 | This is a slightly modified version of C.C which yields a C.COM that	|
 | seems to work and so could probably replace the standard compiler	|
 | driver.  I use this version but just in case there is a bug which I	|
 | have not yet discovered, I am leaving the original C.COM unchanged.	|
 |									|
 | Updates by Tony Nicholson (@agn453) and Thierry Supplisson		|
 | (@tsupplis), 14 January 2021.					|
 |									|
 | Revised to better support building self-relocating .COM files and	|
 | overlays by automating the building of the resident and overlay	|
 | portions (new -Y compiler flag).					|
 |									|
 | For new features, re-implement Z280 version (original sources lost)	|
 |									|
 | Now has an -N option to select minimal _getargs() support (the	|
 | previous -R option is the default - and is ignored if specified)	|
 |									|
 | This version also attempts assembly language optimisation for the	|
 | Z280 MPU via OPTIMH to allow the libraries to be optimised.		|
\*----------------------------------------------------------------------*/

#include    <stdio.h>
#include    <ctype.h>
#include    <string.h>
#include    <cpm.h>
#include    <exec.h>
#include    <stat.h>
#include    <sys.h>
#include    <stdlib.h>
#include    <unixio.h>
#include    <signal.h>

/*
 * C command
 * CP/M-80 version
 *
 * C [-C] [-O] [-I] [-F] [-U] [-D] [-S] [-X] [-P] \
 *	[-W] [-N] [-M] [-V] [-Y] files {-Llib}
 */

#define DFCB    ((struct fcb *)0x5C)

#define MAXLIST 60      /* max arg list */
#define BIGLIST 120     /* room for much more */

#define HITECH  "HITECH"
#define PROMPT  "c"
#define TEMP    "TMP"
#define DEFPATH "0:A:"
#define DEFTMP  ""

#define LIBSUFF ".LIB"      /* library suffix */

#define LFLAGS      "-Z"
#define STDLIB      "C"

static char
    keep,       /* retain .obj files, don't link */
    keepas,     /* retain .as files, don't assemble */
    verbose,    /* verbose - echo all commands */
    optimize,   /* invoke optimizer */
    speed,      /* optimize for speed */
    reloc,      /* auto-relocate program at run time */
    xref,       /* generate cross reference listing */
    nolocal,    /* strip local symbols */
#ifdef Z280
    z280optim,  /* Z280 code optimization */
#endif
    overlay=0;  /* build with overlays */

static char
    *iuds[MAXLIST],  /* -[IUD] args to preprocessor */
    *objs[MAXLIST],  /* .obj files and others for linker */
    *flgs[BIGLIST],  /* flags etc for linker */
    *libs[MAXLIST],  /* .lib files for linker */
    *c_as[MAXLIST];  /* .c files to compile or .as to assemble */

static uchar
    iud_idx,    /* index into uids[] */
    obj_idx,    /*   "     "  objs[] */
    flg_idx,    /*   "     "  flgs[] */
    lib_idx,    /*   "     "  libs[] */
    c_as_idx;   /*   "     "  c_as[] */

static char *paths[] =
{
    "LINQ",	/* Renamed from LINK to avoid conflict with DRI's LINK-80 */
    "OBJTOHEX",
    "CGEN",
    "OPTIM",
    "CPP",
#ifdef USE_Z80AS
    "Z80AS",
#else
    "ZAS",
#endif
#ifdef Z280
    "LIB280",
#else
    "LIB",
#endif
    "P1",
#ifdef Z280
    "C280CPM.OBJ",
#else
    "CRTCPM.OBJ",
#endif
    "$EXEC",
    "CREF",
    "SYMTOAS",
#ifdef Z280
    "C280OPTS",
    "OPTIMH",
#else
    "OPTIONS",
#endif
};

#define linker  paths[0]
#define objto   paths[1]
#define cgen    paths[2]
#define optim   paths[3]
#define cpp     paths[4]
#define assem   paths[5]
#define libpath paths[6]
#define pass1   paths[7]
#define strtoff paths[8]
#define execprg paths[9]
#define cref    paths[10]
#define symtoas paths[11]
#define options	paths[12]
#ifdef Z280
#define optimh  paths[13]
#endif

#define RELSTRT strtoff[plen]

static char *temps[] =
{
    "$CTMP1.$$$",
    "$CTMP2.$$$",
    "$CTMP3.$$$",
    "$CTMP4.$$$",
    "$L.OBJ",
    "$$EXEC.$$$",
    "CREF.TMP",
    "$CTMP5.$$$",
};

static char *tempm[] =
{
    "-Ptext=0%xh,data",
    "-Ptext=0,data,bss",
    "-Pcpm=0,text,data,bss,stack",
};

#define tmpf1       temps[0]
#define tmpf2       temps[1]
#define tmpf3       temps[2]
#define redname     temps[3]
#define l_dot_obj   temps[4]
#define execmd      temps[5]
#define crtmp       temps[6]
#define tmpf5       temps[7]

#define osegs       tempm[0]
#define nsegs       tempm[1]
#define rsegs       tempm[2]

static int      cbase = 0x0100;

static char    *cppdef[] = {
    "-DCPM",
    "-DHI_TECH_C",
    "-Dz80",
#ifdef Z280
    "-DZ280",
#endif
};
static char    *cpppath = "-I";

static char     tmpbuf[128];    /* gen. purpose buffer */
static char     single[40];     /* single object file to be deleted */
static short    nfiles;         /* number of source or object files seen */
static char    *outfile;        /* output file name for objtohex */
static FILE    *cmdfile;        /* command file */
static short    plen;           /* length of path */
static char     ebuf[22];       /* error listing file */
static char    *xrname;
static struct stat  statbuf;

extern char
   **_getargs();		/* explicit for prompt mode */

static char
   *xalloc(short);

int
    sym2as(char * iname);

void
    doexec(char * name, char ** vec),
    addobj(char * s, int p),
    addlib(char * s),
    setup(),
    error(char * s, char * a),
    doit(),
    assemble(char * s),
#ifdef Z280
    optassemble(char * s),
#endif
    compile(char * s),
    print(char * s),
    put_cmd(int i),
    rm(int type, char * file),
    assemble_sym(char * s),
    viewfile(char * s);

int main(int argc, char **argv)
{
    register char *cp, *xp;
    short       i;

    /* Do not swallow queued stream input while writing to the console */
    signal_t prev_sig;
    prev_sig=signal(SIGINT,SIG_IGN);

#ifdef Z280
    fprintf(stderr, "Hi-Tech Z280 C Compiler (CP/M-80) V%s",_HTC_VERSION);
#else
    fprintf(stderr, "Hi-Tech Z80 C Compiler (CP/M-80) V%s",_HTC_VERSION);
#endif
    fprintf(stderr, "\nCopyright (C) 1984-87 HI-TECH SOFTWARE\n");
    fprintf(stderr, "Updated from https://github.com/agn453/HI-TECH-Z80-C\n");
#if EDUC
    fprintf(stderr, "Licensed for Educational purposes only\n");
#endif  EDUC

    signal(SIGINT,prev_sig);

    if (argc == 1)
        argv = _getargs((char *)0, PROMPT);

    setup();

    while (*++argv)
    {
        if ((argv)[0][0] == '-')
        {
            if (islower(i = argv[0][1]))
                argv[0][1] = i = toupper(i);

            switch(i)
            {
            case 'A':
                reloc = 1;
                RELSTRT = 'R';
                flgs[flg_idx++] = "-L";
                break;

            case 'R':
                /* Wildcard expansion from the command line now built-in */
                /* flgs[flg_idx++] = GETARGS; */
                break;

            case 'V':
                verbose = 1;
                break;

            case 'S':
                keepas = 1;

            case 'C':
                if (argv[0][2] == 'r' || argv[0][2] == 'R')
                {
                    xref = 1;
                    if (argv[0][3])
                    {
                        xrname = &argv[0][1];
                        xrname[0] = '-';
                        xrname[1] = 'o';
                    }
                    else
                        xrname = (char *)0;
                }
                else
                    keep = 1;
                break;

            case 'E':
                outfile = &argv[0][2];
                break;

            case 'O':
                optimize = 1;
                if(argv[0][2] == 'F' || argv[0][2] == 'f')
                {
                    speed = 1;
#ifdef Z280
                    if (argv[0][3] == '2')
                        z280optim = 1;
#endif
                }
#ifdef Z280
                else if( argv[0][2] == '2' )
                    z280optim = 1;
#endif
                break;

            case 'I':
            case 'U':
            case 'D':
                iuds[iud_idx++] = argv[0];
                break;

            case 'L':
                addlib(&argv[0][2]);
                break;

            case 'F':
                argv[0][1] = 'D';
                flgs[flg_idx++] = argv[0];
                break;

            case 'X':
                nolocal = 1;

            case 'P':
            case 'M':
            case 'W':
                flgs[flg_idx++] = argv[0];
                break;

            case 'Y':
                overlay = 1;
                break;

	    case 'H':
                viewfile(options);
                exit(0); /* Ignore all other options for HELP */

	    case 'N':
                RELSTRT = 'N'; /* Use minimal getargs */
                break;

            default:
                error("Unknown flag %s - use -H for HELP", argv[0]);
            }
            continue;
        }

        if (overlay && reloc)
        {
            fprintf(stderr, "-Y and -A options are incompatible, ignoring -Y\n");
            overlay = 0;
        }

        ++nfiles;
        cp = argv[0];
        while (*cp)
        {
            if (islower(*cp))
                *cp = toupper(*cp);
            ++cp;
        }
        cp = rindex(argv[0], '.');
        if (cp && (strcmp(cp, ".C") == 0 || strcmp(cp, ".AS") == 0))
        {
            c_as[c_as_idx++] = argv[0];
            if (xp = rindex(argv[0], ':'))
                ++xp;
            else
                xp = argv[0];
            *cp = 0;
            strcat(strcpy(tmpbuf, xp), ".OBJ");
            addobj(tmpbuf, 1);
            strcpy(single, tmpbuf);
            *cp = '.';
        }
        else if (cp && (strcmp(cp, ".SYM")==0 ))
            {
                if (overlay)
                    {
                        c_as[c_as_idx++] = argv[0];
                        if (xp = rindex(argv[0], ':'))
                            xp++;
                        else
                            xp = argv[0];
                        *cp = 0;
                        strcat(strcpy(tmpbuf, xp), ".OBJ");
                        addobj(tmpbuf, 1);
                        strcpy(single, tmpbuf);
                        *cp = '.';
                    }
                else
                    fprintf(stderr,"%s ignored as -Y option missing\n",argv[0]);
            }
        else
            addobj(argv[0], 0);
    }
    doit();
}

void setup()
{
    register char * cp;
    short       i, len;

    if (!(cp = getenv(HITECH)))
        if (stat("P1.COM", &statbuf) >= 0)
            cp = "";
        else
            cp = DEFPATH;
    plen = strlen(cp);
    cpppath = strcat(strcpy(xalloc(plen+strlen(cpppath)+1), cpppath), cp);
    for (i = 0 ; i < sizeof paths/sizeof paths[0] ; i++)
        paths[i] = strcat(strcpy(xalloc(plen+strlen(paths[i])+1), cp),
                          paths[i]);
    if (cp = getenv(TEMP))
    {
        len = strlen(cp);
        for (i = 0; i < sizeof temps/sizeof temps[0]; ++i)
            temps[i] = strcat(strcpy(xalloc(len+strlen(temps[i])+1), cp),
                              temps[i]);
    }
    if (strcmp(fcbname(fileno(stdout)), "CON:"))   /* redirect errors */
    {
        strcat(strcpy(ebuf, "-E"), fcbname(fileno(stdout)));
        close(fileno(stdout));
        stdout->_file = dup(fileno(stderr));
    }
    objs[0] = strtoff;
    obj_idx = 1;
    flgs[0] = LFLAGS;
    flg_idx = 1;
    for (i = 0; i < sizeof cppdef/sizeof cppdef[0]; ++i)
        iuds[i] = cppdef[i];
    iud_idx = i;
}

void doit()
{
    register char * cp;
    register uchar  i;

    if (xref)
        close(creat(crtmp, 0600));
    iuds[iud_idx++] = cpppath;
    if (!(cmdfile = fopen(execmd, "wb")))
        error("Can't create temporary file %s", execmd);
    put_cmd(SKP_ERR);
    if (verbose)
        put_cmd(ECHO);
    for (i = 0 ; i < c_as_idx ; i++)
    {
        cp = rindex(c_as[i], '.');
        if (strcmp(cp, ".C") == 0)
            compile(c_as[i]);
        else if (strcmp(cp, ".AS") == 0)
        {
#ifdef Z280
            if (z280optim)
                optassemble(c_as[i]);
            else
                assemble(c_as[i]);
#else
            assemble(c_as[i]);
#endif
        }
        else if (strcmp(cp, ".SYM") == 0)
            assemble_sym(c_as[i]);
        put_cmd(TRAP);
    }
    rm(RM_FILE, tmpf1);
    rm(RM_FILE, tmpf2);
    rm(RM_FILE, tmpf3);
    rm(RM_FILE, tmpf5);
    if (!keep)
    {
        char * segopt = 0;
        if (overlay)
        {
            segopt = xalloc(strlen(osegs)+10);
            sprintf(segopt, osegs, cbase);
        }
        else
        {
            if (reloc)
                segopt = rsegs;
            else
                segopt = nsegs;
        }
        flgs[flg_idx++] = segopt;
        if (!outfile)
        {
            fprintf(stderr,"No output file specified\n");
            fclose(cmdfile); /* remove the $$EXEC.$$$ file */
            remove(execmd);
            exit(-1);
        }
        if (reloc)
            flgs[flg_idx++] = strcat(strcpy(xalloc(strlen(l_dot_obj)+3), "-O"),
                                     l_dot_obj);
        else
        {
            char *cb = xalloc(10);
            sprintf(cb, "-C%xH", cbase);
            flgs[flg_idx++] = cb;
            if (overlay)
            {
                strcpy(outfile+strlen(outfile)-3,"OVR");
            }
            flgs[flg_idx++] = strcat(strcpy(xalloc(strlen(outfile)+3), "-O"),
                                     outfile);
        }
        for (i = 0 ; i < obj_idx ; i++)
        {
            if (overlay && strcmp(objs[i], strtoff) == 0)
                continue;
            flgs[flg_idx++] = objs[i];
        }
        if (!overlay)
            addlib(STDLIB);
        for(i = 0 ; i < lib_idx ; i++)
            flgs[flg_idx++] = libs[i];
        flgs[flg_idx] = 0;
        put_cmd(IF_NERR);
        doexec(linker, flgs);
        if (reloc)
        {
            flgs[0] = "-R";
            flgs[1] = "-B100H";
            flgs[2] = l_dot_obj;
            flgs[3] = outfile;
            flgs[4] = (char *)0;
            doexec(objto, flgs);
            rm(RM_FILE, l_dot_obj);
        }
        if (c_as_idx == 1 && nfiles == 1)
            rm(RM_FILE, single);
    }
    if (xref)
        if (xrname)
        {
            flgs[0] = xrname;
            strcat(strcpy(tmpbuf, "-H"), outfile);
            if(cp = rindex(tmpbuf, '.'))
                strcpy(cp, ".CRF");
            else
                strcat(tmpbuf, ".CRF");
            flgs[1] = tmpbuf;
            flgs[2] = crtmp;
            flgs[3] = 0;
            put_cmd(IF_NERR);
            doexec(cref, flgs);
            rm(RM_FILE, crtmp);
        }
        else
        {
            sprintf(tmpbuf, "Cross reference info left in %s: "
                            "; run CREF to produce listing\n", crtmp);
            print(tmpbuf);
        }
    put_cmd(TRAP);
    rm(RM_EXIT, execmd);
    fclose(cmdfile);
    fclose(stdout);
    fclose(stdin);
    setfcb(DFCB, execmd);
    execl(execprg, execprg, execmd, (char *)0);
    error("Can't execute %s", execprg);
}

void rm(int type, char *file)
{
    char    buf[40];

    if (verbose)
    {
        strcat(strcpy(buf, "ERA "), file);
        print(buf);
    }
    setfcb(DFCB, file);
    putc(type, cmdfile);
    putc(16, cmdfile);
    fwrite(DFCB, 1, 16, cmdfile);
}

void print(char *s)
{
    putc(PRINT, cmdfile);
    putc(strlen(s), cmdfile);
    fputs(s, cmdfile);
}

void put_cmd(int i)
{
    putc(i, cmdfile);
    putc(0, cmdfile);
}

void addobj(char *s, int p)
{
    char *  cp;
    uchar   len;
    static char oname;

    if (oname == 0 && outfile == 0)
    {
        if (p)
        {
            oname = 1;
        }
        if(cp = rindex(s, '.'))
            len = cp - s;
        else
            len = strlen(s);
        cp = xalloc(len + strlen("-O.COM") + 1);
        strncat(strcpy(cp, "-O"), s, len);
        strcpy(cp+len+2, ".COM");
        outfile = cp+2;
    }
    cp = xalloc(strlen(s)+1);
    strcpy(cp, s);
    objs[obj_idx++] = cp;
}

void addlib(char *s)
{
    char *  cp;

    strcpy(tmpbuf, libpath);
    strcat(strcat(tmpbuf, s), LIBSUFF);
    cp = xalloc(strlen(tmpbuf)+1);
    strcpy(cp, tmpbuf);
    libs[lib_idx++] = cp;
}

void error(char *s, char *a)
{
    fprintf(stderr, s, a);
    exit(1);
}

static char *xalloc(short s)
{
    register char * cp;

    if (!(cp = malloc(s)))
        error("Out of memory", NULL);
    return cp;
}

void upcase(char *s)
{
    while (*s)
    {
        if (*s >= 'a' && *s <= 'z')
            *s -= 'a'-'A';
        ++s;
    }
}

void doexec(char *name, char **vec)
{
    uchar           len;
    char          **pvec;
    char           *redir[2];
    char            redbuf[20];
    FILE           *cfile;
    static short    redno;
    char            xbuf[130];

    pvec = vec;
    len = 0;
    redbuf[0] = 0;
    /* PMO: bug fix we could overrun 255 length
     * as we are only interested in creating a redir
     * for > 124 chars we can quit early
     */
	while(*pvec && len <= 124)
        len += strlen(*pvec++)+1;
    if (len > 124)
    {
        sprintf(xbuf, redname, ++redno);
        if (!(cfile = fopen(xbuf, "w")))
            error("Can't create %s", xbuf);
        len = 0;
        while (*vec)
        {
            /* PMO: bug fix, check if we will
             * overrun the buffer with this item
             * also space between tokens was not
             * counted
             */
			len += strlen(*vec) + 1;    /* account for space */
			if(len > 126) {             /* test if it will overrun */
				fprintf(cfile, "\\\n"); /* put continuation \ */
				len = strlen(*vec) + 1; /* reset len */
			}
			fprintf(cfile, "%s ", *vec++);
        }
        fputc('\n', cfile);
        fclose(cfile);
        redir[1] = (char *)0;
        sprintf(redbuf, "<%s", xbuf);
        redir[0] = redbuf;
        vec = redir;
    }
    xbuf[0] = 0;
    while(*vec)
        strcat(strcat(xbuf, " "), *vec++);
    len = strlen(xbuf);
    putc(EXEC, cmdfile);
    putc(len+50, cmdfile);
    setfcb(DFCB, name);
    strcpy(DFCB->ft, "COM");
    DFCB->nr = 0;
    putc(DFCB->uid, cmdfile);
    fwrite(DFCB, 1, 16, cmdfile);
    setfcb(DFCB, &xbuf[1]);
    DFCB->nr = 0;
    fwrite(DFCB, 1, 32, cmdfile);
    putc(len, cmdfile);
    fwrite(xbuf, 1, len, cmdfile);
    if (redbuf[0])
        rm(RM_FILE, &redbuf[1]);
}

void assemble_sym(char *s)
{
    char  *vec[5];
    char   buf[80];
    char  *cp;
    uchar  i;

    if (overlay)
    {
        cbase = sym2as(s);
        vec[0] = s;
        vec[1] = tmpf5;
        vec[2] = 0;
        doexec(symtoas, vec);
        put_cmd(TRAP);
    }
    if (c_as_idx > 1)
        print(s);
    i = 0;
  /* Commented out - for symbols there's no code to optimize
    if (optimize && !speed)
        vec[i++] = "-J";
  */
    if (nolocal)
        vec[i++] = "-X";
    if (cp = rindex(s, ':'))
        cp++;
    else
        cp = s;
    strcat(strcpy(buf, "-O"), cp);
    if (rindex(buf, '.'))
        *rindex(buf, '.') = 0;
    strcat(buf, ".OBJ");
    vec[i++] = buf;
    vec[i++] = tmpf5;
    vec[i] = (char *)0;
    doexec(assem, vec);
}

void assemble(char *s)
{
    char  *vec[5];
    char   buf[80];
    char  *cp;
    uchar  i;

    if (c_as_idx > 1)
        print(s);
    i = 0;
    if (optimize && !speed)
        vec[i++] = "-J";
    if (nolocal)
        vec[i++] = "-X";
    if (cp = rindex(s, ':'))
        ++cp;
    else
        cp = s;
    strcat(strcpy(buf, "-O"), cp);
    if (rindex(buf, '.'))
        *rindex(buf, '.') = 0;
    strcat(buf, ".OBJ");
    vec[i++] = buf;
    vec[i++] = s;
    vec[i] = (char *)0;
    doexec(assem, vec);
}

#ifdef Z280

/* Optimize then assemble for Z280 */
void optassemble(char *s)
{
    char  *vec[5];
    char   buf[80];
    char  *cp, *as2;
    uchar  i;

    if (c_as_idx > 1)
        print(s);

    cp = s;

    /* Try to optimize into Z280 assembler */
    i = 0;
    if (speed)
        vec[i++] = "-F";
    vec[i++] = cp;
    if (keepas)
        as2 = strcat(strcpy(tmpbuf, s), "2"); /* save as .AS2 */
    else
        as2 = tmpf5;
    vec[i++] = as2;
    vec[i] = (char *)0;
    doexec(optimh, vec);
    put_cmd(TRAP);

    i = 0;
    if (optimize && !speed)
        vec[i++] = "-J";
    if (nolocal)
        vec[i++] = "-X";

    if (cp = rindex(s,':'))
        ++cp;
    else
        cp = s;
    strcat(strcpy(buf, "-O"), cp);
    if (rindex(buf, '.'))
        *rindex(buf, '.') = 0;
    strcat(buf, ".OBJ");

    vec[i++] = buf;
    vec[i++] = as2;
    vec[i] = (char *)0;
    doexec(assem, vec);
}

#endif /* Z280 */

void compile(char *s)
{
    register char *cp;
    short          i, j;
    char          *vec[MAXLIST];
    char           cbuf[50];

    if (c_as_idx > 1)
        print(s);
    for (j = 0; j < iud_idx ; ++j)
        vec[j] = iuds[j];
    vec[j++] = s;
    vec[j++] = tmpf1;
    vec[j] = (char *)0;
    doexec(cpp, vec);

    if (cp = rindex(s, ':'))
        s = cp+1;
    *rindex(s, '.') = 0;
    i = 0;
    if (keepas && !optimize)
        vec[i++] = "-S";
    if (xref)
        vec[i++] = strcat(strcpy(cbuf, "-C"), crtmp);
    /* error redirection */
    if (ebuf[0])
        vec[i++] = ebuf;
    vec[i++] = tmpf1;
    vec[i++] = tmpf2;
    vec[i++] = tmpf3;
    vec[i++] = (char *)0;
    doexec(pass1, vec);

    vec[0] = tmpf2;
    vec[1] = keepas && !optimize ? strcat(strcpy(tmpbuf, s), ".AS") : tmpf1;
    vec[2] = (char *)0;
    doexec(cgen, vec);
    if (keepas && !optimize)
        return;
    cp = tmpf1;
    if (optimize)
    {
        i = 0;
        if (speed)
            vec[i++] = "-F";
        vec[i++] = tmpf1;
#ifdef Z280
        if (keepas && !z280optim)
#else
        if (keepas)
#endif
            vec[i++] = strcat(strcpy(tmpbuf, s), ".AS");
        else
            vec[i++] = tmpf2;
        vec[i] = (char *)0;
        doexec(optim, vec);

        cp = tmpf2;
#ifdef Z280
        if (z280optim)
        {
            i = 0;
            if (speed)
                vec[i++] = "-F";
            vec[i++] = cp;
            if (keepas)
                vec[i++] = strcat(strcpy(tmpbuf, s), ".AS");
            else
                vec[i++] = tmpf5;
            vec[i] = (char *)0;
            doexec(optimh, vec);
            cp = tmpf5;
        }
#endif
        if (keepas)
            return;
    }
    i = 0;
    if (nolocal)
        vec[i++] = "-X";
    if (optimize && !speed)
        vec[i++] = "-J";
    vec[i++] = "-N";
    vec[i++] = strcat(strcat(strcpy(tmpbuf, "-O"), s), ".OBJ");
    vec[i++] = cp;
    vec[i] = (char *)0;
    doexec(assem, vec);
}

#define MAXLINE 200
#define START ("__ovrbgn")

int sym2as(char * fname)
{
    static char line[MAXLINE+1];
    char       *addr = line;
    char       *sym = line+5;
    register int i = 0;
    register int j = 0;
    int         c = 0;
    char       *r = 0;
    int         base = 0x100;
    FILE       *in;

    in = fopen(fname,"rt");
    if (!in)
        return -1;

    while (!feof(in) && !ferror(in))
    {
        i = 0;
        while (i < MAXLINE)
        {
            c = fgetc(in);
            if (isspace(c) && (i==0))
                continue;
            if (c == EOF || c == '\n' || c == '\r')
                break;
            line[i++] = c;
        }
        line[i] = 0;
        r = index(line, ' ');
        if (!r)
            continue;
        *r = 0;
        addr = line;
        sym = r+1;
        while (*sym && isspace(*sym))
            sym++;
        if (strlen(addr) > 4)
        {
            addr += strlen(addr);
            addr -= 4;
        }
        for (j=strlen(sym)-1; j>=0; j--)
        {
            if (isspace(sym[j]))
                sym[j] = 0;
        }
        if (!strcmp(sym, START))
            sscanf(addr,"%x", &base);
    }
    if (ferror(in))
        fclose(in);
    fclose(in);
    return base;
}

void viewfile(char *fn)
{
    FILE  *f;
    char  *bp, buf[200];

    if (!(f = fopen(fn, "r")))
        error("Unable to open help file %s", fn);
    while (bp=fgets(buf, 200, f))
        printf("%s", bp);
    fclose(f);
}


================================================
FILE: cpm/CHMOD.C
================================================
#include	<cpm.h>
#include	<stat.h>

chmod(name, mode)
register char *	name;
{
	struct fcb 	fc;
	register short	luid;

	if(!setfcb(&fc, name)) {
		luid = getuid();
		setuid(fc.uid);
		if(!(mode & S_IWRITE))
			fc.ft[0] |= (char) 0x80;
		if(mode & S_SYSTEM)
			fc.ft[1] |= (char) 0x80;
		if(mode & S_ARCHIVE)
			fc.ft[2] |= (char) 0x80;
		mode = bdos(CPMSATT, &fc);
		setuid(luid);
		return mode;
	}
	return -1;
}


================================================
FILE: cpm/CLEANUP.C
================================================
#include	"cpm.h"

#define	FILL	0, "        ", "   ", 0, {0}, 0, {0}, 0, {0}, 0

/*

   Default stdin, stdout and stderr to the console.

   If PIPEMGR is detected by the start-up routine,
   then it changes these to RSX:, RSX: and ERR: by
   calling the _initrsx function.

 */

struct fcb	_fcb[MAXFILE] =
{
    { FILL, U_CON },	/* stdin */
    { FILL, U_CON },	/* stdout */
    { FILL, U_CON },	/* stderr */
};

void _cpm_clean()
{
    uchar	i;

    i = 0;
    do
        close(i);
    while (++i < MAXFILE);
}

void _putrno(uchar *where, long rno)
{
    where[0] = rno & 0xFF;
    where[1] = (rno >> 8) & 0xFF;
    where[2] = (rno >> 16) & 0xFF;
}

void _initrsx()
{
    /* Use PIPEMGR for stdin, stdout and stderr redirection */
    _fcb[0].use = U_RSX;	/* stdin */
    _fcb[1].use = U_RSX;	/* stdout */
    _fcb[2].use = U_ERR;	/* stderr */
}


================================================
FILE: cpm/CLOSE.C
================================================
#include    <cpm.h>
#include    <stdlib.h>
#include    <ctype.h>
/*
    This is a modified version of close.c to support exact file sizes.

    Unfortunately there are two common conventions used to record the
    exact size in CP/M.

    1) Record the bytes used in the last sector - used by DOSPLUS
    2) Record the bytes unused in the last sector - used by ISX for
       ISIS emulation

    A previous version of this file only supported convention 2.

    To support both of these variants, a global variable _exact is
    set-up by the start-up module.

    The values for _exact are noted below

    'D' for DOSPLUS     This uses convention 1 above
    'I' for ISIS/ISX    This uses convention 2 above
    'C' for CP/M 2      Exact file size is not used

    Under CP/M 3 this defaults to 'D' DOSplus mode.  If you wish
    to use ISIS mode, you must set _exact to 'I' prior to using
    file I/O routines - e.g.

        extern char _exact;

        _exact = 'I';

    Note you need to take extra care with _exact if you are using an
    emulator that can access host files and truncates files to match
    the exact size.  Using the wrong mode will mean that the value
    this function passes to the emulator will be wrong and could
    result in data losss. If in doubt I recommend exact size isn't used.

    For the ZXCC emulator, using _exact as 'D' is safe.
*/

extern char _exact;  /* Exact file size hint for last sector
			'C' = not used (old CP/M),
                        'D' = DOSPLUS mode (count is USED bytes),
			'I' = ISX mode (count is UNUSED bytes)
                      */

int close(uchar fd)
{
    register struct fcb *fc;
    uchar       luid;

    if (fd >= MAXFILE)
        return -1;
    fc = &_fcb[fd];
    luid = getuid();
    setuid(fc->uid);
    if (fc->use == U_WRITE || fc->use == U_RDWR
                           || bdos(CPMVERS)&(MPM|CCPM) && fc->use == U_READ)
        bdos(CPMCLS, fc);
    if (_exact != 'C') { /* skip if old CP/M mode */
        fc->nr = (_exact == 'D' ? fc->fsize : -fc->fsize) & 0x7f; /* Set exact file size */
        fc->name[5] |= (char) 0x80;
        if (fc->use == U_WRITE || fc->use == U_RDWR)
            bdos(CPMSATT, fc);
    }
    fc->use = 0;
    setuid(luid);
    return 0;
}


================================================
FILE: cpm/CONVTIME.C
================================================

#include	<time.h>

/*
 *	This routine converts the date and time in CP/M-86 format
 *	to Unix style date and time - seconds since 00:00:00 Jan  1 1970
 */

#define	EPOCH	2922-1		/* difference between 1970 and 1978 - note
				   adjustment since CP/M numbers days from
				   1 and Unix numbers them from 0 */

struct tod
{
	int	days;		/* since 1 Jan 1978 */
	char	hour;		/* 2 digit BCD!! */
	char	min;		/* ditto */
	char	sec;		/* ditto */
};

frmbcd(c)
unsigned char	c;
{
	return (c & 0xF) + ((c >> 4) & 0xF) * 10;
}

time_t
convtime(tod)
struct tod *	tod;
{
	time_t	t;

	t = tod->days+EPOCH;
	t *= 24;		/* now have hours */
	t += frmbcd(tod->hour);	/* add in hours from the time */
	t *= 60;		/* now minutes */
	t += frmbcd(tod->min);	/* add minutes */
	t *= 60;		/* Seconds! */
	t += frmbcd(tod->sec);
	return t;
}


================================================
FILE: cpm/CREAT.C
================================================
#include    <cpm.h>
#include    <unixio.h>

int creat(char *name, int mode)
{
    register struct fcb *   fc;
    uchar           luid;

    if (!(fc = getfcb()))
        return -1;
    luid = getuid();
    if (!setfcb(fc, name))
    {
        if (unlink(name) == -1 && errno > 16)
            return -1;
        setuid(fc->uid);
        if ((bdos(CPMMAKE, fc) & 0xFF) == 0xFF)
        {
            setuid(luid);
            fc->use = 0;
            return -1;
        }
        setuid(luid);
        fc->use = U_WRITE;
        fc->fsize = 0L;
    }
#if 0
    fc->dm[0] = 0;
    bmove((char *)fc->dm, (char *)&fc->dm[1], sizeof fc->dm - 1);
#endif  0
    return fc - _fcb;
}


================================================
FILE: cpm/CSV.AS
================================================
; CSV.AS	Modified version from Tesseract vol 91
;
	global	csv,cret,indir, ncsv
	psect	text
csv:	pop	hl		;return address
	push	iy
	push	ix
	ld	ix,0
	add	ix,sp		;new frame pointer
	jp	(hl)

cret:	ld	sp,ix
	pop	ix
	pop	iy
	ret

indir:	jp	(hl)

;	New csv: allocates space for stack based on word following
;	call ncsv

ncsv:
	pop	hl
	push	iy
	push	ix
	ld	ix,0
	add	ix,sp
	ld	e,(hl)
	inc	hl
	ld	d,(hl)
	inc	hl
	ex	de,hl
	add	hl,sp
	ld	sp,hl
	ex	de,hl
	jp	(hl)


================================================
FILE: cpm/DUP.C
================================================
#include	"cpm.h"

dup(fd)
uchar	fd;
{
	register struct fcb *	fp;

	if(_fcb[fd].use && (fp = getfcb())) {
		*fp = _fcb[fd];
		return fp - _fcb;
	}
	return -1;
}


================================================
FILE: cpm/EXEC-BLD.SUB
================================================
; Build $$EXEC.COM from source
era exec.com
zas -j exec.as
linq
<-l -ptext=0,bss exec.obj
objtohex -R -b100h l.obj exec.com
era l.obj
era exec.obj


================================================
FILE: cpm/EXEC.AS
================================================
*Title	Indirect command execution
*Head	Description

;	Copyright (C) 1984 HI-TECH SOFTWARE

;This is the indirect command processor
;It is invoked with one argument which is the name of an indirect
;command file, normally created by the C command or a similar
;command processor, and executes the commands in the file. See
;exec.doc for a description of the command syntax in the file.


*Heading	Command values and BDOS calls
BASE	equ	80h		;base of command values

EXIT	equ	BASE+0		;Exit command file
EXEC	equ	BASE+1		;Execute a transient command
IGN_ERR	equ	BASE+2		;Ignore errors
DEF_ERR	equ	BASE+3		;Exit on error
SKP_ERR	equ	BASE+4		;Skip on error to next TRAP
TRAP	equ	BASE+5		;Trap for error skips
IF_ERR	equ	BASE+6		;Execute the next command if any error
IF_NERR	equ	BASE+7		;Execute the next command if no error
ECHO	equ	BASE+8		;Echo all EXEC commands 
PRINT	equ	BASE+9		;Print buffer on console
RM_FILE	equ	BASE+10		;Remove file
RM_EXIT	equ	BASE+11		;Remove file and exit

WBOOT	equ	0		;Address for warm boot
ENTRY	equ	5		;Bdos entry
DFCB	equ	5CH		;Default FCB
DBUF	equ	80H		;Default buffer
TPA	equ	100H		;Transient area
SECSIZE	equ	128		;CP/M record size
FCBSIZ	equ	33		;Size of non-random FCB

CONIN	equ	1		;Console get char
CONOUT	equ	2		;Console out char
CONST	equ	11		;Get console status
RDSK	equ	13		;reset disk system
SELDSK	equ	14		;select drive
OPEN	equ	15		;Open file
DELETE	equ	19		;Delete file
READ	equ	20		;Read record
GETLOG	equ	25		;Get current disk
SDMA	equ	26		;Set DMA address
UID	equ	32		;Set/get user ID

	macro	bdos,fun,arg	;Macro for bdos calls
	ld	de,arg
	ld	c,fun
	call	ENTRY
	endm

	macro	bdosx,fun	;bdos calls with no arg
	ld	c,fun
	call	ENTRY
	endm

CR	equ	0DH		;Carriage return
LF	equ	0AH		;Line feed

*Head	Main program
	psect	text

	global	__Lbss

	defs	TPA		;relocate to start of TPA
start:
	ld	sp,(ENTRY+1)	;Set up stack pointer
	bdosx	GETLOG
	ld	(curdsk),a
	bdos	UID, 0FFh
	ld	(curuid),a
	ld	hl,DFCB
	ld	de,cfcb
	ld	bc,16
	ldir			;set up command FCB
	bdos	OPEN,cfcb
	inc	a
	jr	nz,1f
	ld	hl,nofile
	call	print
	jp	doexit
1:
	ld	hl,(ENTRY+1)	;top of code after relocation
	ld	de,stack	;top before relocation
	scf			;set carry flag
	sbc	hl,de		;gives distance
	ex	de,hl
	ld	bc,(__Lbss)	;reloc count
	ld	hl,__Lbss+2	;start of addresses
1:
	ld	a,c
	or	b		;check for count zero
	jr	z,3f		;start if so
	dec	bc
	ld	a,(hl)		;get address
	inc	hl
	push	hl		;save it
	ld	h,(hl)
	ld	l,a
	push	hl		;save it
	push	de		;and it
	ld	de,5f		;check for legal modify
	or	a
	sbc	hl,de
	pop	de		;restore regs
	pop	hl
	jr	c,4f
	ld	a,(hl)		;get value
	inc	hl
	push	hl
	ld	h,(hl)
	ld	l,a
	add	hl,de		;add difference
	ex	de,hl		;put in de
	ex	(sp),hl		;restore pointer
	ld	(hl),d		;store new value
	dec	hl
	ld	(hl),e
	pop	de		;restore difference
4:
	pop	hl		;restore list pointer
	inc	hl		;point to next
	jr	1b
3:
	ld	hl,stack-1
	add	hl,de		;add in difference
	ex	de,hl		;put dest in de
	ld	hl,stack-1	;source in hl
	ld	bc,stack-cmdstart	;amount to move
	lddr
5:
	jp	cmdstart	;jump to it

cmdstart:
	ld	hl,(ENTRY+1)
	ld	(cmdstart-2),hl
	ld	a,jp
	ld	(cmdstart-3),a
	ld	hl,cmdstart-3
	ld	(ENTRY+1),hl
	ld	hl,(WBOOT+1)
	ld	(bootsave),hl
	ld	hl,loop
	ld	(WBOOT+1),hl
	ld	hl,0
	ld	(DBUF),hl	;initially no error
loop:
	ld	sp,stack
	ld	hl,(DBUF)
	ld	a,h
	or	l
	jr	z,1f		;no error, nothing required
	ld	(errors),a	;update flag
	ld	a,(erract)
	dec	a		;set flags		;default action?
	jp	m,doexit	;default, exit pronto
	jr	z,1f		;ignore errors
	call	skipto		;skip to next trap command
1:
	ld	hl,0
	ld	(DBUF),hl
	call	docmd
	jr	loop

docmd:
	call	getch
	sub	BASE		;Check for legal range
	jp	c,cerr		;too small
	cp	NCMDS		;Check other end of range
	jp	nc,cerr
	ld	hl,ctable
	ld	c,a
	ld	b,0
	add	hl,bc
	add	hl,bc
	ld	a,(hl)
	inc	hl
	ld	h,(hl)
	ld	l,a
	push	hl		;push the address
	call	getch
	ld	(length),a	;store the length
	ret			;dispatch to the routine

ctable:
	defw	doexit		;EXIT
	defw	doexec		;EXEC
	defw	ignerr		;IGN_ERR
	defw	deferr		;DEF_ERR
	defw	skperr		;SKPERR
	defw	trap		;TRAP
	defw	iferr		;IF_ERR
	defw	ifnerr		;IF_NERR
	defw	echo		;ECHO
	defw	xprint		;PRINT
	defw	rm		;RM_FILE
	defw	rm_exit		;RM_EXIT

NCMDS	equ	$-ctable	;number of legal commands

cerr:	ld	hl,errms
	call	print	
	jp	doexit

errms:	defb	7
	defm	'Fmt err'

doexit:
	ld	hl,(bootsave)
	ld	(WBOOT+1),hl
	jp	(hl)

doexec:
	ld	hl,DFCB
	ld	de,DFCB+1
	ld	bc,FCBSIZ-1
	ld	(hl),0
	ldir
	call	getch
	ld	(newuid),a
	ld	hl,DFCB
	ld	b,16
	call	rdbytes
9:
	ld	a,(echflg)
	or	a
	jr	z,2f
	ld	a,(newuid)
	inc	a
	jr	z,4f
	add	a,'0'-1
	call	putch
	ld	a,':'
	call	putch
4:
	ld	a,(DFCB)
	or	a
	jr	z,4f
	add	a,'A'-1
	call	putch
	ld	a,':'
	call	putch
4:
	ld	hl,DFCB+1
	ld	b,8
1:
	ld	a,(hl)
	cp	' '
	jr	z,2f
	push	hl
	push	bc
	call	putch
	pop	bc
	pop	hl
	inc	hl
	djnz	1b
2:
	ld	a,(newuid)
	ld	e,a
	bdosx	UID
	bdos	OPEN,DFCB	;open the file
	inc	a		;-1 is error on return
	jr	nz,1f		;skip if found
filerr:
	ld	a,(curuid)
	ld	e,a
	bdosx	UID
	ld	hl,notfnd
	call	print
	bdosx	CONIN
	bdosx	RDSK
	bdos	SELDSK,(curdsk)
	jr	9b

1:
	ld	de,TPA		;read into transient area
1:
	push	de		;save ptr
	bdosx	SDMA		;set buffer address
	bdos	READ,DFCB	;read sector
	pop	hl		;pop ptr
	ld	de,SECSIZE
	add	hl,de
	ex	de,hl
	or	a
	jr	z,1b		;loop if more

	ld	a,(curuid)	;restore uid
	ld	e,a
	bdosx	UID
	ld	hl,DFCB
	ld	b,32
	call	rdbytes

	call	getch
	ld	hl,DBUF
	ld	(hl),a
	inc	hl
	ld	b,a
	call	rdbytes

	ld	a,(echflg)
	or	a
	jr	z,1f
	ld	hl,DBUF		;just print for now
	call	print
1:
	jp	TPA		;execute program

rdbytes:
	call	getch
	ld	(hl),a
	inc	hl
	djnz	rdbytes
	ret

xprint:
	ld	b,a		;a has the length already
	ld	hl,TPA
	ld	(hl),a
	inc	hl
	call	rdbytes
	ld	hl,TPA

print:
	ld	b,(hl)
	inc	hl
1:
	ld	a,(hl)
	inc	hl
	push	hl
	push	bc
	call	putch
	pop	bc
	pop	hl
	djnz	1b
	ld	a,CR
	call	putch
	ld	a,LF
putch:
	ld	e,a
	bdosx	CONOUT
	ret

ignerr:
	ld	a,1
1:
	ld	(erract),a
	ret

deferr:
	xor	a
	jr	1b

skperr:
	ld	a,2
	jr	1b

skip:
	call	getch		;get the command byte
	push	af		;save it
	call	getch		;length
	ld	b,a		;put into counter
	ld	hl,TPA		;s suitable place to read into
	or	a		;check for zero count
	call	nz,rdbytes	;read if any to read
	pop	af
	ret			;return with command byte in A


;	Skip up to the next trap

skipto:
	call	skip
	cp	EXIT		;End?
	jp	z,doexit	;yes, return to CP/M
	cp	TRAP		;got a trap yet?
	jr	nz,skipto	;loop for more
	ret

rm:
	ld	b,16
	ld	hl,DFCB
	call	rdbytes
	bdos	DELETE,DFCB
	ret

rm_exit:
	call	rm
	jp	doexit

getch:
	push	hl
	ld	hl,(cptr)
	ld	de,cbuf+SECSIZE
	or	a
	sbc	hl,de
	jr	nz,1f
	push	bc
	bdos	SDMA,cbuf
	bdos	READ,cfcb
	pop	bc
	or	a
	jp	nz,doexit		;exit on EOF
	ld	hl,cbuf
	ld	(cptr),hl
1:
	ld	hl,(cptr)
	ld	a,(hl)
	inc	hl
	ld	(cptr),hl
	pop	hl
	ret

trap:
	ret

echo:
	ld	a,1
	ld	(echflg),a
	ret

iferr:
	ld	a,(errors)	;check for errors
	or	a		;set flags
	jp	z,skip		;skip next command if no error
	ret

ifnerr:
	ld	a,(errors)
	or	a		;any error?
	jp	nz,skip		;skip if not
	ret

notfnd:
	defb	40
	defm	': Not found - change disks, hit a key'
	defb	7,0Dh,0Ah
nofile:
	defb	7
	defm	'No file'

*Heading	Data areas

cfcb:	defs	FCBSIZ		;Command file FCB
cbuf:	defs	SECSIZE		;Command file buffer
cptr:	defw	cbuf+SECSIZE	;Pointer to command input
errst:	defb	0		;error status
erract:	defb	0		;action on error
echflg:	defb	0
curdsk:	defs	1
length:
	defs	1		;command length
errors:
	defs	1		;cumulative error flag
curuid:
	defs	1		;current uid
newuid:
	defs	1		;user id for EXEC command
bootsave:
	defs	2
	defs	40		;small stack
stack:

	psect	bss		;for reloc info
	end	start


================================================
FILE: cpm/EXECL.AS
================================================
;	EXECV(), EXECL() - hand crafted from the C

;	#include	<cpm.h>
;	
;	#define	setuid(x)	bdos(CPMSUID, x)
;	#define	getuid()	bdos(CPMSUID, 0xFF)
;	#define	TPA		0x100
;	#define	DBUF		0x80
;	#define	DFCB		0x5C
;	
;	static void
;	doexec(fc, luid)
;	register struct fcb *	fc;
;	uchar			luid;
;	{
;		char *	dma;
;	
;		dma = (char *)TPA;
;		do {
;			bdos(CPMSDMA, dma);
;			dma += SECSIZE;
;		} while(bdos(CPMREAD, fc) == 0);
;		setuid(luid);
;		bdos(CPMSDMA, DBUF);
;		(*(void (*)())TPA)();
;	}
;	
;	
;	execl(name, arg1)
;	char *	name, arg1;
;	{
;		execv(name, &arg1);
;	}
;	
;	execv(name, arg)
;	char *	name, ** arg;
;	{
;		struct fcb	fc;
;		uchar		luid;
;		short		i, j;
;		register char *	cp;
;		char		progbuf[128];	/* storage for the code */
;	
;		for(i = 1, j = 0 ; arg[i] ; i++)
;			j += strlen(arg[i])+1;
;		if(j >= 126)
;			return -1;		/* arg list too big */
;		if(i > 1)
;			setfcb(DFCB, arg[1]);
;		else
;			setfcb(DFCB, "");
;		cp = (char *)DBUF;
;		*cp++ = j;
;		*cp = 0;
;		for(i = 0 ; arg[i] ; i++) {
;			strcat(cp, " ");
;			strcat(cp, arg[i]);
;		}
;		setfcb(&fc, name);
;		if(fc.ft[0] != ' ')
;			return -1;
;		strncpy(fc.ft, "COM", 3);
;		luid = getuid();
;		setuid(fc.uid);
;		if(bdos(CPMOPN, &fc) == -1) {
;			setuid(luid);
;			return -1;
;		}
;		bmove(doexec, progbuf, sizeof progbuf);
;		(*(void (*)())progbuf)(&fc, luid);
;	}
*Title HI-TECH C: EXECV.C

entry	equ	5		; CP/M bdos call entry point
global	indir

psect	text
_doexec:
push	iy
push	ix
ld	ix,0
add	ix,sp
push	bc
ld	c,(ix+6)
ld	b,(ix+7)
push	bc
pop	iy
ld	(ix+-2),0
ld	(ix+-1),1
l5:
ld	e,(ix+-2)
ld	d,(ix+-1)
ld	c,26
push	ix
push	iy
call	entry
pop	iy
pop	ix
ld	de,128
ld	l,(ix+-2)
ld	h,(ix+-1)
add	hl,de
ld	(ix+-2),l
ld	(ix+-1),h
push	iy
pop	de
ld	c,20
push	ix
push	iy
call	entry
pop	iy
pop	ix
or	a
jr	z,l5
ld	e,(ix+8)
ld	c,32
call	entry
ld	de,128
ld	c,26		;SETDMA
call	entry
call	256		;go execute at TPA base
jp	0		;if it returned
global	_execl
global	_execv
_execl:
push	iy
push	ix
ld	ix,0
add	ix,sp
push	ix
pop	de
ld	hl,8
add	hl,de
push	hl
ld	l,(ix+6)
ld	h,(ix+7)
push	hl
call	_execv
ld	sp,ix
pop	ix
pop	iy
ret
global	_strlen
global	_setfcb
global	_strcat
global	_strncpy
global	_bmove
_execv:
push	iy
push	ix
ld	ix,0
add	ix,sp
ld	hl,-175
add	hl,sp
ld	sp,hl
ld	(ix+-45),1
ld	(ix+-44),0
ld	(ix+-47),0
ld	(ix+-46),0
jp	l11
l8:
ld	e,(ix+8)
ld	d,(ix+9)
ld	l,(ix+-45)
ld	h,(ix+-44)
add	hl,hl
add	hl,de
ld	c,(hl)
inc	hl
ld	b,(hl)
push	bc
call	_strlen
pop	bc
ex	de,hl
inc	de
ld	l,(ix+-47)
ld	h,(ix+-46)
add	hl,de
ld	(ix+-47),l
ld	(ix+-46),h
ld	l,(ix+-45)
ld	h,(ix+-44)
inc	hl
ld	(ix+-45),l
ld	(ix+-44),h
l11:
ld	e,(ix+8)
ld	d,(ix+9)
ld	l,(ix+-45)
ld	h,(ix+-44)
add	hl,hl
add	hl,de
ld	a,(hl)
inc	hl
or	(hl)
jp	nz,l8
ld	de,126
ld	l,(ix+-47)
ld	h,(ix+-46)
or	a
sbc	hl,de
jp	m,l12
L2:
ld	hl,-1
ld	sp,ix
pop	ix
pop	iy
ret
l12:
ld	l,(ix+-45)
ld	h,(ix+-44)
ld	de,1
or	a
sbc	hl,de
jp	m,l13
ld	l,(ix+8)
ld	h,(ix+9)
inc	hl
inc	hl
ld	c,(hl)
inc	hl
ld	b,(hl)
push	bc
ld	hl,92
push	hl
call	_setfcb
pop	bc
pop	bc
jp	l14
l13:
ld	hl,19f
push	hl
ld	hl,92
push	hl
call	_setfcb
pop	bc
pop	bc
l14:
ld	iy,128
ld	a,(ix+-47)
ld	(iy+0),a
inc	iy
ld	(iy+0),0
ld	(ix+-45),0
ld	(ix+-44),0
jp	l18
l15:
ld	hl,39f
push	hl
push	iy
call	_strcat
pop	bc
pop	bc
ld	e,(ix+8)
ld	d,(ix+9)
ld	l,(ix+-45)
ld	h,(ix+-44)
add	hl,hl
add	hl,de
ld	c,(hl)
inc	hl
ld	b,(hl)
push	bc
push	iy
call	_strcat
pop	bc
pop	bc
ld	l,(ix+-45)
ld	h,(ix+-44)
inc	hl
ld	(ix+-45),l
ld	(ix+-44),h
l18:
ld	e,(ix+8)
ld	d,(ix+9)
ld	l,(ix+-45)
ld	h,(ix+-44)
add	hl,hl
add	hl,de
ld	a,(hl)
inc	hl
or	(hl)
jp	nz,l15
ld	l,(ix+6)
ld	h,(ix+7)
push	hl
push	ix
pop	de
ld	hl,-42
add	hl,de
push	hl
call	_setfcb
pop	bc
pop	bc
push	ix
pop	de
ld	hl,-33
add	hl,de
ld	a,(hl)
cp	32
jp	nz,L2
ld	hl,3
push	hl
ld	hl,29f
push	hl
push	ix
pop	de
ld	hl,-33
add	hl,de
push	hl
call	_strncpy
pop	bc
pop	bc
pop	bc
ld	e,255
ld	c,32
push	ix
push	iy
call	entry
pop	iy
pop	ix
ld	(ix+-43),a
ld	e,(ix+-1)	;get fc.uid
ld	c,32		; CPMSUID
push	ix
push	iy
call	entry
pop	iy
pop	ix
push	ix
pop	de
ld	hl,-42
add	hl,de
ex	de,hl
ld	c,15
push	ix
push	iy
call	entry
pop	iy
pop	ix
cp	255
jp	nz,l20
ld	e,(ix+-43)
ld	c,32
push	ix
push	iy
call	entry
pop	iy
pop	ix
jp	L2
l20:
ld	hl,128
push	hl
push	ix
pop	de
ld	hl,-175
add	hl,de
push	hl
ld	hl,_doexec
push	hl
call	_bmove
pop	bc
pop	bc
pop	bc
ld	l,(ix+-43)
ld	h,0
push	hl
push	ix
pop	de
ld	hl,-42
add	hl,de
push	hl
push	ix
pop	de
ld	hl,-175
add	hl,de
call	indir
ld	sp,ix
pop	ix
pop	iy
ret
psect	data
19:
defb	0
29:
defb	67,79,77,0
39:
defb	32,0


================================================
FILE: cpm/EXIT.AS
================================================
	global	_exit, __cpm_clean

BDOS	equ	00005h
CPMVERS	equ	12
CPMRCOD	equ	108		; CP/M+ Get/Set Error Return Code 

	psect	text
_exit:	ld	(80h),hl
	call	__cpm_clean
	ld	c,CPMVERS
	call	BDOS		;Get version
	dec	h		; set Z if MP/M
	jp	z,0		; Warm boot if MP/M
	cp	30h	      
	jp	c,0		;Warm boot CP/M if < CP/M 3
	ld	hl,(80h)
	ld	a,l		;For compatibility with conditionals system,
				;use 7-bit CP/M 3 error codes.
	and	7fh
	ld	e,a
	ld	a,h		;Set D=0FFh for error
	or	l		;or 0 for all clear.
	jr	z,exit0
	ld	a,0ffh
exit0:	ld	d,a
	ld	c,CPMRCOD
	call	BDOS		;Report error.
	rst	0


================================================
FILE: cpm/FAKECLEA.AS
================================================
	global	__cleanup

	psect	text
__cleanup:
	ret


================================================
FILE: cpm/FAKECPCL.AS
================================================
	global	__cpm_clean

	psect	text
__cpm_clean:
	ret


================================================
FILE: cpm/FCBNAME.C
================================================
#include    <cpm.h>
#include    <string.h>

/*
 *  char *  fcbname(i);
 *  short   i;
 *
 *  Returns a character string which is the name of the file currently
 *  open on file descriptor i. The name is extracted from the corresponding
 *  fcb.
 */

char *fcbname(short i)
{
    register struct fcb *fc;
    static char          abuf[20];
    register char       *cp, *xp;


    fc = &_fcb[i];
    switch(fc->use)
    {
    case U_CON:
        return "CON:";

    case U_RDR:
        if ((bdos(CPMVERS)&0xFF) < 0x30)
            return "RDR:";
        else
            return "AUXIN:";
    case U_PUN:
        if ((bdos(CPMVERS)&0xFF) < 0x30)
            return "PUN:";
        else
            return "AUXOUT:";
    case U_LST:
        return "LST:";

    case U_READ:
    case U_WRITE:
    case U_RDWR:
        cp = abuf;
        if (fc->dr)
            *cp++ = 'A' + fc->dr - 1;
        sprintf(cp, "%d:", fc->uid);
        cp += strlen(cp);
        for (xp = fc->name ; *xp > ' ' && xp < fc->name+sizeof fc->name;)
            *cp++ = (*xp++) & 0x7F;
        *cp++ = '.';
        for (xp = fc->ft ; *xp > ' ' && xp < fc->ft+sizeof fc->ft ;)
            *cp++ = (*xp++) & 0x7F;
        *cp = 0;
        return abuf;

	case U_RSX:
		return "RSX:";
	case U_ERR:
		return "ERR:";

    default:
        return (char *)0;
    }
}


================================================
FILE: cpm/GETCH.C
================================================
#include	<cpm.h>

static short	pushback;

getch()
{
	short	c;

	if(c = pushback) {
		pushback = 0;
		return c;
	}
	while(!(c = bdos(CPMDCIO, 0xFF)))
		continue;
	return c;
}


getche()
{
	short	c;

	if(c = pushback) {
		pushback = 0;
		return c;
	}
	return bdos(CPMRCON) & 0xFF;
}

ungetch(c)
unsigned char	c;
{
	pushback = c;
}

putch(c)
unsigned char	c;
{
	if(c == '\n')
		bdos(CPMWCON, '\r');
	bdos(CPMWCON, c);
}

kbhit()
{
	return (bdos(CPMICON) & 0xFF) != 0;
}


================================================
FILE: cpm/GETFCB.C
================================================
#include    <cpm.h>
#include    <ctype.h>
#include    <sys.h>

/*
 *  Syntax of CP/M file names is:
 *
 *  [[0-9]+[:]][[a-pA-P]:]name[.ext] | [[a-pA-p][[0-9]+]:]name[.ext]
 *
 *  E.g.
 *      file.txt
 *      a:file
 *      10:b:READ-ME.doc
 */


#define DNAMLEN 4   /* length of device names */

static char dnames[][DNAMLEN] =
{
    "CON:",
    "RDR:",
    "PUN:",
    "LST:",
    "RSX:",
    "ERR:"
};

#define NDNAMES 6

extern int  atoi(char *);
static void fc_parse(struct fcb *, char *);

struct fcb *getfcb()
{
    register struct fcb *fp;

    for (fp = _fcb ; fp < &_fcb[MAXFILE] ; fp++)
        if (!fp->use)
        {
            fp->use = U_READ;
            fp->rwp = 0;
            return fp;
        }
    return (struct fcb *)0;
}

void putfcb(struct fcb *fc)
{
    fc->use = 0;
}

uchar setfcb(struct fcb *fc, char *name)
{
    uchar           i,j;

    while (isspace(*name))
        ++name;
    /* Check device names */
    for (i = 0 ; i < NDNAMES ; ++i)
        for (j = 0; ;)
            if (dnames[i][j] != toupper(name[j]))
                break;
            else if (++j == DNAMLEN)
            {
                fc->use = i+U_CON;
                return 1;
            }
    /* Not a device; could be a file. */
    fc_parse(fc, name);
    return 0;
}

static void fc_parse(struct fcb *fc, char *name)
{
    char
        *cp,
        *np,
         c,
         num[3];

    fc->dr = 0;
    fc->uid = getuid();

    cp = name;
    if (cp[1]==':'  || cp[2]==':' || cp[3]==':')  /* Drive/user */
    {
        np = num;
        while (*cp != ':')
        {
            if (isdigit(*cp)) 
                *np++ = *cp;
            else if (fc->dr == 0)
                fc->dr = toupper(*cp) - 'A' + 1;  
            ++cp;
        }
        *np = 0;
        if (num[0])
            fc->uid=atoi(num);
        ++cp;
    }
    if (cp[1]==':' && fc->dr == 0 && !isdigit(cp[0]))  /* u:d: */
    {
        fc->dr=toupper(*cp) - 'A' + 1;
        cp += 2;
    }
    name = cp;
    cp = fc->name;
    while (*name != '.' && *name != '*' && *name > ' ' && cp < &fc->name[8])
        *cp++ = toupper(*name++);
    if (*name == '*')
        c = '?';
    else
        c = ' ';
    while (cp < &fc->name[8])
        *cp++ = c;
    while (*name && *name++ != '.')
        continue;
    while (*name > ' ' && *name != '*' && cp < &fc->ft[3])
        *cp++ = toupper(*name++);
    if (*name == '*')
        c = '?';
    else
        c = ' ';
    while (cp < &fc->ft[3])
        *cp++ = c;
    fc->ex = fc->nr = 0;
}


================================================
FILE: cpm/GETUID.AS
================================================
;	Set/get uid for CP/M

	global	_getuid, _setuid, csv, cret

	entry	equ	5		;CP/M system call entry
	sguid	equ	32		;set/get user number
	arg	equ	6		;offset of 1st arg

	psect	text
_getuid:
	call	csv
	ld	e,0FFh			;to get rather than set
	jr	4f			;Go to common code
_setuid:
	call	csv
	ld	e,(ix+arg)		;get argument
4:
	ld	c,sguid
	push	ix
	call	entry
	pop	ix
	jp	cret


================================================
FILE: cpm/ISATTY.C
================================================
#include    "cpm.h"

int isatty(uchar f)
{
    switch(_fcb[f].use)
    {
    case U_CON:
    case U_RDR:
    case U_PUN:
    case U_LST:
    case U_RSX:
    case U_ERR:
        return 1;
    }
    return 0;
}


================================================
FILE: cpm/MAKEFILE
================================================
.SUFFIXES:	.c .obj .as .lib

BIN	= /usr/hitech/bin
LIB	= ../lib
PACK	= ../pack
LIBR	= $(BIN)/libr
AS	= $(BIN)/zas
CC	= $(BIN)/zc
LINK	= $(BIN)/link
OBJHEX	= $(BIN)/objtohex
ENHUFF	= ../bin/enhuff
CFLAGS	= -O -x $(DEFS) -Uunix
ASFLAGS	= -j

.c.obj:	;	$(CC) $(CFLAGS) -c $*.c
.as.obj: ;	$(AS) $(ASFLAGS) $*.as

OBJS	= start1.obj start2.obj open.obj read.obj write.obj chmod.obj seek.obj \
	  fcbname.obj rename.obj creat.obj time.obj convtime.obj timezone.obj \
	  stat.obj isatty.obj cleanup.obj close.obj unlink.obj dup.obj getfcb.obj \
	  srand1.obj getch.obj signal.obj getuid.obj \
	  abort.obj execl.obj bdos.obj bdoshl.obj \
	  bios.obj _exit.obj exit.obj fakeclean.obj fakecpcln.obj sys_err.obj

all:	zcrtcpm.obj zdrtcpm.obj zrrtcpm.obj  zlibcpm.lib c.com

install:	all
	cp zcrtcpm.obj zdrtcpm.obj zrrtcpm.obj  zlibcpm.lib $(LIB)
	chmod og+r $(LIB)/zcrtcpm.obj $(LIB)/zdrtcpm.obj $(LIB)/zrrtcpm.obj \
		 $(LIB)/zlibcpm.lib
	touch install

zlibcpm.lib:	$(OBJS)
	$(LIBR) r zlibcpm.lib $(OBJS)

c.com:	c.obj
	zc -mmap -f c.obj

exec.com:	exec.obj
	$(LINK) -l -ptext=0,bss exec.obj
	$(OBJHEX) -R -B100H l.obj exec.com
	-rm l.obj

clean:
	-rm -f zlibcpm.lib *.obj

huff:
	-rm cpm.huf
	$(ENHUFF) -a cpm.huf Makefile \
	cleanup.c close.c convtime.c creat.c dup.c getch.c \
	fcbname.c getfcb.c isatty.c open.c stat.c chmod.c \
	read.c rename.c seek.c signal.c srand1.c sys_err.c \
	time.c timezone.c unlink.c write.c _exit.as bdos.as bdoshl.as \
	bios.as csv.as exec.as exit.as fakeclean.as getuid.as srand.as \
	start1.as start2.as zcrtcpm.as zdrtcpm.as zrrtcpm.as execl.as \
	abort.c c.c fakecpcln.as

print:
	print Makefile *.h *.c *.as


================================================
FILE: cpm/MKTIME.C
================================================
/* Convert structure to time value */

#include <time.h>

/* leap year calculator expects year argument as years offset from 1900 */
#define LEAP_YEAR(Y)  ( ((1900+(Y))>0) && !((1900+(Y))%4) && ( ((1900+(Y))%100) || !((1900+(Y))%400) ) )

#define SECS_PER_DAY  (86400l)
#define SECS_PER_HOUR (3600l)
#define SECS_PER_MIN  (60l)

static unsigned char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
 
time_t mktime(struct tm *ptm){   
  
   int i;
   time_t seconds;

   /* seconds from 1970 till 1 jan 00:00:00 of the given year */
   seconds= (ptm->tm_year-70)*(SECS_PER_DAY * 365);
   for (i = 70; i < ptm->tm_year; i++) {
      if (LEAP_YEAR(i)) {
         seconds += SECS_PER_DAY;   /* add extra days for leap years */
      }
   }
  
   /* add days for this year */
   for (i = 0; i < ptm->tm_mon; i++) {
      if ( (i == 1) && LEAP_YEAR(ptm->tm_year)) { 
         seconds += SECS_PER_DAY * 29;
      } else {
         seconds += SECS_PER_DAY * (int)monthDays[i];
      }
   }
   seconds += (ptm->tm_mday-1) * SECS_PER_DAY;
   seconds += ptm->tm_hour * SECS_PER_HOUR;
   seconds += ptm->tm_min * SECS_PER_MIN;
   seconds += ptm->tm_sec;
   seconds += time_zone * SECS_PER_MIN;
   return (time_t)seconds; 
}


================================================
FILE: cpm/OPEN.C
================================================
#include    "cpm.h"

extern int errno;

extern char _exact;  /* Exact file size hint for last sector
			'C' = not used (old CP/M),
                        'D' = DOSPLUS mode (count is USED bytes),
			'I' = ISX mode (count is UNUSED bytes)
                      */

long _fsize(uchar fd)
{
    register struct fcb *fc;
    long            tmp;
    uchar           d, luid, buf[SECSIZE];

    if (fd >= MAXFILE)
        return -1;
    fc = &_fcb[fd];
    luid = getuid();
    setuid(fc->uid);
    bdos(CPMCFS, fc);
/*
    tmp = (long)fc->ranrec[0] + ((long)fc->ranrec[1] << 8)
                              + ((long)fc->ranrec[2] << 16);
    tmp *= SECSIZE;

    A slightly more efficient but more obscure coding ... */
    tmp = (*(long *)(&fc->ranrec[-1]) & 0xFFFFFF00) / 2;

    bdos(CPMSDMA,buf);
    /* Account for CP/M3 bytewise file sizes in last sector */
    if ((d = bdos(CPMFFST, fc) & 0xFF) < 4)
    {
        d = (buf[13 + (d << 5)] & 0x7F); /* Count of UNUSED bytes */
        if ((_exact == 'D') && (d != 0)) /* DOS Plus has count of USED bytes */
            d = 0x80 - d;
        tmp -= d;
    }
    setuid(luid);
    return tmp;
}


int open(char *name, int mode)
{
    register struct fcb *fc;
    uchar           luid;

    if (++mode > U_RDWR)
        mode = U_RDWR;
    if (!(fc = getfcb()))
        return -1;
    if (!setfcb(fc, name))
   {
        if (mode == U_READ && (bdos(CPMVERS)&0x7F) >= 0x30)
            fc->name[5] |= (char) 0x80;    /* read-only mode */
        luid = getuid();
        setuid(fc->uid);
        if ((bdos(CPMOPN, fc) & 0xFF)  == 0xFF)
        {
            putfcb(fc);
            setuid(luid);
            if (errno == 16)
                errno = 7; /* File not found */
            return -1;
        }
        fc->fsize = _fsize(fc - _fcb);    /* Set file size */
        setuid(luid);
        fc->use = mode;
    }
    return fc - _fcb;
}


================================================
FILE: cpm/READ.C
================================================
#include    "cpm.h"

extern char _piped; /* PIPEMGR loaded? */

#define CPMEOF 0x1A         /* Control-Z */

static char RSXPB[] = {0x7C,0};

int read(uchar fd, char *buf, ushort nbytes)
{
    register struct fcb *   fc;
    uchar   size, offs, luid;
    ushort  cnt;
    ushort  pipev;
    char    buffer[SECSIZE+2];

    cnt = 0;
    if (fd >= MAXFILE)
        return -1;
    fc = &_fcb[fd];
    switch(fc->use)
    {
    case U_RDR:
        cnt = nbytes;
        while(nbytes)
        {
            --nbytes;
            if ((*buf++ = (bdos(CPMRRDR) & 0x7f)) == '\n')
                break;
        }
        return cnt - nbytes;

    case U_RSX:       /* PIPEMGR RSX : input */
        if (_piped)
        {
            cnt = nbytes;
            while (nbytes) 
            {
                pipev = bdos(CPMRSX, &RSXPB);
                if (pipev < 0x100) 
                    break;
                else
                    *buf++ = (pipev & 0xFF);
                --nbytes; /* Only decrement if the read worked*/
                if ((pipev & 0xFF) == '\n') 
                    break;
            }
            return cnt - nbytes;
        }

    case U_CON:
        if (nbytes > SECSIZE)
            nbytes = SECSIZE;
        buffer[0] = nbytes;
        bdos(CPMRCOB, buffer);
        cnt = (uchar)buffer[1];

        /* [JCE] Return EOF for Ctrl-Z on a line by itself. */
        if (cnt == 1 && buffer[2] == CPMEOF)
            return 0;

        if(cnt < nbytes)
        {
            bdos(CPMWCON, '\n');
            buffer[cnt+2] = '\n';
            ++cnt;
        }
        bmove(&buffer[2], buf, cnt);
        return cnt;

    case U_READ:
    case U_RDWR:
        if (nbytes + fc->rwp > fc->fsize)   /* Limit length */
            nbytes = fc->fsize - fc->rwp;
        luid = getuid();
        cnt = nbytes;
        while(nbytes)
        {
            _sigchk();
            setuid(fc->uid);
            offs = fc->rwp%SECSIZE;
            if ((size = SECSIZE - offs) > nbytes)
                size = nbytes;
            _putrno(fc->ranrec, fc->rwp/SECSIZE);
            if (size == SECSIZE)
            {
                bdos(CPMSDMA, buf);
#ifdef  LARGE_MODEL
                bdos(CPMDSEG, (int)((long)buf >> 16));  /* set DMA segment */
#endif
                if (bdos(CPMRRAN, fc))
                    break;
            }
            else
            {
                bdos(CPMSDMA, buffer);
#ifdef  LARGE_MODEL
                bdos(CPMDSEG, (int)((long)buffer >> 16)); /* set DMA segment */
#endif
                if (bdos(CPMRRAN, fc))
                    break;
                bmove(buffer+offs, buf, size);
            }
            buf += size;
            fc->rwp += size;
            nbytes -= size;
            setuid(luid);
        }
        setuid(luid);
        return cnt - nbytes;

    default:
        return -1;
    }
}


================================================
FILE: cpm/RELIBCPM.SUB
================================================
libr 
<r libc3.lib \
<start1.obj open.obj read.obj write.obj chmod.obj seek.obj \
<fcbname.obj rename.obj creat.obj time.obj convtime.obj timezone.obj \
<stat.obj isatty.obj cleanup.obj close.obj unlink.obj dup.obj getfcb.obj \
<srand1.obj getch.obj signal.obj getuid.obj <abort.obj execl.obj bdos.obj \
<bios.obj _exit.obj exit.obj fakeclean.obj fakecpcln.obj sys_err.obj


================================================
FILE: cpm/RENAME.C
================================================
#include    "cpm.h"

int rename(char *n1, char *n2)
{
    struct fcb  fc[2];

    unlink(n2);
    if (!(setfcb(&fc[0], n1) || setfcb((struct fcb *)(fc[0].dm), n2))
      && (bdos(CPMREN, &fc[0]) & 0xFF) >= 0)
        return 0;
    return -1;
}


================================================
FILE: cpm/SEEK.C
================================================
#include	"cpm.h"

long
lseek(fd, offs, whence)
uchar	fd, whence;
long	offs;
{
	register struct fcb *	fc;
	long			pos;

	if(fd >= MAXFILE)
		return -1;
	fc = &_fcb[fd];
	switch(whence) {

	default:
		pos = offs;
		break;

	case 1:
		pos = fc->rwp + offs;
		break;

	case 2:
		if (fc->rwp > fc->fsize)
			pos = fc->rwp   + offs;
		else	pos = fc->fsize + offs;
		break;
	}
	if(pos >= 0) {
		fc->rwp = pos;
		return fc->rwp;
	}
	return -1;
}


================================================
FILE: cpm/SIGNAL.C
================================================
#include	"cpm.h"
#include	<signal.h>

static signal_t where;

signal_t signal(int sig, signal_t action) 
{
	signal_t prev;

	if(sig != SIGINT)
		return (signal_t)-1;
	prev = where;
	where = action;
	return prev;
}

void
_sigchk()
{
	char	c;

	if(where == SIG_IGN || (c = bdos(CPMDCIO,0xFF)) == 0)
		return;
	if(c != CPMRBT)
		return;
	if(where == SIG_DFL)
		exit(-SIGINT);
	((int(*)())where)(SIGINT);
}


================================================
FILE: cpm/SRAND.AS
================================================
	psect	text
	global	_randomiz, _srand

_randomiz:
	ld	a,r
	ld	l,a
	ld	h,0
	push	hl
	call	_srand
	pop	hl
	ret


================================================
FILE: cpm/SRAND1.C
================================================
#include <conio.h>

srand1(s)
char *	s;
{
	int	i;
	while(*s)
		putchar(*s++);
	while(!kbhit())
		i++;
	srand(i);
}


================================================
FILE: cpm/START1.AS
================================================
	psect	text
	global	__getargs, startup, __argc_

startup:
	jp	__getargs

	psect	bss
__argc_:
	defs	2


================================================
FILE: cpm/START2.AS
================================================
	global	__getargs, __argc_
	psect	text

__getargs:
	pop	hl		;return address
	exx
	pop	hl
	pop	hl		;unjunk stack
	ld	a,(80h)		;get buffer length
	inc	a		;allow for null byte
	neg
	ld	l,a
	ld	h,-1
	add	hl,sp
	ld	sp,hl			;allow space for args
	ld	bc,0		;flag end of args
	push	bc
	ld	hl,80h		;address of argument buffer
	ld	c,(hl)
	ld	b,0
	add	hl,bc
	ld	b,c
	ex	de,hl
	ld	hl,(6)
	ld	c,1
	dec	hl
	ld	(hl),0
	inc	b
	jr	3f

2:	ld	a,(de)
	cp	' '
	dec	de
	jr	nz,1f
	push	hl
	inc	c
4:	ld	a,(de)		;remove extra spaces
	cp	' '
	jr	nz,5f
	dec	de
	jr	4b
5:
	xor	a
1:	dec	hl
	ld	(hl),a
3:
	djnz	2b
	ld	(__argc_),bc		;store argcount
	ld	hl,nularg
	push	hl
	ld	hl,0
	add	hl,sp
	exx
	push	de		;junk the stack again
	push	de
	push	hl		;return address
	exx
	ret

	psect	data
nularg:	defb	0


================================================
FILE: cpm/STAT.C
================================================
#include    <stat.h>
#include    <cpm.h>
#include    <time.h>

extern char _exact;  /* Exact file size hint for last sector
			'C' = not used (old CP/M),
                        'D' = DOSPLUS mode (count is USED bytes),
			'I' = ISX mode (count is UNUSED bytes)
                      */

/*
 *  int stat(char * s, struct stat * b);
 *
 *  Fills  in the supplied struct stat with modification and
 *  access time and file size.
 */

struct tod
{
    int days;
    int hoursmins;
    char    secs;
};

extern time_t convtime();

int stat(register char * s, register struct stat * b)
{
    short       c,d;
    struct fcb  fc;
    struct tod  td;
    uchar       buf[SECSIZE+1];    /* For bytewise lengths */

    c = getuid();
    if (setfcb(&fc, s))
        return -1;      /* A device ! */
    setuid(fc.uid);
    if (!bdos(CPMCFS, &fc) || bdos(CPMVERS) < 0x30)
    {
        /* get size */
        b->st_size = fc.ranrec[0]
                   + ((long)fc.ranrec[1] << 8)
                   + ((long)fc.ranrec[2] << 16);
        b->st_size *= SECSIZE;
        if (fc.ft[0] & 0x80)
            b->st_mode = S_IREAD|S_IFREG;
        else
            b->st_mode = S_IREAD|S_IFREG|S_IWRITE;
        if (fc.ft[1] & 0x80)
            b->st_mode |= S_SYSTEM;
        if (fc.ft[2] & 0x80)
            b->st_mode |= S_ARCHIVE;
        td.secs = 0;
        td.days = td.hoursmins = 0;
        bdos(CPMSDMA,buf);
        if ((d = bdos(CPMFFST,&fc)) < 4)
        {
            /* Account for CP/M3 bytewise file sizes */
            d = (buf[13 + (d << 5)] & 0x7F); /* count of UNUSED bytes */
            if (( _exact == 'D') && (d != 0)) /* DOS Plus has USED bytes */
                d=0x80-d;
            b->st_size-=d;
        }
	/* Corrected to account for directory code return [jrs 2014-04-20] */
        if ((bdos(CPMGFTS, &fc) & 0xFF) < 4) /* Get file date stamp */
        {
            td.days = ((int *)&fc)[24/sizeof(int)];
            td.hoursmins = ((int *)&fc)[26/sizeof(int)];
            b->st_atime = convtime(&td);
            td.secs = 0;
            td.days = ((int *)&fc)[28/sizeof(int)];
            td.hoursmins = ((int *)&fc)[30/sizeof(int)];
            b->st_mtime = convtime(&td);
        }
        setuid(c);
        return 0;
    }
    setuid(c);
    return -1;
}


================================================
FILE: cpm/SYS_ERR.C
================================================
short   errno;

static char uerr[]="Unknown error";

char *  sys_err[] =
{
    uerr,                           /* 0 */
    "Reading empty space",          /* 1 */
    "Disc is full",                 /* 2 */
    "Can't close extent",           /* 3 */
    "Unwritten extent",             /* 4 */
    "Directory full",               /* 5 */
    "File pointer out of range",    /* 6 */
    "File not found",               /* 7 */
    uerr,                           /* 8 */
    "Invalid FCB",                  /* 9 */
    "Disc has been changed",        /* 10 */
    uerr,uerr,uerr,uerr,uerr,uerr,  /* 11-16 - Below are CP/M-3 errors */
    "Disc I/O error",               /* 17 */
    "Disc is read-only",            /* 18 */
    "File is read-only",            /* 19 */
    "Invalid drive",                /* 20 */
    "File already open",            /* 21 */
    uerr,                           /* 22 */
    "Password error",               /* 23 */
    "File exists",                  /* 24 */
    "Ambiguous filename",           /* 25 */
    "File is wheel protected",      /* 26 */ 
    uerr    
};
short   sys_ner = sizeof sys_err / sizeof sys_err[0];


================================================
FILE: cpm/TIME.C
================================================
/*
 *  time() for CP/M-86 type machines
 */

#include    <cpm.h>
#include    <time.h>

struct tod
{
    short   days;
    char    hours;
    char    mins;
    char    secs;
};

extern time_t   convtime();

time_t time(time_t *tp)
{
    struct tod  tod;
    time_t      t;

    tod.hours = tod.mins = tod.secs = tod.days = 0;
    tod.secs = bdos(CPMGDAT, &tod);
    t = convtime(&tod);
    if (tp)
        *tp = t;
    return t;
}


================================================
FILE: cpm/TIMEZONE.C
================================================
#include	<time.h>

int	time_zone = 0;


================================================
FILE: cpm/UNLINK.C
================================================
#include    "cpm.h"

unlink(char *name)
{
    struct fcb  fc;
    uchar       luid;
    short       retval;

    if (setfcb(&fc, name))
        return -1;
    luid = getuid();
    setuid(fc.uid);
    retval = bdos(CPMDEL, &fc);
    if ((retval & 0xFF) == 0xFF && errno == 16)
        errno = 7; /* file not found */
    setuid(luid);
    return retval;
}


================================================
FILE: cpm/WRITE.C
================================================
#include    "cpm.h"

extern char _piped; /* PIPEMGR loaded? */

write(uchar fd, char *buf, ushort nbytes)
{
    register struct fcb *fc;
    uchar   size, offs, luid;
    short   c;
    ushort  count;
    char    RSXPB[4];
    char    buffer[SECSIZE];

    if (fd >= MAXFILE)
        return -1;
    fc = &_fcb[fd];
    offs = CPMWCON;
    RSXPB[0]=0x7D;
    RSXPB[1]=0;
    RSXPB[3]=0;
    count = nbytes;
    switch (fc->use)
    {
    case U_PUN:
        while (nbytes--)
        {
            _sigchk();
            bdos(CPMWPUN, *buf++);
        }
        return count;

    case U_LST:
        offs = CPMWLST;

    case U_CON:
        while (nbytes--)
        {
            _sigchk();
            c = *buf++;
            bdos(offs, c);
        }
        return count;

    case U_ERR:
        RSXPB[0]=0x7A;
    case U_RSX:
        while (nbytes--)
        {
            _sigchk();
            RSXPB[2]= *buf++;
            if (_piped)
                bdos(CPMRSX,RSXPB);
            else
                bdos(CPMWCON,RSXPB[2]);
        }
        return count;   
    case U_WRITE:
    case U_RDWR:
        luid = getuid();
        while (nbytes)
        {
            _sigchk();
            setuid(fc->uid);
            offs = fc->rwp%SECSIZE;
            if ((size = SECSIZE - offs) > nbytes)
                size = nbytes;
            _putrno(fc->ranrec, fc->rwp/SECSIZE);
            if (size == SECSIZE)
            {
                bdos(CPMSDMA, buf);
#ifdef  LARGE_MODEL
                bdos(CPMDSEG, (int)((long)buf >> 16));  /* set DMA segment */
#endif
            }
            else
            {
                bdos(CPMSDMA, buffer);
#ifdef  LARGE_MODEL
                bdos(CPMDSEG, (int)((long)buffer >> 16));   /* set DMA segment */
#endif
                buffer[0] = CPMETX;
                bmove(buffer, buffer+1, SECSIZE-1);
                bdos(CPMRRAN, fc);
                bmove(buf, buffer+offs, size);
            }
            if (bdos(CPMWRAN, fc))
                break;
            buf += size;
            fc->rwp += size;
            if (fc->fsize < fc->rwp)
                fc->fsize = fc->rwp;
            nbytes -= size;
            setuid(luid);
        }
        setuid(luid);
        return count-nbytes;

    default:
        return -1;
    }
}


================================================
FILE: cpm/ZC280CPM.AS
================================================
; This is ZCRTCPM for the Z280 MPU
;
	psect	text,global,pure
	psect	data,global
	psect	bss,global

	psect	text
	defs	100h		;Base of CP/M's TPA

	global	start,_main,_exit,__Hbss, __Lbss, __argc_, __z3env, startup
        global  __piped,__initrsx,__exact

;	Start with MS-DOS x86 detection
start:		; DOS Protection	8080/Z80	x86
				;	---------  --------------------
	defb	0EBh,04h	;	EX DE,HL   JMPS LABE
				;	INC B

	ex	de,hl		;	EX DE,HL
	defb	0C3h		;	JP BEGIN
	defw	begin		; (We don't want the assembler optimising
				;  this to a relative branch)

labe:	defb	0B8h,0,09h	;		   MOV AX,9 ; print string

	defb	0BAh		;		   MOV DX,OFFSET BVMES
	defw	bvmes

	defb	0CDh,021h	;		   INT 21h  ; call DOS

	defb	0B8h,01h,4Ch	;		   MOV AX,4C01h ; terminate
				;		   ; with CTRL-BREAK code (1)

	defb	0CDh,021h	;		   INT 21h  ; call DOS
						   ; we never return here

	defb	13
	defm	'Compiled with Hi-Tech C'
	defb	13,10,26

	psect	data
z3ecst:	defm	'Z3ENV'
bvmes:	defm	'This CP/M program requires a Z280 MPU.'
	defb	13,10,'$'
memmes:	defm	'Not enough memory to run.'
	defb	13,10,'$'
	psect	text

begin:
	sub	a		;Stop 8080 processors running this.
	jp	po,okver

badcpu:	ld	de,bvmes
	ld	c,9		;Print error message
	jp	5

okver:	ld	a,40h		;Check for Z280 MPU
;	tset	a		; (this instruction will set the S flag
	defb	0CBh,037h
	jp	m,badcpu	; on a Z80 and clear it on a Z280)

;Check if HL holds a valid Z-System environment descriptor

	ld	l,0		;Start of the page
	ld	a,(hl)
	cp	0c3h		;Must start with a jump
	jr	nz,noz3
	ld	l,1bh
	ld	a,(hl)		;Must refer to itself
	or	a
	jr	nz,noz3
	inc	hl
	ld	a,(hl)
	cp	h
	jr	nz,noz3
	ld	l,3		;Must contain the string "Z3ENV"
	ld	de,z3ecst
	ld	b,5		;Check 5 characters
z3ecmp:	ld	a,(de)
	cp	(hl)
	jr	nz,noz3
	inc	hl
	inc	de
	djnz	z3ecmp
	ld	l,0
	defb	3eh		;Swallow the LD HL
noz3:	ld	hl,0
yesz3:	ld	(__z3env),hl
	ld	hl,(6)		;Base of FDOS
	push	hl
	dec	h		;Allow 128 stack levels at least
	ld	de,__Hbss	;Last address used by the program
	and	a
	sbc	hl,de
	jr	nc,memok
	ld	de,memmes	;Bss segment hits the BDOS.
	ld	c,9
	call	5
	rst	0

memok:	
	ld	c,12
	call	5		;Check CP/M version
	ld	a,h
	dec	a		; MP/M (H == 1) has no RSX
	jr	z,norsx
	ld	a,l
	cp	30h		; CP/M Plus (L >= 30h)?
	jr	nc,iscpm3
	xor	a		; CP/M 2.2 has no RSX
	jr	norsx

iscpm3:	ld	hl,__exact	; Default exact file size
	inc	(hl)		;  to DOSplus mode ('C' becomes 'D')

;If the PIPEMGR RSX is loaded, initialise it.

	ld	c,60		; RSX call
	ld	de,rsxpb	; RSX data
	call	5
	ld	a,h
	inc	l		;HL=00FFh if no PIPEMGR present.
	or	l
norsx:	ld	(__piped),a
	call	nz,__initrsx	;use PIPEMGR for stdin, stdout and stderr
        pop	hl		;base address of fdos
	ld	sp,hl		;stack grows downwards
	ld	de,__Lbss	;Start of BSS segment
	or	a		;clear carry
	ld	hl,__Hbss
	sbc	hl,de		;size of uninitialized data area
	ld	c,l
	ld	b,h
	dec	bc	
	ld	l,e
	ld	h,d
	inc	de
	ld	(hl),0
	ldir			;clear memory
	ld	hl,nularg
	push	hl
	ld	hl,80h		;argument buffer
	ld	c,(hl)
	inc	hl
	ld	b,0
	add	hl,bc
	ld	(hl),0		;zero terminate it
	ld	hl,81h
	push	hl
	call	startup
	pop	bc		;unjunk stack
	pop	bc
	ld	bc,(__z3env)	;main (argc,argv,z3env)
	push	bc
	push	hl
	ld	hl,(__argc_)
	push	hl
	call	_main
	push	hl
	call	_exit
	rst	0

	psect	data
nularg:	defb	0
__z3env:
	defw	0
__piped:
        defw    0
__exact:		; Exact file size mode
	defb	'C',0	; 'C' is CP/M 2 (none), 'I' is ISIS, 'D' is DOSPLUS
rsxpb:	defb	79h,1
	defw	pipesgn
pipesgn:
	defm	'PIPEMGR '

	end	start


================================================
FILE: cpm/ZCRTCPM.AS
================================================
	psect	text,global,pure
	psect	data,global
	psect	bss,global

	psect	text
	defs	100h		;Base of CP/M's TPA

	global	start,_main,_exit,__Hbss, __Lbss, __argc_, __z3env, startup
        global  __piped,__initrsx,__exact

start:		; DOS Protection	8080/Z80	x86
				;	---------  --------------------
	defb	0EBh,04h	;	EX DE,HL   JMPS LABE
				;	INC B

	ex	de,hl		;	EX DE,HL
	defb	0C3h		;	JP BEGIN
	defw	begin		; (We don't want the assembler optimising
				;  this to a relative branch)

labe:	defb	0B8h,0,09h	;		   MOV AX,9 ; print string

	defb	0BAh		;		   MOV DX,OFFSET BVMES
	defw	bvmes

	defb	0CDh,021h	;		   INT 21h  ; call DOS

	defb	0B8h,01h,4Ch	;		   MOV AX,4C01h ; terminate
				;		   ; with CTRL-BREAK code (1)

	defb	0CDh,021h	;		   INT 21h  ; call DOS
						   ; we never return here

	; Some text for viewing if typed

	defm	'Compiled with Hi-Tech C'
	defb	13,10,26

	psect	data
z3ecst:	defm	'Z3ENV'
bvmes:	defm	'This CP/M program requires a Z80 CPU.'
	defb	13,10,'$'
memmes:	defm	'Not enough memory to run.'
	defb	13,10,'$'
	psect	text

begin:	sub	a		;Stop 8080 processors running this.
	jp	po,okver

	ld	de,bvmes
	ld	c,9		;Print error message
	jp	5

;Check if HL holds a valid Z-System environment descriptor

okver:	ld	l,0		;Start of the page
	ld	a,(hl)
	cp	0c3h		;Must start with a jump
	jr	nz,noz3
	ld	l,1bh
	ld	a,(hl)		;Must refer to itself
	or	a
	jr	nz,noz3
	inc	hl
	ld	a,(hl)
	cp	h
	jr	nz,noz3
	ld	l,3		;Must contain the string "Z3ENV"
	ld	de,z3ecst
	ld	b,5		;Check 5 characters
z3ecmp:	ld	a,(de)
	cp	(hl)
	jr	nz,noz3
	inc	hl
	inc	de
	djnz	z3ecmp
	ld	l,0
	defb	3eh		;Swallow the LD HL
noz3:	ld	hl,0
yesz3:	ld	(__z3env),hl
	ld	hl,(6)		;Base of FDOS
	push	hl
	dec	h		;Allow 128 stack levels at least
	ld	de,__Hbss	;Last address used by the program
	and	a
	sbc	hl,de
	jr	nc,memok
	ld	de,memmes	;Bss segment hits the BDOS.
	ld	c,9
	call	5
	rst	0

memok:	
	ld	c,12
	call	5		;Check CP/M version
	ld	a,h
	dec	a		; MP/M (H == 1) has no RSX
	jr	z,norsx		;  Z bit is set and A=0
	ld	a,l
	cp	30h		; CP/M Plus (L >= 30h)?
	jr	nc,iscpm3
	xor	a		; CP/M 2.2 has no RSX
	jr	norsx		;  Z bit is set and A=0

iscpm3:	ld	hl,__exact	; Default exact file size
	inc	(hl)		;  to DOSplus mode ('C' becomes 'D')

;If the PIPEMGR RSX is loaded, initialise it.

	ld	c,60		; RSX call
	ld	de,rsxpb	; RSX data
	call	5
	ld	a,h
	inc	l		;HL=00FFh if no PIPEMGR present.
	or	l
norsx:	ld	(__piped),a
	call	nz,__initrsx	;use PIPEMGR for stdin, stdout and stderr
        pop	hl		;base address of fdos
	ld	sp,hl		;stack grows downwards
	ld	de,__Lbss	;Start of BSS segment
	or	a		;clear carry
	ld	hl,__Hbss
	sbc	hl,de		;size of uninitialized data area
	ld	c,l
	ld	b,h
	dec	bc	
	ld	l,e
	ld	h,d
	inc	de
	ld	(hl),0
	ldir			;clear memory
	ld	hl,nularg
	push	hl
	ld	hl,80h		;argument buffer
	ld	c,(hl)
	inc	hl
	ld	b,0
	add	hl,bc
	ld	(hl),0		;zero terminate it
	ld	hl,81h
	push	hl
	call	startup
	pop	bc		;unjunk stack
	pop	bc
	ld	bc,(__z3env)	;main (argc,argv,z3env)
	push	bc
	push	hl
	ld	hl,(__argc_)
	push	hl
	call	_main
	push	hl
	call	_exit
	rst	0

	psect	data
nularg:	defb	0
__z3env:
	defw	0
__piped:
        defw    0
__exact:		; Exact file size mode
	defb	'C',0	; 'C' is CP/M 2 (none), 'I' is ISIS, 'D' is DOSPLUS
rsxpb:	defb	79h,1
	defw	pipesgn
pipesgn:
	defm	'PIPEMGR '

	end	start


================================================
FILE: cpm/ZD280CPM.AS
================================================
; This is ZDRTCPM for the Z280 MPU
;
	psect	text,global,pure
	psect	data,global
	psect	bss,global

	psect	text
	defs	100h		;Base of CP/M's TPA
	global	start,_main,_exit,__Hdata, __trap, __piped,__exact
start:	ld	hl,(6)		;base address of fdos
	ld	sp,hl		;stack grows downwards
	ld	de,__Hdata	;end of initialized data
	scf
	sbc	hl,de		;size of uninitialized data area
	ld	c,l
	ld	b,h
	dec	bc	
	ld	l,e
	ld	h,d
	inc	de
	ld	(hl),0
	ldir			;clear memory
	ld	hl,-80h		;allow room for args
	add	hl,sp
	ld	sp,hl		;allow space for args
	ld	bc,0		;flag end of args
	push	bc
	ld	hl,80h		;address of argument buffer
	ld	c,(hl)
	ld	b,0
	add	hl,bc
	ld	b,c
	ex	de,hl
	ld	hl,(6)
	ld	c,1
	dec	hl
	ld	(hl),0
	inc	b
	jr	3f

2:	ld	a,(de)
	cp	' '
	dec	de
	jr	nz,1f
	xor	a
	push	hl
	inc	c
1:	dec	hl
	ld	(hl),a
3:
	djnz	2b
	ld	hl,nularg
	push	hl
	ld	hl,0
	add	hl,sp
	push	hl
	push	bc
	ld	hl,__trap
	ld	(39h),hl
	ld	a,0c3h
	ld	(38h),a
	rst	38h
	call	_main
	push	hl
	call	_exit
	jp	p,0

	psect	data
__piped:
        defw    0
__exact:		; Exact file size mode
	defb	'C',0	; 'C' is CP/M 2 (none), 'I' is ISIS, 'D' is DOSPLUS
nularg:	defm	'main'
	defb	0
	end	start


================================================
FILE: cpm/ZDRTCPM.AS
================================================
	psect	text,global,pure
	psect	data,global
	psect	bss,global

	psect	text
	defs	100h		;Base of CP/M's TPA
	global	start,_main,_exit,__Hdata, __trap, __piped, __exact
start:	ld	hl,(6)		;base address of fdos
	ld	sp,hl		;stack grows downwards
	ld	de,__Hdata	;end of initialized data
	scf
	sbc	hl,de		;size of uninitialized data area
	ld	c,l
	ld	b,h
	dec	bc	
	ld	l,e
	ld	h,d
	inc	de
	ld	(hl),0
	ldir			;clear memory
	ld	hl,-80h		;allow room for args
	add	hl,sp
	ld	sp,hl		;allow space for args
	ld	bc,0		;flag end of args
	push	bc
	ld	hl,80h		;address of argument buffer
	ld	c,(hl)
	ld	b,0
	add	hl,bc
	ld	b,c
	ex	de,hl
	ld	hl,(6)
	ld	c,1
	dec	hl
	ld	(hl),0
	inc	b
	jr	3f

2:	ld	a,(de)
	cp	' '
	dec	de
	jr	nz,1f
	xor	a
	push	hl
	inc	c
1:	dec	hl
	ld	(hl),a
3:
	djnz	2b
	ld	hl,nularg
	push	hl
	ld	hl,0
	add	hl,sp
	push	hl
	push	bc
	ld	hl,__trap
	ld	(39h),hl
	ld	a,0c3h
	ld	(38h),a
	rst	38h
	call	_main
	push	hl
	call	_exit
	jp	p,0

	psect	data
__piped:
        defw    0
__exact:		; Exact file size mode
	defb	'C',0	; 'C' is CP/M 2 (none), 'I' is ISIS, 'D' is DOSPLUS
nularg:	defm	'main'
	defb	0
	end	start


================================================
FILE: cpm/ZN280CPM.AS
================================================
; This is ZNRTCPM for the Z280 MPU (with minimal getargs)
;
	psect	text,global,pure
	psect	data,global
	psect	bss,global

	psect	text
	defs	100h		;Base of CP/M's TPA

	global	start,_main,_exit,__Hbss, __Lbss, __argc_, __z3env, startup
        global  __piped,__initrsx,__exact
	global	__getargs

;	Start with MS-DOS x86 detection
start:		; DOS Protection	8080/Z80	x86
				;	---------  --------------------
	defb	0EBh,04h	;	EX DE,HL   JMPS LABE
				;	INC B

	ex	de,hl		;	EX DE,HL
	defb	0C3h		;	JP BEGIN
	defw	begin		; (We don't want the assembler optimising
				;  this to a relative branch)

labe:	defb	0B8h,0,09h	;		   MOV AX,9 ; print string

	defb	0BAh		;		   MOV DX,OFFSET BVMES
	defw	bvmes

	defb	0CDh,021h	;		   INT 21h  ; call DOS

	defb	0B8h,01h,4Ch	;		   MOV AX,4C01h ; terminate
				;		   ; with CTRL-BREAK code (1)

	defb	0CDh,021h	;		   INT 21h  ; call DOS
						   ; we never return here

	defb	13
	defm	'Compiled with Hi-Tech C'
	defb	13,10,26

	psect	data
z3ecst:	defm	'Z3ENV'
bvmes:	defm	'This CP/M program requires a Z280 MPU.'
	defb	13,10,'$'
memmes:	defm	'Not enough memory to run.'
	defb	13,10,'$'
	psect	text

begin:
	sub	a		;Stop 8080 processors running this.
	jp	po,okver

badcpu:	ld	de,bvmes
	ld	c,9		;Print error message
	jp	5

okver:	ld	a,40h		;Check for Z280 MPU
;	tset	a		; (this instruction will set the S flag
	defb	0CBh,037h
	jp	m,badcpu	; on a Z80 and clear it on a Z280)

;Check if HL holds a valid Z-System environment descriptor

	ld	l,0		;Start of the page
	ld	a,(hl)
	cp	0c3h		;Must start with a jump
	jr	nz,noz3
	ld	l,1bh
	ld	a,(hl)		;Must refer to itself
	or	a
	jr	nz,noz3
	inc	hl
	ld	a,(hl)
	cp	h
	jr	nz,noz3
	ld	l,3		;Must contain the string "Z3ENV"
	ld	de,z3ecst
	ld	b,5		;Check 5 characters
z3ecmp:	ld	a,(de)
	cp	(hl)
	jr	nz,noz3
	inc	hl
	inc	de
	djnz	z3ecmp
	ld	l,0
	defb	3eh		;Swallow the LD HL
noz3:	ld	hl,0
yesz3:	ld	(__z3env),hl
	ld	hl,(6)		;Base of FDOS
	push	hl
	dec	h		;Allow 128 stack levels at least
	ld	de,__Hbss	;Last address used by the program
	and	a
	sbc	hl,de
	jr	nc,memok
	ld	de,memmes	;Bss segment hits the BDOS.
	ld	c,9
	call	5
	rst	0

memok:	
	ld	c,12
	call	5		;Check CP/M version
	ld	a,h
	dec	a		; MP/M (H == 1) has no RSX
	jr	z,norsx
	ld	a,l
	cp	30h		; CP/M Plus (L >= 30h)?
	jr	nc,iscpm3
	xor	a		; CP/M 2.2 has no RSX
	jr	norsx

iscpm3:	ld	hl,__exact	; Default exact file size
	inc	(hl)		;  to DOSplus mode ('C' becomes 'D')

;If the PIPEMGR RSX is loaded, initialise it.

	ld	c,60		; RSX call
	ld	de,rsxpb	; RSX data
	call	5
	ld	a,h
	inc	l		;HL=00FFh if no PIPEMGR present.
	or	l
norsx:	ld	(__piped),a
	call	nz,__initrsx	;use PIPEMGR for stdin, stdout and stderr
        pop	hl		;base address of fdos
	ld	sp,hl		;stack grows downwards
	ld	de,__Lbss	;Start of BSS segment
	or	a		;clear carry
	ld	hl,__Hbss
	sbc	hl,de		;size of uninitialized data area
	ld	c,l
	ld	b,h
	dec	bc	
	ld	l,e
	ld	h,d
	inc	de
	ld	(hl),0
	ldir			;clear memory
	ld	hl,nularg
	push	hl
	ld	hl,80h		;argument buffer
	ld	c,(hl)
	inc	hl
	ld	b,0
	add	hl,bc
	ld	(hl),0		;zero terminate it
	ld	hl,81h
	push	hl
	call	startup
	pop	bc		;unjunk stack
	pop	bc
	ld	bc,(__z3env)	;main (argc,argv,z3env)
	push	bc
	push	hl
	ld	hl,(__argc_)
	push	hl
	call	_main
	push	hl
	call	_exit
	rst	0

;
; This is a substitute getargs() function that is of minimal
; size and does not perform wildcard argument expansion and
; redirection.
;

__getargs:
	pop	hl		;return address
	exx
	pop	hl
	pop	hl		;unjunk stack
	ld	a,(80h)		;get buffer length
	inc	a		;allow for null byte
	neg
	ld	l,a
	ld	h,-1
	add	hl,sp
	ld	sp,hl		;allow space for args
	ld	bc,0		;flag end of args
	push	bc
	ld	hl,80h		;address of argument buffer
	ld	c,(hl)
	ld	b,0
	add	hl,bc
	ld	b,c
	ex	de,hl
	ld	hl,(6)
	ld	c,1
	dec	hl
	ld	(hl),0
	inc	b
	jr	3f

2:	ld	a,(de)
	cp	' '
	dec	de
	jr	nz,1f
	push	hl
	inc	c
4:	ld	a,(de)		;remove extra spaces
	cp	' '
	jr	nz,5f
	dec	de
	jr	4b
5:
	xor	a
1:	dec	hl
	ld	(hl),a
3:
	djnz	2b
	ld	(__argc_),bc		;store argcount
	ld	hl,nularg
	push	hl
	ld	hl,0
	add	hl,sp
	exx
	push	de		;junk the stack again
	push	de
	push	hl		;return address
	exx
	ret

	psect	data
nularg:	defb	0
__z3env:
	defw	0
__piped:
        defw    0
__exact:		; Exact file size mode
	defb	'C',0	; 'C' is CP/M 2 (none), 'I' is ISIS, 'D' is DOSPLUS
rsxpb:	defb	79h,1
	defw	pipesgn
pipesgn:
	defm	'PIPEMGR '

	end	start


================================================
FILE: cpm/ZNRTCPM.AS
================================================
; This is ZNRTCPM for the Z80 (with minimal getargs)

	psect	text,global,pure
	psect	data,global
	psect	bss,global

	psect	text
	defs	100h		;Base of CP/M's TPA

	global	start,_main,_exit,__Hbss, __Lbss, __argc_, __z3env, startup
        global  __piped,__initrsx,__exact
	global	__getargs

start:		; DOS Protection	8080/Z80	x86
				;	---------  --------------------
	defb	0EBh,04h	;	EX DE,HL   JMPS LABE
				;	INC B

	ex	de,hl		;	EX DE,HL
	defb	0C3h		;	JP BEGIN
	defw	begin		; (We don't want the assembler optimising
				;  this to a relative branch)

labe:	defb	0B8h,0,09h	;		   MOV AX,9 ; print string

	defb	0BAh		;		   MOV DX,OFFSET BVMES
	defw	bvmes

	defb	0CDh,021h	;		   INT 21h  ; call DOS

	defb	0B8h,01h,4Ch	;		   MOV AX,4C01h ; terminate
				;		   ; with CTRL-BREAK code (1)

	defb	0CDh,021h	;		   INT 21h  ; call DOS
						   ; we never return here

	; Some text for viewing if typed

	defm	'Compiled with Hi-Tech C'
	defb	13,10,26

	psect	data
z3ecst:	defm	'Z3ENV'
bvmes:	defm	'This CP/M program requires a Z80 CPU.'
	defb	13,10,'$'
memmes:	defm	'Not enough memory to run.'
	defb	13,10,'$'
	psect	text

begin:	sub	a		;Stop 8080 processors running this.
	jp	po,okver

	ld	de,bvmes
	ld	c,9		;Print error message
	jp	5

;Check if HL holds a valid Z-System environment descriptor

okver:	ld	l,0		;Start of the page
	ld	a,(hl)
	cp	0c3h		;Must start with a jump
	jr	nz,noz3
	ld	l,1bh
	ld	a,(hl)		;Must refer to itself
	or	a
	jr	nz,noz3
	inc	hl
	ld	a,(hl)
	cp	h
	jr	nz,noz3
	ld	l,3		;Must contain the string "Z3ENV"
	ld	de,z3ecst
	ld	b,5		;Check 5 characters
z3ecmp:	ld	a,(de)
	cp	(hl)
	jr	nz,noz3
	inc	hl
	inc	de
	djnz	z3ecmp
	ld	l,0
	defb	3eh		;Swallow the LD HL
noz3:	ld	hl,0
yesz3:	ld	(__z3env),hl
	ld	hl,(6)		;Base of FDOS
	push	hl
	dec	h		;Allow 128 stack levels at least
	ld	de,__Hbss	;Last address used by the program
	and	a
	sbc	hl,de
	jr	nc,memok
	ld	de,memmes	;Bss segment hits the BDOS.
	ld	c,9
	call	5
	rst	0

memok:	
	ld	c,12
	call	5		;Check CP/M version
	ld	a,h
	dec	a		; MP/M (H == 1) has no RSX
	jr	z,norsx
	ld	a,l
	cp	30h		; CP/M Plus (L >= 30h)?
	jr	nc,iscpm3
	xor	a		; CP/M 2.2 has no RSX
	jr	norsx

iscpm3:	ld	hl,__exact	; Default exact file size
	inc	(hl)		;  to DOSplus mode ('C' becomes 'D')

;If the PIPEMGR RSX is loaded, initialise it.

	ld	c,60		; RSX call
	ld	de,rsxpb	; RSX data
	call	5
	ld	a,h
	inc	l		;HL=00FFh if no PIPEMGR present.
	or	l
norsx:	ld	(__piped),a
	call	nz,__initrsx	;use PIPEMGR for stdin, stdout and stderr
        pop	hl		;base address of fdos
	ld	sp,hl		;stack grows downwards
	ld	de,__Lbss	;Start of BSS segment
	or	a		;clear carry
	ld	hl,__Hbss
	sbc	hl,de		;size of uninitialized data area
	ld	c,l
	ld	b,h
	dec	bc	
	ld	l,e
	ld	h,d
	inc	de
	ld	(hl),0
	ldir			;clear memory
	ld	hl,nularg
	push	hl
	ld	hl,80h		;argument buffer
	ld	c,(hl)
	inc	hl
	ld	b,0
	add	hl,bc
	ld	(hl),0		;zero terminate it
	ld	hl,81h
	push	hl
	call	startup
	pop	bc		;unjunk stack
	pop	bc
	ld	bc,(__z3env)	;main (argc,argv,z3env)
	push	bc
	push	hl
	ld	hl,(__argc_)
	push	hl
	call	_main
	push	hl
	call	_exit
	rst	0
;
; This is a substitute getargs() function that is of minimal
; size and 
Download .txt
gitextract_om_jot2q/

├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── cpm/
│   ├── ABORT.C
│   ├── BDOS.AS
│   ├── BIOS.AS
│   ├── BUILD-C.LOG
│   ├── BUILD-C.SUB
│   ├── BUILDCPM.SUB
│   ├── BUILDCRT.SUB
│   ├── C-ORIG.C
│   ├── C309-20.C
│   ├── CHMOD.C
│   ├── CLEANUP.C
│   ├── CLOSE.C
│   ├── CONVTIME.C
│   ├── CREAT.C
│   ├── CSV.AS
│   ├── DUP.C
│   ├── EXEC-BLD.SUB
│   ├── EXEC.AS
│   ├── EXECL.AS
│   ├── EXIT.AS
│   ├── FAKECLEA.AS
│   ├── FAKECPCL.AS
│   ├── FCBNAME.C
│   ├── GETCH.C
│   ├── GETFCB.C
│   ├── GETUID.AS
│   ├── ISATTY.C
│   ├── MAKEFILE
│   ├── MKTIME.C
│   ├── OPEN.C
│   ├── READ.C
│   ├── RELIBCPM.SUB
│   ├── RENAME.C
│   ├── SEEK.C
│   ├── SIGNAL.C
│   ├── SRAND.AS
│   ├── SRAND1.C
│   ├── START1.AS
│   ├── START2.AS
│   ├── STAT.C
│   ├── SYS_ERR.C
│   ├── TIME.C
│   ├── TIMEZONE.C
│   ├── UNLINK.C
│   ├── WRITE.C
│   ├── ZC280CPM.AS
│   ├── ZCRTCPM.AS
│   ├── ZD280CPM.AS
│   ├── ZDRTCPM.AS
│   ├── ZN280CPM.AS
│   ├── ZNRTCPM.AS
│   ├── ZR280CPM.AS
│   ├── ZRRTCPM.AS
│   └── _EXIT.AS
├── dist/
│   ├── $EXEC.COM
│   ├── ASSERT.H
│   ├── C-ORIG.COM
│   ├── C309-20.COM
│   ├── C309.COM
│   ├── CGEN.COM
│   ├── CONIO.H
│   ├── CPM.H
│   ├── CPM.HUF
│   ├── CPP.COM
│   ├── CREF.COM
│   ├── CRTCPM.OBJ
│   ├── CTYPE.H
│   ├── DEBUG.COM
│   ├── DEHUFF.COM
│   ├── DRTCPM.OBJ
│   ├── EXEC.H
│   ├── FLOAT.H
│   ├── FLOAT.HUF
│   ├── GEN.HUF
│   ├── HITECH.H
│   ├── HUFF.HUF
│   ├── HUFFORIG.HUF
│   ├── LIBC.LIB
│   ├── LIBCORIG.LIB
│   ├── LIBF.LIB
│   ├── LIBFORIG.LIB
│   ├── LIBOVR.LIB
│   ├── LIBR.COM
│   ├── LIMITS.H
│   ├── LINQ.COM
│   ├── MATH.H
│   ├── NRTCPM.OBJ
│   ├── OBJTOHEX.COM
│   ├── OPTIM.COM
│   ├── OPTIONS
│   ├── OVERLAY.H
│   ├── P1.COM
│   ├── RRTCPM.OBJ
│   ├── SETJMP.H
│   ├── SIGNAL.H
│   ├── STAT.H
│   ├── STDARG.H
│   ├── STDDEF.H
│   ├── STDINT.H
│   ├── STDIO.H
│   ├── STDIO.HUF
│   ├── STDLIB.H
│   ├── STRING.H
│   ├── SYMTOAS.COM
│   ├── SYS.H
│   ├── TIME.H
│   ├── UNIXIO.H
│   └── ZAS.COM
├── doc/
│   ├── DEBUGMAN.TXT
│   ├── HTCZ80.TXT
│   ├── OBJCODE.TXT
│   └── SYMFILE.TXT
├── float/
│   ├── ACOS.C
│   ├── ASFLOAT.AS
│   ├── ASIN.C
│   ├── ATAN.C
│   ├── ATAN2.C
│   ├── ATOF.C
│   ├── CEIL.C
│   ├── COS.C
│   ├── COSH.C
│   ├── DOPRNT.C
│   ├── DOSCAN.C
│   ├── EVALPOLY.C
│   ├── EXP.C
│   ├── FABS.C
│   ├── FBCD.AS
│   ├── FINC.AS
│   ├── FLOAT.AS
│   ├── FLOOR.C
│   ├── FNUM.C
│   ├── FPRINTF.C
│   ├── FREXP.AS
│   ├── FRNDINT.AS
│   ├── FSCANF.C
│   ├── FTOL.AS
│   ├── LIBFVER.C
│   ├── LOG.C
│   ├── LTOF.AS
│   ├── M280LIBF.LOG
│   ├── M280LIBF.SUB
│   ├── MAKEFILE
│   ├── MAKELIBF.LOG
│   ├── MAKELIBF.SUB
│   ├── PRINTF.C
│   ├── SCANF.C
│   ├── SIN.C
│   ├── SINH.C
│   ├── SPRINTF.C
│   ├── SQRT.C
│   ├── SSCANF.C
│   ├── TAN.C
│   └── TANH.C
├── gen/
│   ├── ABS.AS
│   ├── ALLSH.AS
│   ├── ALRSH.AS
│   ├── ASALLSH.AS
│   ├── ASALRSH.AS
│   ├── ASAR.AS
│   ├── ASDIV.AS
│   ├── ASLADD.AS
│   ├── ASLAND.AS
│   ├── ASLL.AS
│   ├── ASLLRSH.AS
│   ├── ASLMUL.AS
│   ├── ASLOR.AS
│   ├── ASLR.AS
│   ├── ASLSUB.AS
│   ├── ASLXOR.AS
│   ├── ASMOD.AS
│   ├── ASMUL.AS
│   ├── ATOI.AS
│   ├── ATOL.C
│   ├── BITFIELD.AS
│   ├── BLKCLR.AS
│   ├── BLKCPY.C
│   ├── BMOVE.AS
│   ├── BRELOP.AS
│   ├── BUILDGEN.SUB
│   ├── CALLOC.C
│   ├── CSV.AS
│   ├── CTYPE.C
│   ├── CTYPE_.C
│   ├── FRELOP.AS
│   ├── GETSP.AS
│   ├── IDIV.AS
│   ├── IMUL.AS
│   ├── INDEX.AS
│   ├── INOUT.AS
│   ├── IREGSET.AS
│   ├── ISALPHA.AS
│   ├── ISDIGIT.AS
│   ├── ISLOWER.AS
│   ├── ISSPACE.AS
│   ├── ISUPPER.AS
│   ├── LADD.AS
│   ├── LAND.AS
│   ├── LDIV.AS
│   ├── LIBCVER.C
│   ├── LINC.AS
│   ├── LLRSH.AS
│   ├── LMUL.AS
│   ├── LONGJMP.AS
│   ├── LOR.AS
│   ├── LRELOP.AS
│   ├── LSUB.AS
│   ├── LXOR.AS
│   ├── MAKEFILE
│   ├── MALLOC.C
│   ├── MAX.AS
│   ├── MEMCMP.C
│   ├── MEMCPY.C
│   ├── MEMSET.C
│   ├── PNUM.C
│   ├── QSORT.C
│   ├── RAND.C
│   ├── RCSV.AS
│   ├── RINDEX.AS
│   ├── SBRK.AS
│   ├── SHAR.AS
│   ├── SHLL.AS
│   ├── SHLR.AS
│   ├── STRCAT.AS
│   ├── STRCHR.AS
│   ├── STRCMP.AS
│   ├── STRCPY.AS
│   ├── STRDUP.C
│   ├── STRFTIME.C
│   ├── STRICMP.AS
│   ├── STRISTR.C
│   ├── STRLEN.AS
│   ├── STRNCAT.AS
│   ├── STRNCMP.AS
│   ├── STRNCPY.AS
│   ├── STRNICMP.AS
│   ├── STRNISTR.C
│   ├── STRNSTR.C
│   ├── STRRCHR.AS
│   ├── STRSTR.C
│   ├── STRTOK.C
│   ├── SWAP.AS
│   ├── TOLOWER.AS
│   ├── TOUPPER.AS
│   ├── WRELOP.AS
│   └── XTOI.AS
├── historical/
│   ├── HTC13.LBR
│   └── Z80V309.LBR
├── htc-bin.lbr
├── huff/
│   ├── DECODE.C
│   ├── DEHUF.C
│   ├── DEHUFF.C
│   ├── DEHUFF.COM
│   ├── ENCODE.C
│   ├── ENHUFF.C
│   ├── ENHUFF.COM
│   ├── HUFF.H
│   ├── MAKEFILE
│   └── MISC.C
├── msx2dist/
│   ├── cc_01/
│   │   ├── CC.C
│   │   ├── CC.COM
│   │   ├── CC.TXT
│   │   ├── LIBDOS2.LIB
│   │   ├── MAKEFILE
│   │   ├── REDIR.AS
│   │   ├── REDIR.OBJ
│   │   ├── VSH.TXT
│   │   ├── VSH1.O
│   │   ├── VSH2.O
│   │   ├── VSH3.O
│   │   └── VSHRT.AS
│   ├── ldos2_04/
│   │   ├── ACT_FILE.AS
│   │   ├── ASSERT.C
│   │   ├── BUF.C
│   │   ├── CGETS.C
│   │   ├── CHANGES
│   │   ├── CHDIR.C
│   │   ├── CHMOD.C
│   │   ├── CLOSE.C
│   │   ├── CLOSEDIR.AS
│   │   ├── CPUTS.C
│   │   ├── CREAT.C
│   │   ├── DIRENT.H
│   │   ├── DOPRNT.C
│   │   ├── DOSCAN.C
│   │   ├── DUP.C
│   │   ├── ERRNO.C
│   │   ├── EXIT.AS
│   │   ├── FAKECPCL.AS
│   │   ├── FCLOSE.C
│   │   ├── FFLUSH.C
│   │   ├── FGETC.AS
│   │   ├── FILBUF.C
│   │   ├── FLSBUF.C
│   │   ├── FOPEN.C
│   │   ├── FPRINTF.C
│   │   ├── FREAD.C
│   │   ├── FREOPEN.C
│   │   ├── FSCANF.C
│   │   ├── FSEEK.C
│   │   ├── FWRITE.C
│   │   ├── GETARGS.C
│   │   ├── GETCWD.AS
│   │   ├── GETENV.AS
│   │   ├── GETS.C
│   │   ├── GETW.C
│   │   ├── ISATTY.C
│   │   ├── LIBDOS2.LIB
│   │   ├── LIBDOS2.TXT
│   │   ├── MAKEFILE
│   │   ├── MKDIR.C
│   │   ├── OPEN.C
│   │   ├── OPENDIR.AS
│   │   ├── PERROR.C
│   │   ├── PRINTF.C
│   │   ├── PUTCHAR.C
│   │   ├── PUTS.C
│   │   ├── READ.C
│   │   ├── READDIR.AS
│   │   ├── REMOVE.C
│   │   ├── RENAME.C
│   │   ├── REWIND.C
│   │   ├── REWNDDIR.AS
│   │   ├── RMDIR.C
│   │   ├── SCANF.C
│   │   ├── SEEK.C
│   │   ├── SETBUF.C
│   │   ├── SETENV.AS
│   │   ├── SPRINTF.C
│   │   ├── SSCANF.C
│   │   ├── START1.AS
│   │   ├── START2.AS
│   │   ├── STAT.C
│   │   ├── STAT.H
│   │   ├── STDCLEAN.C
│   │   ├── UNGETC.C
│   │   ├── UNIXIO.H
│   │   ├── UNLINK.C
│   │   ├── UTIME.C
│   │   └── WRITE.C
│   ├── libfix01/
│   │   ├── CONVTIME.C
│   │   ├── DOPRNT.C
│   │   ├── FBCD.OBJ
│   │   ├── FDOPRNT.C
│   │   ├── FIXES.TXT
│   │   ├── FRELOP.AS
│   │   ├── GETCH.AS
│   │   ├── INOUT.AS
│   │   ├── LIBC.LIB
│   │   ├── LIBF.LIB
│   │   ├── MAKEFILE
│   │   ├── MEMCHR.AS
│   │   ├── MEMCMP.AS
│   │   ├── MEMCPY.AS
│   │   ├── MEMMOVE.AS
│   │   ├── MEMSET.AS
│   │   ├── MSXTIME.AS
│   │   ├── PEEKPOKE.AS
│   │   ├── RCSV.AS
│   │   ├── SIGNAL.AS
│   │   ├── SLEEP.C
│   │   ├── STRCHR.AS
│   │   ├── STRDUP.C
│   │   ├── STRFTIME.C
│   │   ├── STRICMP.AS
│   │   ├── STRING.H
│   │   ├── STRISTR.C
│   │   ├── STRNICMP.AS
│   │   ├── STRNISTR.C
│   │   ├── STRNSTR.C
│   │   ├── STRRCHR.AS
│   │   ├── STRSTR.C
│   │   ├── STRTOK.C
│   │   ├── TIME.C
│   │   └── TIME.H
│   ├── make_004/
│   │   ├── FILE.C
│   │   ├── MACRO.C
│   │   ├── MAKE.C
│   │   ├── MAKE.COM
│   │   ├── MAKE.H
│   │   ├── MAKE.MAN
│   │   ├── MAKEFILE
│   │   ├── MSPAWN.C
│   │   ├── PARSEDIR.C
│   │   ├── PATH.C
│   │   ├── README
│   │   ├── TOKEN.C
│   │   ├── UTILS.C
│   │   ├── XARGS.C
│   │   └── XARGS.COM
│   └── original/
│       ├── CC.LZH
│       ├── CC_01.LZH
│       ├── LDOS2_03.LZH
│       ├── LDOS2_04.LZH
│       ├── LIBFIX01.LZH
│       ├── MAKE_003.LZH
│       └── MAKE_004.LZH
├── overlays/
│   ├── B280OVR.SUB
│   ├── BUILDOVR.SUB
│   ├── LIBOVR.LIB
│   ├── LIBOVR.SUB
│   ├── M280LIBV.SUB
│   ├── OVERLAY.H
│   ├── OVRBGN.AS
│   ├── OVREADME.TXT
│   ├── OVRLOAD.C
│   └── SYMTOAS.C
├── pipemgr/
│   ├── MKRSX.SUB
│   ├── PIPEMGR.ARC
│   ├── PIPEMGR.C
│   ├── PIPEMGR.DOC
│   ├── PIPEMGR.H
│   ├── PIPEMGR.LBR
│   ├── PIPEMGR.RSX
│   ├── PIPEMGR.TXT
│   ├── PIPEMGR.Z80
│   ├── TEE.C
│   └── TEE.COM
├── stdio/
│   ├── ASSERT.C
│   ├── BUF.C
│   ├── BUILDSTD.SUB
│   ├── C280LIBC.LOG
│   ├── C280LIBC.SUB
│   ├── CGETS.C
│   ├── COMPLIBC.LOG
│   ├── COMPLIBC.SUB
│   ├── CPUTS.C
│   ├── CTIME.C
│   ├── DOPRNT.C
│   ├── DOSCAN.C
│   ├── EXIT.C
│   ├── FAKECLEA.C
│   ├── FCLOSE.C
│   ├── FFLUSH.C
│   ├── FGETC.C
│   ├── FILBUF.C
│   ├── FLSBUF.C
│   ├── FOPEN.C
│   ├── FPRINTF.C
│   ├── FPUTC.C
│   ├── FREAD.C
│   ├── FREOPEN.C
│   ├── FSCANF.C
│   ├── FSEEK.C
│   ├── FWRITE.C
│   ├── GETARGS.C
│   ├── GETENV.C
│   ├── GETS.C
│   ├── GETW.C
│   ├── LISTMODC.SUB
│   ├── M280LIBC.LOG
│   ├── M280LIBC.SUB
│   ├── M280LIBV.SUB
│   ├── MAKEFILE
│   ├── MAKELIBC.LOG
│   ├── MAKELIBC.SUB
│   ├── PERROR.C
│   ├── PRINTF.C
│   ├── PUTCHAR.C
│   ├── PUTS.C
│   ├── PUTW.C
│   ├── RELIBCPM.SUB
│   ├── RELIBGEN.SUB
│   ├── RELIBSTD.SUB
│   ├── REMOVE.C
│   ├── REWIND.C
│   ├── SCANF.C
│   ├── SETBUF.C
│   ├── SPRINTF.C
│   ├── SSCANF.C
│   ├── STDCLEAN.C
│   ├── STDIO.I
│   └── UNGETC.C
├── test/
│   ├── TEST-OPT.AS
│   ├── TEST-OPT.AS2
│   ├── TEST-OPT.AS3
│   ├── TEST.LOG
│   ├── TEST.SUB
│   ├── TEST280.LOG
│   ├── TEST280.SUB
│   ├── TESTAES.C
│   ├── TESTARGS.C
│   ├── TESTBDOS.C
│   ├── TESTBIOS.C
│   ├── TESTFILE.C
│   ├── TESTFTIM.C
│   ├── TESTHELL.C
│   ├── TESTIO.C
│   ├── TESTOVR.C
│   ├── TESTOVR1.C
│   ├── TESTOVR2.C
│   ├── TESTPR.C
│   ├── TESTPWD.C
│   ├── TESTRC.C
│   ├── TESTREL.C
│   ├── TESTSTR.C
│   ├── TESTTRIG.C
│   ├── TESTUID.C
│   ├── TESTVER.C
│   ├── TESTVER.SUB
│   ├── TESTVIEW.C
│   └── TESTWILD.C
├── z280bin.lbr
└── z280dist/
    ├── C280-20.COM
    ├── C280CPM.OBJ
    ├── C280OPTS
    ├── C280ORIG.COM
    ├── D280CPM.OBJ
    ├── LIB280C.LIB
    ├── LIB280F.LIB
    ├── LIB280OV.LIB
    ├── N280CPM.OBJ
    ├── OPTIMH.C
    ├── OPTIMH.COM
    └── R280CPM.OBJ
Download .txt
SYMBOL INDEX (350 symbols across 117 files)

FILE: cpm/ABORT.C
  function abort (line 5) | void

FILE: cpm/C-ORIG.C
  type stat (line 121) | struct stat
  function put_cmd (line 383) | put_cmd(i)

FILE: cpm/C309-20.C
  type stat (line 207) | struct stat
  function main (line 236) | int main(int argc, char **argv)
  function setup (line 421) | void setup()
  function doit (line 458) | void doit()
  function rm (line 591) | void rm(int type, char *file)
  function print (line 606) | void print(char *s)
  function put_cmd (line 613) | void put_cmd(int i)
  function addobj (line 619) | void addobj(char *s, int p)
  function addlib (line 645) | void addlib(char *s)
  function error (line 656) | void error(char *s, char *a)
  function upcase (line 671) | void upcase(char *s)
  function doexec (line 681) | void doexec(char *name, char **vec)
  function assemble_sym (line 747) | void assemble_sym(char *s)
  function assemble (line 786) | void assemble(char *s)
  function optassemble (line 817) | void optassemble(char *s)
  function compile (line 866) | void compile(char *s)
  function sym2as (line 958) | int sym2as(char * fname)
  function viewfile (line 1014) | void viewfile(char *fn)

FILE: cpm/CHMOD.C
  type fcb (line 7) | struct fcb

FILE: cpm/CLEANUP.C
  type fcb (line 15) | struct fcb
  function _cpm_clean (line 22) | void _cpm_clean()
  function _putrno (line 32) | void _putrno(uchar *where, long rno)
  function _initrsx (line 39) | void _initrsx()

FILE: cpm/CLOSE.C
  function close (line 48) | int close(uchar fd)

FILE: cpm/CONVTIME.C
  type tod (line 13) | struct tod
  function time_t (line 27) | time_t

FILE: cpm/CREAT.C
  function creat (line 4) | int creat(char *name, int mode)

FILE: cpm/DUP.C
  type fcb (line 6) | struct fcb

FILE: cpm/FCBNAME.C
  type fcb (line 15) | struct fcb

FILE: cpm/GETFCB.C
  type fcb (line 32) | struct fcb
  type fcb (line 34) | struct fcb
  type fcb (line 36) | struct fcb
  type fcb (line 45) | struct fcb
  function putfcb (line 48) | void putfcb(struct fcb *fc)
  function uchar (line 53) | uchar setfcb(struct fcb *fc, char *name)
  function fc_parse (line 74) | static void fc_parse(struct fcb *fc, char *name)

FILE: cpm/ISATTY.C
  function isatty (line 3) | int isatty(uchar f)

FILE: cpm/MKTIME.C
  function time_t (line 14) | time_t mktime(struct tm *ptm){

FILE: cpm/OPEN.C
  function _fsize (line 11) | long _fsize(uchar fd)
  function open (line 45) | int open(char *name, int mode)

FILE: cpm/READ.C
  function read (line 9) | int read(uchar fd, char *buf, ushort nbytes)

FILE: cpm/RENAME.C
  function rename (line 3) | int rename(char *n1, char *n2)

FILE: cpm/SEEK.C
  function lseek (line 3) | long

FILE: cpm/SIGNAL.C
  function signal_t (line 6) | signal_t signal(int sig, signal_t action)
  function _sigchk (line 17) | void

FILE: cpm/STAT.C
  type tod (line 18) | struct tod
  function stat (line 27) | int stat(register char * s, register struct stat * b)

FILE: cpm/TIME.C
  type tod (line 8) | struct tod
  function time_t (line 18) | time_t time(time_t *tp)

FILE: cpm/UNLINK.C
  type fcb (line 5) | struct fcb

FILE: dist/CPM.H
  type fcb (line 30) | struct	fcb
  type fcb (line 50) | struct fcb
  type fcb (line 54) | struct fcb
  type fcb (line 55) | struct fcb
  type BIOSfns (line 172) | enum BIOSfns

FILE: dist/STAT.H
  type stat (line 4) | struct stat
  type stat (line 25) | struct stat

FILE: dist/STDIO.H
  type _iobuf (line 34) | struct	_iobuf

FILE: dist/TIME.H
  type time_t (line 8) | typedef	long	time_t;
  type tm (line 9) | struct tm {
  type tm (line 36) | struct tm
  type tm (line 38) | struct tm
  type tm (line 39) | struct tm
  type tm (line 40) | struct tm
  type tm (line 41) | struct tm

FILE: float/ACOS.C
  function acos (line 7) | double

FILE: float/ASIN.C
  function asin (line 7) | double

FILE: float/ATAN.C
  function atan (line 7) | double

FILE: float/ATAN2.C
  function atan2 (line 7) | double

FILE: float/ATOF.C
  function atof (line 3) | double

FILE: float/CEIL.C
  function ceil (line 6) | double

FILE: float/COS.C
  function cos (line 7) | double

FILE: float/COSH.C
  function cosh (line 4) | double

FILE: float/EVALPOLY.C
  function eval_poly (line 1) | double

FILE: float/EXP.C
  function exp (line 4) | double
  function pow (line 39) | double

FILE: float/FABS.C
  function fabs (line 1) | double

FILE: float/FLOOR.C
  function floor (line 5) | double

FILE: float/LOG.C
  function log (line 4) | double
  function log10 (line 33) | double

FILE: float/SIN.C
  function sin (line 7) | double

FILE: float/SINH.C
  function sinh (line 4) | double

FILE: float/SQRT.C
  function sqrt (line 3) | double

FILE: float/TAN.C
  function tan (line 3) | double

FILE: float/TANH.C
  function tanh (line 4) | double

FILE: gen/ATOL.C
  function atol (line 3) | long

FILE: gen/CTYPE.C
  function isdig (line 1) | isdig(c)

FILE: gen/MALLOC.C
  type store (line 32) | struct store
  type store (line 38) | struct store
  type store (line 39) | struct store
  type store (line 40) | struct store
  type store (line 41) | struct store
  type store (line 48) | struct store
  type store (line 51) | struct store
  type store (line 57) | struct store
  type store (line 57) | struct store
  type store (line 57) | struct store
  type store (line 67) | struct store
  type store (line 67) | struct store
  type store (line 80) | struct store
  type store (line 81) | struct store
  type store (line 82) | struct store
  type store (line 85) | struct store
  type store (line 95) | struct store
  type store (line 95) | struct store
  type store (line 101) | struct store
  type store (line 118) | struct store
  type store (line 120) | struct store
  type store (line 134) | struct store
  type store (line 138) | struct store
  type store (line 139) | struct store
  type store (line 139) | struct store
  type store (line 143) | struct store
  type store (line 148) | struct store
  type store (line 158) | struct store

FILE: gen/STRFTIME.C
  function strftime (line 119) | size_t strftime(char *s, size_t maxs, char *f, struct tm *t)
  function strfmt (line 288) | static void strfmt(char *str, char *fmt, ...)
  function main (line 329) | int main(int argc, char *argv[])

FILE: huff/DECODE.C
  function bld_tree (line 18) | void bld_tree(void) {
  function node (line 28) | node * get_tree(void) {
  function align (line 41) | void align(void) {
  function get_bit (line 46) | int get_bit(void) {
  function gethch (line 55) | int gethch(void) {

FILE: huff/DEHUF.C
  function main (line 29) | int main(int argc, char **	argv) {
  function isarg (line 99) | int isarg(char * s) {
  function list (line 133) | void list(short i) {
  function extract (line 153) | void extract(short i) {
  function prtree (line 183) | void prtree(register node * np) {

FILE: huff/DEHUFF.C
  function main (line 29) | int main(int argc, char **	argv) {
  function isarg (line 99) | int isarg(char * s) {
  function list (line 133) | void list(short i) {
  function extract (line 153) | void extract(short i) {
  function prtree (line 183) | void prtree(register node * np) {

FILE: huff/ENCODE.C
  type np (line 4) | typedef struct {
  function make_tree (line 40) | void make_tree(char ** namlist) {
  function node (line 103) | node * newnode(void) {
  function node (line 114) | node * bld(short first, short last) {
  function cmpr (line 152) | int cmpr(register chent ** p1, chent ** p2) {
  function cmpnp (line 166) | int cmpnp(np * p1, np * p2) {
  function bld_bits (line 174) | void bld_bits(register node * nodep, h_char tch) {
  function pinit (line 190) | void pinit(void) {
  function align (line 199) | void align(void) {
  function put_bit (line 209) | void put_bit(int i) {
  function puthch (line 223) | void puthch(uchar c) {
  function put_tchrs (line 242) | void put_tchrs(register node * tp) {
  function walk_tree (line 254) | void walk_tree(register node * tp) {
  function put_tree (line 267) | void put_tree(void) {

FILE: huff/ENHUFF.C
  function main (line 32) | int main(int argc, char ** argv) {
  function putnames (line 113) | void putnames(void) {
  function putfiles (line 130) | void putfiles(void) {
  function puthdr (line 150) | void puthdr(void) {
  function prtree (line 172) | void prtree(register node * np) {
  function prchars (line 193) | void prchars(void) {
  function putbch (line 218) | void putbch(h_char tch) {

FILE: huff/HUFF.H
  type node (line 29) | typedef struct node {
  type h_char (line 35) | typedef	struct {
  type chent (line 40) | typedef struct {
  type filent (line 46) | typedef	struct {
  type hdr (line 54) | typedef struct {

FILE: huff/MISC.C
  function casecmp (line 20) | int casecmp(register char * s1, char * s2) {
  function error (line 45) | void error(char *fmt, ...) {
  function put2 (line 74) | void put2(unsigned short i) {
  function put4 (line 83) | void put4(unsigned long i) {
  function get4 (line 91) | unsigned long get4(void) {
  function get2 (line 106) | unsigned short get2(void) {

FILE: msx2dist/cc_01/CC.C
  function main (line 157) | int
  function setup (line 309) | void
  function doit (line 349) | int
  function error (line 455) | void
  function doexec (line 488) | int
  function assemble (line 546) | int
  function compile (line 574) | int
  type frame (line 675) | typedef struct sf {
  function stack_trace (line 681) | void stack_trace()

FILE: msx2dist/ldos2_04/ASSERT.C
  function _fassert (line 4) | void

FILE: msx2dist/ldos2_04/CHDIR.C
  function chdir (line 7) | int chdir(char * pad)

FILE: msx2dist/ldos2_04/DIRENT.H
  type dirent (line 6) | struct dirent /* A dos2 file information block. */
  type _dir (line 19) | struct _dir {
  type DIR (line 24) | typedef struct _dir DIR;
  type dirent (line 27) | struct dirent

FILE: msx2dist/ldos2_04/FSEEK.C
  function ftell (line 13) | long

FILE: msx2dist/ldos2_04/GETARGS.C
  function nxtch (line 164) | static char
  function error (line 180) | static void
  function sputs (line 193) | static void
  function redirect (line 215) | static void
  function iswild (line 226) | static char
  function isspecial (line 233) | static char
  function isseparator (line 240) | static char

FILE: msx2dist/ldos2_04/PERROR.C
  function perror (line 15) | void perror(char * s)

FILE: msx2dist/ldos2_04/PUTCHAR.C
  function putchar (line 14) | putchar(c)

FILE: msx2dist/ldos2_04/STAT.C
  type fib (line 14) | struct fib /* MSX-DOS2 file info block */
  type tm (line 29) | struct tm
  function stat (line 31) | int
  function time_t (line 83) | static time_t seconds(struct tm * tp)

FILE: msx2dist/ldos2_04/STAT.H
  type stat (line 1) | struct stat
  type utimbuf (line 21) | struct utimbuf {
  type stat (line 26) | struct stat
  type utimbuf (line 27) | struct utimbuf

FILE: msx2dist/ldos2_04/STDCLEAN.C
  type _iobuf (line 6) | struct _iobuf

FILE: msx2dist/ldos2_04/UTIME.C
  function utime (line 11) | int utime(char * name, struct utimbuf *tb)

FILE: msx2dist/libfix01/CONVTIME.C
  function convtime (line 11) | long convtime(dostime,dosdate)

FILE: msx2dist/libfix01/SLEEP.C
  function sleep (line 8) | void sleep(seconds)

FILE: msx2dist/libfix01/STRFTIME.C
  function strftime (line 119) | size_t strftime(char *s, size_t maxs, char *f, struct tm *t)
  function strfmt (line 288) | static void strfmt(char *str, char *fmt, ...)
  function main (line 329) | int main(int argc, char *argv[])

FILE: msx2dist/libfix01/TIME.C
  function time_t (line 19) | time_t
  function time_t (line 30) | time_t timerset(value)
  function timeup (line 36) | int timeup(timer)

FILE: msx2dist/libfix01/TIME.H
  type time_t (line 8) | typedef	long	time_t;
  type tm (line 9) | struct tm {
  type tm (line 40) | struct tm
  type tm (line 42) | struct tm
  type tm (line 43) | struct tm
  type tm (line 47) | struct tm

FILE: msx2dist/make_004/FILE.C
  function FILENODE (line 17) | FILENODE *filenode(char *fname)
  function FILENODE (line 81) | FILENODE *gfile(char *fn)
  function FILENODE (line 96) | FILENODE *afnode(char *name)

FILE: msx2dist/make_004/MACRO.C
  function emacro (line 95) | static int emacro(char *name, char * dest)
  function defmac (line 162) | void defmac(char *name, char *def)
  function diffmac (line 209) | void diffmac(char *name, char *del)
  function catmac (line 248) | void catmac(char * name, char * suf)
  function undefmac (line 271) | int undefmac(char * name)

FILE: msx2dist/make_004/MAKE.C
  function opt_char (line 52) | static void opt_char(char c)
  function main (line 66) | int main(int argc, char** argv)

FILE: msx2dist/make_004/MAKE.H
  type node (line 26) | struct node {
  type NODE (line 30) | typedef struct node NODE;
  type filenode (line 33) | struct filenode {
  type FILENODE (line 41) | typedef struct filenode FILENODE;
  type macro (line 44) | struct macro {
  type MACRO (line 49) | typedef struct macro MACRO;

FILE: msx2dist/make_004/MSPAWN.C
  function mkfile (line 26) | int mkfile(char *s, char *fds, char **q)
  type env_sav (line 89) | struct env_sav {
  type env_sav (line 94) | struct env_sav
  function pop_env (line 99) | void pop_env()
  function redir (line 112) | int redir(char *p, char *fds)
  function spawnblock (line 179) | int spawnblock(char *blok)
  function do_set (line 238) | int do_set(char * line)
  function spawnline (line 267) | int spawnline(char *line, char *fds)

FILE: msx2dist/make_004/PARSEDIR.C
  type stat (line 6) | struct stat
  function getdate (line 13) | int getdate(FILENODE *f)
  function laterdt (line 32) | int laterdt(DATE date1, DATE date2)

FILE: msx2dist/make_004/PATH.C
  type stat (line 23) | struct stat

FILE: msx2dist/make_004/TOKEN.C
  function stripwh (line 71) | void stripwh(char **strpp)

FILE: msx2dist/make_004/UTILS.C
  function fmake (line 45) | int fmake(char * fn)
  function fparse (line 66) | void fparse(FILE *fp)
  function finish (line 140) | void finish(FILENODE * fnd)
  function match (line 215) | int match(char *buf, char *pat, char *name)
  function determ (line 260) | int determ()
  function examine (line 308) | int examine(FILENODE *fnd, DATE date)
  function recomp (line 363) | int recomp(FILENODE *f)

FILE: msx2dist/make_004/XARGS.C
  function print_help (line 27) | void print_help(FILE* fp)
  function parse (line 51) | int parse(int argc, char *argv[], char **name, char **prog, char **iniargs)
  function do_read (line 159) | int do_read(char * name, int fd, char* buf, unsigned blen)
  function do_once (line 184) | int do_once(char * prog, char * argbuf, char * fds)
  function do_xargs (line 198) | int do_xargs(char * input, int in, char * prog, char * iniargs)
  function main (line 263) | int main(int argc, char *argv[])

FILE: overlays/OVRLOAD.C
  function ovrload (line 11) | intptr_t ovrload(char *name,intptr_t args)

FILE: overlays/SYMTOAS.C
  function main (line 25) | int main(int argc, char ** argv) {
  function sym2as (line 43) | int sym2as(char * fname, char * tmpas) {

FILE: pipemgr/PIPEMGR.C
  function stdin_piped (line 24) | int stdin_piped(void)
  function init_args (line 32) | void init_args(int *argc, char ***argv)
  function safe_toupper (line 46) | char safe_toupper(char c)

FILE: pipemgr/TEE.C
  function main (line 27) | int main(int argc, char **argv)

FILE: stdio/ASSERT.C
  function _fassert (line 5) | void

FILE: stdio/BUF.C
  function _buffree (line 21) | void _buffree(char *pp)

FILE: stdio/CPUTS.C
  function cputs (line 3) | void cputs(s)

FILE: stdio/CTIME.C
  type tm (line 31) | struct tm
  type tm (line 41) | struct tm
  type tm (line 47) | struct tm

FILE: stdio/EXIT.C
  function exit (line 4) | exit(v)

FILE: stdio/FFLUSH.C
  function fflush (line 8) | int fflush(register FILE *f)

FILE: stdio/FSEEK.C
  function _ssize (line 6) | static long
  function ftell (line 85) | long

FILE: stdio/GETARGS.C
  type fcb (line 78) | struct fcb
  type fcb (line 157) | struct fcb
  function nxtch (line 206) | static char nxtch()
  function error (line 225) | static void error(char *s, ...)
  function sputs (line 236) | static void sputs(char *s)
  function redirect (line 255) | static void redirect(char *str_name, char *file_name, char *mode, FILE *...
  function iswild (line 263) | static char iswild(char *buf)
  function isspecial (line 268) | static char isspecial(char c)
  function isseparator (line 273) | static char isseparator(char c)

FILE: stdio/GETENV.C
  function loadenv (line 14) | static char loadenv(char *name, char **avec, char *abuf, short *i,

FILE: stdio/PERROR.C
  function ps (line 7) | static void ps(char *s)
  function perror (line 13) | void perror(char *s)

FILE: stdio/PUTCHAR.C
  function putchar (line 14) | putchar(c)

FILE: stdio/SETBUF.C
  function setbuf (line 7) | void setbuf(f, c)

FILE: stdio/STDCLEAN.C
  type _iobuf (line 6) | struct _iobuf

FILE: test/TESTAES.C
  type aes256_context (line 26) | typedef struct {
  type aes256_context (line 33) | typedef aes256_context * aes256_ptr;
  function gf_alog (line 116) | uint8_t gf_alog(x) /* calculate anti-logarithm gen 3 */
  function gf_log (line 127) | uint8_t gf_log(x) /* calculate logarithm gen 3 */
  function gf_mulinv (line 142) | uint8_t gf_mulinv(x) /* calculate multiplicative inverse */
  function rj_sbox (line 149) | uint8_t rj_sbox(x)
  function rj_sb_inv (line 162) | uint8_t rj_sb_inv(x)
  function rj_xtime (line 177) | uint8_t rj_xtime(x)
  function aes_subBytes (line 184) | void aes_subBytes(buf)
  function aes_sb_inv (line 193) | void aes_sb_inv(buf)
  function aes_addRoundKey (line 202) | void aes_addRoundKey(buf,key)
  function aes_ar_cpy (line 211) | void aes_ar_cpy(buf,key,cpk)
  function aes_shiftRows (line 221) | void aes_shiftRows(buf)
  function aes_sr_inv (line 234) | void aes_sr_inv(buf)
  function aes_mixColumns (line 247) | void aes_mixColumns(buf)
  function aes_mc_inv (line 262) | void aes_mc_inv(buf)
  function aes_expandEncKey (line 279) | void aes_expandEncKey(k,rc)
  function aes_expDecKey (line 303) | void aes_expDecKey(k, rc)
  function aes256_init (line 328) | void aes256_init(ctx, k)
  function aes_done (line 340) | void aes_done(ctx)
  function aes256_encrypt_ecb (line 350) | void aes256_encrypt_ecb(ctx, buf)
  function aes256_decrypt_ecb (line 372) | void aes256_decrypt_ecb(ctx, buf)
  function main (line 406) | int main (int argc, char *argv[])

FILE: test/TESTARGS.C
  function main (line 4) | int main(int argc, char ** argv) {

FILE: test/TESTBDOS.C
  function test (line 12) | void test(short func, void *data)
  function vogon (line 23) | void vogon(char *fn)	/* Just for the debugger */
  function main (line 37) | int main(int argc, char *argv[])

FILE: test/TESTBIOS.C
  function main (line 16) | int main(int argc, char *argv[], char *z3env)

FILE: test/TESTFILE.C
  function main (line 5) | int main() {

FILE: test/TESTFTIM.C
  function main (line 7) | int main(int argc, char *argv[])

FILE: test/TESTHELL.C
  function main (line 3) | int main() {

FILE: test/TESTIO.C
  function main (line 5) | int main(int argc, char ** argv)

FILE: test/TESTOVR.C
  function main (line 5) | int main(int argc, char ** argv)

FILE: test/TESTPWD.C
  type fcb (line 6) | struct fcb
  type fcb (line 10) | struct fcb
  function main (line 31) | int main(int argc, char *argv[])

FILE: test/TESTRC.C
  function main (line 8) | int main(int argc, char ** argv)

FILE: test/TESTREL.C
  function main (line 3) | int main() {

FILE: test/TESTSTR.C
  function main (line 14) | int main() {

FILE: test/TESTTRIG.C
  function main (line 78) | int main() {

FILE: test/TESTUID.C
  function main (line 8) | int main(int argc, char ** argv)

FILE: test/TESTVER.C
  function main (line 8) | int main(int argc, char ** argv)

FILE: test/TESTVIEW.C
  function main (line 19) | int main(int argc, char *argv[])
  function view (line 31) | void view(char *fn)

FILE: test/TESTWILD.C
  function main (line 15) | int main(int argc, char *argv[])

FILE: z280dist/OPTIMH.C
  function instr (line 157) | int instr(char *t, char *s) {
  function copyn (line 168) | void copyn(char *a, char *b, int p, int i) {
  function csv (line 178) | void csv(char *str1,char *bytes) {
  function cret (line 189) | void cret(char *str1) {
  function mult (line 200) | void mult(char *str1, char *str2,char *bytes) {
  function ldw1 (line 211) | void ldw1(char *str1, char *byte1) {  /* ldw  (hl),xx */
  function ldw2 (line 233) | void ldw2(char *str1, char *byte1) {  /* ldw  xx,(hl) */
  function ldw3 (line 255) | void ldw3(char *str1, char *str2, char *byte1) {  /* ldw xx,(yy+ofs) */
  function ldw4 (line 276) | void ldw4(char *str1, char *str2, char *byte1) {  /* ldw  (xx+ofs),yy */
  function pushix (line 297) | void pushix(void) {
  function pushiy (line 307) | void pushiy(void) {
  function subwhl (line 317) | void subwhl(char *str1, char *byte1) {
  function label (line 334) | void label(void) {
  function check (line 357) | void check(void) {
Condensed preview — 518 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,437K chars).
[
  {
    "path": ".gitattributes",
    "chars": 657,
    "preview": "# Default is to keep crlf line endings\ntext=auto\n\nREADME.md text eol=crlf\nLICENSE text eol=crlf\nMAKEFILE text eol=crlf\n*"
  },
  {
    "path": ".gitignore",
    "chars": 23,
    "preview": "**/.*.swp\n**/.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "chars": 498,
    "preview": "The HI-TECH Z80 CP/M C compiler V3.09 is provided free of charge for\r\nany use, private or commercial, strictly as-is.  N"
  },
  {
    "path": "README.md",
    "chars": 71663,
    "preview": "# HI-TECH Z80 C Compiler for CP/M\r\n\r\n## Introduction\r\n\r\nThis repository contains the HI-TECH C Compiler for Z80 v3.09 al"
  },
  {
    "path": "cpm/ABORT.C",
    "chars": 138,
    "preview": "#include <cpm.h>\r\n\r\nstatic char\tmess[] = \"Fatal error - program aborted\\r\\n$\";\r\n\r\nvoid\r\nabort()\r\n{\r\n\tbdos(CPMWCOB, mess)"
  },
  {
    "path": "cpm/BDOS.AS",
    "chars": 8592,
    "preview": ";-----------------------------------------------------------------------------\r\n;\r\n; All BDOS calls on all versions of C"
  },
  {
    "path": "cpm/BIOS.AS",
    "chars": 8034,
    "preview": ";------------------------------------------------------------------------------\r\n;\r\n; Modified bios() function for Hi-Te"
  },
  {
    "path": "cpm/BUILD-C.LOG",
    "chars": 5337,
    "preview": "\r\n10E>;\r\n10E>date\r\nA:DATE     COM  (User 0)\r\n\rFri 05/09/2025 13:20:24\r\n10E>;\r\n10E>; Build Z80 version\r\n10E>c -o -v c309-"
  },
  {
    "path": "cpm/BUILD-C.SUB",
    "chars": 856,
    "preview": "era build-c.log\r\nput console output to file build-c.log [system]\r\n;\r\ndate\r\n;\r\n; Build Z80 version\r\nc -o -v c309-20.c\r\n;\r"
  },
  {
    "path": "cpm/BUILDCPM.SUB",
    "chars": 323,
    "preview": "c\r\n<-c -o start1.as open.c read.c write.c chmod.c seek.c \\\r\n<fcbname.c rename.c creat.c time.c convtime.c timezone.c \\\r\n"
  },
  {
    "path": "cpm/BUILDCRT.SUB",
    "chars": 149,
    "preview": ";\r\n; Build the start-up modules\r\n;\r\nc -c -o zcrtcpm.as zdrtcpm.as zrrtcpm.as znrtcpm.as\r\nc280 -c -o zc280cpm.as zd280cpm"
  },
  {
    "path": "cpm/C-ORIG.C",
    "chars": 12361,
    "preview": "/*\r\n *\tCopyright (C) 1984-1897 HI-TECH SOFTWARE\r\n *\r\n *\tThis software remains the property of HI-TECH SOFTWARE and is\r\n "
  },
  {
    "path": "cpm/C309-20.C",
    "chars": 25525,
    "preview": "/*\r\n *  Copyright (C) 1984-1987 HI-TECH SOFTWARE\r\n *\r\n *  This software remains the property of HI-TECH SOFTWARE and is\r"
  },
  {
    "path": "cpm/CHMOD.C",
    "chars": 436,
    "preview": "#include\t<cpm.h>\r\n#include\t<stat.h>\r\n\r\nchmod(name, mode)\r\nregister char *\tname;\r\n{\r\n\tstruct fcb \tfc;\r\n\tregister short\tlu"
  },
  {
    "path": "cpm/CLEANUP.C",
    "chars": 892,
    "preview": "#include\t\"cpm.h\"\r\n\r\n#define\tFILL\t0, \"        \", \"   \", 0, {0}, 0, {0}, 0, {0}, 0\r\n\r\n/*\r\n\r\n   Default stdin, stdout and s"
  },
  {
    "path": "cpm/CLOSE.C",
    "chars": 2324,
    "preview": "#include    <cpm.h>\r\n#include    <stdlib.h>\r\n#include    <ctype.h>\r\n/*\r\n    This is a modified version of close.c to sup"
  },
  {
    "path": "cpm/CONVTIME.C",
    "chars": 859,
    "preview": "\r\n#include\t<time.h>\r\n\r\n/*\r\n *\tThis routine converts the date and time in CP/M-86 format\r\n *\tto Unix style date and time "
  },
  {
    "path": "cpm/CREAT.C",
    "chars": 708,
    "preview": "#include    <cpm.h>\r\n#include    <unixio.h>\r\n\r\nint creat(char *name, int mode)\r\n{\r\n    register struct fcb *   fc;\r\n    "
  },
  {
    "path": "cpm/CSV.AS",
    "chars": 491,
    "preview": "; CSV.AS\tModified version from Tesseract vol 91\r\n;\r\n\tglobal\tcsv,cret,indir, ncsv\r\n\tpsect\ttext\r\ncsv:\tpop\thl\t\t;return addr"
  },
  {
    "path": "cpm/DUP.C",
    "chars": 173,
    "preview": "#include\t\"cpm.h\"\r\n\r\ndup(fd)\r\nuchar\tfd;\r\n{\r\n\tregister struct fcb *\tfp;\r\n\r\n\tif(_fcb[fd].use && (fp = getfcb())) {\r\n\t\t*fp ="
  },
  {
    "path": "cpm/EXEC-BLD.SUB",
    "chars": 155,
    "preview": "; Build $$EXEC.COM from source\r\nera exec.com\r\nzas -j exec.as\r\nlinq\r\n<-l -ptext=0,bss exec.obj\r\nobjtohex -R -b100h l.obj "
  },
  {
    "path": "cpm/EXEC.AS",
    "chars": 7908,
    "preview": "*Title\tIndirect command execution\r\n*Head\tDescription\r\n\r\n;\tCopyright (C) 1984 HI-TECH SOFTWARE\r\n\r\n;This is the indirect c"
  },
  {
    "path": "cpm/EXECL.AS",
    "chars": 4834,
    "preview": ";\tEXECV(), EXECL() - hand crafted from the C\r\n\r\n;\t#include\t<cpm.h>\r\n;\t\r\n;\t#define\tsetuid(x)\tbdos(CPMSUID, x)\r\n;\t#define\t"
  },
  {
    "path": "cpm/EXIT.AS",
    "chars": 596,
    "preview": "\tglobal\t_exit, __cpm_clean\r\n\r\nBDOS\tequ\t00005h\r\nCPMVERS\tequ\t12\r\nCPMRCOD\tequ\t108\t\t; CP/M+ Get/Set Error Return Code \r\n\r\n\tp"
  },
  {
    "path": "cpm/FAKECLEA.AS",
    "chars": 52,
    "preview": "\tglobal\t__cleanup\r\n\r\n\tpsect\ttext\r\n__cleanup:\r\n\tret\r\n"
  },
  {
    "path": "cpm/FAKECPCL.AS",
    "chars": 56,
    "preview": "\tglobal\t__cpm_clean\r\n\r\n\tpsect\ttext\r\n__cpm_clean:\r\n\tret\r\n"
  },
  {
    "path": "cpm/FCBNAME.C",
    "chars": 1391,
    "preview": "#include    <cpm.h>\r\n#include    <string.h>\r\n\r\n/*\r\n *  char *  fcbname(i);\r\n *  short   i;\r\n *\r\n *  Returns a character "
  },
  {
    "path": "cpm/GETCH.C",
    "chars": 514,
    "preview": "#include\t<cpm.h>\r\n\r\nstatic short\tpushback;\r\n\r\ngetch()\r\n{\r\n\tshort\tc;\r\n\r\n\tif(c = pushback) {\r\n\t\tpushback = 0;\r\n\t\treturn c;"
  },
  {
    "path": "cpm/GETFCB.C",
    "chars": 2648,
    "preview": "#include    <cpm.h>\r\n#include    <ctype.h>\r\n#include    <sys.h>\r\n\r\n/*\r\n *  Syntax of CP/M file names is:\r\n *\r\n *  [[0-9]"
  },
  {
    "path": "cpm/GETUID.AS",
    "chars": 387,
    "preview": ";\tSet/get uid for CP/M\r\n\r\n\tglobal\t_getuid, _setuid, csv, cret\r\n\r\n\tentry\tequ\t5\t\t;CP/M system call entry\r\n\tsguid\tequ\t32\t\t;"
  },
  {
    "path": "cpm/ISATTY.C",
    "chars": 225,
    "preview": "#include    \"cpm.h\"\r\n\r\nint isatty(uchar f)\r\n{\r\n    switch(_fcb[f].use)\r\n    {\r\n    case U_CON:\r\n    case U_RDR:\r\n    cas"
  },
  {
    "path": "cpm/MAKEFILE",
    "chars": 1697,
    "preview": ".SUFFIXES:\t.c .obj .as .lib\r\n\r\nBIN\t= /usr/hitech/bin\r\nLIB\t= ../lib\r\nPACK\t= ../pack\r\nLIBR\t= $(BIN)/libr\r\nAS\t= $(BIN)/zas\r"
  },
  {
    "path": "cpm/MKTIME.C",
    "chars": 1256,
    "preview": "/* Convert structure to time value */\r\n\r\n#include <time.h>\r\n\r\n/* leap year calculator expects year argument as years off"
  },
  {
    "path": "cpm/OPEN.C",
    "chars": 1966,
    "preview": "#include    \"cpm.h\"\r\n\r\nextern int errno;\r\n\r\nextern char _exact;  /* Exact file size hint for last sector\r\n\t\t\t'C' = not u"
  },
  {
    "path": "cpm/READ.C",
    "chars": 2972,
    "preview": "#include    \"cpm.h\"\r\n\r\nextern char _piped; /* PIPEMGR loaded? */\r\n\r\n#define CPMEOF 0x1A         /* Control-Z */\r\n\r\nstati"
  },
  {
    "path": "cpm/RELIBCPM.SUB",
    "chars": 380,
    "preview": "libr \r\n<r libc3.lib \\\r\n<start1.obj open.obj read.obj write.obj chmod.obj seek.obj \\\r\n<fcbname.obj rename.obj creat.obj t"
  },
  {
    "path": "cpm/RENAME.C",
    "chars": 256,
    "preview": "#include    \"cpm.h\"\r\n\r\nint rename(char *n1, char *n2)\r\n{\r\n    struct fcb  fc[2];\r\n\r\n    unlink(n2);\r\n    if (!(setfcb(&f"
  },
  {
    "path": "cpm/SEEK.C",
    "chars": 473,
    "preview": "#include\t\"cpm.h\"\r\n\r\nlong\r\nlseek(fd, offs, whence)\r\nuchar\tfd, whence;\r\nlong\toffs;\r\n{\r\n\tregister struct fcb *\tfc;\r\n\tlong\t\t"
  },
  {
    "path": "cpm/SIGNAL.C",
    "chars": 432,
    "preview": "#include\t\"cpm.h\"\r\n#include\t<signal.h>\r\n\r\nstatic signal_t where;\r\n\r\nsignal_t signal(int sig, signal_t action) \r\n{\r\n\tsigna"
  },
  {
    "path": "cpm/SRAND.AS",
    "chars": 120,
    "preview": "\tpsect\ttext\r\n\tglobal\t_randomiz, _srand\r\n\r\n_randomiz:\r\n\tld\ta,r\r\n\tld\tl,a\r\n\tld\th,0\r\n\tpush\thl\r\n\tcall\t_srand\r\n\tpop\thl\r\n\tret\r\n"
  },
  {
    "path": "cpm/SRAND1.C",
    "chars": 127,
    "preview": "#include <conio.h>\r\n\r\nsrand1(s)\r\nchar *\ts;\r\n{\r\n\tint\ti;\r\n\twhile(*s)\r\n\t\tputchar(*s++);\r\n\twhile(!kbhit())\r\n\t\ti++;\r\n\tsrand(i"
  },
  {
    "path": "cpm/START1.AS",
    "chars": 110,
    "preview": "\tpsect\ttext\r\n\tglobal\t__getargs, startup, __argc_\r\n\r\nstartup:\r\n\tjp\t__getargs\r\n\r\n\tpsect\tbss\r\n__argc_:\r\n\tdefs\t2\r\n"
  },
  {
    "path": "cpm/START2.AS",
    "chars": 832,
    "preview": "\tglobal\t__getargs, __argc_\r\n\tpsect\ttext\r\n\r\n__getargs:\r\n\tpop\thl\t\t;return address\r\n\texx\r\n\tpop\thl\r\n\tpop\thl\t\t;unjunk stack\r\n"
  },
  {
    "path": "cpm/STAT.C",
    "chars": 2363,
    "preview": "#include    <stat.h>\r\n#include    <cpm.h>\r\n#include    <time.h>\r\n\r\nextern char _exact;  /* Exact file size hint for last"
  },
  {
    "path": "cpm/SYS_ERR.C",
    "chars": 1186,
    "preview": "short   errno;\r\n\r\nstatic char uerr[]=\"Unknown error\";\r\n\r\nchar *  sys_err[] =\r\n{\r\n    uerr,                           /* "
  },
  {
    "path": "cpm/TIME.C",
    "chars": 459,
    "preview": "/*\r\n *  time() for CP/M-86 type machines\r\n */\r\n\r\n#include    <cpm.h>\r\n#include    <time.h>\r\n\r\nstruct tod\r\n{\r\n    short  "
  },
  {
    "path": "cpm/TIMEZONE.C",
    "chars": 41,
    "preview": "#include\t<time.h>\r\n\r\nint\ttime_zone = 0;\r\n"
  },
  {
    "path": "cpm/UNLINK.C",
    "chars": 373,
    "preview": "#include    \"cpm.h\"\r\n\r\nunlink(char *name)\r\n{\r\n    struct fcb  fc;\r\n    uchar       luid;\r\n    short       retval;\r\n\r\n   "
  },
  {
    "path": "cpm/WRITE.C",
    "chars": 2389,
    "preview": "#include    \"cpm.h\"\r\n\r\nextern char _piped; /* PIPEMGR loaded? */\r\n\r\nwrite(uchar fd, char *buf, ushort nbytes)\r\n{\r\n    re"
  },
  {
    "path": "cpm/ZC280CPM.AS",
    "chars": 3584,
    "preview": "; This is ZCRTCPM for the Z280 MPU\r\n;\r\n\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,global\r\n\r\n\tpsect\ttext\r\n\td"
  },
  {
    "path": "cpm/ZCRTCPM.AS",
    "chars": 3426,
    "preview": "\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,global\r\n\r\n\tpsect\ttext\r\n\tdefs\t100h\t\t;Base of CP/M's TPA\r\n\r\n\tgloba"
  },
  {
    "path": "cpm/ZD280CPM.AS",
    "chars": 1211,
    "preview": "; This is ZDRTCPM for the Z280 MPU\r\n;\r\n\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,global\r\n\r\n\tpsect\ttext\r\n\td"
  },
  {
    "path": "cpm/ZDRTCPM.AS",
    "chars": 1173,
    "preview": "\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,global\r\n\r\n\tpsect\ttext\r\n\tdefs\t100h\t\t;Base of CP/M's TPA\r\n\tglobal\t"
  },
  {
    "path": "cpm/ZN280CPM.AS",
    "chars": 4532,
    "preview": "; This is ZNRTCPM for the Z280 MPU (with minimal getargs)\r\n;\r\n\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,gl"
  },
  {
    "path": "cpm/ZNRTCPM.AS",
    "chars": 4355,
    "preview": "; This is ZNRTCPM for the Z80 (with minimal getargs)\r\n\r\n\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,global\r\n"
  },
  {
    "path": "cpm/ZR280CPM.AS",
    "chars": 4874,
    "preview": "; This is ZRRTCPM for the Z280 MPU\r\n;\r\n\r\n;\tSelf relocating startup for CP/M\r\n\r\n\tpsect\tcpm,global\r\n\tpsect\ttext,global,pur"
  },
  {
    "path": "cpm/ZRRTCPM.AS",
    "chars": 4591,
    "preview": ";\tSelf relocating startup for CP/M\r\n\r\n\tpsect\tcpm,global\r\n\tpsect\ttext,global,pure\r\n\tpsect\tdata,global\r\n\tpsect\tbss,global\r"
  },
  {
    "path": "cpm/_EXIT.AS",
    "chars": 737,
    "preview": "EXITSTS\tequ\t80h\t\t;where to store exit status [CP/M 2]\r\n\r\nBDOS\tequ\t00005h\r\n\r\nCPMVERS\tequ\t12\t\t; Get CP/M Version number\r\nC"
  },
  {
    "path": "dist/ASSERT.H",
    "chars": 521,
    "preview": "#ifndef _HTC_ASSERT_H\r\n#define _HTC_ASSERT_H\r\n\r\n/*\r\n *\tAssertion - use liberally for debugging. Defining NDEBUG\r\n *\tturn"
  },
  {
    "path": "dist/CONIO.H",
    "chars": 620,
    "preview": "#ifndef _HTC_CONIO_H\r\n#define _HTC_CONIO_H\r\n\r\n/*\r\n *\tLow-level console I/O functions\r\n */\r\n\r\n#ifndef\t_STDDEF\r\ntypedef\tin"
  },
  {
    "path": "dist/CPM.H",
    "chars": 7365,
    "preview": "#ifndef _HTC_CPM_H\r\n#define _HTC_CPM_H\r\n\r\n/* Header file for CP/M routines for Z-80 C */\r\n\r\n/* get basic definitions */\r"
  },
  {
    "path": "dist/CTYPE.H",
    "chars": 1229,
    "preview": "#ifndef _HTC_CTYPE_H\r\n#define _HTC_CTYPE_H\r\n\r\n#define\t_U\t0x01\r\n#define\t_L\t0x02\r\n#define\t_N\t0x04\r\n#define\t_S\t0x08\r\n#defin"
  },
  {
    "path": "dist/EXEC.H",
    "chars": 351,
    "preview": "#ifndef _HTC_EXEC_H\r\n#define _HTC_EXEC_H\r\n\r\n/*\r\n *\tDefinitions of the EXEC format\r\n */\r\n\r\n#define\tEXITIT\t0x80\r\n#define\tE"
  },
  {
    "path": "dist/FLOAT.H",
    "chars": 2166,
    "preview": "#ifndef _HTC_FLOAT_H\r\n#define _HTC_FLOAT_H\r\n\r\n/*\tCharacteristics of floating types */\r\n\r\n#define\tDBL_RADIX\t2\t\t/* radix o"
  },
  {
    "path": "dist/HITECH.H",
    "chars": 2075,
    "preview": "#ifndef _HTC_HITECH_H\r\n#define _HTC_HITECH_H\r\n\r\n/*\tStandard types for HI-TECH Software code\r\n\tThese types may need to be"
  },
  {
    "path": "dist/LIMITS.H",
    "chars": 763,
    "preview": "#ifndef _HTC_LIMITS_H\r\n#define _HTC_LIMITS_H\r\n\r\n/*\tCharacteristics of integral types */\r\n\r\n#define\tCHAR_BIT\t8\t\t/* bits p"
  },
  {
    "path": "dist/MATH.H",
    "chars": 504,
    "preview": "#ifndef _HTC_MATH_H\r\n#define _HTC_MATH_H\r\n\r\nextern double fabs(double), floor(double), ceil(double), modf(double, double"
  },
  {
    "path": "dist/OPTIONS",
    "chars": 999,
    "preview": "HI-TECH Z80 CP/M C compiler options:\r\n\r\n-A\tGenerate a self-relocating .COM program.\r\n-C\tGenerate object code only; don't"
  },
  {
    "path": "dist/OVERLAY.H",
    "chars": 128,
    "preview": "#ifndef _HTC_OVERLAY_H\r\n#define _HTC_OVERLAY_H\r\n\r\n#include <stdint.h>\r\nintptr_t ovrload(char *ovr_name,intptr_t args);\r\n"
  },
  {
    "path": "dist/SETJMP.H",
    "chars": 306,
    "preview": "#ifndef _HTC_SETJMP_H\r\n#define _HTC_SETJMP_H\r\n\r\n#if\tz80\r\ntypedef\tint\tjmp_buf[4];\r\n#endif\r\n\r\n#if\ti8086\r\ntypedef\tint\tjmp_b"
  },
  {
    "path": "dist/SIGNAL.H",
    "chars": 1153,
    "preview": "#ifndef _HTC_SIGNAL_H\r\n#define _HTC_SIGNAL_H\r\n\r\n/*\r\n *\tSignal definitions for CP/M\r\n */\r\n#ifdef\tunix\r\n#define NSIG 17\r\n#"
  },
  {
    "path": "dist/STAT.H",
    "chars": 730,
    "preview": "#ifndef _HTC_STAT_H\r\n#define _HTC_STAT_H\r\n\r\nstruct stat\r\n{\r\n\tshort\tst_mode;\t/* flags */\r\n\tlong\tst_atime;\t/* access time "
  },
  {
    "path": "dist/STDARG.H",
    "chars": 272,
    "preview": "#ifndef _HTC_STDARG_H\r\n#define _HTC_STDARG_H\r\n\r\n/*\tMacros for accessing variable arguments */\r\n\r\ntypedef void *\tva_list["
  },
  {
    "path": "dist/STDDEF.H",
    "chars": 385,
    "preview": "#ifndef _HTC_STDDEF_H\r\n#define _HTC_STDDEF_H\r\n\r\n#ifndef\t_STDDEF\r\ntypedef\tint\t\tptrdiff_t;\t/* result type of pointer diffe"
  },
  {
    "path": "dist/STDINT.H",
    "chars": 297,
    "preview": "#ifndef _HTC_STDINT_H\r\n#define _HTC_STDINT_H\r\n\r\n#if z80||i8086||i8096||m68k\r\ntypedef unsigned char uint8_t;\r\ntypedef cha"
  },
  {
    "path": "dist/STDIO.H",
    "chars": 3604,
    "preview": "#ifndef _HTC_STDIO_H\r\n#define _HTC_STDIO_H\r\n\r\n/*\r\n * STDIO.H\tHI-TECH C standard I/O for V3.09-xx\r\n *\r\n *\t\tThis version i"
  },
  {
    "path": "dist/STDLIB.H",
    "chars": 1067,
    "preview": "#ifndef _HTC_STDLIB_H\r\n#define _HTC_STDLIB_H\r\n\r\n/*\tStandard utility functions */\r\n\r\n#ifndef\t_STDDEF\r\ntypedef\tint\t\tptrdif"
  },
  {
    "path": "dist/STRING.H",
    "chars": 1836,
    "preview": "#ifndef _HTC_STRING_H\r\n#define _HTC_STRING_H\r\n\r\n/*\tString functions v3.09-4 */\r\n\r\n#ifndef\t_STDDEF\r\ntypedef\tint\t\tptrdiff_"
  },
  {
    "path": "dist/SYS.H",
    "chars": 1004,
    "preview": "#ifndef _HTC_SYS_H\r\n#define _HTC_SYS_H\r\n\r\n/*\r\n *\tSystem-dependent functions.\r\n */\r\n\r\n#ifndef\t_STDDEF\r\ntypedef\tint\t\tptrdi"
  },
  {
    "path": "dist/TIME.H",
    "chars": 1267,
    "preview": "#ifndef _HTC_TIME_H\r\n#define _HTC_TIME_H\r\n\r\n/* time.h for HI-TECH C Z80 v3.09-4*/\r\n\r\n#ifndef\t_HTC_TIME_T\r\n\r\ntypedef\tlong"
  },
  {
    "path": "dist/UNIXIO.H",
    "chars": 794,
    "preview": "#ifndef _HTC_UNIXIO_H\r\n#define _HTC_UNIXIO_H\r\n\r\n/*\r\n *\tDeclarations for Unix style low-level I/O functions.\r\n */\r\n\r\n#ifn"
  },
  {
    "path": "doc/DEBUGMAN.TXT",
    "chars": 12767,
    "preview": "\r\n\r\n\r\n\r\n\r\n       1. Debugger Reference Manual\r\n\r\n\r\n            HI-TECH C is supplied  with  an  interactive  debugging\r\n"
  },
  {
    "path": "doc/HTCZ80.TXT",
    "chars": 298752,
    "preview": "\r\n       HI-TECH C USER'S MANUAL                                    i\r\n\r\n       CONTENTS\r\n\r\n\r\n\r\n       1. Introduction  "
  },
  {
    "path": "doc/OBJCODE.TXT",
    "chars": 13249,
    "preview": "\r\nHI-TECH Software\r\nObject Code Format\r\n\r\n1.  Introduction\r\n\r\n\tThis describes the format of the object code recognized b"
  },
  {
    "path": "doc/SYMFILE.TXT",
    "chars": 6396,
    "preview": "HI-TECH C\r\n\r\nSymbol File Format\r\n\r\nIntroduction\r\n\r\nThe symbol files produced by the HI-TECH linker using the -h option a"
  },
  {
    "path": "float/ACOS.C",
    "chars": 182,
    "preview": "#include\t<math.h>\r\n\r\n#define\tPI\t3.14159265358979\r\n#define\tTWO_PI\t6.28318530717958\r\n#define\tHALF_PI\t1.570796326794895\r\n\r\n"
  },
  {
    "path": "float/ASFLOAT.AS",
    "chars": 336,
    "preview": "\tglobal\tasfladd, asflsub, asflmul, asfldiv\r\n\tglobal\tfladd, flsub, flmul, fldiv\r\n\tglobal \tiregset, iregstore\r\n\tpsect\ttext"
  },
  {
    "path": "float/ASIN.C",
    "chars": 376,
    "preview": "#include\t<math.h>\r\n\r\n#define\tPI\t3.14159265358979\r\n#define\tTWO_PI\t6.28318530717958\r\n#define\tHALF_PI\t1.570796326794895\r\n\r\n"
  },
  {
    "path": "float/ATAN.C",
    "chars": 834,
    "preview": "#include\t<math.h>\r\n\r\n#define\tPI\t3.14159265358979\r\n#define\tTWO_PI\t6.28318530717958\r\n#define\tHALF_PI\t1.570796326794895\r\n\r\n"
  },
  {
    "path": "float/ATAN2.C",
    "chars": 391,
    "preview": "#include\t<math.h>\r\n\r\n#define\tPI\t3.14159265358979\r\n#define\tTWO_PI\t6.28318530717958\r\n#define\tHALF_PI\t1.570796326794895\r\n\r\n"
  },
  {
    "path": "float/ATOF.C",
    "chars": 792,
    "preview": "#include\t<ctype.h>\r\n\r\ndouble\r\natof(s)\r\nregister char *\ts;\r\n{\r\n\tchar\tsign;\r\n\tdouble\tl;\r\n\tshort\texp;\r\n\tshort\teexp;\r\n\tchar\t"
  },
  {
    "path": "float/CEIL.C",
    "chars": 162,
    "preview": "\r\n#include\t<math.h>\r\n\r\nextern double\t_frndint();\r\n\r\ndouble\r\nceil(x)\r\ndouble\tx;\r\n{\r\n\tdouble\ti;\r\n\r\n\ti = _frndint(x);\r\n\tif("
  },
  {
    "path": "float/COS.C",
    "chars": 278,
    "preview": "#include\t<math.h>\r\n\r\n#define\tPI\t3.14159265358979\r\n#define\tTWO_PI\t6.28318530717958\r\n#define\tHALF_PI\t1.570796326794895\r\n\r\n"
  },
  {
    "path": "float/COSH.C",
    "chars": 95,
    "preview": "\r\n#include\t<math.h>\r\n\r\ndouble\r\ncosh(x)\r\ndouble\tx;\r\n{\r\n\tx = exp(x);\r\n\treturn 0.5*(x+1.0/x);\r\n}\r\n"
  },
  {
    "path": "float/DOPRNT.C",
    "chars": 2643,
    "preview": "#include\t<stdio.h>\r\n#include\t<ctype.h>\r\n\r\n\r\n/*\r\n *\tdoprnt for 8086\r\n */\r\n\r\nstatic uchar\tival;\r\nstatic char *\tx;\r\nstatic "
  },
  {
    "path": "float/DOSCAN.C",
    "chars": 3912,
    "preview": "/*\r\n *\t_doscan - implement scanf, fscanf, sscanf\r\n */\r\n\r\n#include\t<stdio.h>\r\n#include \t<ctype.h>\r\n\r\n\r\nstatic FILE *\tfp;\r"
  },
  {
    "path": "float/EVALPOLY.C",
    "chars": 173,
    "preview": "double\r\neval_poly(x, d, n)\r\ndouble\tx;\r\n/* const */ double * d;\r\nint\tn;\r\n{\r\n\tint\ti;\r\n\tdouble\tres;\r\n\r\n\tres = d[i = n];\r\n\tw"
  },
  {
    "path": "float/EXP.C",
    "chars": 953,
    "preview": "#include\t<math.h>\r\n\r\nextern double\teval_poly();\r\ndouble\r\nexp(x)\r\ndouble x;\r\n{\r\n\tint\texp;\r\n\tchar\tsign;\r\n\r\n\t/* const */ st"
  },
  {
    "path": "float/FABS.C",
    "chars": 74,
    "preview": "double\r\nfabs(d)\r\ndouble\td;\r\n{\r\n\tif(d < 0.0)\r\n\t\treturn -d;\r\n\treturn d;\r\n}\r\n"
  },
  {
    "path": "float/FBCD.AS",
    "chars": 3573,
    "preview": ";\tlong\t_fbcd(x, exp, buf)\r\n;\tdouble\tx;\r\n;\tint *\texp;\r\n;\tchar *\tbuf;\r\n\r\n;\tsplit x into mantissa and decimal exponent part"
  },
  {
    "path": "float/FINC.AS",
    "chars": 843,
    "preview": ";\tlfinc - floating increment\r\n;\tlfdec - floating decrement\r\n\r\n\tpsect\ttext\r\n\tglobal\tlfinc, lfdec, asfladd\r\n\r\nlfinc:\r\n\texx"
  },
  {
    "path": "float/FLOAT.AS",
    "chars": 10211,
    "preview": ";\tThis is a set of routines for floating point handling for C\r\n\r\n;\tThe format of a floating point number is as follows:\r"
  },
  {
    "path": "float/FLOOR.C",
    "chars": 161,
    "preview": "#include\t<math.h>\r\n\r\nextern double\t_frndint();\r\n\r\ndouble\r\nfloor(x)\r\ndouble\tx;\r\n{\r\n\tdouble\ti;\r\n\r\n\ti = _frndint(x);\r\n\tif(i"
  },
  {
    "path": "float/FNUM.C",
    "chars": 3484,
    "preview": "/*\r\n *\t_fnum() - converts floating numbers to ascii decimal\r\n *\trepresentations.\r\n */\r\n\r\n\r\n#define\tuchar\tunsigned char\r\n"
  },
  {
    "path": "float/FPRINTF.C",
    "chars": 139,
    "preview": "#include\t<stdio.h>\r\n\r\nextern int\t_doprnt();\r\n\r\nfprintf(file, f, a)\r\nFILE *\tfile;\r\nchar *\tf;\r\nint\ta;\r\n{\r\n\treturn(_doprnt("
  },
  {
    "path": "float/FREXP.AS",
    "chars": 928,
    "preview": ";\tThese functions allow the mantissa and exponent of floating\r\n;\tnumbers to be manipulate separately.\r\n\r\n\r\n\tpsect\ttext\r\n"
  },
  {
    "path": "float/FRNDINT.AS",
    "chars": 270,
    "preview": "\tpsect\ttext\r\n\r\n;\tdouble\tfrndint(val)\r\n;\tdouble\tval;\r\n\r\n;\tRound the argument to an integral value, return as a double\r\n\r\n"
  },
  {
    "path": "float/FSCANF.C",
    "chars": 178,
    "preview": "/*\r\n *\tStdio fscanf\r\n */\r\n\r\n#include\t<stdio.h>\r\nextern int\t_doscan();\r\n\r\nfscanf(file, fmt, args)\r\nFILE *\tfile;\r\nchar *\tf"
  },
  {
    "path": "float/FTOL.AS",
    "chars": 769,
    "preview": ";\tftol - convert floating to long, by using lower bits can also\r\n;\tbe used to convert from float to int or char\r\n\r\n\tpsec"
  },
  {
    "path": "float/LIBFVER.C",
    "chars": 119,
    "preview": "#include <stdio.h>\r\n\r\nchar *_libfver =\r\n#ifdef Z280\r\n \"LIB280F \" _HTC_VERSION;\r\n#else\r\n \"LIBF \" _HTC_VERSION;\r\n#endif\r\n"
  },
  {
    "path": "float/LOG.C",
    "chars": 675,
    "preview": "#include\t<math.h>\r\n\r\nextern double\teval_poly();\r\ndouble\r\nlog(x)\r\ndouble\tx;\r\n{\r\n\tint\texp;\r\n\r\n\tstatic /* const */ double c"
  },
  {
    "path": "float/LTOF.AS",
    "chars": 1188,
    "preview": ";\tConversion of integer type things to floating. Uses routines out\r\n;\tof float.as.\r\n\r\n\tpsect\ttext\r\n\r\n\tglobal\taltof, llto"
  },
  {
    "path": "float/M280LIBF.LOG",
    "chars": 17318,
    "preview": "\r\n10D>date\r\nA:DATE     COM  (User 0)\r\n\rMon 01/09/2025 13:28:32\r\n10D>;----------  M280LIBF.SUB  ----------\r\n10D>; Assumes"
  },
  {
    "path": "float/M280LIBF.SUB",
    "chars": 1499,
    "preview": "era m280libf.log\r\nput console output to file m280libf.log [system]\r\ndate\r\n;----------  M280LIBF.SUB  ----------\r\n; Assum"
  },
  {
    "path": "float/MAKEFILE",
    "chars": 1472,
    "preview": ".SUFFIXES:\t.c .obj .as\r\nBIN\t= /usr/hitech/bin\r\nPACK\t= ../../pack\r\nLIB\t= ../../lib\r\nAR\t= $(BIN)/libr r\r\nC\t= $(BIN)/zc\r\nCF"
  },
  {
    "path": "float/MAKELIBF.LOG",
    "chars": 14029,
    "preview": "\r\n10D>date\r\nA:DATE     COM  (User 0)\r\n\rMon 01/09/2025 12:08:16\r\n10D>;----------  MAKELIBF.SUB  ----------\r\n10D>; Assumes"
  },
  {
    "path": "float/MAKELIBF.SUB",
    "chars": 1477,
    "preview": "era makelibf.log\r\nput console output to file makelibf.log [system]\r\ndate\r\n;----------  MAKELIBF.SUB  ----------\r\n; Assum"
  },
  {
    "path": "float/PRINTF.C",
    "chars": 120,
    "preview": "#include\t<stdio.h>\r\n\r\nextern int\t_doprnt();\r\n\r\nprintf(f, a)\r\nchar *\tf;\r\nint\ta;\r\n{\r\n\treturn(_doprnt(stdout, f, &a));\r\n}\r\n"
  },
  {
    "path": "float/SCANF.C",
    "chars": 159,
    "preview": "/*\r\n *\tStdio scanf\r\n */\r\n\r\n#include\t<stdio.h>\r\n\r\nextern int\t_doscan();\r\n\r\nscanf(fmt, args)\r\nchar *\tfmt;\r\nint\targs;\r\n{\r\n\t"
  },
  {
    "path": "float/SIN.C",
    "chars": 801,
    "preview": "#include\t<math.h>\r\n\r\n#define\tPI\t3.14159265358979\r\n#define\tTWO_PI\t6.28318530717958\r\n#define\tHALF_PI\t1.570796326794895\r\n\r\n"
  },
  {
    "path": "float/SINH.C",
    "chars": 95,
    "preview": "\r\n#include\t<math.h>\r\n\r\ndouble\r\nsinh(x)\r\ndouble\tx;\r\n{\r\n\tx = exp(x);\r\n\treturn 0.5*(x-1.0/x);\r\n}\r\n"
  },
  {
    "path": "float/SPRINTF.C",
    "chars": 269,
    "preview": "#include\t<stdio.h>\r\n\r\nstatic\tFILE\tspf;\r\n\r\nsprintf(wh, f, a)\r\nchar *\twh;\r\nchar *\tf;\r\nint\ta;\r\n{\r\n\tspf._size = 32767;\r\n\tspf"
  },
  {
    "path": "float/SQRT.C",
    "chars": 403,
    "preview": "#include\t<math.h>\r\n\r\ndouble\r\nsqrt(x)\r\ndouble\tx;\r\n{\r\n\tdouble\tog, ng;\r\n\tshort\tniter;\r\n\tint\texp;\r\n\r\n\tif(x <= 0.0)\r\n\t\treturn"
  },
  {
    "path": "float/SSCANF.C",
    "chars": 329,
    "preview": "/*\r\n *\tStdio sscanf\r\n */\r\n\r\n#include\t<stdio.h>\r\n#include\t<string.h>\r\n\r\nextern int\t_doscan();\r\n\r\nsscanf(str, fmt, args)\r\n"
  },
  {
    "path": "float/TAN.C",
    "chars": 78,
    "preview": "#include\t<math.h>\r\n\r\ndouble\r\ntan(x)\r\ndouble\tx;\r\n{\r\n\treturn sin(x)/cos(x);\r\n}\r\n"
  },
  {
    "path": "float/TANH.C",
    "chars": 101,
    "preview": "\r\n#include\t<math.h>\r\n\r\ndouble\r\ntanh(x)\r\ndouble\tx;\r\n{\r\n\tx = exp(x);\r\n\treturn (x-1.0/x)/(x+1.0/x);\r\n}\r\n"
  },
  {
    "path": "gen/ABS.AS",
    "chars": 243,
    "preview": ";\tabs(i) returns the absolute value of i\r\n\r\n\tglobal\t_abs\r\n\r\n\tpsect\ttext\r\n_abs:\r\n\tpop\tde\t\t;Return address\r\n\tpop\thl\r\n\tpush"
  },
  {
    "path": "gen/ALLSH.AS",
    "chars": 281,
    "preview": ";\tarithmetic long left shift\r\n;\tvalue in HLDE, count in B\r\n\r\n\tglobal\tallsh, lllsh\r\n\tpsect\ttext\r\n\r\nallsh:\r\nlllsh:\r\n\tld\ta,"
  },
  {
    "path": "gen/ALRSH.AS",
    "chars": 249,
    "preview": ";\tarithmetic long right shift\r\n;\tvalue in HLDE, count in B\r\n\r\n\tglobal\talrsh\r\n\tpsect\ttext\r\n\r\nalrsh:\r\n\tld\ta,b\t\t;check for "
  },
  {
    "path": "gen/ASALLSH.AS",
    "chars": 414,
    "preview": ";\tASsign Arithmetic Long Left  SHift\r\n;\tASsign Logical Long Left SHift\r\n\r\n\tpsect\ttext\r\n\tglobal\tasallsh, aslllsh, allsh, "
  },
  {
    "path": "gen/ASALRSH.AS",
    "chars": 362,
    "preview": ";\tASsign Arithmetic Long Right  SHift\r\n\r\n\tpsect\ttext\r\n\tglobal\tasalrsh, alrsh, iregstore\r\n\r\nasalrsh:\r\n\tpush\tbc\t\t;save the"
  },
  {
    "path": "gen/ASAR.AS",
    "chars": 451,
    "preview": ";\tShift operations - the count is always in B,\r\n;\tthe quantity to be shifted is in HL, except for the assignment\r\n;\ttype"
  },
  {
    "path": "gen/ASDIV.AS",
    "chars": 428,
    "preview": ";\tAssign versions of divide\r\n\r\n\tglobal\tasadiv, asldiv, adiv, ldiv\r\n\r\n\tpsect\ttext\r\n\r\nasadiv:\r\n\tld\tc,(hl)\r\n\tinc\thl\r\n\tld\tb,"
  },
  {
    "path": "gen/ASLADD.AS",
    "chars": 131,
    "preview": "\tpsect\ttext\r\n\tglobal\tiregset, iregstore, asaladd, aslladd, aladd\r\n\r\nasaladd:\r\naslladd:\r\n\tcall\tiregset\r\n\tcall\taladd\r\n\tjp\t"
  },
  {
    "path": "gen/ASLAND.AS",
    "chars": 131,
    "preview": "\tpsect\ttext\r\n\tglobal\tiregset, iregstore, asaland, aslland, aland\r\n\r\nasaland:\r\naslland:\r\n\tcall\tiregset\r\n\tcall\taland\r\n\tjp\t"
  },
  {
    "path": "gen/ASLL.AS",
    "chars": 475,
    "preview": ";\tShift operations - the count is always in B,\r\n;\tthe quantity to be shifted is in HL, except for the assignment\r\n;\ttype"
  },
  {
    "path": "gen/ASLLRSH.AS",
    "chars": 359,
    "preview": ";\tASsign Logical Long Right  SHift\r\n\r\n\tpsect\ttext\r\n\tglobal\tasllrsh, llrsh, iregstore\r\n\r\nasllrsh:\r\n\tpush\tbc\t\t;save the co"
  },
  {
    "path": "gen/ASLMUL.AS",
    "chars": 131,
    "preview": "\tpsect\ttext\r\n\tglobal\tiregset, iregstore, asalmul, asllmul, almul\r\n\r\nasalmul:\r\nasllmul:\r\n\tcall\tiregset\r\n\tcall\talmul\r\n\tjp\t"
  },
  {
    "path": "gen/ASLOR.AS",
    "chars": 125,
    "preview": "\tpsect\ttext\r\n\tglobal\tiregset, iregstore, asalor, asllor, alor\r\n\r\nasalor:\r\nasllor:\r\n\tcall\tiregset\r\n\tcall\talor\r\n\tjp\tiregst"
  },
  {
    "path": "gen/ASLR.AS",
    "chars": 448,
    "preview": ";\tShift operations - the count is always in B,\r\n;\tthe quantity to be shifted is in HL, except for the assignment\r\n;\ttype"
  },
  {
    "path": "gen/ASLSUB.AS",
    "chars": 131,
    "preview": "\tpsect\ttext\r\n\tglobal\tiregset, iregstore, asalsub, asllsub, alsub\r\n\r\nasalsub:\r\nasllsub:\r\n\tcall\tiregset\r\n\tcall\talsub\r\n\tjp\t"
  },
  {
    "path": "gen/ASLXOR.AS",
    "chars": 131,
    "preview": "\tpsect\ttext\r\n\tglobal\tiregset, iregstore, asalxor, asllxor, alxor\r\n\r\nasalxor:\r\nasllxor:\r\n\tcall\tiregset\r\n\tcall\talxor\r\n\tjp\t"
  },
  {
    "path": "gen/ASMOD.AS",
    "chars": 429,
    "preview": ";\tAssign versions of modulus\r\n\r\n\tglobal\tasamod, aslmod, amod, lmod\r\n\r\n\tpsect\ttext\r\n\r\nasamod:\r\n\tld\tc,(hl)\r\n\tinc\thl\r\n\tld\tb"
  },
  {
    "path": "gen/ASMUL.AS",
    "chars": 261,
    "preview": ";\tAssign versions of multiply\r\n\r\n\tglobal\tasamul, aslmul, amul\r\n\r\n\tpsect\ttext\r\n\r\nasamul:\r\naslmul:\r\n\tld\tc,(hl)\r\n\tinc\thl\r\n\t"
  },
  {
    "path": "gen/ATOI.AS",
    "chars": 560,
    "preview": "\tpsect\ttext\r\ndigit:\tsub\t'0'\r\n\tret\tc\r\n\tcp\t10\r\n\tccf\r\n\tret\r\n\r\n\tglobal\t_atoi\r\n_atoi:\tpop\tbc\t;return address\r\n\tpop\tde\r\n\tpush\t"
  },
  {
    "path": "gen/ATOL.C",
    "chars": 314,
    "preview": "#include\t<ctype.h>\r\n\r\nlong\r\natol(s)\r\nregister char *\ts;\r\n{\r\n\tlong\ta;\r\n\tunsigned char\tsign;\r\n\r\n\twhile(*s == ' ' || *s == "
  },
  {
    "path": "gen/BITFIELD.AS",
    "chars": 1800,
    "preview": ";\tFunctions to implement bitfields:\r\n\r\n;\tthe width and offset (in bits) of the bitfield concerned\r\n;\tappear in the code "
  },
  {
    "path": "gen/BLKCLR.AS",
    "chars": 340,
    "preview": ";\tblkclr(ptr, size)\r\n;\tchar *\tptr; unsigned short size;\r\n\r\n;\tFills memory with size null bytes\r\n\r\n\tpsect\ttext\r\n\tglobal\t_"
  },
  {
    "path": "gen/BLKCPY.C",
    "chars": 106,
    "preview": "blkcpy(dp, sp, n)\r\n\tregister char *dp, *sp;\r\n\tregister unsigned n;\r\n{\r\n\twhile (n--)\r\n\t\t*dp++ = *sp++;\r\n}\r\n"
  },
  {
    "path": "gen/BMOVE.AS",
    "chars": 270,
    "preview": ";\tbmove(from, to, count)\r\n\r\n\tglobal\t_bmove, _movmem\r\n\tpsect\ttext\r\n\r\n_movmem:\r\n_bmove:\r\n\tpop\thl\t\t;return address\r\n\texx\r\n\t"
  },
  {
    "path": "gen/BRELOP.AS",
    "chars": 460,
    "preview": ";\tbyte relational\toperation - returns flags correctly for\r\n;\tcomparision of words in a and b\r\n\r\n\tpsect\ttext\r\n\tglobal\tbre"
  },
  {
    "path": "gen/BUILDGEN.SUB",
    "chars": 804,
    "preview": "c\r\n<-o -c \\\r\n<abs.as allsh.as alrsh.as asallsh.as asalrsh.as asar.as \\\r\n<asdiv.as asladd.as asland.as asll.as asllrsh.as"
  },
  {
    "path": "gen/CALLOC.C",
    "chars": 390,
    "preview": "/*\r\n *\tcalloc - alloc space for n items of size s, and clear it to nulls\r\n */\r\n\r\nextern char * malloc();\r\nextern void\tfr"
  },
  {
    "path": "gen/CSV.AS",
    "chars": 439,
    "preview": "\tglobal\tcsv,cret,indir, ncsv\r\n\tpsect\ttext\r\ncsv:\tpop\thl\t\t;return address\r\n\tpush\tiy\r\n\tpush\tix\r\n\tld\tix,0\r\n\tadd\tix,sp\t\t;new "
  },
  {
    "path": "gen/CTYPE.C",
    "chars": 50,
    "preview": "isdig(c)\r\n{\r\n\treturn(c >= '0' && c <= '9');\r\n}\r\n\r\n"
  },
  {
    "path": "gen/CTYPE_.C",
    "chars": 639,
    "preview": "#include\t<ctype.h>\r\n\r\nunsigned char _ctype_[] = {\r\n\t0,\r\n\t_C,\t_C,\t_C,\t_C,\t_C,\t_C,\t_C,\t_C,\r\n\t_C,\t_S,\t_S,\t_S,\t_S,\t_S,\t_C,\t_"
  },
  {
    "path": "gen/FRELOP.AS",
    "chars": 1069,
    "preview": ";\tfloating relational operation - returns flags as though\r\n;\ta floating subtract was done.\r\n\r\n\tpsect\ttext\r\n\tglobal\tfrelo"
  },
  {
    "path": "gen/GETSP.AS",
    "chars": 107,
    "preview": ";\tReturn value of the stack pointer\r\n\r\n\tpsect\ttext\r\n\tglobal\t__getsp\r\n__getsp:\r\n\tld\thl,0\r\n\tadd\thl,sp\r\n\tret\r\n"
  },
  {
    "path": "gen/IDIV.AS",
    "chars": 1132,
    "preview": ";\t16 bit divide and modulus routines\r\n\r\n;\tcalled with dividend in hl and divisor in de\r\n\r\n;\treturns with result in hl.\r\n"
  },
  {
    "path": "gen/IMUL.AS",
    "chars": 370,
    "preview": ";\t16 bit integer multiply\r\n\r\n;\ton entry, left operand is in hl, right operand in de\r\n\r\n\tpsect\ttext\r\n\tglobal\tamul,lmul\r\na"
  },
  {
    "path": "gen/INDEX.AS",
    "chars": 170,
    "preview": "\tpsect\ttext\r\n\tglobal\trcsv, cret, _index\r\n\r\n_index:\tcall\trcsv\r\n\r\n\tjr\t3f\r\n1:\r\n\tinc\thl\r\n3:\r\n\tld\ta,(hl)\r\n\tor\ta\r\n\tjr\tz,2f\r\n\tc"
  },
  {
    "path": "gen/INOUT.AS",
    "chars": 378,
    "preview": "\tglobal\t_in, _out, _inp, _outp\r\n\tpsect\ttext\r\n\r\n_in:\r\n_inp:\r\n\tpop\thl\t\t;return address\r\n\tpop\tbc\t\t;port address\r\n\tpush\tbc\r\n"
  },
  {
    "path": "gen/IREGSET.AS",
    "chars": 1047,
    "preview": ";\troutines to support the assignment versions of the long operations\r\n\r\n\tpsect\ttext\r\n\tglobal\tiregset, iregstore\r\n\r\niregs"
  },
  {
    "path": "gen/ISALPHA.AS",
    "chars": 297,
    "preview": "\tglobal\t_isalpha\r\n\r\n\tpsect\ttext\r\n_isalpha:\r\n\tpop\tde\t\t;return address\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tld\ta,h\t\t;check for a"
  },
  {
    "path": "gen/ISDIGIT.AS",
    "chars": 257,
    "preview": "\tglobal\t_isdigit, _isdig\r\n\r\n\tpsect\ttext\r\n_isdigit:\r\n_isdig:\r\n\tpop\tde\t\t;return address\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tld\t"
  },
  {
    "path": "gen/ISLOWER.AS",
    "chars": 240,
    "preview": "\tglobal\t_islower\r\n\r\n\tpsect\ttext\r\n_islower:\r\n\tpop\tde\t\t;return address\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tld\ta,h\t\t;check for a"
  },
  {
    "path": "gen/ISSPACE.AS",
    "chars": 277,
    "preview": "\tglobal\t_isspace\r\n\r\n\tpsect\ttext\r\n_isspace:\r\n\tpop\tde\t\t;return address\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tld\ta,h\t\t;check for a"
  },
  {
    "path": "gen/ISUPPER.AS",
    "chars": 240,
    "preview": "\tglobal\t_isupper\r\n\r\n\tpsect\ttext\r\n_isupper:\r\n\tpop\tde\t\t;return address\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tld\ta,h\t\t;check for a"
  },
  {
    "path": "gen/LADD.AS",
    "chars": 166,
    "preview": "\tpsect\ttext\r\n\tglobal\taladd, lladd\r\n\r\naladd:\r\nlladd:\r\n\texx\r\n\tpop\thl\r\n\texx\r\n\tpop\tbc\r\n\tex\tde,hl\r\n\tadd\thl,bc\r\n\tex\tde,hl\r\n\tpo"
  },
  {
    "path": "gen/LAND.AS",
    "chars": 224,
    "preview": "\tpsect\ttext\r\n\tglobal\taland, lland\r\n\r\naland:\r\nlland:\r\n\texx\r\n\tpop\thl\r\n\texx\r\n\tpop\tbc\r\n\tld\ta,c\r\n\tand\te\r\n\tld\te,a\r\n\tld\ta,b\r\n\ta"
  },
  {
    "path": "gen/LDIV.AS",
    "chars": 5459,
    "preview": ";\tLong division routines for Z80\r\n\r\n\r\n\r\n\tglobal\tlldiv,aldiv,almod,llmod,aslldiv,asaldiv,asllmod,asalmod\r\n\r\n\tpsect\ttext\r\n"
  },
  {
    "path": "gen/LIBCVER.C",
    "chars": 116,
    "preview": "#define VERSION \"3.09-18\"\r\n\r\nchar *_libcver =\r\n#ifdef Z280\r\n \"LIB280C \" VERSION;\r\n#else\r\n \"LIBC \" VERSION;\r\n#endif\r\n"
  },
  {
    "path": "gen/LINC.AS",
    "chars": 648,
    "preview": ";\tLong increment\r\n\r\n\tpsect\ttext\r\n\r\n\tglobal\tlainc, llinc, ladec, lldec\r\n\r\ngval:\r\n\texx\r\n\tpop\thl\t\t;return address\r\n\texx\r\n\tl"
  },
  {
    "path": "gen/LLRSH.AS",
    "chars": 246,
    "preview": ";\tlogical long right shift\r\n;\tvalue in HLDE, count in B\r\n\r\n\tglobal\tllrsh\r\n\tpsect\ttext\r\n\r\nllrsh:\r\n\tld\ta,b\t\t;check for zer"
  },
  {
    "path": "gen/LMUL.AS",
    "chars": 811,
    "preview": ";\tLong multiplication for Z80\r\n\r\n;\tCalled with 1st arg in HLDE, 2nd arg on stack. Returns with\r\n;\tresult in HLDE, other "
  },
  {
    "path": "gen/LONGJMP.AS",
    "chars": 1068,
    "preview": ";\tsetjump, longjump - non local goto\r\n\r\n\tpsect\ttext\r\n\tglobal\t_longjmp, _setjmp\r\n\r\n_setjmp:\r\n\tpop\tbc\t\t;return address\r\n\te"
  },
  {
    "path": "gen/LOR.AS",
    "chars": 216,
    "preview": "\tpsect\ttext\r\n\tglobal\talor, llor\r\n\r\nalor:\r\nllor:\r\n\texx\r\n\tpop\thl\r\n\texx\r\n\tpop\tbc\r\n\tld\ta,c\r\n\tor\te\r\n\tld\te,a\r\n\tld\ta,b\r\n\tor\td\r\n"
  },
  {
    "path": "gen/LRELOP.AS",
    "chars": 1044,
    "preview": ";\tlong relational\toperation - returns flags as though\r\n;\ta long subtract\twas done.\r\n\r\n\tpsect\ttext\r\n\tglobal\tlrelop,arelop"
  },
  {
    "path": "gen/LSUB.AS",
    "chars": 173,
    "preview": "\tpsect\ttext\r\n\tglobal\talsub, llsub\r\n\r\nalsub:\r\nllsub:\r\n\texx\r\n\tpop\thl\r\n\texx\r\n\tpop\tbc\r\n\tex\tde,hl\r\n\tor\ta\r\n\tsbc\thl,bc\r\n\tex\tde,"
  },
  {
    "path": "gen/LXOR.AS",
    "chars": 224,
    "preview": "\tpsect\ttext\r\n\tglobal\talxor, llxor\r\n\r\nalxor:\r\nllxor:\r\n\texx\r\n\tpop\thl\r\n\texx\r\n\tpop\tbc\r\n\tld\ta,c\r\n\txor\te\r\n\tld\te,a\r\n\tld\ta,b\r\n\tx"
  },
  {
    "path": "gen/MAKEFILE",
    "chars": 2239,
    "preview": ".SUFFIXES:\t.c .as .obj\r\n\r\nCC\t= /usr/hitech/bin/zc\r\nAS\t= /usr/hitech/bin/zas\r\nLIBR\t= /usr/hitech/bin/libr\r\nCFLAGS\t= -O -x"
  },
  {
    "path": "gen/MALLOC.C",
    "chars": 4018,
    "preview": "#ifdef debug\r\n#define ASSERT(p) if(!(p))botch(\"p\");else\r\nbotch(s)\r\nchar *s;\r\n{\r\n\tprintf(\"assertion botched: %s\\n\",s);\r\n\t"
  },
  {
    "path": "gen/MAX.AS",
    "chars": 293,
    "preview": "\tglobal\t_max\r\n\tpsect\ttext\r\n\r\n_max:\r\n\tpop\tbc\t\t;return address\r\n\tpop\tde\t\t;arg 1\r\n\tpop\thl\t\t;arg 2\r\n\tpush\thl\r\n\tpush\tde\r\n\tpus"
  },
  {
    "path": "gen/MEMCMP.C",
    "chars": 148,
    "preview": "\r\nmemcmp(s1, s2, n)\r\nregister char *\ts1, * s2;\r\nregister int\tn;\r\n{\r\n\tshort\ti;\r\n\r\n\twhile(n--)\r\n\t\tif(i = *s1++ - *s2++)\r\n\t"
  },
  {
    "path": "gen/MEMCPY.C",
    "chars": 94,
    "preview": "memcpy(d, s, n)\r\nregister char *\td, * s;\r\nregister int\tn;\r\n{\r\n\twhile(n--)\r\n\t\t*d++ = *s++;\r\n}\r\n"
  },
  {
    "path": "gen/MEMSET.C",
    "chars": 998,
    "preview": "/*------------------------------------------------------------------------*\\\r\n | memset()\r\n |\r\n |\tThis is the original H"
  },
  {
    "path": "gen/PNUM.C",
    "chars": 739,
    "preview": "/*\r\n *\tFormatted number printing for Z80 printf and debugger\r\n */\r\n#define\tNDIG\t30\t\t/* max number of digits to be printe"
  },
  {
    "path": "gen/QSORT.C",
    "chars": 1232,
    "preview": "/*\r\n *\tQuicksort based on the algorithm given in\r\n *\t\"Algorithms + Data Structures = Programs\" by N. Wirth.\r\n */\r\n\r\nqsor"
  },
  {
    "path": "gen/RAND.C",
    "chars": 146,
    "preview": "static\tlong\trandx = 1;\r\n\r\nsrand(x)\r\nunsigned x;\r\n{\r\n\trandx = x;\r\n}\r\n\r\nrand()\r\n{\r\n\treturn(((randx = randx*1103515245L + 1"
  },
  {
    "path": "gen/RCSV.AS",
    "chars": 280,
    "preview": "\tglobal\trcsv\r\n\r\nARG\tequ\t6\t\t;offset of 1st arg\r\n\tpsect\ttext\r\nrcsv:\r\n\tex\t(sp),iy\t\t;save iy, get return address\r\n\tpush\tix\r\n"
  },
  {
    "path": "gen/RINDEX.AS",
    "chars": 254,
    "preview": "\tpsect\ttext\r\n\tglobal\trcsv, cret, _rindex\r\n\r\n_rindex:\r\n\tcall\trcsv\r\n\r\n\tld\tbc,0\r\n\tjr\t5f\r\n6:\r\n\tinc\thl\r\n\tinc\tbc\r\n5:\r\n\tld\ta,(h"
  },
  {
    "path": "gen/SBRK.AS",
    "chars": 825,
    "preview": "\tpsect\ttext\r\n\tglobal\t_sbrk,__Hbss, _brk, _checksp\r\n\r\n;\tNB This brk() does not check that the argument is reasonable.\r\n\r\n"
  },
  {
    "path": "gen/SHAR.AS",
    "chars": 397,
    "preview": ";\tShift operations - the count is always in B,\r\n;\tthe quantity to be shifted is in HL, except for the assignment\r\n;\ttype"
  },
  {
    "path": "gen/SHLL.AS",
    "chars": 430,
    "preview": ";\tShift operations - the count is always in B,\r\n;\tthe quantity to be shifted is in HL, except for the assignment\r\n;\ttype"
  },
  {
    "path": "gen/SHLR.AS",
    "chars": 394,
    "preview": ";\tShift operations - the count is always in B,\r\n;\tthe quantity to be shifted is in HL, except for the assignment\r\n;\ttype"
  },
  {
    "path": "gen/STRCAT.AS",
    "chars": 316,
    "preview": "\tpsect\ttext\r\n\tglobal\t_strcat\r\n\r\n_strcat:\r\n\tpop\tbc\r\n\tpop\tde\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tpush\tbc\r\n\tld\tc,e\t\t;save destin"
  },
  {
    "path": "gen/STRCHR.AS",
    "chars": 350,
    "preview": "; strchr(char *s, int c)\r\n; version that can find the closing \\0 by Arnold M\r\n\r\n\tpsect\ttext\r\n\tglobal\trcsv, cret, _strchr"
  },
  {
    "path": "gen/STRCMP.AS",
    "chars": 233,
    "preview": "\tpsect\ttext\r\n\tglobal\t_strcmp\r\n\r\n_strcmp:\tpop\tbc\r\n\tpop\tde\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tpush\tbc\r\n\r\n1:\tld\ta,(de)\r\n\tcp\t(hl"
  },
  {
    "path": "gen/STRCPY.AS",
    "chars": 230,
    "preview": "\tpsect\ttext\r\n\tglobal\t_strcpy\r\n\r\n_strcpy:\tpop\tbc\r\n\tpop\tde\r\n\tpop\thl\r\n\tpush\thl\r\n\tpush\tde\r\n\tpush\tbc\r\n\tld\tc,e\r\n\tld\tb,d\t\t;save"
  },
  {
    "path": "gen/STRDUP.C",
    "chars": 216,
    "preview": "#include <string.h>\r\nextern char *malloc();\r\n\r\nchar * strdup(char * str)\r\n{\r\n  char *dup;\r\n\r\n  if ( (dup = malloc(strlen"
  }
]

// ... and 318 more files (download for full content)

About this extraction

This page contains the full source code of the agn453/HI-TECH-Z80-C GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 518 files (1.2 MB), approximately 417.9k tokens, and a symbol index with 350 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!