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