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 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 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 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 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 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 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 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 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 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 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() 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 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 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 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 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 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 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 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 @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 * 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 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 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 #include #include 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 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) 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 * Minor change to allow size optimization (-O2 switch) for Z280. ## Easy binary download 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 ``` 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 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 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 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 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 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 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 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 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 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 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. 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 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 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 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 ``````. 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 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 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 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 \ #include #include #include #include /* * 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 #include #include #include #include #include #include #include #include #include /* * 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 #include 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 #include #include /* 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 /* * 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 #include 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 ; ; #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 #include /* * 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 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 #include #include /* * 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 /* 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 = 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 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 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 #include #include 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 #include 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 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 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/ZR280CPM.AS ================================================ ; This is ZRRTCPM for the Z280 MPU ; ; Self relocating startup for CP/M psect cpm,global psect text,global,pure psect data,global psect bss,global psect stack,global defs 256 ;a minimal stack psect cpm defs 100h ;Base of CP/M's TPA global start,_main,_exit,__Lbss,__Hstack, __z3env global __piped,__initrsx,__exact reloc: ; 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 [Relocatable]' 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 cpm 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) push hl ;HL holds possible Z3ENV address ld hl,(6) ;get base of fdos ld de,__Hstack or a sbc hl,de ;get distance to move ld c,l ;save it in bc ld b,h 1: ld hl,(__Lbss) ;get count ld a,l ;zero? or h jr z,2f dec hl ld (__Lbss),hl ld hl,(addr) ;get address ld e,(hl) ;pick up value inc hl ld d,(hl) inc hl ld (addr),hl ;save for next ex de,hl ld (where),hl ;save it ld de,3f ;dont relocate any of our addresses or a sbc hl,de ;check for range jr c,1b ;skip if less than 3f ld hl,(where) ld e,(hl) ;get value to relocate inc hl ld d,(hl) ex de,hl add hl,bc ;add difference ex de,hl ld (hl),d ;put relocated value back dec hl ld (hl),e jr 1b ;loop for more addr: defw __Lbss+2 ;start of addresses where: defs 2 ;temp storage 2: ld hl,__Lbss ;now find how much to move ld de,start or a sbc hl,de ld c,l ;save in bc ld b,h ld hl,__Hstack ;top of memory ld de,__Lbss ;top of code and data sbc hl,de ;room to leave at top of mem ex de,hl ld hl,(6) scf ;discount it sbc hl,de ex de,hl ;destination into de ld hl,__Lbss-1 ;source in hl - count is already in bc ld a,c ;check for zero or b jr z,3f lddr ;move it pop hl 3: jp start ;go to it psect text start: 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 ; 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,3Ch ld de,rsxpb 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 ld hl,(6) ;base address of fdos ld sp,hl ;stack grows downwards ld de,__Lbss ;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 ;arg buf ld c,(hl) ;size of buffer ld b,0 ld hl,0 scf ;one for the road sbc hl,bc ;negate it add hl,sp ld sp,hl ;allow space for args ld de,0 ;flag end of args push de ld hl,80h ;address of argument buffer add hl,bc ;bc has size of arg buffer 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 call _main push hl call _exit jp p,0 psect data nularg: defm 'main' 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 reloc ================================================ FILE: cpm/ZRRTCPM.AS ================================================ ; Self relocating startup for CP/M psect cpm,global psect text,global,pure psect data,global psect bss,global psect stack,global defs 256 ;a minimal stack psect cpm defs 100h ;Base of CP/M's TPA global start,_main,_exit,__Lbss,__Hstack, __z3env global __piped,__initrsx,__exact reloc: ; 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 [Relocatable]' 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 cpm begin: sub a ;Stop 8080 processors running this. jp po,okver ; ld de,bvmes ld c,9 ;Print error message jp 5 okver: push hl ;HL holds possible Z3ENV address ld hl,(6) ;get base of fdos ld de,__Hstack or a sbc hl,de ;get distance to move ld c,l ;save it in bc ld b,h 1: ld hl,(__Lbss) ;get count ld a,l ;zero? or h jr z,2f dec hl ld (__Lbss),hl ld hl,(addr) ;get address ld e,(hl) ;pick up value inc hl ld d,(hl) inc hl ld (addr),hl ;save for next ex de,hl ld (where),hl ;save it ld de,3f ;dont relocate any of our addresses or a sbc hl,de ;check for range jr c,1b ;skip if less than 3f ld hl,(where) ld e,(hl) ;get value to relocate inc hl ld d,(hl) ex de,hl add hl,bc ;add difference ex de,hl ld (hl),d ;put relocated value back dec hl ld (hl),e jr 1b ;loop for more addr: defw __Lbss+2 ;start of addresses where: defs 2 ;temp storage 2: ld hl,__Lbss ;now find how much to move ld de,start or a sbc hl,de ld c,l ;save in bc ld b,h ld hl,__Hstack ;top of memory ld de,__Lbss ;top of code and data sbc hl,de ;room to leave at top of mem ex de,hl ld hl,(6) scf ;discount it sbc hl,de ex de,hl ;destination into de ld hl,__Lbss-1 ;source in hl - count is already in bc ld a,c ;check for zero or b jr z,3f lddr ;move it pop hl 3: jp start ;go to it psect text start: 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 ; 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 ;If the PIPEMGR RSX is loaded, initialise it. iscpm3: ld c,3Ch ld de,rsxpb 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 ld hl,(6) ;base address of fdos ld sp,hl ;stack grows downwards ld de,__Lbss ;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 ;arg buf ld c,(hl) ;size of buffer ld b,0 ld hl,0 scf ;one for the road sbc hl,bc ;negate it add hl,sp ld sp,hl ;allow space for args ld de,0 ;flag end of args push de ld hl,80h ;address of argument buffer add hl,bc ;bc has size of arg buffer 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 call _main push hl call _exit jp p,0 psect data nularg: defm 'main' 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 reloc ================================================ FILE: cpm/_EXIT.AS ================================================ EXITSTS equ 80h ;where to store exit status [CP/M 2] BDOS equ 00005h CPMVERS equ 12 ; Get CP/M Version number CPMRCOD equ 108 ; CP/M+ Get/Set Error Return Code global __exit, __cpm_clean psect text __exit: call __cpm_clean pop hl ;return address ld c,CPMVERS call BDOS ;Get version dec h ;sets Z flag if MP/M pop hl ;exit status jp z,0 ;Warm boot if MP/M cp 30h ld (EXITSTS),hl jp c,0 ;Warm boot CP/M if < CP/M 3 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 end ================================================ FILE: dist/ASSERT.H ================================================ #ifndef _HTC_ASSERT_H #define _HTC_ASSERT_H /* * Assertion - use liberally for debugging. Defining NDEBUG * turns assertions off. * assert(exp) where exp is non-zero does nothing, while * assert(exp) where exp evaluates to zero aborts the program * with a message like * * Assertion failed: prog.c line 123: "exp" * */ #ifndef NDEBUG extern void _fassert(int, char *, char *); #define assert(exp) if(!(exp)) {_fassert(__LINE__, __FILE__, "exp");} #else #define assert(exp) #endif #endif ================================================ FILE: dist/CONIO.H ================================================ #ifndef _HTC_CONIO_H #define _HTC_CONIO_H /* * Low-level console I/O functions */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ extern char getch(void); extern char getche(void); extern void putch(int); extern void ungetch(int); extern int kbhit(void); extern char * cgets(char *); extern void cputs(char *); #endif ================================================ FILE: dist/CPM.H ================================================ #ifndef _HTC_CPM_H #define _HTC_CPM_H /* Header file for CP/M routines for Z-80 C */ /* get basic definitions */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ #endif _STDDEF /* hitech.h has definitions for uchar, ushort etc */ #include #if z80 #define MAXFILE 8 /* max number of files open */ #else z80 #define MAXFILE 15 /* max number of files open */ #endif z80 #define SECSIZE 128 /* no. of bytes per sector */ extern struct fcb { uchar dr; /* 0: drive code */ char name[8]; /* 1: file name */ char ft[3]; /* 9: file type */ uchar ex; /* 12: file extent */ char fil[2]; /* 13: not used */ char rc; /* 15: number of records in present extent */ char dm[16]; /* 16: CP/M disk map */ char nr; /* 32: next record to read or write */ uchar ranrec[3]; /* 35: random record number (24 bit no.) */ long rwp; /* 38: read/write pointer in bytes */ uchar use; /* 42: use flag */ uchar uid; /* 43: user id belonging to this file */ long fsize; /* 44: file length in bytes */ } _fcb[MAXFILE]; extern short bdos(int, ...); #define bdoshl bdos #define bdose bdos extern struct fcb* getfcb(void); extern char * fcbname(short i); extern short getuid(void); extern short setuid(short); extern uchar setfcb(struct fcb *, char *); extern char * (*_passwd)(struct fcb *); extern short bios(short fn, ...); #define bios3 bios /* flag values in fcb use */ #define U_READ 1 /* file open for reading */ #define U_WRITE 2 /* file open for writing */ #define U_RDWR 3 /* open for read and write */ #define U_CON 4 /* device is console */ #define U_RDR 5 /* device is reader */ #define U_PUN 6 /* device is punch */ #define U_LST 7 /* list device */ #define U_RSX 8 /* PIPEMGR RSX */ #define U_ERR 9 /* PIPEMGR stderr channel */ /* special character values */ #define CPMETX 032 /* ctrl-Z, CP/M end of file for text */ #define CPMRBT 003 /* ctrl-C, reboot CPM */ /* operating systems */ #define MPM 0x100 /* bit to test for MP/M */ #define CCPM 0x400 /* bit to test for CCP/M */ #define ISMPM() (bdoshl(CPMVERS)&MPM) /* macro to test for MPM */ /* what to do after you hit return */ #define EXIT (*(int (*)())0) /* where to go to reboot CP/M */ /* BDOS calls etc. */ #define CPMRCON 1 /* read console */ #define CPMWCON 2 /* write console */ #define CPMRRDR 3 /* read reader */ #define CPMWPUN 4 /* write punch */ #define CPMWLST 5 /* write list */ #define CPMDCIO 6 /* direct console I/O */ #define CPMGIOB 7 /* get I/O byte */ #define CPMSIOB 8 /* set I/O byte */ #define CPMWCOB 9 /* write console buffered */ #define CPMRCOB 10 /* read console buffered */ #define CPMICON 11 /* interrogate console ready */ #define CPMVERS 12 /* return version number */ #define CPMRDS 13 /* reset disk system */ #define CPMLGIN 14 /* log in and select disk */ #define CPMOPN 15 /* open file */ #define CPMCLS 16 /* close file */ #define CPMFFST 17 /* find first */ #define CPMFNXT 18 /* find next */ #define CPMDEL 19 /* delete file */ #define CPMREAD 20 /* read next record */ #define CPMWRIT 21 /* write next record */ #define CPMMAKE 22 /* create file */ #define CPMREN 23 /* rename file */ #define CPMILOG 24 /* get bit map of logged in disks */ #define CPMIDRV 25 /* interrogate drive number */ #define CPMSDMA 26 /* set DMA address for i/o */ #define CPMGALL 27 /* get allocation vector address */ #define CPMWPRD 28 /* write protect disk */ #define CPMGROV 29 /* get read-only vector */ #define CPMSATT 30 /* set file attributes */ #define CPMDPB 31 /* get disk parameter block */ #define CPMSUID 32 /* set/get user id */ #define CPMRRAN 33 /* read random record */ #define CPMWRAN 34 /* write random record */ #define CPMCFS 35 /* compute file size */ #define CPMSRAN 36 /* set random record */ #define CPMRDRV 37 /* reset drive */ #define CPMACDV 38 /* MP/M access drive */ #define CPMFRDV 39 /* MP/M free drive */ #define CPMWRZF 40 /* write random with zero fill */ #define CPMTWR 41 /* MP/M test and write record */ #define CPMLOKR 42 /* MP/M lock record */ #define CPMUNLR 43 /* MP/M unlock record */ #define CPMSMSC 44 /* CP/M+ set multi-sector count */ #define CPMERRM 45 /* CP/M+ set BDOS error mode */ #define CPMDFS 46 /* CP/M+ get disk free space */ #define CPMCHN 47 /* CP/M+ chain to program */ #define CPMFLSH 48 /* CP/M+ flush buffers */ #define CPMGZSD 48 /* ZSDOS get ZSDOS/ZDDOS version */ #define CPMSCB 49 /* access CP/M+ system control block */ #define CPMBIOS 50 /* CP/M+ direct BIOS call */ #define CPMDSEG 51 /* set DMA segment */ #define CPMGFTM 54 /* Z80DOS/ZPM3 get file time-stamp */ #define CPMSFTM 55 /* Z80DOS/ZPM3 set file time-stamp */ #define CPMLDOV 59 /* CP/M+ Load Overlay - requires LOADER RSX */ #define CPMRSX 60 /* CP/M+ call RSX */ #define CPMLGI 64 /* CP/Net login */ #define CPMLGO 65 /* CP/Net logout */ #define CPMSMSG 66 /* CP/Net send message */ #define CPMRMSG 67 /* CP/Net receive message */ #define CPMNETS 68 /* CP/Net get network status */ #define CPMGCFT 69 /* CP/Net get configuration table address */ #define CPMSCAT 70 /* CP/Net set compatibility attributes */ #define CPMGSVC 71 /* CP/Net get server configuration */ #define CPMFRBL 98 /* CP/M+ free blocks */ #define CPMTRNC 99 /* CP/M+ truncate file */ #define CPMSLBL 100 /* CP/M+ set directory label */ #define CPMDLD 101 /* CP/M+ get directory label data */ #define CPMGFTS 102 /* CP/M+ get file timestamp and password mode */ #define CPMWXFC 103 /* CP/M+ write file XFCB */ #define CPMSDAT 104 /* CP/M+ set date and time */ #define CPMGDAT 105 /* CP/M+ get date and time */ #define CPMSPWD 106 /* CP/M+ set default password */ #define CPMGSER 107 /* CP/M+ get serial number */ #define CPMRCOD 108 /* CP/M+ get/set return code */ #define CPMCMOD 109 /* CP/M+ get/set console mode */ #define CPMODEL 110 /* CP/M+ get/set output delimiter */ #define CPMPBLK 111 /* CP/M+ print block */ #define CPMLBLK 112 /* CP/M+ list block */ #define CPMPARS 152 /* CP/M+ parse filename */ /* CP/M BIOS functions. Numbers above 16 pertain to CP/M 3 only. */ enum BIOSfns { _BOOT = 0, _WBOOT = 1, _CONST = 2, _CONIN = 3, _CONOUT = 4, _LIST = 5, _PUNOUT = 6, /* CP/M 2.2 name */ _AUXOUT = 6, /* CP/M 3.1 name */ _RDRIN = 7, /* CP/M 2.2 name */ _AUXIN = 7, /* CP/M 3.1 name */ _LISTST = 15, _CONOST = 17, _AUXIST = 18, _AUXOST = 19, _DEVTBL = 20, _DEVINI = 21, _DRVTBL = 22, _HOME = 8, _SELDSK = 9, _SETTRK = 10, _SETSEC = 11, _SETDMA = 12, _READ = 13, _WRITE = 14, _SECTRN = 16, _MULTIO = 23, _FLUSH = 24, _MOVE = 25, _SELMEM = 27, _SETBNK = 28, _XMOVE = 29, _TIME = 26, _USERF = 30 }; #endif ================================================ FILE: dist/CTYPE.H ================================================ #ifndef _HTC_CTYPE_H #define _HTC_CTYPE_H #define _U 0x01 #define _L 0x02 #define _N 0x04 #define _S 0x08 #define _P 0x10 #define _C 0x20 #define _X 0x40 extern unsigned char _ctype_[]; /* in libc.lib */ #define isalpha(c) ((_ctype_+1)[c]&(_U|_L)) #define isupper(c) ((_ctype_+1)[c]&_U) #define islower(c) ((_ctype_+1)[c]&_L) #define isdigit(c) ((_ctype_+1)[c]&_N) #define isxdigit(c) ((_ctype_+1)[c]&(_N|_X)) #define isspace(c) ((_ctype_+1)[c]&_S) #define ispunct(c) ((_ctype_+1)[c]&_P) #define isalnum(c) ((_ctype_+1)[c]&(_U|_L|_N)) #define isprint(c) ((_ctype_+1)[c]&(_P|_U|_L|_N|_S)) #define isgraph(c) ((_ctype_+1)[c]&(_P|_U|_L|_N)) #define iscntrl(c) ((_ctype_+1)[c]&_C) #define isascii(c) (!((c)&0xFF80)) /*--------------------------------------*\ | Changed 2014-07-04 (Jon Saxton) | |--------------------------------------| | Original macro definitions | | #define toupper(c) ((c)-'a'+'A') | | #define tolower(c) ((c)-'A'+'a') | |--------------------------------------| | Use functions instead | \*--------------------------------------*/ extern int toupper(int); /* in LIBC.LIB */ extern int tolower(int); /* in LIBC.LIB */ #define toascii(c) ((c)&0x7F) #endif ================================================ FILE: dist/EXEC.H ================================================ #ifndef _HTC_EXEC_H #define _HTC_EXEC_H /* * Definitions of the EXEC format */ #define EXITIT 0x80 #define EXEC 0x81 #define IGN_ERR 0x82 #define DEF_ERR 0x83 #define SKP_ERR 0x84 #define TRAP 0x85 #define IF_ERR 0x86 #define IF_NERR 0x87 #define ECHO 0x88 #define PRINT 0x89 #define RM_FILE 0x8A #define RM_EXIT 0x8B #endif ================================================ FILE: dist/FLOAT.H ================================================ #ifndef _HTC_FLOAT_H #define _HTC_FLOAT_H /* Characteristics of floating types */ #define DBL_RADIX 2 /* radix of exponent for a double */ #define DBL_ROUNDS 1 /* doubles round when converted to int */ #define FLT_RADIX 2 /* radix of float exponent */ #define FLT_ROUNDS 1 /* float also rounds to int */ #if z80 #define FLT_MANT_DIG 24 /* 24 bits in mantissa */ #define DBL_MANT_DIG 24 /* ditto for double */ #define DBL_MANT_DIG 24 /* ditto long double */ #define FLT_EPSILON -1.192093 /* smallest x, x+1.0 != 1.0 */ #define DBL_EPSILON -1.192093 /* smallest x, x+1.0 != 1.0 */ #define FLT_DIG 6 /* decimal significant digs */ #define DBL_DIG 6 #define FLT_MIN_EXP -62 /* min binary exponent */ #define DBL_MIN_EXP -62 #define FLT_MIN 1.084202e-19 /* smallest floating number */ #define DBL_MIN 1.084202e-19 #define FLT_MIN_10_EXP -18 #define DBL_MIN_10_EXP -18 #define FLT_MAX_EXP 64 /* max binary exponent */ #define DBL_MAX_EXP 64 #define FLT_MAX 1.84467e19 /* max floating number */ #define DBL_MAX 1.84467e19 #define FLT_MAX_10_EXP 19 /* max decimal exponent */ #define DBL_MAX_10_EXP 19 #endif z80 #if i8086 || m68k /* The 8086 and 68000 use IEEE 32 and 64 bit floats */ #define FLT_RADIX 2 #define FLT_MANT_DIG 24 #define FLT_EPSILON 1.19209290e-07 #define FLT_DIG 6 #define FLT_MIN_EXP -125 #define FLT_MIN 1.17549435e-38 #define FLT_MIN_10_EXP -37 #define FLT_MAX_EXP 128 #define FLT_MAX 3.40282347e+38 #define FLT_MAX_10_EXP 38 #define DBL_MANT_DIG 53 #define DBL_EPSILON 2.2204460492503131e-16 #define DBL_DIG 15 #define DBL_MIN_EXP -1021 #define DBL_MIN 2.225073858507201e-308 #define DBL_MIN_10_EXP -307 #define DBL_MAX_EXP 1024 #define DBL_MAX 1.797693134862316e+308 #define DBL_MAX_10_EXP 308 #endif i8086 || m68k /* long double equates to double */ #define LDBL_MANT_DIG DBL_MANT_DIG #define LDBL_EPSILON DBL_EPSILON #define LDBL_DIG DBL_DIG #define LDBL_MIN_EXP DBL_MIN_EXP #define LDBL_MIN DBL_MIN #define LDBL_MIN_10_EXP DBL_MIN_10_EXP #define LDBL_MAX_EXP DBL_MAX_EXP #define LDBL_MAX DBL_MAX #define LDBL_MAX_10_EXP DBL_MAX_10_EXP #endif ================================================ FILE: dist/HITECH.H ================================================ #ifndef _HTC_HITECH_H #define _HTC_HITECH_H /* Standard types for HI-TECH Software code These types may need to be tuned for different machines/compilers. Notes with each one indicate assumptions that should be maintained for each type. */ /* Turn ANSI on if the compiler supports function prototypes and has the ANSI header files */ #if HI_TECH_C #define ANSI 1 #endif HI_TECH_C /* shorthand types */ #define uchar unsigned char #define ulong unsigned long #define ushort unsigned short /* useful, tuneable types. Change only if: 1) compiler does not support type, e.g. unsigned char. 2) compiler generates bad code for a particular type. 3) a larger type would generate faster code, e.g. byte counters on the 65816 are inefficient code-wise. */ #define BOOL unsigned char /* boolean variable. Any integral type will do. */ #define FAST char /* fast, small counter. Must permit values -128 to 127 but may be larger. */ #define UFAST unsigned char /* fast, small unsigned counter. Must permit values 0-255 at least */ #define BYTE unsigned char /* sizeof(BYTE) must == 1 */ #define INT_16 short /* signed, >= 16 bits */ #define UINT_16 unsigned short /* unsigned, >= 16 bits */ #define INT_32 long /* signed, >= 32 bits */ #define UINT_32 unsigned long /* unsigned, >= 32 bits */ /* Register variable selectors; REG1 is for things that must go in registers at all costs, REG2 for things that should, REG3 for things that could go in registers if there are any left over. Ordering of declarations will of course come into it too. */ #if z80 /* only has one register variable */ #define REG1 register #define REG2 auto #define REG3 auto #endif z80 #if i8086 /* only has two register variable */ #define REG1 register #define REG2 register #define REG3 auto #endif i8086 #if i8096 || m68k /* lots of registers! */ #define REG1 register #define REG2 register #define REG3 register #endif i8096 || m68k #endif ================================================ FILE: dist/LIMITS.H ================================================ #ifndef _HTC_LIMITS_H #define _HTC_LIMITS_H /* Characteristics of integral types */ #define CHAR_BIT 8 /* bits per char */ #define CHAR_MAX 127 /* max value of a char */ #define CHAR_MIN -128 /* min value */ #define SCHAR_MAX CHAR_MAX /* chars are signed */ #define SCHAR_MIN CHAR_MIN #define UCHAR_MAX 255 /* for unsigned chars */ #define SHRT_MAX 32767 /* max value of a short */ #define SHRT_MIN -32768 #define USHRT_MAX 65535 /* unsigned short */ #define INT_MAX 32767 /* max for int */ #define INT_MIN -32768 /* min for int */ #define UINT_MAX 65535 /* unsigned int */ #define LONG_MAX 2147483647 /* max value of long */ #define LONG_MIN -2147483648 /* min value */ #define ULONG_MAX 4294967295 /* unsigned long */ #endif ================================================ FILE: dist/MATH.H ================================================ #ifndef _HTC_MATH_H #define _HTC_MATH_H extern double fabs(double), floor(double), ceil(double), modf(double, double *); extern double sqrt(double), atof(char *); extern double sin(double), cos(double), tan(double); extern double asin(double), acos(double), atan(double), atan2(double, double); extern double frexp(double, int *), ldexp(double, int); extern double log(double), log10(double), pow(double, double), exp(double); extern double sinh(double), cosh(double), tanh(double); #endif ================================================ FILE: dist/OPTIONS ================================================ HI-TECH Z80 CP/M C compiler options: -A Generate a self-relocating .COM program. -C Generate object code only; don't link. -CR Produce a cross-reference listing e.g. -CRfile.crf -D Define a symbol, e.g. -DDEBUG=1 -E Specify executable output filename, e.g. -Efile.com -Ffile Generate a symbol file for debug.com or overlay build (default L.SYM) -H Output help (the OPTIONS file) and exit. -I Specify an include directory, e.g. -I1:B: -L Scan a library, e.g. -LF scans the floating point library. -M Generate a map file, e.g. -Mfile.map -N Use the NRTCPM.OBJ start-up with minimal _getargs(). -O Invoke the peephole optimizer (reduced code-size) -OF Invoke the optimizer for speed (Fast) -S Generate assembler code in a .AS file; don't assemble or link. -U Undefine a predefined symbol, e.g. -UDEBUG -V Be verbose during compilation. -W Set warning level, e.g. -w5 or -w-2 -X Suppress local symbols in symbol tables. -Y Generate an overlay output file (.OVR file-type) ================================================ FILE: dist/OVERLAY.H ================================================ #ifndef _HTC_OVERLAY_H #define _HTC_OVERLAY_H #include intptr_t ovrload(char *ovr_name,intptr_t args); #endif ================================================ FILE: dist/SETJMP.H ================================================ #ifndef _HTC_SETJMP_H #define _HTC_SETJMP_H #if z80 typedef int jmp_buf[4]; #endif #if i8086 typedef int jmp_buf[8]; #endif #if i8096 typedef int jmp_buf[10]; #endif #if m68k typedef int jmp_buf[10]; #endif extern int setjmp(jmp_buf); extern void longjmp(jmp_buf, int); #endif ================================================ FILE: dist/SIGNAL.H ================================================ #ifndef _HTC_SIGNAL_H #define _HTC_SIGNAL_H /* * Signal definitions for CP/M */ #ifdef unix #define NSIG 17 #define SIGHUP 1 /* hangup (not used by terminal driver) */ #define SIGINT 2 /* interrupt (^C or BREAK) */ #define SIGQUIT 3 /* quit (^\) */ #define SIGILL 4 /* illegal instruction (not reset when caught) */ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGIOT 6 /* IOT instruction */ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #else #define NSIG 1 #define SIGINT 1 /* control-C */ #endif typedef void* signal_t; #define SIG_DFL ((signal_t)0) /* default action is to exit */ #define SIG_IGN ((signal_t)1) /* ignore them */ signal_t signal(int sig, signal_t action); #endif ================================================ FILE: dist/STAT.H ================================================ #ifndef _HTC_STAT_H #define _HTC_STAT_H struct stat { short st_mode; /* flags */ long st_atime; /* access time */ long st_mtime; /* modification time */ long st_size; /* file size in bytes */ }; /* Flag bits in st_mode */ #define S_IFMT 0x600 /* type bits */ #define S_IFDIR 0x400 /* is a directory */ #define S_IFREG 0x200 /* is a regular file */ #define S_IREAD 0400 /* file can be read */ #define S_IWRITE 0200 /* file can be written */ #define S_IEXEC 0100 /* file can be executed */ #define S_HIDDEN 0x1000 /* file is hidden */ #define S_SYSTEM 0x2000 /* file is marked system */ #define S_ARCHIVE 0x4000 /* file has been written to */ extern int stat(char *, struct stat *); #endif ================================================ FILE: dist/STDARG.H ================================================ #ifndef _HTC_STDARG_H #define _HTC_STDARG_H /* Macros for accessing variable arguments */ typedef void * va_list[1]; #define va_start(ap, parmn) *ap = (char *)&parmn + sizeof parmn #define va_arg(ap, type) (*(*(type **)ap)++) #define va_end(ap) #endif ================================================ FILE: dist/STDDEF.H ================================================ #ifndef _HTC_STDDEF_H #define _HTC_STDDEF_H #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ #endif ================================================ FILE: dist/STDINT.H ================================================ #ifndef _HTC_STDINT_H #define _HTC_STDINT_H #if z80||i8086||i8096||m68k typedef unsigned char uint8_t; typedef char int8_t; typedef unsigned short uint16_t; typedef short int16_t; typedef unsigned long uint32_t; typedef long int32_t; typedef unsigned short intptr_t; #endif #endif ================================================ FILE: dist/STDIO.H ================================================ #ifndef _HTC_STDIO_H #define _HTC_STDIO_H /* * STDIO.H HI-TECH C standard I/O for V3.09-xx * * This version incorporates changes to stdio routines * resulting from backporting features from V4.11 */ #define _HTC_VERSION "3.09-20" #define _HTC_MAJOR 3 #define _HTC_MINOR 9 #define _HTC_REV 20 #if z80 #define BUFSIZ 512 #define _NFILE 8 #else z80 #define BUFSIZ 1024 #define _NFILE 20 #endif z80 #ifndef _STDDEF typedef int ptrdiff_t; typedef unsigned size_t; #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef FILE #define uchar unsigned char extern struct _iobuf { char *_ptr; int _cnt; char *_base; unsigned short _flag; char _file; size_t _size; } _iob[_NFILE]; #define FILE struct _iobuf #endif FILE #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif /* I/O status flag word bits */ #define _IOREAD 01 /* Allow file reading */ #define _IOWRT 02 /* Allow file writing */ #define _IORW 03 /* Mask for reading or writing */ #define _IONBF 04 /* Not being buffered */ #define _IOMYBUF 010 /* Using buffer */ #define _IOEOF 020 /* At end-of-file */ #define _IOERR 040 /* An I/O error has occurred */ #define _IOSTRG 0100 /* End of string reached */ #define _IOBINARY 0200 /* Binary mode */ #define _IOLBF 0400 /* Using line buffering */ #define _IODIRN 01000 /* Direction - writing to a R/W file */ #define _IOAPPEND 02000 /* Append mode */ #define _IOSEEKED 04000 /* A seek has occurred since last write */ #define _IOFBF 010000 /* Using full buffering */ #ifndef NULL #define NULL ((void *)0) #endif NULL #define EOF (-1) #define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2]) #define getchar() getc(stdin) #define putchar(x) putc(x,stdout) /* * getc() and putc() must be functions for CP/M to allow the special * handling of '\r', '\n' and '\032'. The same for MSDOS except that * it at least knows the length of a file. */ #if UNIX #define getc(p) (--(p)->_cnt>=0?(unsigned)*(p)->_ptr++:_filbuf(p)) #define putc(x,p) (--(p)->_cnt>=0?((unsigned)(*(p)->_ptr++=x)):_flsbuf((unsigned)(x),p)) #else UNIX #define getc(p) fgetc(p) #define putc(x,p) fputc(x,p) #endif UNIX #define feof(p) (((p)->_flag&_IOEOF)!=0) #define ferror(p) (((p)->_flag&_IOERR)!=0) #define fileno(p) ((uchar)p->_file) #define clrerr(p) p->_flag &= ~_IOERR #define clreof(p) p->_flag &= ~_IOEOF extern int fclose(FILE *); extern int fflush(FILE *); extern int fgetc(FILE *); extern int ungetc(int, FILE *); extern int fputc(int, FILE *); extern int getw(FILE *); extern int putw(int, FILE *); extern char *gets(char *); extern int puts(char *); extern int fputs(char *, FILE *); extern int fread(void *, unsigned, unsigned, FILE *); extern int fwrite(void *, unsigned, unsigned, FILE *); extern int fseek(FILE *, long, int); extern int rewind(FILE *); extern void setbuf(FILE *, char *); extern int setvbuf(FILE *, char *, int, size_t); extern int printf(char *, ...); extern int fprintf(FILE *, char *, ...); extern int sprintf(char *, char *, ...); extern int scanf(char *, ...); extern int fscanf(FILE *, char *, ...); extern int sscanf(char *, char *, ...); extern int remove(char *); extern FILE *fopen(char *, char *); extern FILE *freopen(char *, char *, FILE *); extern FILE *fdopen(int, char *); extern long ftell(FILE *); extern char *fgets(char *, int, FILE *); extern char *_bufallo(void); #endif _HTC_STDIO_H ================================================ FILE: dist/STDLIB.H ================================================ #ifndef _HTC_STDLIB_H #define _HTC_STDLIB_H /* Standard utility functions */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #define _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ #endif _STDDEF #define RAND_MAX 32767 /* max value returned by rand() */ extern double atof(char *); extern int atoi(char *); extern long atol(char *); extern int rand(void); extern void srand(unsigned int); extern void *calloc(size_t, size_t); extern void free(void *); extern void *malloc(size_t); extern void *realloc(void *, size_t); extern void abort(void); extern void exit(int); extern char *getenv(char *); extern int system(char *); typedef int (*__qsort_compf)(void *, void *); /* workaround compiler bug */ extern void qsort(void *, size_t, size_t, __qsort_compf); extern int abs(int); extern long labs(long); #endif ================================================ FILE: dist/STRING.H ================================================ #ifndef _HTC_STRING_H #define _HTC_STRING_H /* String functions v3.09-4 */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ extern void *memcpy(void *, void *, size_t); extern void *memmove(void *, void *, size_t); extern char *strcpy(char *, char *); extern char *strncpy(char *, char *, size_t); extern char *strcat(char *, char *); extern char *strncat(char *, char *, size_t); extern int memcmp(void *, void *, size_t); extern int strcmp(char *, char *); extern int strcasecmp(char *, char *); #define stricmp strcasecmp extern int strncmp(char *, char *, size_t); extern int strncasecmp(char *, char *, size_t); #define strnicmp strncasecmp /* extern size_t strcoll(char *, size_t, char *); */ /* missing */ extern void *memchr(void *, int, size_t); /* extern size_t strcspn(char *, char *); */ /* missing */ /* extern char *strpbrk(char *, char *); */ /* missing */ /* extern size_t strspn(char *, char *); *//* missing */ extern char *strstr(char *, char *); extern char *strtok(char *, char *); extern void *memset(void *, int, size_t); extern char *strerror(int); extern size_t strlen(char *); extern char *strchr(char *, int); /* #define index strchr */ /* these are equivalent */ extern char *index(char *, int); extern char *strrchr(char *, int); /* #define rindex *strrchr */ /* these are equivalent */ extern char *rindex(char *, int); extern char *strcasestr(char *, char *); #define stristr strcasestr extern char *strncasestr(char *, char *, size_t); #define strnistr strncasestr #endif ================================================ FILE: dist/SYS.H ================================================ #ifndef _HTC_SYS_H #define _HTC_SYS_H /* * System-dependent functions. */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ extern int execl(char *, char *, char *, ...); extern int execv(char *, char **); extern int spawnl(char *, char *, char *, ...); extern int spawnv(char *, char **); extern int spawnle(char *, char *, char *, char *, ...); extern int spawnve(char *, char **, char *); extern short getuid(void); extern short setuid(short); extern int chdir(char *); extern int mkdir(char *); extern int rmdir(char *); extern int getcwd(int); extern char **_getargs(char *, char *); extern int _argc_; extern int inp(int); extern void outp(int, int); extern void * sbrk(size_t); #endif ================================================ FILE: dist/TIME.H ================================================ #ifndef _HTC_TIME_H #define _HTC_TIME_H /* time.h for HI-TECH C Z80 v3.09-4*/ #ifndef _HTC_TIME_T typedef long time_t; /* for representing times in seconds */ struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; #define _HTC_TIME_T #endif _HTC_TIME_T #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif extern int time_zone; /* minutes WESTWARD of Greenwich */ /* this value defaults to 0 since with operating systems like MS-DOS there is no time zone information available */ extern time_t time(time_t *); /* seconds since 00:00:00 Jan 1 1970 */ extern char * asctime(struct tm *); /* converts struct tm to ascii time */ extern char * ctime(time_t *); /* current local time in ascii form */ extern struct tm * gmtime(time_t *); /* Universal time */ extern struct tm * localtime(time_t *); /* local time */ extern size_t strftime(char *s, size_t maxs, char *f, struct tm *t); extern time_t mktime(struct tm *); /* convert struct tm to time value */ #endif ================================================ FILE: dist/UNIXIO.H ================================================ #ifndef _HTC_UNIXIO_H #define _HTC_UNIXIO_H /* * Declarations for Unix style low-level I/O functions. */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ extern int open(char *, int); extern int close(int); extern int creat(char *, int); extern int dup(int); extern long lseek(int, long, int); extern int read(int, void *, int); extern int rename(char *, char *); extern int unlink(char *); extern int write(int, void *, int); extern int isatty(int); extern int chmod(char *, int); #endif ================================================ FILE: doc/DEBUGMAN.TXT ================================================ 1. Debugger Reference Manual HI-TECH C is supplied with an interactive debugging tool oriented toward C programs. It is not a "source level" debugger, i.e. it has no knowledge of the C source code, however it does have the facility to handle C symbols and to show the C function calling sequence. The command structure is modelled on that of the Unix debugger known as adb. It provides facilities to display memory in various radices or as instructions, to set and remove breakpoints, which may have a repeat count and/or a command associated with them. It is possible to set a break- point which will stop only if a certain condition is true. The debugger may be used on any .COM file, however in order to take advantage of the symbolic facilities, it is necessary to generate a symbol file, usually with the -F option to the C command. This file consists of one line per symbol, with the hexadecimal value of the symbol preceding the symbol on the line. 1.1. Invoking Debug The debugger is invoked by the command DEBUG. It may have zero, one or two file arguments. The first argument is the name of a file in .COM format to be be debugged, and the second a symbol file name. If the symbol file name is omit- ted, no symbols will be available. If the .COM format file is omitted, no code will be loaded. Some examples: DEBUG fred.com DEBUG bill.com l.sym 1.2. Run Time Organization DEBUG relocates itself below the BDOS when executed, allowing the debugee to be loaded at the start of the TPA, as usual. The symbol table, if loaded, grows downwards from the base of the relocated debugger. The BDOS entry at loca- tion 5 is changed to reflect the base of the symbol table rather than the base of the BDOS. Thus the symbol table and the debugger are not owerwritten by the debugee's stack. Breakpoints are inserted in the code as RST 8 instruc- tions. A jump is placed at location 8 to the debugger's trap handler. This is unfortunate if your system happens to use RST 8 for interrupts, but this is probably no more likely than that it uses any other restart location. Page 2 HI-TECH C (Z80) USER'S MANUAL 1.3. Commands The basic debugger command syntax is: address , count command modifier extrastuff This may seem a little obscure, so read on. Address and count are expressions, in their simplest form simply hexade- cimal numbers. Both address and count are optional, but if count is to be specified with no address, the comma must appear. Command is a single character specifying what the com- mand should do. Modifier is another character which deter- mines more specifically what the command is. Extrastuff is dependent on the particular command, and is usually omitted. 1.3.1. Expressions Expressions may consist of: . The value of the current location (not necessarily the current PC or last breakpoint, this is an internal current value). SYMBOL The value of a symbol, as looked up in the symbol table. If the symbol is not found, the same symbol prepended by and underscore will be looked for. This allows C symbols to be referred to without the leading underscore tacked on by the compiler. INTEGER A hexadecimal integer. It must start with a digit, oth- erwise the debugger will think it is a symbol. allows the values of registers to be changed. Both word and byte registers may be specified. The interrupt flag may also be changed. 0 means off, 1 means on. 1.4. Example An example of the use of the debugger follows: A>type tst.c main() { int i, j; scanf("%d", &i); printf("%d\n", j); Note the error - j should be i } A>c -f tst.c Compile requesting a symbol file Page 6 HI-TECH C (Z80) USER'S MANUAL A>debug tst.com l.sym Default symbol file name is l.sym ZDEBUG : printf/i Disassemble at printf _printf: call csv : Step down with RETURN _printf+3: push ix : :b Set a breakpoint here : :r Run the program - no arguments 123 Scanf waits for input - enter 123 Breakpoint _printf+3 _printf+3: push ix Stopped at the breakpoint : $c Get a stack trace _printf(1872,0) 1872 is the format string "d\n" _main() : main/i Look at main() now _main: call csv : Step down with RETURN _main+3: ld hl,FFFC : _main+6: add hl,sp : ,10 Disassemble 16 instructions _main+7: ld sp,hl _main+8: push ix _main+A: pop hl _main+B: dec hl _main+C: dec hl _main+D: push hl _main+E: ld hl,186F _main+11: push hl _main+12: call _scanf _main+15: ld hl,4 _main+18: add hl,sp _main+19: ld sp,hl _main+1A: ld l,(ix+-4) here j is loaded _main+1D: ld h,(ix+-3) _main+20: push hl And pushed onto the stack _main+21: ld hl,1872 : main+1a/i _main+1A: ld l,(ix+-4) : /h Look at the bytes as hex _main+1A: DD Indexing prefix byte : Step down with RETURN _main+1B: 6E : _main+1C: FC The index offset = -4 : /w 0fe Change to -2 : _main+1D: DD : _main+1E: 66 : _main+1F: FD : /w 0ff Change the hi byte to -1 to address i instead of j : :r Run it again HI-TECH C (Z80) USER'S MANUAL Page 7 123 Enter the same number again Breakpoint _printf+3 _printf+3: push ix : $c _printf(1872,7B) _main() : 7b=d 7b was the argument above 123 Now we have the correct value : :c Continue the program 123 Which prints the correct value A> ================================================ FILE: doc/HTCZ80.TXT ================================================ HI-TECH C USER'S MANUAL i CONTENTS 1. Introduction 1 1.1. Features 1 1.2. System Requirements 2 1.3. Using this Manual 2 2. Getting Started 3 3. Compiler Structure 5 4. Operating Details 7 5. Specific Features 13 5.1. ANSI C Standard Compatibility 13 5.2. Type Checking 13 5.3. Member Names 13 5.4. Unsigned Types 14 5.5. Arithmetic Operations 14 5.6. Structure Operations 15 5.7. Enumerated Types 16 5.8. Initialization Syntax 16 5.9. Function Prototypes 17 5.10. Void and Pointer to Void 18 5.11. Type qualifiers 19 5.12. In-line Assembler 20 5.13. Pragma Directives 20 6. Machine Dependencies 21 6.1. Predefined Macros 21 7. Error Checking and Reporting 23 8. Standard Libraries 25 8.1. Standard I/O 25 8.2. Compatibility 25 8.3. Libraries for Embedded Systems 25 8.4. Binary I/O 26 8.5. Floating Point Library 27 9. Stylistic Considerations 29 9.1. Member Names 29 9.2. Use of Int 30 9.3. Extern Declarations 30 10. Memory Models 31 11. What Went Wrong 33 12. Z80 Assembler Reference Manual 35 12.1. Introduction 35 12.2. Usage 35 12.3. The Assembly Language 36 12.3.1. Symbols 36 12.3.1.1. Temporary Labels 37 12.3.2. Constants 37 12.3.2.1. Character Constants 38 ii HI-TECH C USER'S MANUAL 12.3.2.2. Floating Constants 38 12.3.2.3. Opcode Constants 38 12.3.3. Expressions 38 12.3.3.1. Operators 38 12.3.3.2. Relocatability 39 12.3.4. Pseudo-ops 40 12.3.4.1. DEFB, DB 40 12.3.4.2. DEFF 41 12.3.4.3. DEFW 41 12.3.4.4. DEFS 41 12.3.4.5. EQU 41 12.3.4.6. DEFL 41 12.3.4.7. DEFM 42 12.3.4.8. END 42 12.3.4.9. COND, IF, ELSE, ENDC 42 12.3.4.10. ELSE 42 12.3.4.11. ENDC 42 12.3.4.12. ENDM 43 12.3.4.13. PSECT 43 12.3.4.14. GLOBAL 43 12.3.4.15. ORG 44 12.3.4.16. MACRO 44 12.3.4.17. LOCAL 45 12.3.4.18. REPT 46 12.3.5. IRP and IRPC 47 12.3.6. Extended Condition Codes 48 12.4. Assembler Directives 48 12.5. Diagnostics 49 12.6. Z80/Z180/64180 Instruction Set 50 13. Linker Reference Manual 69 13.1. Relocation and Psects 69 13.1.1. Program Sections 69 13.1.2. Local Psects and the Large Model 70 13.2. Global Symbols 70 13.3. Operation 71 13.4. Examples 74 13.5. Invoking the Linker 74 14. Librarian 75 14.1. The Library Format 75 14.2. Using 75 14.3. Examples 76 14.4. Supplying Arguments 77 14.5. Listing Format 77 14.6. Ordering of Libraries 77 14.7. Error Messages 78 15. Objtohex 79 16. Cref 83 APPENDIX 1 Error Messages 85 APPENDIX 2 Standard Library Functions 99 INDEX 165 HI-TECH C COMPILER User's Manual March 1989 1. Introduction The HI-TECH C Compiler is a set of software which translates programs written in the C language to executable machine code programs. Versions are available which compile programs for operation under the host operating system, or which produce programs for execution in embedded systems without an operating system. 1.1. Features Some of HI-TECH C's features are: A single command will compile, assemble and link entire programs. The compiler performs strong type checking and issues warnings about various constructs which may represent programming errors. The generated code is extremely small and fast in exe- cution. A full run-time library is provided implementing all standard C input/output and other functions. The source code for all run-time routines is provided. A powerful general purpose macro assembler is included. Programs may be generated to execute under the host operating system, or customized for installation in ROM. PC-DOS/MS-DOS CP/M-86 Concurrent DOS Atari ST Xenix Unix CP/M-80 Table 1. Supported Hosts Page 2 HI-TECH C USER'S MANUAL 1.2. System Requirements The HI-TECH C Compilers operate under the operating systems listed in table 1. Ensure that the version of the compiler you have matches the system you have. Note that in general you must have a hard disk or two floppy disks on your system (it is possible to use one floppy disk of 800K or more). A hard disk is strongly recommended. Note that the CP/M-80 native compiler does not have all the features described in this manual, as it has not been upgraded past V3.09 due to memory limitations. The Z80 cross compiler does support all of the features described here and can be used to generate programs to execute under CP/M-80. 1.3. Using this Manual The documentation supplied with the HI-TECH C compiler comprises two separate manuals within the one binder. The manual you are reading now covers all versions of the com- piler (reflecting the portable nature of the compiler). A separate manual covers machine dependent aspects of your compiler, e.g. installation. This manual assumes you are familiar with the C language already. If you are not, you should have at least one reference book covering C, of which a large number are available from most computer bookstores, e.g. "A Book on C" by Kelley and Pohl. Other suitable texts are "Programming in ANSI C" by S. Kochan and "The C Programming Language", by Kernighan and Ritchie. You should read the "Getting Started" chapter in this manual, and the "Installation" chapter in the machine-specific manual. This will provide you with sufficient information to work through the introductory examples in the C reference you are using. Once you have a basic grasp of the C language, the remainder of this manual will provide you with information to enable you to explore the more advanced aspects of C. Most of the manual covers all implementations of the HI-TECH C compiler. A separate manual is provided for the macro assembler for your particular machine, and other machine-dependent information. HI-TECH C USER'S MANUAL Page 3 2. Getting Started If using the compiler on a hard disk system you will need to install the compiler before using it. See the "Installation" chapter for more details. If using a floppy disk based system, in general you should have a copy of the distribution disk #1 in drive A: and maintain your files on a disk in the B: drive. Again see the "Installation" chapter for more information. main() { printf("Hello, world\n"); } Fig. 1. Sample C Program Before compiling your program it must be contained in a file with an extension (or file type, i.e. that part of the name after the '.') of .C. For example you may type the program shown in fig. 1 into a file called HELLO.C. You will need a text editor to do this. Generally any text editor that can create a straight ASCII file (i.e. not a "word pro- cessor" type file) will be suitable. If using editors such as Wordstar, you should use the "non-document mode". Once you have the program in such a file all that is required to compile it is to issue the C command, e.g. to compile HELLO.C simply type the command C -V HELLO.C Cross compilers (i.e. compilers that operate on one system but produce code for a separate target system) will have a compiler driver named slightly differently, e.g. the 68HC11 cross compiler driver is called C68. If you are using a floppy disk based system (or a CP/M system) it may be necessary to specify where to find the C command, e.g. if the C command is on a disk in drive A: and you are working on B:, type the command A:C -V HELLO.C The compiler will issue a sign on message, then proceed to execute the various passes of the compiler in sequence to compile the program. If you are using a floppy disk based system where the compiler will not fit on a single disk you will be prompted to change disks whenever the compiler can- not find a pass. In this case you should insert a copy of the next distribution disk in drive A: and press RETURN. As each pass of the compiler is about to be executed, a command line to that pass will be displayed on the screen. Page 4 HI-TECH C USER'S MANUAL This is because the -V option has been used. This stands for Verbose, and had it not been given the compilation would have been silent except for the sign on message. Error mes- sages can be redirected to a file by using the standard out- put redirection notation, e.g. > somefile. After completion of compilation, the compiler will exit to command level. You will notice that several temporary files created during compilation will have been deleted, and all that will be left on the disk (apart from the original source file HELLO.C) will be an executable file. The name of this executable file will be HELLO.EXE for MS-DOS, HELLO.PRG for the Atari ST, HELLO.COM for CP/M-80 and HELLO.CMD for CP/M-86. For cross compilers it will be called HELLO.HEX or HELLO.BIN depending on the default output format for the particular compiler. To execute this program, simply type HELLO and you should be rewarded with the message "Hello, world!" on your screen. If you are using a cross compiler you will need to put the program into EPROM or download to the target system to execute it. Cross compilers do not produce pro- grams executable on the host system. There are other options that may be used with the C command, but you will not need to use them unless you wish to do so. If you are new to the C language it will be advis- able to enter and compile a few simple programs (e.g. drawn from one of the C reference texts mentioned above) before exploring other capabilities of the HI-TECH C compiler. There is one exception to the above; if you compile a program which uses floating point arithmetic (i.e. real numbers) you MUST specify to the compiler that the floating point library should be searched. This is done with a -LF option at the END of the command line, e.g. C -V FLOAT.C -LF HI-TECH C USER'S MANUAL Page 5 3. Compiler Structure The compiler is made up of several passes; each pass is implemented as a separate program. Note that it is not necessary for the user to invoke each pass individually, as the C command runs each pass automatically. Note that the machine dependent passes are named differently for each pro- cessor, for example those with 86 in their name are for the 8086 and those with 68K in their name are for the 68000. The passes are: CPP The pre-processor - handles macros and conditional com- pilation P1 The syntax and semantic analysis pass. This writes intermediate code for the code generator to read. CGEN, CG86 etc. The code generator - produces assembler code. OPTIM, OPT86 etc. The code improver - may optionally be omitted, reducing compilation time at a cost of larger, slower code pro- duced. ZAS, AS86 etc. The assembler - in fact a general purpose macro assem- bler. LINK The link editor - links object files with libraries. OBJTOHEX This utility converts the output of LINK into the appropriate executable file format (e.g. .EXE or .PRG or .HEX). The passes are invoked in the order given. Each pass reads a file and writes a file for its successor to read. Each intermediate file has a particular format; CPP produces C code without the macro definitions and with uses of macros expanded; P1 writes a file containing a program in an inter- mediate code; CGEN translates this to assembly code; AS pro- duces object code, a binary format containing code bytes along with relocation and symbol information. LINK accepts object files and libraries of object files and writes another object file; this may be in absolute form or it may preserve relocation information and be input to another LINK command. There are also other utility programs: LIBR Creates and maintains libraries of object modules Page 6 HI-TECH C USER'S MANUAL CREF Produces cross-reference listings of C or assembler programs. HI-TECH C USER'S MANUAL Page 7 4. Operating Details HI-TECH C was designed for ease of use; a single com- mand will compile, assemble and link a C program. The syntax of the C command is as follows: C [ options ] files [ libraries ] The options are zero or more options, each consisting of a dash ('-'), a single key letter, and possibly an argu- ment following the key letter with no intervening space. The files are one or more C source files, assembler source files, or object files. Libraries may be zero or more library names, or the abbreviated form -lname which will be expanded to the library name libname.lib. The C command will, as determined by the specified options, compile any C source files given, assemble them into object code unless requested otherwise, assemble any assembler source files specified, then link the results of the assemblies with any object or library files specified. If the C command is invoked without arguments, then it will prompt for a command line to be entered. This command line may be extended by typing a backslash ('\') on the end of the line. Another line will then be requested. If the standard input of the command is from a file (e.g. by typing C < afile) then the command lines will be read from that file. Within the file more than one line may be given if each line but the last ends with a backslash. Note that this mechanism does not work in MS-DOS batch file, i.e. the com- mand file for the C command must be a separate file. MS-DOS has no mechanism for providing long command lines or stan- dard input from inside a batch file. The options recognized by the C command are as follows: -S Leave the results of compilation of any C files as assembler output. C source code will be interspersed as comments in the assembler code. -C Leave the results of all compiles and assemblies as object files; do not invoke the linker. This allows the linker to be invoked separately, or via the C command at a later stage. -CR Produce a cross reference listing. -CR on its own will leave the raw cross-reference information in a tem- porary file, allowing the user to run CREF explicitly, while supplying a file name, e.g. -CRFRED.CRF will cause CREF to be invoked to process the raw information into the specified file, in this case FRED.CRF. -CPM For the Z80 cross compiler only, produce CP/M-80 COM files. Unless the -CPM option is given, the Z80 cross Page 8 HI-TECH C USER'S MANUAL compiler uses the ROM runtime startoff module and pro- duces hex or binary images. If the -CPM option is given, CP/M-80 runtime startoff code is linked used and a CP/M-80 COM file is produced. -O Invoke the optimizer on all compiled code; also requests the assembler to perform jump optimization. -OOUTFILE Specify a name for the executable file to be created. By default the name for the executable file is derived from the name of the first source or object file speci- fied to the compiler. This option allows the default to be overridden. If no dot ('.') appears in the given file name, an extension appropriate for the particular operating system will be added, e.g. -OFRED will gen- erate a file FRED.EXE on MS-DOS or FRED.CMD on CP/M-86. For cross compilers this also provides a means for specifying the output format, e.g. specifying an output file PROG.BIN will make the compiler generate a binary file, while specifying PROG.HEX will make it generate a hexadecimal file. -V Verbose: each step of the compilation will be echoed as it is executed. -I Specify an additional filename prefix to use in search- ing for #include files. For CP/M the default prefix is 0:A: (user number 0, disk drive A). For MS-DOS the default prefix is A:\HITECH\. Under Unix and Xenix the default prefix is /usr/hitech/include/. Note that on MS-DOS a trailing backslash must be appended to any directory name given as an argument to -I; e.g. -I\FRED\ not -I\FRED. Under Unix a trailing slash should be added. -D Define a symbol to the preprocessor: e.g. -DCPM will define the symbol CPM as though via #define CPM 1. -U Undefine a pre-defined symbol. The complement of -D. -F Request the linker to produce a symbol file, for use with the debugger. -R For the Z80 CP/M compiler only this option will link in code to perform command line I/O redirection and wild card expansion in file names. See the description of _getargs() in appendix 5 for details of the syntax of the redirections. -X Strip local symbols from any files compiled, assembled or linked. Only global symbols will remain. -M Request the linker to produce a link map. -A This option, for the Z80 only, will cause the compiler to produce an executable program that will, on execu- tion, self-relocate itself to the top of the TPA HI-TECH C USER'S MANUAL Page 9 (Transient Program Area). This allows the writing of programs which may execute other programs under them- selves. Note that a program compiled in such a manner will not automatically reset the bdos address at loca- tion 6 in order to protect itself. This must be done by the program itself. For cross compilers this provides a way of specifying to the linker the addresses that the compiled program is to be linked at. The format of the option is -AROMADR,RAMADR,RAMSIZE. ROMADR is the address of the ROM in the system, and is where the executable code and initialized data will be placed. RAMADR is the start address of RAM, and is where the bss psect will be placed, i.e. uninitialized data. RAMSIZE is the size of RAM available to the program, and is used to set the top of the stack. For the 6801/6301/68HC11 compiler, the -A option takes a fourth value which is the address of a four byte direct page area called ctemp which the compiled code uses as a scratch pad. If the ctemp address is omitted from the -A option, it defaults to address 0. Normally this will be acceptable, however some 6801 variants (like the 6303) have memory mapped I/O ports at address 0 and start their direct page RAM at address $80. For the large memory model of the 8051 compiler, the -A option takes the form -AROMADR,INTRAM,EXTRAM,EXTSIZE. ROMADR is the address of ROM in the system. INTRAM is the start address of internal RAM, and is where the rbss psect will be placed. The 8051 internal stack will start after the end of the rbss psect. EXTRAM is the start address of external RAM, and is where the bss psect will be placed. EXTSIZE is the size of external RAM available to the program, and is used to set the top of the external stack. -B For compilers which support more than one "memory model", this option is used to select which memory model code is to be generated for. The format of this option is -Bx where x is one or more letters specifying which memory model to use. For the 8086, this option is used to select which one of five memory models (Tiny, Small, Medium, Compact or Large) is to be used. For the 8051 compiler this this option is used to select which one of the three memory models (Small, Medium or Large) is to be used. For the 8051 compiler only, this option can also be used to select static allocation of auto variables by appending an A to the end of the -B option. For example, -Bsa would select small model with static allocation of all variables, while -Bm would select medium model with auto variables dynamically allocated on the stack. Page 10 HI-TECH C USER'S MANUAL -E By default the 8086 compiler will initialize the exe- cutable file header to request a 64K data segment at run time. This may be overridden by the -E option. It takes an argument (usually in hexadecimal representa- tion) which is the number of BYTES (not paragraphs) to be allocated to the program at run time. For example -E0ffff0h will request a megabyte. Since this much will not be available, the operating system will allocate as much as it can. -W This options sets the warning level, i.e. it determines how picky the compiler is about legal but dubious type conversions etc. -W0 will allow all warning messages (default), -W1 will suppress the message "Func() declared implicit int". -W3 is recommended for compil- ing code originally written with other, less strict, compilers. -W9 will suppress all warning messages. -H This option generates a symbol file for use with debuggers. The format of the symbol file is described elsewhere. The default name of the symbol file is l.sym. An alternate name may be specfied with the option, e.g. -Hsymfile.abc. -G Like -H, -G also generates a symbol file, but one that contains line and file number information for a source level debugger. Like -H a file name may be specified. When used in conjunction with -O, only partial optimi- zation will be performed to avoid confusing the debugger. -P Execution profiling is available on native compilers running under DOS, CP/M-86 and on the Atari ST. This option generates code to turn on execution profiling when the program is run. A -H option should also be specified to provide a symbol table for the profiler EPROF. -Z For version 5.xx compilers only, the -Z option is used to select global optimization of the code generated. For the 8086 and 6801/6301/68HC11 compilers the only valid -Z option is -Zg. For the 8051 compiler, the valid -Z options are -Zg which invokes global optimiza- tion, -Zs which optimizes for space, and -Zf which optimizes for speed. The s and f options may be used with the g option, thus the options -Zgf and -Zgs are valid. Speed and space optimization are mutually exclusive, i.e. the s and f options cannot be used together. -1 For the 8086 compiler only, request the generation of code which takes advantage of the extra instructions of the 80186 processor. A program compiled with -1 will not execute on an 8086 or 8088 processor. For the 68000 compiler, generate instructions for the 68010 proces- sor. HI-TECH C USER'S MANUAL Page 11 -2 Like -1 but for the 80286 and 68020. -11 For the 6801/HC11 compiler, this option will request generation of instructions specific to the 68HC11 pro- cessor. -6301 For the 6801/HC11 compiler, this option will request generation of instructions specific to the 6301/6303 processors. Some examples of the use of the C command are: c prog.c c -mlink.map prog.c x.obj -lx c -S prog.c c -O -C -CRprog.crf prog.c prog2.c c -v -Oxfile.exe afile.obj anfile.c -lf Upper and lower case has been used in the above exam- ples for emphasis: the compiler does not distinguish between cases, although arguments specifying names, e.g. -D, are inherently case sensitive. Taking the above examples in order; the first compiles and links the C source file prog.c with the standard C library. The second example will compile the file prog.c and link it with the object file x.obj and the library libx.lib; a link map will be written to the file link.map. The third example compiles the file prog.c, leaving the assembler output in a file prog.as. It does not assemble this file or invoke the linker. The next example compiles both prog.c and prog2.c, invoking the optimizer on both files, but does not perform any linking. A cross reference listing will be left in the file prog.crf. The last example pertains to the 8086 version of the compiler, It runs the compiler with the verbose option, and will cause anfile.c to be compiled without optimization to object code, yielding anfile.obj, then afile.obj and anfile.obj will be linked together with the floating point library (from the -LF option) and the standard library to yield the executable program xfile.exe (assuming this is performed on an MS-DOS system). One would expect this pro- gram to use floating point, if it did not then the -LF option would have been required. If more than one C or assembler source file is given to the C command, the name of each file will be printed on the console as it is processed. If any fatal errors occur dur- ing the compilation or assembly of source files, further source files will be processed, but the linker will not be Page 12 HI-TECH C USER'S MANUAL invoked. Other commands which may be issued by the user, rather than automatically by the C command, are: ZAS The Z80 assembler. AS86 The 8086 assembler. LINK The linker LIBR The library maintainer OBJTOHEX Object to hex converter CREF Cross reference generator. In general, these commands accept the same type of com- mand line as the C command, i.e. zero or more options (indi- cated by a leading '-') followed by one or more file argu- ments. If the linker or the librarian is invoked with no arguments, it wll prompt for a command line. This allows command lines of more than 128 bytes to be entered. Input may also be taken from a file by using the redirection capa- blities (see _getargs() in the library function listing). See the discussion above of the C command. These commands are described in further detail in their respective manuals. HI-TECH C USER'S MANUAL Page 13 5. Specific Features The HI-TECH C compiler has a number of features, which while largely compatible with other C compilers, contribute to more reliable programming methods. 5.1. ANSI C Standard Compatibility At the time of writing the Draft ANSI Standard for the C Language was at an advanced stage, though not yet an offi- cial standard. Accordingly it is not possible to claim com- pliance with that standard, however HI-TECH C includes the majority of the new and altered features in the draft ANSI standard. Thus it is in the sense that most people under- stand it "ANSI compatible". 5.2. Type Checking Previous C compilers have adopted a lax approach to type checking. This is typified by the Unix C compiler, which allows almost arbritary mixing of types in expres- sions. The HI-TECH C compiler performs much more strict type checking, although in most cases only warning messages are issued, allowing compilation to proceed if the user knows that the errors are harmless. This would occur, for example, when an integer value was assigned to a pointer variable. The generated code would almost certainly be what the user intended, however if in fact it represented an error in the source code, the user is prompted to check and correct it where necessary. 5.3. Member Names In early C compilers member names in different struc- tures were required to be distinct except under certain cir- cumstances. HI-TECH C, like most recent implementations of C, allows member names in different structures and unions to overlap. A member name is recognized only in the context of an expression whose type is that of the structure in which the member is defined. In practice this means that a member name will be recognized only to the right of a '.' or '->' operator, where the expression to the left of the operator is of type structure or pointer to structure the same as that in which the member name was declared. This not only allows structure names to be re-used without conflict in more than one structure, it permits strict checking of the usage of members; a common error with other C compilers is the use of a member name with a structure pointer of the wrong type, or worse with a variable which is a pointer to a simple type. There is however an escape from this, where the user desires to use as a structure pointer something which is not declared as such. This is via the use of a typecast. For example, suppose it is desired to access a memory-mapped i/o device, consisting of several registers. The declarations Page 14 HI-TECH C USER'S MANUAL and use may look something like the code fragment in fig. 2. struct io_dev { short io_status; /* status */ char io_rxdata; /* rx data */ char io_txdata; /* tx data */ }; #define RXRDY 01 /* rx ready */ #define TXRDY 02 /* tx ready */ /* define the (absolute) device address */ #define DEVICE ((struct io_dev *)0xFF00) send_byte(c) char c; { /* wait till transmitter ready */ while(!(DEVICE->io_status & TXRDY)) continue; /* send the data byte */ DEVICE->io_txdata = c; } Fig. 2. Use of Typecast on an Absolute Address In this example, the device in question has a 16 bit status port, and two 8 bit data ports. The address of the device (i.e. the address of its status port) is given as (hex)0FF00. This address is typecast to the required struc- ture pointer type to enable use of the structure member names. The code generated by this will use absolute memory references to access the device, as required. Some examples of right and wrong usage of member names are shown in fig. 3. 5.4. Unsigned Types HI-TECH C implements unsigned versions of all integral types; i.e. unsigned char, short, int and long. If an unsigned quantity is shifted right, the shift will be per- formed as a logical shift, i.e. bringing zeros into the rightmost bits. Similarly right shifts of a signed quantity will sign extend the rightmost bits. 5.5. Arithmetic Operations On machines where arithmetic operations may be per- formed more efficiently in lengths shorter than int, operands shorter than int will not be extended to int length unless necessary. For example, if two characters are added and the result stored into another character, it is only necessary to HI-TECH C USER'S MANUAL Page 15 struct fred { char a; int b; } s1, * s2; struct bill { float c; long b; } x1, * x2; main() { /* wrong - c is not a member of fred */ s1.c = 2; /* correct */ s1.a = 2; /* wrong - s2 is a pointer */ s2.a = 2; /* correct */ x2->b = 24L; /* right, but note type conversion from long to int */ s2->b = x2->b; } Fig. 3. Examples of Member Usage perform arithmetic in 8 bits, since any overflow into the top 8 bits will be lost. However, if the sum of two charac- ters is stored into an int, the addition should be done in 16 bits to ensure the correct result. In accordance with the draft ANSI standard, operations on float rather than double quantities will be performed in the shorter precision rather than being converted to double precision then back again. 5.6. Structure Operations HI-TECH C implements structure assignments, structure arguments and structure-valued functions in their full gen- erality. The example in fig. 4 is a function returning a structure. Some legal (and illegal) uses of the function are also shown. Page 16 HI-TECH C USER'S MANUAL struct bill { char a; int b; } afunc() { struct bill x; return x; } main() { struct bill a; a = afunc(); /* ok */ pf("%d", afunc().a); /* ok */ /* illegal, afunc() cannot be assigned to, therefore neither can afunc().a */ afunc().a = 1; /* illegal, same reason */ afunc().a++; } Fig. 4. Example of a Function Returning a Structure 5.7. Enumerated Types HI-TECH C supports enumerated types; these provide a structured way of defining named constants. The uses of enumerated types are more restricted than that allowed by the Unix C compiler, yet more flexible than permitted by LINT. In particular, an expression of enumerated type may be used to dimension arrays, as an array index or as the operand of a switch statement. Arithmetic may be performed on enumerated types, and enumerated type expressions may be compared, both for equality and with the relation operators. An example of the use of an enumerated type is given in fig. 5. 5.8. Initialization Syntax Kernighan and Ritchie in "The C Programming Language" state that pairs of braces may be omitted from an initial- izer in certain contexts; the draft ANSI standard provides that a conforming C program must either include all braces in an initializer, or leave them all out. HI-TECH C allows any pairs of braces to be omitted providing that the front end of the compiler can determine the size of any arrays being initialized, and providing that there is no ambiguity as to which braces have been omitted. To avoid ambiguity if any pairs of braces are present then any braces which would HI-TECH C USER'S MANUAL Page 17 /* a represents 0, b -> 1 */ enum fred { a, b, c = 4 }; main() { enum fred x, y, z; x = z; if(x < z) func(); x = (enum fred)3; switch(z) { case a: case b: default: } } Fig. 5. Use of an Enumerated Type enclose those braces must also be present. The compiler will complain ("initialization syntax") if any ambiguity is present. 5.9. Function Prototypes A new feature of C included in the proposed ANSI for C, known as "function prototypes", provides C with an argument checking facility, i.e. it allows the compiler to check at compile time that actual arguments supplied to a function invocation are consistent with the formal parameters expected by the function. The feature allows the programmer to include in a function declaration (either an external declaration or an actual definition) the types of the param- eters to that function. For example, the code fragment shown in fig. 6 shows two function prototypes. void fred(int, long, char *); char * bill(int a, short b, ...) { return a; } Fig. 6. Function Prototypes The first prototype is an external declaration of the function fred(), which accepts one integer argument, one long argument, and one argument which is a pointer to char. Any usage of fred() while the prototype declaration is in scope will cause the actual parameters to be checked for number and type against the prototype, e.g. if only two arguments were supplied or an integral value was supplied for the third argument the compiler would report an error. Page 18 HI-TECH C USER'S MANUAL In the second example, the function bill() expects two or more arguments. The first and second will be converted to int and short respectively, while the remainder (if present) may be of any type. The ellipsis symbol (...) indicates to the compiler that zero or more arguments of any type may follow the other arguments. The ellipsis symbol must be last in the argument list, and may not appear as the only argu- ment in a prototype. All prototypes for a function must agree exactly, how- ever it is legal for a definition of a function in the old style, i.e. with just the parameter names inside the parentheses, to follow a prototype declaration provided the number and type of the arguments agree. In this case it is essential that the function definition is in scope of the prototype declaration. Access to unspecified arguments (i.e. arguments sup- plied where an ellipsis appeared in a prototype) must be via the macros defined in the header file . This defines the macros va_start, va_arg and va_end. See va_start in the library function listing for more information. NOTE that is is a grave error to use a function which has an associated prototype unless that prototype is in scope, i.e. the prototype MUST be declared (possibly in a header file) before the function is invoked. Failure to comply with this rule may result in strange behaviour of the program. HI-TECH C will issue a warning message ("func() declared implicit int") whenever a function is called without an explicit declaration. It is good practice to declare all functions and global variables in one or more header files which are included wherever the functions are defined or referenced. 5.10. Void and Pointer to Void The void type may be used to indicate to the compiler that a function does not return a value. Any usage of the return value from a void function will be flagged as an error. The type void *, i.e. pointer to void, may be used as a "universal" pointer type. This is intended to assist in the writing of general purpose storage allocators and the like, where a pointer is returned which may be assigned to another variable of some other pointer type. The compiler permits without typecasting and without reporting an error the conversion of void * to any other pointer type and vice versa. The programmer is advised to use this facility care- fully and ensure that any void * value is usable as a pointer to any other type, e.g. the alignment of any such pointer should be suitable for storage of any object. HI-TECH C USER'S MANUAL Page 19 5.11. Type qualifiers The ANSI C standard introduced the concept of type qualifiers to C; these are keywords that qualify the type to which they are applied. The type qualifiers defined by ANSI C are const and volatile. HI-TECH C also implements several other type qualifiers. The extra qualifiers include: far near interrupt fast interrupt port Not all versions of the compilers implement all of the extra qualifiers. See the machine dependent section for further information. When constructing declarations using type qualifiers, it is very easy to be confused as to the exact semantics of the declaration. A couple of rules-of-thumb will make this easier. Firstly, where a type qualifier appears at the left of a declaration it may appear with any storage class specifier and the basic type in any order, e.g. static void interrupt func(); is semantically the same as interrupt static void func(); Where a qualifier appears in this context, it applies to the basic type of the declaration. Where a qualifier appears to the right of one or more '*' (star) pointer modifiers, then you should read the declaration from right to left, e.g. char * far fred; should be read as "fred is a far pointer to char". This means that fred is qualified by far, not the char to which it points. On the other hand, char far * bill; should be read as "bill is a pointer to a far char", i.e. the char to which bill points is located in the far address space. In the context of the 8086 compiler this will mean that bill is a 32 bit pointer while fred is a 16 bit pointer. You will hear bill referred to as a "far pointer", however the terminology "pointer to far" is preferred. Page 20 HI-TECH C USER'S MANUAL 5.12. In-line Assembler There are two methods provided for in-line assembler code in C programs. The first allows several lines of assembler anywhere in a program. This is via the #asm and #endasm preprocessor directives. Any lines between these two directives will be copied straight through to the assem- bler file produced by the compiler. Alternatively you can use the asm("string"); construct anywhere a C statement is expected. The string will be copied through to the assembler file. Care should be taken with using in-line assembler since it may interact with compiler generated code. 5.13. Pragma Directives The draft ANSI C standard provides for a #pragma preprocessor directive that allows compiler implementations to control various aspects of the compilation process. Currently HI-TECH C only supports one pragma, the pack directive. This allows control over the manner in which members are allocated inside a structure. By default, some of the compilers (especially the 8086 and 68000 compilers) will align structure members onto even boundaries to optim- ize machine accesses. It is sometimes desired to override this to achieve a particular layout inside a structure. The pack pragma allows specification of a maximum packing fac- tor. For example, #pragma pack1(1) will instruct the com- piler that no additional padding be inserted between struc- ture members, i.e. that all members should be aligned on boundaries divisible by 1. Similarly #pragma pack(2) will allow alignment on boundaries divisible by 2. In no case will use of the pack pragma force a greater alignment than would have been used for that data type anyway. More that one pack pragma may be used in a program. Any use will remain in force until changed by another pack or until the end of the file. Do not use a pack pragma before include files such as as this will cause incorrect declarations of run-time library data structures. HI-TECH C USER'S MANUAL Page 21 6. Machine Dependencies HI-TECH C eliminates many of the machine dependent aspects of C, since it uniformly implements such features as unsigned char. There are however certain areas where machine dependencies are inherent in the C language; programmers should be aware of these and take them into account when writing portable code. The most obvious of these machine dependencies is the varying size of C types; on some machines an int will be 16 bits, on others it may be 32 bits. HI-TECH C conforms to the following rules, which represent common practice in most C compilers. char is at least 8 bits short is at least 16 bits long is at least 32 bits int is the same as either short or long float is at least 32 bits double is at least as wide as float Because of the variable width of an int, it is recom- mended that short or long be used wherever possible in preference to int. The exception to this is where a quantity is required to correspond to the natural word size of the machine. Another area of machine differences is that of byte ordering; the ordering of bytes in a short or long can vary significantly between machines. There is no easy approach to this problem other than to avoid code which depends on a particular ordering. In particular you should avoid writing out whole structures to a file (via fwrite()) unless the file is only to be read by the same program then deleted. Different compilers use different amounts of padding between structure members, though this can be modified via the #pragma pack(n) construct. 6.1. Predefined Macros One technique through which machine unavoidable machine dependencies may be managed is the predefined macros pro- vided by each compiler to identify the target processor and operating system (if any). These are defined by the compiler driver and may be tested with conditional compilation preprocessor directives. The macros defined by various compilers are listed in table 2. These can be used as shown in the example in fig . Page 22 HI-TECH C USER'S MANUAL ___________________________________________ | Macro Defined_for | | i8051 8051 processor family | | i8086 8086 processor family | | i8096 8096 processor family | | z80 Z80 processor and derivatives | | m68000 68000 processor family | | m6800 6801, 68HC11 and 6301 processors| | m6809 6809 processor | | DOS MS-DOS and PC-DOS | | CPM CP/M-80 and CP/M-86 | | TOS Atari ST | |__________________________________________| Table 2. Predefined Macros #if DOS char * filename = "c:file"; #endif /* DOS */ #if CPM char * filename = "0:B:afile"; #endif /* CPM */ Use this page for notes HI-TECH C USER'S MANUAL Page 23 7. Error Checking and Reporting Errors may be reported by any pass of the compiler, however in practice the assembler and optimizer will not encounter any errors in the generated code. The types of errors produced by each pass are summarized below. In gen- eral any error will be indentified by the name of the source file in which it was encountered, and the line number at which it was detected. P1 will also nominate the name of the function inside which the error was detected. Errors may be redirected to a file with the usual syn- tax, i.e. a 'greater than' symbol ('>') followed by the name of a file into which the errors should be written. The file name may of course be a device name, e.g. LST: for CP/M or PRN for MS-DOS. CPP will report errors relating to macro definitions and expansions, as well as conditional compilation. P1 is the pass which reports most errors; it performs syntax and semantic checking of the input, and will report both fatal and warning errors when encountered. Syntax errors will normally be expressed as "symbol expected" or "symbol unexpected". Semantic errors may relate to unde- clared, redeclared or misdeclared variables. P1 will also report variable definitons which are unused or unreferenced. These errors are warnings, as are most type checking errors. When P1 encounters errors it will list the source line containing the error on the screen, and underneath display the error message and an up arrow pointing to the point at which the compiler detected the error. In some cases the actual cause of the error may be earlier in the line or even on previous line. CGEN may occasionally report errors, usually warnings, and mostly related to unusual combinations of types with constants, for example testing if an unsigned quantity is less than zero. One fatal error produced by CGEN is "can't generate code for this expression" and means that the expression currently being compiled is in some way too com- plicated to produce code for. This can usually be overcome by rewriting the source code. Such errors are rare and will occur only for unusual constructs. The linker will report undefined or multiply defined symbols. Note that variable declarations inside a header file which is included in more than one source file must be declared as extern, to avoid multiply defined symbol errors. These symbols must then be defined in one and one only source file. A comprehensive list of error messages is included in an appendix. Page 24 HI-TECH C USER'S MANUAL Use this page for notes HI-TECH C USER'S MANUAL Page 25 8. Standard Libraries 8.1. Standard I/O C is a language which does not specify the I/O facil- ites in the language itself; rather all I/O is performed via library routines. In practice this results in I/O handling which is no less convenient than any other language, with the added possibility of customising the I/O for a specific application. For example it is possible to provide a routine to replace the standard getchar() (which gets one character from the standard input) with a special getchar(). This is particulary useful when writing code which is to run on a special hardware configuration, while maintaining a high level of compatibility with "standard" C I/O. There is in fact a Standard I/O library (STDIO) which defines a portable set of I/O routines. These are the rou- tines which are normally used by any C application program. These routines, along with other non-I/O library routines, are listed in detail in a subsequent section of the manual. 8.2. Compatibility The libraries supplied with HI-TECH C are highly compa- tible with the ANSI libraries, as well as the V7 UNIX libraries, both at the Standard I/O level and the UNIX sys- tem call level. The Standard I/O library is complete, and conforms in all respects with the UNIX Standard I/O library. The library routines implementing UNIX system call like functions are as close as possible to those system calls, however there are some UNIX system calls that cannot be simulated on other systems, e.g. the link() operation. How- ever the basic low level I/O routines, i.e. open, close, read, write and lseek are identical to the UNIX equivalents. This means that many programs written to run on UNIX, even if they do not use Standard I/O, will run with little modif- ication when compiled with HI-TECH C. 8.3. Libraries for Embedded Systems The cross compilers, designed to produce code for tar- get systems without operating systems, are supplied with libraries implementing a subset of the STDIO functions. Not provided are those functions dealing with files. Included are printf(), scanf() etc. These operate by calling two low level functions putch and getch() which typically send and receive characters via a serial port. Where the compiler is aimed at a single-chip micro with on-board UART this is used. The source code for all these functions is supplied enabling the user to modify it to address a different serial port. Page 26 HI-TECH C USER'S MANUAL 8.4. Binary I/O On some operating systems, notably CP/M, files are treated differently according to whether they contain ASCII (i.e. printable) or binary data. MD-DOS also suffers from this problem, not due to any lack in the operating system itself, but rather because of the hangover from CP/M which results in many programs putting a redundant ctrl-Z at the end of files. Unfortunately there is no way to determine which type of data a file contains (except perhaps by the name or type of the file, and this is not reliable). To overcome this difficulty, there is an extra character which may be included in the MODE string to a fopen() call. To open a file for ASCII I/O, the form of the fopen() call is: fopen("filename.ext", "r") /* for reading */ fopen("filename.ext", "w") /* for writing */ To open a file for binary I/O, the character 'b' may be appended to the fopen("filename.ext", "rb") fopen("filename.ext", "wb") The additional character instructs the STDIO library that this file is to be handled in a strict binary fashion. On CP/M or MS-DOS, a file opened in ASCII mode will have the following special character handling performed by the STDIO routines: newline ('\n') converted to carriage return/newline on output. return ('\r') ignored on input Ctrl-Z interpreted as End-Of-File on input and, for CP/M only, appended when closing the file. The special actions performed on ASCII files ensure that the file is written in a format compatible with other programs handling text files, while eliminating the require- ment for any special handling by the user program - the file appears to the user program as though it were a UNIX-like text file. None of these special actions are performed on a file opened in binary mode. This is required when handling any kind of binary data, to ensure that spurious bytes are not inserted, and premature EOF's are not seen. Since the binary mode character is additional to the normal mode character, this usage is quite compatible with UNIX C. When compiled on UNIX, the additional character will be ignored. HI-TECH C USER'S MANUAL Page 27 A mention here of the term `stream' is appropriate; stream is used in relation to the STDIO library routines to mean the source or sink of bytes (characters) manipulated by those routines. Thus the FILE pointer supplied as an argu- ment to the STDIO routines may be regarded as a handle on the corresponding stream. A stream may be viewed as a featureless sequence of bytes, originating from or being sent to a device or file or even some other indeterminate source. A FILE pointer should not be confused with the 'file descriptors' used with the low-level I/O functions open(), close(), read() and write(). These form an independent group of I/O functions which perform unbuffered reads and writes to files. 8.5. Floating Point Library HI-TECH C supports floating point as part of the language, however the Z80 implementation provides single precision only; double floats are permitted but are no dif- ferent to floats. In addition, the standard library, LIBC.LIB, does not contain any floating point routines. These have been separated out into another library, LIBF.LIB. This means that if this library is not searched no floating point support routines will be linked in, thus avoiding any size penalty for the floating point support if it is not used. This is particulary important for printf and scanf, and thus LIBF.LIB contains versions of printf and scanf that do support floating point formats. Thus, if floating point is used, a -LF option should be used AFTER the source and/or object files to the C command. E.g.: C -V -O x.c y.c z.obj -LF Page 28 HI-TECH C USER'S MANUAL Use this page for notes HI-TECH C USER'S MANUAL Page 29 9. Stylistic Considerations Although it is not the purpose of this manual to set out a coding standard for C, some comments regarding use of some of the features of HI-TECH C may be useful. 9.1. Member Names Although HI-TECH C allows the same structure or union member name to be used in more than one structure or union, this may not be allowed by another C compiler. To help ensure portability of the code, it is recommended that member names all be distinct, and a useful way of ensuring this is to prefix each member name with one or two letters derived from the name of the structure itself. An example is given in fig. 7. struct tree_node { struct tree_node * t_left; struct tree_node * t_right; short t_operator; }; Fig. 7. Member Naming Because HI-TECH C insists on use of all intermediate names when referencing a member nested inside several struc- tures, some simple macro definitions can serve as a short- hand. An example is given in fig. 8. struct tree_node { short t_operator; union { struct tree_node * t_un_sub[2]; char * t_un_name; long t_un_val; } t_un; }; #define t_left t_un.t_un_sub[0] #define t_right t_un.t_un_sub[1] #define t_name t_un.t_un_name #define t_val t_un.t_un_val Fig. 8. Member Name Shorthand This enables the variant components of the structure to be referred to by short names, while guaranteeing portabil- ity and presenting a clean definition of the structure. Page 30 HI-TECH C USER'S MANUAL 9.2. Use of Int It is recommended that the type int be avoided wherever possible, in preference to the types short or long. This is because of the variable size of int, whereas short is com- monly 16 bits and long 32 bits in most C implementations. 9.3. Extern Declarations Some compilers permit a non-initialized global variable to be declared in more than one place, with the multiple definitions being resolved by the linker as all defining the same thing. HI-TECH C specifically disallows this, since it may lead to subtle bugs. Instead, global variables may be declared extern in as many places as you wish, and must be defined in one and one only place. Typically this will mean declaring global variables in a header file as extern, and defining each variable in the file most closely associated with that variable. This usage will be portable to virually all other C implementations. HI-TECH C USER'S MANUAL Page 31 10. Memory Models With many of the processors supported by the HI-TECH C compilers there are more than one address space accessible to a program. Typically one address space is more economical to access than another, larger address space. Thus it is desirable to be able to tailor a prorgram's use of memory to achieve the greatest economy in addressing (thus minimizing program size and maximizing speed) while allowing access to as much memory as the program requires. This concept of different address spaces is not catered for by either K&R or ANSI C (except to recognize the possi- bility of separate address spaces for code and data). Without any extensions to the language itself it is possible to devise more than one memory model for a given processor, selected at compile time. This has the effect of selecting one addressing method for all data and/or code. This permits the model for a particular program to be chosen depending on that program's memory requirements. In many programs, however, only one or two data struc- tures are large enough to need to be placed in the larger address space. Selection of a "large" memory model for the whole of the program makes the whole program larger and slower just to allow a few large data structures. This can be overcome by allowing individual selection of the address space for each data structure. Unfortunately this entails extensions to the language, never a desirable approach. To minimize the effect of such extensions they should satisfy the following criteria: 1. As far as possible the extensions should be consistent with common practice. 2. The extensions should fit a machine-independent model to maximize portability across processors and operating systems. These goals have been achieved within HI-TECH C by means of the following model: Each memory model defines three address spaces each for code and data. These address spaces are known as the near, far and default spaces. Any object qualified by the near keyword will be placed in the near address space, any object qual- ified by the far keyword shall be placed in the far address space, and all other objects shall be placed in the default address space. The near address space shall be a (possibly improper) sub- space of the default address space, while the default address space shall be a (possibly improper) subspace of the far address space. There shall be up to three kinds of pointers correspond- ing to the three address spaces, each capable of Page 32 HI-TECH C USER'S MANUAL addressing an object in its own address space or a subspace of that address space. This implies that the address of an object may be con- verted to a pointer into a larger address space, e.g. a near object may have its address converted to a pointer to far, but a far object may not be able to be addressed by a pointer to near. In practice the default address space will usually correspond exactly to either the near or far address spaces. If all three address spaces correspond to the same memory then there is only one memory model possible. This occurs with the 68000 processor. Where the default code and data spaces may each correspond to either the near or far address spaces then there will be a total of four memory models. This is the case with the 8086 processor. The keywords far and near are supported by all the HI- TECH C compilers, but the exact correspondence of address spaces is determined by the individual characteristics of each processor and the choice of memory model (if there is a choice). However code written using these keywords will be portable providing it obeys the constraints of the model described above. This model also corresponds well with other implementa- tions using the near and far keywords, although such imple- mentations do not appear to have been designed around a for- mal, portable model. HI-TECH C USER'S MANUAL Page 33 11. What Went Wrong There are numerous error messages that the compiler may produce. Most of these relate to errors in the source code (syntax errors of various kinds and so forth) but some represent limitations, particularly of memory. The two passes most likely to be affected by memory limitations are the code generator and the optimizer. The code generator will issue the message "No room" if it runs out of dynamic memory. This can usually be eliminated by simplifying the expression at the line nominated in the error message. The more complex the expression, the more memory is required to store the tree representing it. Reducing the number of sym- bols used in the program will also help. Note that this error is different from the message "Can't generate code for this expression" which indicates that the expression is in some way too difficult for the code generator to handle. This message will be encountered very infrequently, and can be eliminated by changing the expression in some way, e.g. computing an intermediate value into a temporary variable. The optimizer reads the assembler code for a whole function into memory at one time. Very large functions will not fit, giving the error message "Optim: out of memory in _func" where func is the name of the function responsible. In this case the function should be broken up into smaller functions. This will only occur with functions with several hundred lines of C source code. Good coding practice will normally limit functions to less than 50 lines each. If a pass exits with the message "Error closing file", or "Write error on file", this usually indicates that there is insufficient room on the current disk. If you use a wordprocessing editor such as Wordstar, ensure that you use the "non-document" mode or whatever the corresponding mode is. The edited file should not contain any characters with the high bit set, and the line feed at the end of the line must be present. Lines should be not more than 255 characters long. When using floating point, ensure that you use a -LF flag at the END of the command line, to cause the floating point library to be searched. This will cause floating ver- sions of printf and scanf to be linked in, as well as specific floating point routines. If the non-floating version of printf is used with a floating format such as %f then it will simply print the letter f. If the linker gives an "Undefined symbol" message for some symbol which you know nothing about, it is possible that it is a library routine which was not found during the Page 34 HI-TECH C USER'S MANUAL library search due to incorrect library ordering. In this case you can search the library twice, e.g. for the stan- dard library add a -LC to the end of the C command line, or -LF for the floating library. If you have specified the library by name simply repeat its name. HI-TECH C USER'S MANUAL Page 35 12. Z80 Assembler Reference Manual 12.1. Introduction The assembler incorporated in the HI-TECH C compiler system is a full-featured relocating macro assembler accept- ing Zilog mnemonics. These mnemonics and the syntax of the Z80 assembly language are described in the "Z80 Assembly Language Handbook" published by Zilog and are included at the end of this manual as a reference. The assembler imple- ments certain extensions to the operands allowed, and cer- tain additional pseudo-ops, which are described here. The assembler also accepts the additional opcodes for the Hita- chi 64180 and Z180 processors. 12.2. Usage The assembler is named zas, and is invoked as follows: ZAS options files ... The files are one or more assembler source files which will be assembled, but note that all the files are assembled as one, not as separate files. To assemble separate files, the assembler must be invoked on each file separately. The options are zero or more options from the following list: -N Ignore arithmetic overflow in expressions. The -N option suppresses the normal check for arithmetic over- flow. The assembler follows the "Z80 Assembly Language Handbook" in its treatment of overflow, and in certain instances this can lead to an error where in fact the expression does evaluate to what the user intended. This option may be used to override the overflow check- ing. -J Attempt to optimize jumps to branches. The -J option will request the assembler to attempt to assemble jumps and conditional jumps as relative branches where possi- ble. Only those conditional jumps with branch equivalents will be optimized, and jumps will only be optimized to branches where the target is in branch range. Note that the use of this option slows the assembly down, due to the necessity for the assembler to make an additional pass over the input code. -U Treat undefined symbols as external. The -U option will suppress error messages relating to undefined sym- bols. Such symbols are treated as externals in any case. The use of this option will not alter the object code generated, but merely serves to suppress the error messages. Page 36 HI-TECH C USER'S MANUAL -Ofile Place the object code in file. The default object file name is constructed from the name of the first source file. Any suffix or file type (i.e. anything following the rightmost dot ('.') in the name is stripped, and the suffix .obj appended. Thus the command ZAS file1.as file2.z80 will produce an object file called file1.obj. The use of the -O option will override this default convention, allowing the object file to be arbitrarily named. For example: ZAS -ox.obj file1.obj will place the object code in x.obj. -Llist Place an assembly listing in the file list, or on stan- dard output if list is null A listfile may be produced with the -L option. If a file name is supplied to the option, the list file will be created with that name, otherwise the listing will be written to standard out- put (i.e. the console). List file names such as CON: and LST: are acceptable. -Wwidth The listing is to be formatted for a printer of given width The -W option specifies the width to which the listing is to be formatted. E.g. ZAS -Llst: -W80 x.as will output a listing formatted for an 80 column printer to the list device. -C This options requests ZAS to produce cross reference information in a file. The file will be called xxx.crf where xxx is the base part of the first source file name. It will then be necessary to run the CREF utility to turn this information into a formatted listing. 12.3. The Assembly Language As mentioned above, the assembly language accepted by zas is based on the Zilog mnemonics. You should have some reference book such as the "Z80 Assembly Language Handbook". Described below are those areas in which zas differs, or has extensions, compared to the standard Zilog assembly language. 12.3.1. Symbols The symbols (labels) accepted by the assembler may be of any length, and all characters are significant. The char- acters used to form a symbol may be chosen from the upper and lower case alphabetics, the digits 0-9, and the special HI-TECH C USER'S MANUAL Page 37 symbols underscore ('_'), dollar ('$') and question mark ('?'). The first character may not be numeric. Upper and lower case are distinct. The following are all legal and distinct symbols. An_identifier an_identifier an_identifier1 $$$ ?$_123455 Note that the symbol $ is special (representing the current location) and may not be used as a label. Nor may any opcode or pseudo-op mnemonic, register name or condition code name. You should note the additional condition code names described later. 12.3.1.1. Temporary Labels The assembler implements a system of temporary labels, useful for use within a localized section of code. These help eliminate the need to generate names for labels which are referenced only in the immediate vicinity of their definition, for example where a loop is implemented. A temporary label takes the form of a digit string. A reference to such a label requires the same digit string, plus an appended b or f to signify a backward or forward reference respectively. Here is an example of the use of such labels. entry_point: ;This is referenced from far away ld b,10 1: dec c jr nz,2f ;if zero, branch forward to 2: ld c,8 djnz 1b ;decrement and branch back to 1: jr 1f ;this does not branch to the ;same label as the djnz 2: call fred ;get here from the jr nz,2f 1: ret ;get here from the jr 1f The digit string may be any positive decimal number 0 to 65535. A temporary label value may be re-used any number of times. Where a reference to e.g. 1b is made, this will reference the closest label 1: found by looking backwards from the current point in the file. Similarly 23f will reference the first label 23: found by looking forwards from the current point in the file. 12.3.2. Constants Constants may be entered in one of the radices 2, 8, 10 or 16. The default is 10. Constants in the other radices may be denoted by a trailing character drawn from the following set: Page 38 HI-TECH C USER'S MANUAL Character Radix Name B 2 binary O 8 octal Q 8 octal o 8 octal q 8 octal H 16 hexadecimal h 16 hexadecimal Hexadecimal constants may also be specified in C style, for example LD A,0x21. Note that a lower case b may not be used to indicate a binary number, since 1b is a backward reference to a temporary label 1:. 12.3.2.1. Character Constants A character constant is a single character enclosed in single quotes ('). Multi character constants may be used only as an operand to a DEFM pseudo-op. 12.3.2.2. Floating Constants A floating constant in the usual notation (e.g. 1.234 or 1234e-3) may be used as the operand to a DEFF pseudo-op. 12.3.2.3. Opcode Constants Any z80 opcode may be used as a constant in an expres- sion. The value of the opcode in this context will be the byte that the opcode would have assembled to if used in the normal way. If the opcode is a 2-byte opcode (CB or ED pre- fix byte) only the second byte of the opcode will be used. This is particularly useful when setting up jump vectors. For example: ld a,jp ;a jump instruction ld (0),a ;0 is jump to warm boot ld hl,boot ;done here ld (1),hl 12.3.3. Expressions Expressions are constructed largely as described in the "Z80 Assembly Language Handbook". 12.3.3.1. Operators The following operators may be used in expressions: Operator Meaning & Bitwise AND * Multiplication + Addition - Subtraction HI-TECH C USER'S MANUAL Page 39 .and. Bitwise AND .eq. Equality test .gt. Signed greater than .high. Hi byte of operand .low. Low byte of operand .lt. Signed less than .mod. Modulus .not. Bitwise complement .or. Bitwise or .shl. Shift left .shr. Shift right .ult. Unsigned less than .ugt. Unsigned greater than .xor. Exclusive or / Divison < Signed less than = Equality > Signed greater than ^ Bitwise or Operators starting with a dot "." should be delimited by spaces, thus label .and. 1 is valid but label.and.1 is not. 12.3.3.2. Relocatability Zas produces object code which is relocatable; this means that it is not necessary to specify assembly time where the code is to be located in memory. It is possible to do so, by use of the ORG pseudo-op, however the preferred approach is to use program sections or psects. A psect is a named section of the program, in which code or data may be defined at assembly time. All parts of a psect will be loaded contiguously into memory, even if they were defined in separate files, or in the same file but separated by code for another psect. For example, the following code will load some executable instructions into the psect named text, and some data bytes into the data psect. Page 40 HI-TECH C USER'S MANUAL psect text, global alabel: ld hl,astring call putit ld hl,anotherstring psect data, global astring: defm 'A string of chars' defb 0 anotherstring: defm 'Another string' defb 0 psect text putit: ld a,(hl) or a ret z call outchar inc hl jr putit Note that even though the two blocks of code in the text psect are separated by a block in the data psect, the two text psect blocks will be contiguous when loaded by the linker. The instruction "ld hl,anotherstring" will fall through to the label "putit:" during execution. The actual location in memory of the two psects will be determined by the linker. See the linker manual for information on how psect addresses are determined. A label defined in a psect is said to be relocatable, that is, its actual memory address is not determined at assembly time. Note that this does not apply if the label is in the default (unnamed) psect, or in a psect declared abso- lute (see the PSECT pseudo-op description below). Any labels declared in an absolute psect will be absolute, that is their address will be determined by the assembler. With the version of ZAS supplied with version 7 or later of HI-TECH C, relocatable expressions may be combined freely in expressions. Older versions of ZAS allowed only limited arithmetic on relocatable expressions. 12.3.4. Pseudo-ops The pseudo-ops are based on those described in the "Z80 Assembly Language Handbook", with some additions. 12.3.4.1. DEFB, DB This pseudo-op should be followed by a comma-separated list of expressions, which will be assembled into sequential HI-TECH C USER'S MANUAL Page 41 byte locations. Each expression must have a value between -128 and 255 inclusive. DB can be used as a synonym for DEFB. Example: DEFB 10, 20, 'a', 0FFH DB 'hello world',13,10,0 12.3.4.2. DEFF This pseudo-op assembles floating point constants into 32 bit HI-TECH C format floating point constants. For exam- ple: pi: DEFF 3.14159 12.3.4.3. DEFW This operates in a similar fashion to DEFB, except that it assembles expressions into words, without the value res- triction. Example: DEFW -1, 3664H, 'A', 3777Q 12.3.4.4. DEFS Defs reserves memory locations without initializing them. Its operand is an absolute expression, representing the number of bytes to be reserved. This expression is added to the current location counter. Note however that locations reserved by DEFS may be initialized to zero by the linker if the reserved locations are in the middle of the program. Example: DEFS 20h ;reserve 32 bytes of memory 12.3.4.5. EQU Equ sets the value of a symbol on the left of EQU to the expression on the right. It is illegal to set the value of a symbol which is already defined. Example: SIZE equ 46 12.3.4.6. DEFL This is identical to EQU except that it may redefine existing symbols. Example: Page 42 HI-TECH C USER'S MANUAL SIZE defl 48 12.3.4.7. DEFM Defm should be followed by a string of characters, enclosed in single quotes. The ASCII values of these char- acters are assembled into successive memory locations. Example: DEFM 'A string of funny *@$ characters' 12.3.4.8. END The end of an assembly is signified by the end of the source file, or the END pseudo-op. The END pseudo-op may optionally be followed by an expression which will define the start address of the program. This is not actually use- ful for CP/M. Only one start address may be defined per pro- gram, and the linker will complain if there are more. Exam- ple: END somelabel 12.3.4.9. COND, IF, ELSE, ENDC Conditional assembly is introduced by the COND pseudo- op. The operand to COND must be an absolute expression. If its value is false (zero) the code following the COND up to the corresponding ENDC pseudo-op will not be assembled. COND/ENDC pairs may be nested. IF may be used as a synonym for COND. The ELSE pseudo operation may be included within a COND/ENDC block, for example: IF CPM call 5 ELSE call os_func ENDC 12.3.4.10. ELSE See COND. 12.3.4.11. ENDC See COND. HI-TECH C USER'S MANUAL Page 43 12.3.4.12. ENDM See MACRO. 12.3.4.13. PSECT This pseudo-op allows specification of relocatable pro- gram sections. Its arguments are a psect name, optionally followed by a list of psect flags. The psect name is a sym- bol constructed according to the same rules as for labels, however a psect may have the same name as a label without conflict. Psect names are recognized only after a PSECT pseudo-op. The psect flags are as follows: ABS Psect is absolute GLOBAL Psect is global LOCAL Psect is not global OVRLD Psect is to be overlapped by linker PURE Psect is to be read-only If a psect is global, the linker will merge it with any other global psects of the same name from other modules. Local psects will be treated as distinct from any other psect from another module. Psects are global by default. By default the linker concatenates code within a psect from various modules. If a psect is specified as OVRLD, the linker will overlap each module's contribution to that psect. This is particularly useful when linking modules which initialize e.g. interrupt vectors. The PURE flag instructs the linker that the psect is to be made read-only at run time. The usefulness of this flag depends on the ability of the linker to enforce the require- ment. CP/M fails miserably in this regard. The ABS flag makes a psect absolute. The psect will be loaded at zero. This is useful for statically initializing interrupt vectors and jump tables. Examples: PSECT text, global, pure PSECT data, global PSECT vectors, ovrld 12.3.4.14. GLOBAL Global should be followed by one more symbols (comma separated) which will be treated by the assembler as global symbols, either internal or external depending on whether they are defined within the current module or not. Example: Page 44 HI-TECH C USER'S MANUAL GLOBAL label1, putchar, _printf 12.3.4.15. ORG An ORG pseudo-op sets the current psect to the default (absolute) psect, and the location counter to its operand, which must be an absolute expression. Example: ORG 100H 12.3.4.16. MACRO This pseudo-op defines a macro. It should be either preceded or followed by the macro name, then optionally fol- lowed by a comma-separated list of formal parameters. The lines of code following the MACRO pseudo-op up to the next ENDM pseudo-op will be stored as the body of the macro. The macro name may subsequently be used in the opcode part of an assembler statement, followed by actual parameters. The text of the body of the macro will be substituted at that point, with any use of the formal parameters substituted with the corresponding actual parameter. For example: print MACRO string psect data 999: db string,'$' psect text ld de,999b ld c,9 call 5 ENDM When used, this macro will expand to the 3 instructions in the body of the macro, with the actual parameters substi- tuted for func and arg. Thus print 'hello world' expands to psect data 999: db 'hello world','$' psect text ld de,999b ld c,9 call 5 Macro arguments can be enclosed in angle brackets ('<' HI-TECH C USER'S MANUAL Page 45 and '>') to pass arbitrary text including delimiter charac- ters like commas as a single argument. For example, suppose you wanted to use the print macro defined above to print a string which includes the carriage return and linefeed char- acters. The macro invocation: print 'hello world',13,10 would fail because 13 and 10 are treated as extra arguments and ignored. In order to pass a string which includes commas as a single argument, you could write: print <'hello world',13,10> which would cause the text 'hello world',13,10 to be passed through as a single argument. This would expand to the fol- lowing code: psect data 999: db 'hello world',13,10,'$' psect text ld de,999b ld c,9 call 5 ZAS supports two forms of macro declaration for compa- tibility with older versions of ZAS and other Z80 assem- blers. The macro name may be declared either in the label field before the MACRO pseudo-op, or in the operand field after the MACRO pseudo-op. Thus these two MACRO declara- tions are equivalent: bdos MACRO func,arg ld de,arg ld c,func call 5 ENDM and MACRO bdos,func,arg ld de,arg ld c,func call 5 ENDM 12.3.4.17. LOCAL The LOCAL pseudo-op allows unique labels to be defined for each expansion of a macro. Any symbols listed after the LOCAL directive will have a unique assembler-generated sym- bol substituted for them when the macro is expanded. For Page 46 HI-TECH C USER'S MANUAL example: copy MACRO source,dest,count LOCAL nocopy push af push bc ld bc,source ld a,b or c jr z,nocopy push de push hl ld de,dest ld hl,source ldir pop hl pop de nocopy: pop bc pop af ENDM when expanded will include a unique assembler generated label in place of nocopy. For example, copy (recptr),buf,(recsize) will expand to: push af push bc ld bc,(recsize) ld a,b or c jr z,??0001 push de push hl ld de,buf ld hl,(recptr) ldir pop hl pop de ??0001: pop bc pop af if invoked a second time, the label nocopy would expand to ??0002. 12.3.4.18. REPT The REPT pseudo-op defines a temporary macro which is then expanded a number of times, as determined by its argu- ment. For example: REPT 3 ld (hl),0 inc hl ENDM will expand to HI-TECH C USER'S MANUAL Page 47 ld (hl),0 inc hl ld (hl),0 inc hl ld (hl),0 inc hl 12.3.5. IRP and IRPC The IRP and IRPC directives are similar to REPT, how- ever instead of repeating the block a fixed number of times it is repeated once for each member of an argument list. In the case of IRP the list is a conventional macro argument list, in the case of IRPC it is successive characters from a string. For example: IRP string,<'hello world',13,10>,'arg2' LOCAL str psect data str: db string,'$' psect text ld c,9 ld de,str call 5 ENDM would expand to psect data ??0001: db 'hello world',13,10,'$' psect text ld c,9 ld de,??0001 call 5 psect data ??0002: db 'arg2','$' psect text ld c,9 ld de,??0002 call 5 Note the use of LOCAL labels and angle brackets in the same manner as with conventional macros. IRPC is best demonstrated using the following example: IRPC char,ABC ld c,2 ld e,'char' call 5 ENDM Page 48 HI-TECH C USER'S MANUAL will expand to: ld c,2 ld e,'A' call 5 ld c,2 ld e,'B' call 5 ld c,2 ld e,'C' call 5 12.3.6. Extended Condition Codes The assembler recognizes several additional condition codes. These are: _________________________________________________ | Code| Equivalent| Meaning | | alt | m | Arithmetic less than | | llt | c | Logical less than | | age | p | Arithmetic greater or equal| | lge | nc | Logical greater or equal | | di | | Use after ld a,i for test-| | ei | | ing state of interrupt| | | | enable flag - enabled or| |_____|____________|__disabled_respectively._____| 12.4. Assembler Directives An assembler directive is a line in the source file which produces no code, but rather which modifies the behaviour of the assembler. Each directive is recognized by the presence of an asterisk in the first column of the line, followed immediately by a word, only the first character of which is looked at. the line containing the directive itself is never listed. The directives are: *Title Use the text following the directive as a title for the listing. *Heading Use the text following the directive as a subtitle for the listing; also causes an *Eject. *List May be followed by ON or OFF to turn listing on or off respectively. Note that this directive may be used inside a macro or include file to control listing of that macro or include file. The previous listing state will be restored on exit from the macro or include file. HI-TECH C USER'S MANUAL Page 49 *Include The file named following the directive will be included in the assembly at that point. *Eject A new page will be started in the listing at that point. A form feed character in the source will have the same effect. Some examples of the use of these directives: *Title Widget Control Program *Heading Initialization Phase *Include widget.i 12.5. Diagnostics An error message will be written on the standard error stream for each error encountered in the assembly. This mes- sage identifies the file name and line number and describes the error. In addition the line in the listing where the error occurred will be flagged with a single character to indicate the error. The characters and the corresponding messages are: Page 50 HI-TECH C USER'S MANUAL A: Absolute expression required B: Bad arg to *L Bad arg to IM Bad bit number Bad character constant Bad jump condition D: Directive not recognized Digit out of range E: EOF inside conditional Expression error G: Garbage after operands Garbage on end of line I: Index offset too large J: Jump target out of range L: Lexical error M: Multiply defined symbol O: Operand error P: Phase error Psect may not be local and global R: Relocation error S: Size error Syntax error U: Undefined symbol Undefined temporary label Unterminated string 12.6. Z80/Z180/64180 Instruction Set The remainder of this chapter is devoted to a complete instruction set listing for the Z80, Z180, 64180 and NSC800 processors. The Z180 and 64180 will execute all Z80 instructions, although the timing is different. HI-TECH C USER'S MANUAL Page 51 Page 52 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 53 Page 54 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 55 Page 56 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 57 Page 58 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 59 Page 60 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 61 Page 62 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 63 Page 64 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 65 Page 66 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 67 Page 68 HI-TECH C USER'S MANUAL HI-TECH C USER'S MANUAL Page 69 13. Linker Reference Manual HI-TECH C incorporates a relocating assembler and linker to permit separate compilation of C source files. This means that a program may be divided into several source files, each of which may be kept to a manageable size for ease of editing and compilation, then each object file com- piled separately and finally all the object files linked together into a single executable program. The assembler is described in the machine-specific manual. This appendix describes the theory behind and the usage of the linker. 13.1. Relocation and Psects The fundamental task of the linker is to combine several relocatable object files into one. The object files are said to be relocatable since the files have sufficient information in them so that any references to program or data addresses (e.g. the address of a function) within the file may be adjusted according to where the file is ulti- mately located in memory after the linkage process. Thus the file is said to be relocatable. Relocation may take two basic forms; relocation by name, i.e. relocation by the ultimate value of a global symbol, or relocation by psect, i.e. relocation by the base address of a particular section of code, for example the section of code containing the actual excutable instructions. 13.1.1. Program Sections Any object file may contain bytes to be stored in memory in one or more program sections, which will be referred to as psects. These psects represent logical group- ings of certain types of code bytes in the program. The section of the program containing executable instructions is normally referred to as the text psect. Other sections are the initialized data psect, called simply the data psect, and the uninitialized data psect, called the bss psect. In fact the linker will handle any number of psects, and in fact more may be used in special applications. How- ever the C compiler uses only the three mentioned, and the names text, data and bss are simply chosen for identifica- tion; the linker assigns no special significance to the name of a psect. The difference between the data and bss psects may be exemplified by considering two external variables; one is initialized to the value 1, and the other is not initial- ized. The first will be placed into the data psect, and the second in the bss psect. The bss psect is always cleared to zeros on startup of the program, thus the second variable will be initialized at run time to zero. The first will how- ever occupy space in the program file, and will maintain its Page 70 HI-TECH C USER'S MANUAL initialized value of 1 at startup. It is quite possible to modify the value of a variable in the data psect during exe- cution, however it is better practice not to do so, since this leads to more consistent use of variables, and allows for restartable and romable programs. The text psect is the section into which all executable instructions are placed. On CP/M-80 the text psect will nor- mally start at the base of the TPA, which is where execution commences. The data psect will normally follow the text psect, and the bss will be last. The bss does not occupy space in the program (.COM) file. This ordering of psects may be overridden by an option to the linker. This is espe- cially useful when producing code for special hardware. For MS-DOS and CP/M-86 the psects are ordered in the same way, but since the 8086 processor has segment registers providing relocation, both the text and data psects start at 0, even though they will be loaded one after the other in memory. This allows 64k code and 64k data and stack. Suffi- cient information is placed in the executable file (.EXE or .CMD) for the operating system to load the program in memory. 13.1.2. Local Psects and the Large Model Since for practical purposes the psects are limited to 64K on the 8086, to allow more than 64K code the compiler makes use of local psects. A psect is considered local if the .psect directive has a LOCAL flag. Any number of local psects may be linked from different modules without being combined even if they have the same name. Note however that no local psect may have the same name as a global psect. All references to a local psect within the same module (or within the same library) will be treated as references to the same psect. Between modules however two local psects of the same name are treated as distinct. In order to allow collective referencing of local psects via the -P option (described later) a local psect may have a class name asso- ciated with it. This is achieved witht the CLASS flag on the .psect directive. 13.2. Global Symbols The linker handles only symbols which have been declared as global to the assembler. From the C source level, this means all names which have storage class exter- nal and which are not declared as static. These symbols may be referred to by modules other than the one in which they are defined. It is the linker's job to match up the defini- tion of a global symbol with the references to it. HI-TECH C USER'S MANUAL Page 71 13.3. Operation A command to the linker takes the following form: LINK options files ... Options is zero or more linker options, each of which modifies the behaviour of the linker in some way. Files is one or more object files, and zero or more library names. The options recognized by the linker are as follows: they will be recognized in upper or lower case. -R Leave the output relocatable. -L Retain absolute relocation info. -LM will retain only segement relocation information. -I Ignore undefined symbols. -N Sort symbols by address. -Caddr Produce a binary output file offset by addr. -S Strip symbol information from the output file. -X Suppress local symbols in the output file. -Z Suppress trivial (compiler-generated) symbols in the output file. -Oname Call the output file name. -Pspec Spec is a psect location specification. -Mname Write a link map to the file name. -Usymbol Make symbol initially undefined. -Dfile Write a symbol file. -Wwidth Specify map width. Taking each of these in turn: The -R option will instruct the linker to leave the output file (as named by a -O option, or l.obj by default) relocatable. This is normally because there are further files to be linked in, and the output of this link will be used as input to the linker subsequently. Without this option, the linker will make the output file absolute, that Page 72 HI-TECH C USER'S MANUAL is with all relocatable addresses made into absolute refer- ences. This option may not be used with the -L or -C options. The -L option will cause the linker to output null relocation information even though the file will be abso- lute. This information allows self-relocating programs to know what addresses must be relocated at run time. This option is not usable with the -C option. In order to create an executable file (i.e. a .COM file) the program objtohex must be used. If a -LM option is used, only segment reloca- tion information will be retained. This is used in conjuc- tion with the large memory model. Objtohex will use the relocation information (when invoked with a -L flag) to insert segment relocation addresses into the executable file. The -I option is used when it is desired to link code which contains symbols which are not defined in any module. This is normally only used during top-down program develop- ment, when routines are referenced in code written before the routines themselves have been coded. When obtaining a link map via the -M option, the symbol table is by default sorted in order of symbol name. To sort in order of address, the -N option may be used. The output of the linker is by default an object file. To create an executable program, this must be converted into an executable image. For CP/M this is a .COM file, which is simply an image of the executable program as it should appear in memory, starting at location 100H. The linker will produce such a file with the -C100H option. File formats for other applications requiring an image binary file may also be produced with the -C option. The address following the -C may be given in decimal (default), octal (by using o or O suffix) or hexadecimal (by using an h or H suffix). Note that because of the complexity of the executable file formats for MS-DOS and CP/M-86, LINK will not produce these (.EXE and .CMD resp.) formats directly. The compiler automatically runs OBJTOHEX with appropriate options to gen- erate the correct file format. The -S, -X and -Z options, which are meaningless when the -C option is used, will strip respectively all symbols, all local symbols or all trivial local symbols from the out- put file. Trivial symbols are symbols produced by the com- piler, and have the form of one of a set of alphabetic char- acters followed by a digit string. The default output file name is l.obj, or l.bin when the -C option is used. This may be overridden by the -Oname option. The output file will be called name in this instance. Note that no suffix is appended to the name; the file will be called exactly the argument to the option. For certain specialized applications, e.g. producing HI-TECH C USER'S MANUAL Page 73 code for an embedded microprocessor, it is necessary to specify to the linker at what address the various psects should be located. This is accomplished with the -P option. It is followed by a specification consisting of a comma- separated list of psect names, each with an optional address specification. In the absence of an address specification for a psect listed, it will be concatenated with the previ- ous psect. For example -Ptext=0c000h,data,bss=8000h This will cause the text psect to be located at 0C000H, the data psect to start at the end of the text psect, and the bss psect to start at 8000H. This may be for a processor with ROM at 0C000H and RAM at 8000H. Where the link address, that is the address at which the code will be addressed at execution time, and the load address, that is the address offset within the output file, are different (e.g for the 8086) it is possible to specify the load address separately from the link address. For exam- ple: -Ptext=100h/0,data=0C000h/ This specification will cause the text segment to be linked for execution at 100h, but loaded in the output file at 0, while the data segment will be linked for 0C000h, but loaded contiguously with the text psect in the file. Note that if the slash (`/') is omitted, the load address is the same as the link address, while if the slash is supplied, but not followed by an address, the psect will be loaded after the previous psect. In order to specify link and load addresses for local psects, the group name to which the psects belong may be used in place of a global psect name. The local psects will then have a link address as specified in the -P option, and load addresses incrementing upwards from the specified load address. The -Mname option requests a link map, containing sym- bol table and module load address information to be written onto the file name. If name is omitted, the map will be written to standard output. -W may be used to specify the desired width of the map. The -U option allows the specification to the linker of a symbol which is to be initially entered into the symbol table as undefined. This is useful when loading entirely from libraries. More than one -U flag may be used. If it is desired to use the debugger on the program being linked, it is useful to produce a symbol file. The -Dfile option will write such a symbol file onto the named file, or l.sym if no file is given. The symbol file consists Page 74 HI-TECH C USER'S MANUAL of a list of addresses and symbols, one per line. 13.4. Examples Here are some examples of using the linker. Note how- ever that in the normal case it is not necessary to invoke the linker explicitly, since it is invoked automatically by the C command. LINK -MMAP -C100H START.OBJ MAIN.OBJ A:LIBC.LIB This command links the files start.obj and main.obj with the library a:libc.lib. Only those modules that are required from the library will be in fact linked in. The output is to be in .COM format, placed in the default file l.bin. A map is to be written to the file of the name map. Note that the file start.obj should contain startup code, and in fact the lowest address code in that file will be executed when the program is run, since it will be at 100H. LINK -X -R -OX.OBJ FILE1.OBJ FILE2.OBJ A:LIBC.LIB The files file1.obj and file2.obj will be linked with any necessary routines from a:libc.lib and left in the file x.obj. This file will remain relocatable. Undefined symbols will not cause an error. The file x.obj will probably later be the object of another link invocation. All local symbols will be stripped from the output file, thus saving space. 13.5. Invoking the Linker The linker is called LINK, and normally resides on the A: drive, under CP/M, or in the directory A:\HITECH\ under MS-DOS. It may be invoked with no arguments, in which case it will prompt for input from standard input. If the stan- dard input is a file, no prompts will be printed. The input supplied in this manner may contain lower case, whereas CP/M converts the entire command line to upper case by default. This is useful with the -U and -P options. This manner of invocation is generally useful if the number of arguments to LINK is large. Even if the list of files is too long to fit on one line, continuation lines may be included by leaving a backslash ('\') at the end of the preceding line. In this fashion, LINK commands of almost unlimited length may be issued. HI-TECH C USER'S MANUAL Page 75 14. Librarian The librarian program, LIBR, has the function of com- bining several object files into a single file known as a library. The purposes of combining several such object modules are several. a. fewer files to link b. faster access c. uses less disk space In order to make the library concept useful, it is necessary for the linker to treat modules in a library dif- ferently from object files. If an object file is specified to the linker, it will be linked into the final linked module. A module in a library, however, will only be linked in if it defines one or more symbols previously known, but not defined, to the linker. Thus modules in a library will be linked only if required. Since the choice of modules to link is made on the first pass of the linker, and the library is searched in a linear fashion, it is possible to order the modules in a library to produce special effects when linking. More will be said about this later. 14.1. The Library Format The modules in a library are basically just con- catenated, but at the beginning of a library is maintained a directory of the modules and symbols in the library. Since this directory is smaller than the sum of the modules, the linker is speeded up when searching a library since it need read only the directory and not all the modules on the first pass. On the second pass it need read only those modules which are required, seeking over the others. This all minim- izes disk i/o when linking. It should be noted that the library format is geared exclusively toward object modules, and is not a general pur- pose archiving mechanism as is used by some other compiler systems. This has the advantage that the format may be optimized toward speeding up the linkage process. 14.2. Using The librarian program is called LIBR, and the format of commands to it is as follows: LIBR k file.lib file.obj ... Interpreting this, LIBR is the name of the program, k is a key letter denoting the function requested of the librarian (replacing, extracting or deleting modules, list- ing modules or symbols), file.lib is the name of the library file to be operated on, and file.obj is zero or more object Page 76 HI-TECH C USER'S MANUAL file names. The key letters are: r replace modules d delete modules x extract modules m list module names s list modules with symbols When replacing or extracting modules, the file.obj arguments are the names of the modules to be replaced or extracted. If no such arguments are supplied, all the modules in the library will be replaced or extracted respec- tively. Adding a file to a library is performed by request- ing the librarian to replace it in the library. Since it is not present, the module will be appended to the library. If the r key is used and the library does not exist, it will be created. Under the d keyletter, the named object files will be deleted from the library. In this instance, it is an error not to give any object file names. The m and s keyletters will list the named modules and, in the case of the s keyletter, the symbols defined or referenced within (global symbols only are handled by the librarian). As with the r and x keyletters, an empty list of modules means all the modules in the library. 14.3. Examples Here are some examples of usage of the librarian. LIBR m file.lib List all modules in the library file.lib. LIBR s file.lib a.obj b.obj c.obj List the global symbols in the modules a.obj, b.obj and c.obj LIBR r file.lib 1.obj 2.obj Replace the module 1.obj in the file file.lib with the contents of the object file 1.obj, and repeat for 2.obj. If the object module is not already present in the library, append it to the end. LIBR x file.lib Extract, without deletion, all the modules in file.lib and write them as object files on disk. LIBR d file.lib a.obj b.obj 2.obj Delete the object modules a.obj, b.obj and 2.obj from the library file.lib. HI-TECH C USER'S MANUAL Page 77 14.4. Supplying Arguments Since it is often necessary to supply many object file arguments to LIBR, and command lines are restricted to 127 characters by CP/M and MS-DOS, LIBR will accept commands from standard input if no command line arguments are given. If the standard input is attached to the console, LIBR will prompt. Multiple line input may be given by using a backslash as a continuation character on the end of a line. If standard input is redirected from a file, LIBR will take input from the file, without prompting. For example: LIBR libr> r file.lib 1.obj 2.obj 3.obj \ libr> 4.obj 5.obj 6.obj will perform much the same as if the .obj files had been typed on the command line. The libr> prompts were printed by LIBR itself, the remainder of the text was typed as input. LIBR prompt. A backslash at the end of the line will be interpreted to mean that more command lines follow. HI-TECH C USER'S MANUAL Page 85 APPENDIX 1 Error Messages Error Messages produced by the compiler are listed below. Each message is followed by the name of the program which produces it, and some further description of what causes the message or what to do about it. '.' expected after '..' P1 The ellipsis symbol must have three dots actuals too long CPP Reduce length of macro arguments argument list conflicts with prototype P1 The argument list in a function definition must agree with a prototype if one exists argument redeclared P1 This argument has been declared twice arithmetic overflow in constant expression CGEN Evaluation of this constant expression produced an arithmetic overflow. This may or may not represent a true error. array index out of bounds P1 An array index expression evaluates to a constant which is less than zero or greater than or equal to the dimension of the array Assertion CGEN Internal error - contact HI-TECH attempt to modify const object P1 An attempt has been made to assign to or otherwise modify an object designated as 'const' bad bitfield type P1 Bitfields must be of type 'int' Bad conval CGEN Internal error - contact HI-TECH Bad dimensions CGEN An array has bad dimensions - probably zero Bad element count expr CGEN Internal error - contact HI-TECH bad formal CPP Check macro defintion syntax Page 86 HI-TECH C USER'S MANUAL bad include syntax CPP Use only "" and <> for include files Bad int. code CGEN The intermediate code file has been corrupted - can be caused by running out of disk space Bad -M option CGEN A -M option passed to the code generator is unknown Bad mod '+' for how = c CGEN Internal error - contact HI-TECH bad object code format LINK This file is either corrupted or not a valid object file Bad op d to swaplog CGEN Internal error - contact HI-TECH Bad op n to revlog CGEN Internal error - contact HI-TECH bad origin format in spec LINK An address in a -p option is invalid bad '-p' format LINK The -p option provided is invalid Bad pragma c CGEN The code generator has been passed a pragma it does not know about Bad putwsize CGEN Internal error - contact HI-TECH bad storage class P1, CGEN The speficied storage class is illegal Bad U usage CGEN Internal error - contact HI-TECH Bit field too large (n bits) CGEN A bit field may not be larger than an int Cannot get memory LINK The linker has run out of dynamic memory Can't be both far and near P1 The 'far' and 'near' keywords cannot appear in the same type specifier can't be long P1 Chars and shorts cannot be long can't be register P1 An extern or static variable may not be register HI-TECH C USER'S MANUAL Page 87 can't be short P1 Float and char cannot be short can't be unsigned P1 Float cannot be unsigned can't call an interrupt function P1 A function qualified 'interrupt' can only be called by hardware, not by an ordinary function call Can't create filename CGEN The file specified could not be created Can't create xref file P1 The cross reference file specified could not be created Can't create CPP Output file could not be created Can't create LINK The linker cannot create a file Can't find include file CPP Check and correct the include file name - spaces are not allowed in file names Can't find register for bits CGEN Internal error - contact HI-TECH Can't generate code for this expression CGEN The code generator is unable to generate code for this expression - simplifying the expression (e.g. computing values into temporary variables) will usually correct it, otherwise contact HI-TECH can't have array of functions P1 You cannot have an array of functions - you can have an array of pointers to functions Can't have 'port' variable CGEN You cannot declare a variable to be qualified 'port' - you can only use port to qualify pointers or typecast constant values can't have storage class P1 A storage class may not appear in a prototype argument can't initialise auto aggregates P1 You cannot initialise a structure or array inside a function unless it is static can't initialize arg P1 An argument cannot have an initializer can't mix proto and non-proto args P1 You cannot mix prototype and non-prototype arguments even in a function definition Page 88 HI-TECH C USER'S MANUAL Can't open filename CGEN The file specified could not be opened for reading Can't open LINK The linker cannot open a file Can't seek LINK The linker could not seek in file can't take address of register variable P1 You can't take the address of a variable in a register can't take sizeof func CGEN You can't take the size of a function. You can take the size of a function call can't take this address P1 The expression does not have an address 'case' not in switch P1 A 'case' label is permitted only inside a switch char const too long P1 A character constant may have only one character in it close error (disk space?) P1 Probably out of disk space common symbol psect conflict LINK A common symbol is defined to be in more than one psect constant conditional branch CGEN You have a program structure testing a constant expres- sion, e.g. while(1). You should substitute for this the more efficient for(;;) constant expression required P1 A constant expression is required in e.g. an array dimension constant operand to || or && CGEN A logical operator has a constant operand which has been optimized out declarator too complex P1 This declaration is too complex for the compiler to handle default case redefined P1 Only one default case is permitted in a switch 'default' not in switch P1 A 'default' label is permitted only inside a switch digit out of range P1 An octal constant may not contain 7 or 8, and a decimal constant may not contain A-F HI-TECH C USER'S MANUAL Page 89 dimension required P1 A dimension is required for all except the most signi- ficant in an array declaration Division by zero CGEN Attempt to divide by zero in this expression Duplicate case label n CGEN There are two case labels in this switch that have the same value Duplicate -d flag LINK Only one -d flag is allowed to the linker duplicate label P1 This label is defined twice Duplicate -m flag LINK Only one -m flag is allowed to the linker duplicate qualifier P1 The same qualifier appears more than once in this type specifier entry point multiply defined LINK A program can only have one entry point (start address) EOF in #asm P1 End of file was encounterd after #asm and before a #endasm was seen Error closing output file CGEN,CPP Probably means you have run out of disk space excessive -I file ignored CPP Use fewer -I options expand - bad how CGEN Internal error - contact HI-TECH expand - bad which CGEN Internal error - contact HI-TECH exponent expected P1 An exponent is expected after the 'e' or 'E' in a floating point constant. The exponent must contain only +, - and digits 0-9 Expression error CGEN Internal error - contact HI-TECH expression generates no code CGEN This expression has no side effects and thus generates no code. It has been optimized out expression syntax P1 The expression is badly formed Page 90 HI-TECH C USER'S MANUAL expression too complex P1 The expression has too many nested parantheses or other nested constructs Fixup overflow referencing LINK The linker has relocated a reference to a psect or sym- bol and the relocated address is too big to fit into the space, e.g. a relocated one byte address exceeds 256 or a relocated 16 bit address exceeds 65536 float param coerced to double P1 This float parameter has been converted to double - a prototype will override this coercion function() declared implicit int P1 This function has been called without an explicit declaration. It is wise to explicitly declare all func- tions, preferably with a prototype. This will avoid many potential errors where your program comprises more than one source file function does not take arguments P1 The prototype for this function indicates it takes no arguments function or function pointer required P1 A function identifier or pointer to function is required for a function call. functions can't return arrays P1 A function cannot return an array - it can return a pointer functions can't return functions P1 A function cannot return a function - it can return a pointer to function hex digit expected P1 A hex digit is expected after '0x' identifier is a structure tag P1 A structure tag has been used in a context where another kind of tag is expected, e.g. saying struct fred where fred has previously been declared as union fred. identifier is a union tag P1 Similar to the above error identifier is an enum tag P1 Similar to the above error identifier: large offset CGEN Z80 only: This identifier has a large offset from the stack frame and thus access to it is inefficient. In a function any arrays should be declared after any simple variables HI-TECH C USER'S MANUAL Page 91 identifier redeclared P1 The identifier has been redeclared with different attributes identifier redefined P1 An identifier has been defined twice If-less else CPP Check #if usage If-less endif CPP Check #if usage illegal '#' directive P1 A # directive passed through to the first pass is unk- nown. If this occurs with a #include it may be caused by a previous include file not having a or newline on the last line. Illegal character in preprocessor if CPP Check for strange character illegal character P1 A character unknown to the compiler has been encoun- tered. The value given is the octal value of the char- acter illegal conversion between pointer types P1 The expression causes one pointer type to be converted to another incompatible type illegal conversion of integer to pointer P1 An integer is used where a pointer is expected illegal conversion of pointer to integer P1 A pointer is used where an integer is expected illegal conversion P1 The type conversion here is illegal Illegal flag LINK This option is illegal illegal function qualifier(s) P1 A function cannot have 'const' qualification illegal initialisation P1 The initialisation of this variable is illegal Illegal number CPP Check number syntax illegal type for array dimension P1 An array dimension must be an integral quantity illegal type for index expression P1 An array index must be a simple integral expression Page 92 HI-TECH C USER'S MANUAL illegal type for switch expression P1 The expression in a 'switch' must be integral illegal use of void expression P1 Void expressions may not be used in any way implicit conversion of float to integer P1 A floating point value has been converted to integer - truncation may occur implicit return at end of non-void function P1 A function with a non-void type has returned without a return statement implict signed to unsigned conversion P1 Unwanted sign extension may occur here. Add an explicit typecast to force exactly the conversion you want inappropriate break/continue P1 inappropriate 'else' P1 An 'else' has appeared without a matching 'if' inconsistent storage class P1 Only one storage class may be specified in a declara- tion inconsistent type P1 Only one basic type may be specified in a declaration initialisation illegal in arg list P1 You cannot initialise a function parameter initialisation syntax P1 The syntax of this initialisation is illegal initializer in 'extern' declaration P1 A declaration with the 'extern' keyword has an initial- izer; this is not permitted as the extern declaration reserves no storage integer constant expected P1 An integer constant was expected here integer expression required P1 An integral expression is required here integral type required P1 An integral type is required here large offset CGEN Z80 only: This identifier has a large offset from the stack frame and thus access to it is inefficient. In a function any arrays should be declared after any simple variables HI-TECH C USER'S MANUAL Page 93 Line too long P1 The source line is too long, or does not have a or newline at the end local psect conflicts with global psect of same name LINK A local psect cannot have the same name as a global psect logical type required P1 A logical type (i.e. an integral type) is required as the subject of a conditional expression lvalue required P1 An lvalue, i.e. something which can be assigned to, is required after an '&' or on the left hand of an assign- ment macro recursion CPP A preprocessor macro has attempted to expand itself. This would create infinite recursion member is not a member of the struct/union P1 This member is not in the structure or union with which it is used members cannot be functions P1 A member cannot be a function - it can be a pointer to function Missing arg to -u LINK -u requires an argument Missing arg to -w LINK -w requires an argument missing ) CPP Put correct ) in expression Missing number after % in -p option LINK After % in a -p option there must be a number Missing number after pragma 'pack' P1 The correct syntax is #pragma pack(n) where n is 1, 2 or 4. module has code below file base LINK A -C option was specified but the program has code below the address specified as the base of the binary file multiply defined symbol LINK A symbol is defined more than once name is a union, struct or enum P1 A union, struct or enum tag has been re-used in a dif- ferent context Page 94 HI-TECH C USER'S MANUAL No case labels CGEN This switch has no case labels no identifier in declaration P1 This declaration should have an identifier in it No room CGEN The code generator has run out of dynamic memory. You will need to reduce the number of symbols and/or the complexity of expressions No source file CPP Source file could not be found - check spelling, direc- tory paths etc. no space CPP Reduce number/size of macro definitions no start record: entry point defaults to zero LINK No start address has been specified for the program; the linker has set the start address to 0 Non-constant case label CGEN This case label does not evaluate to an integral con- stant non-void function returns no value P1 A function which should return a value has a 'return' statement with no value not a variable identifier P1 The identifier is not a variable - it may be e.g. a label or structure tag not an argument P1 This identifier is not in the argument list for this function only functions may be qualified interrupt P1 The type qualifier 'interrupt' may be applied only to functions, not variables. only functions may be void P1 Only functions, not variables, may be declared void only lvalues may be assigned to or modified P1 You have attempted to modify an expression which does not identify a storage location only register storage class allowed P1 A parameter may only be auto or register operands of operator not same pointer type P1 The operands to the named operator in the expression are both pointers but are not the same pointer type HI-TECH C USER'S MANUAL Page 95 operands of operator not same type P1 The operands to the named operator in the expression are incompatible types pointer required P1 A pointer is required after a '*' (indirection) opera- tor popreg - bad reg CGEN Internal error - contact HI-TECH portion of expression has no effect CGEN A portion of this expression has no effect on its value and no side effects probable missing '}' in previous block P1 A declaration has been encountered where an expression was expected. The likely cause of this is that you have omitted a closing '}' in the function above this point. psect cannot be in classes a and b LINK A psect can only be in one class psect exceeds max size LINK This psect is larger than a specified maximum size psect is absolute LINK This psect is absolute and cannot have a link address specified in a -p option Psect not loaded on 0xhexnum boundary LINK This psect must be loaded on a specific boundary Psect not relocated on 0xhexnum boundary LINK This psect must be linked on a specific boundary psect origin multiply defined LINK This psect has its link address defined more than once pushreg - bad reg CGEN Internal error - contact HI-TECH redundant & applied to array P1 An array type has an '&' operator applied to it. It has been ignored since use of an array implicitly gives its address regused - bad arg to G CGEN Internal error - contact HI-TECH signatures do not matchLINK An extern function has been declared with an incorrect prototype. For example if an argument is declared as a long in an extern declaration, but is really an int, a signature mismatch will occur. Page 96 HI-TECH C USER'S MANUAL signed bitfields not supported P1 Only unsigned bitfields are supported simple type required P1 An array or structure type cannot be used here Sizeof yields 0 CGEN The size of an object has evaluated to zero in a con- text where this is illegal, e.g. incrementing a pointer to a zero length object. storage class illegal P1 A storage class may not be specified here struct/union member expected P1 A structure or union member is required after a '. or '->' struct/union redefined P1 This structure or union has been defined twice struct/union required P1 A structure or union identifier is required before a '.' Switch on long! CGEN Switching on a long expression is not supported symbol cannot be global LINK Stack, filename or line number symbols cannot be global Syntax error in checksum list LINK The checksum list provided is invalid token too long CPP Shorten token (e.g. identifier) too few arguments P1 The protype for this function lists more arguments than have been supplied too many arguments P1 More arguments have been supplied than listed in the prototype for this function Too many cases in switch CGEN,P1 There are too many cases in this switch too many -D options CPP Use fewer -D options too many defines CPP Reduce number of macro definitions Too many errors CGEN CGEN has given up because there were too many errors. HI-TECH C USER'S MANUAL Page 97 too many formals CPP Reduce number of parameters to this macro definition Too many initializers CGEN There are too many initializers for this object Too many psects LINK There are too many psects for the symbol table Too many symbols LINK There are too many symbols for the linker symbol table too many -U options CPP Use fewer -U options too much defining CPP Reduce number/size of macros too much indirection P1 Too many '*'s in this declaration too much pushback CPP Simplify macro usage type conflict P1 There is a conflict of types in this expression, e.g. attempting to assign a structure to a simple type type specifier reqd. for proto arg P1 A prototype argument must have a basic type undefined control CPP Check use of # undefined enum tag P1 This enumerated type tag has not been defined undefined identifier P1 This identifier has not been defined before use undefined struct/union P1 The structure or union used has not been defined undefined symbol LINK A list of undefined symbols follows. If some of the symbols should be in a library which was linked, it may be caused by a library ordering problem. In this case rebuild the library with the correct ordering or specify the library more than once in the link command unexpected EOF P1 End of file was encountered in the middle of a C con- struct. This is commonly caused by omission of a clos- ing '}' earlier in the program. Unknown predicate CGEN Internal error - contact HI-TECH Page 98 HI-TECH C USER'S MANUAL unknown psect LINK The psect specifed in a -p option is not present in the program. Check the spelling and check the case - upper case does not match lower case unreachable code P1 This section of code can never be executed as there is no possible path to reach it Unreasonable include nesting CPP Reduce number of include files Unreasonable matching depth CGEN Internal error - contact HI-TECH unterminated macro call CPP Probably missing ) void function cannot return value P1 A function declared void cannot return a value Write error (out of disk space?) LINK Probably means the disk is full HI-TECH C USER'S MANUAL Page 99 APPENDIX 2 Standard Library Functions The functions accessible to user programs in the stan- dard library libc.lib are listed below, by category with a short comment, then alphabetically with a longer descrip- tion. In the detailed description of each function, the SYNOPSIS section describes the function in roughly the manner in which the function would be declared in the source file defining it. Where an include file is shown, this implies that that include file must be included in any source file using that function. Where an include file is not provided, it will normally be necessary for an extern declaration of the function to be included in any source module using it, to ensure that the type of the function is correct. For example, if the func- tion lseek() was to be used, a declaration of the form extern long lseek(); should be in either the source file itself or an include file included in the source file. This ensures that the com- piler knows that lseek() returns a long value and not the default int. Where reference is made to STDIO, this means the group of functions under the heading STANDARD I/O below. These all have one thing in common; they operate on pointers to a defined data type called FILE. Such a pointer is often referred to as a stream pointer. The concept of a stream is central to these routines. Essentially a stream is a source or sink of data bytes. To the operating system and library routines this stream is featureless, i.e. no record struc- ture is implied or assumed. Some routines do however recog- nize end of line characters. STANDARD I/O fopen(name, mode) Open file for I/O freopen(name, mode, stream) Re-open existing stream fdopen(fd, mode) Associate a stream with a file descriptor fclose(stream) Close open file fflush(stream) Flush buffered data getc(stream) Read byte from stream fgetc(stream) Same as getc ungetc(c, stream) Push char back onto stream putc(c, stream) Write byte to stream fputc(c, stream) Same as putc() getchar() Read byte from standard input putchar(c) Write byte to standard output getw(stream) Read word from stream Page 100 HI-TECH C USER'S MANUAL putw(w, stream) Write word to stream gets(s) Read line from standard input fgets(s, n, stream) Read string from stream puts(s) Write string to standard output fputs(s, stream) Write string to stream fread(buf, size, cnt, stream) Binary read from stream fwrite(buf, size, cnt, stream) Binary write to stream fseek(stream, offs, wh) Random access positioning ftell(stream) Current file read/write position rewind(stream) Reposition file pointer to start setvbuf(stream, buf, mode, size) Enable/disable buffering of stream fprintf(stream, fmt, args) Formatted output on stream printf(fmt, args) Formatted standard output sprintf(buf, fmt, args) Formatted output to a string vfprintf(stream, fmt, va_ptr) Formatted output on stream vprintf(fmt, va_ptr) Formatted standard output vsprintf(buf, fmt, va_ptr) Formatted output to a string fscanf(stream, fmt, args) Formatted input from stream scanf(fmt, args) Formatted standard input sscanf(buf, fmt, va_ptr) Formatted input from a string vfscanf(stream, fmt, va_ptr) Formatted input from stream vscanf(fmt, args) Formatted standard input vsscanf(buf, fmt, va_ptr) Formatted input from a string feof(stream) True if stream at EOF ferror(stream) True if error on stream clrerr(stream) Reset error status on stream fileno(stream) Return fd from stream remove(name) Remove (delete) file STRING HANDLING atoi(s) Convert ASCII decimal to integer atol(s) Convert ASCII decimal to long integer atof(s) Convert ASCII decimal to float xtoi(s) Convert ASCII hexadecimal to integer memchr(s, c, n) Find char in memory block memcmp(s1, s2, n) Compare n bytes of memory memcpy(s1, s2, n) Copy n bytes from s2 to s1 memmove(s1, s2, n) Copy n bytes from s2 to s1 memset(s, c, n) Set n bytes at s to c strcat(s1, s2) Append string 2 to string 1 strncat(s1, s2, n) Append at most n chars to string 1 strcmp(s1, s2) Compare strings strncmp(s1, s2, n) Compare n bytes of strings strcpy(s1, s2) Copy s2 to s1 strncpy(s1, s2, n) Copy at most n bytes of s2 strerror(errnum) Map errnum to an error message string strlen(s) Length of string strchr(s, c) Find char in string strrchr(s, c) Find rightmost char in string strspn(s1, s2) Length of s1 composed of chars from s2 strcspn(s1, s2) Length of s2 composed of chars not from s2 strstr(s1, s2) Locate the first occurence of s2 in s1 HI-TECH C USER'S MANUAL Page 101 LOW LEVEL I/O open(name, mode) Open a file close(fd) Close a file creat(name) Create a file dup(fd) Duplicate file descriptor lseek(fd, offs, wh) Random access positioning read(fd, buf, cnt) Read from file rename(name1, name2) Rename file unlink(name) Remove file from directory write(fd, buf, cnt) Write to file isatty(fd) True if fd refers to tty-like device stat(name, buf) Get information about a file chmod(name, mode) Set file attributes CHARACTER TESTING isalpha(c) True if c is a letter isupper(c) Upper case letter islower(c) Lower case letter isdigit(c) Digit isalnum(c) Alphnumeric character isspace(c) Space, tab, newline, return or formfeed ispunct(c) Punctuation character isprint(c) Printable character isgraph(c) Printable non-space character iscntrl(c) Control character isascii(c) Ascii character (0-127) FLOATING POINT cos(f) Cosine function sin(f) Sine function tan(f) Tangent function acos(f) Arc cosine function asin(f) Arc sine function atan(f) Arc tangent function exp(f) Exponential of f log(f) Natural log of f log10(f) Base 10 log of f pow(x,y) X to the y'th power sqrt(f) Square root fabs(f) Floating absolute value ceil(f) Smallest integral value >= f floor(f) Largest integral value <= f sinh(f) Hyperbolic sine cosh(f) Hyperbolic cosine tanh(f) Hyperbolic tangent frexp(y, p) Split into mantissa and exponent ldexp(y, i) Load new exponent CONSOLE I/O Page 102 HI-TECH C USER'S MANUAL getch() Get single character getche() Get single character with echo putch(c) Put single character ungetch(c) Push character back kbhit() Test for key pressed cgets(s) Get line from console cputs(s) Put string to console DATE AND TIME FUNCTIONS time(p) Get current date/time gmtime(p) Get broken down Universal time localtime(p) Get broken down local time asctime(t) Convert broken down time to ascii ctime(p) Convert time to ascii MISCELLANEOUS execl(name, args) Execute another program execv(name, argp) Execute another program spawnl(name, arg, ...) Execute a subprogram spawnv(name, argp) Execute a subprogram system(s) Execute system command atexit(func) Install func to be executed on termination exit(status) Terminate execution _exit(status) Terminate execution immediately getuid() Get user id (CP/M) setuid(uid) Set user id (CP/M) chdir(s) Change directory (MS-DOS) mkdir(s) Create directory (MS-DOS) rmdir(s) Remove directory (MS-DOS) getcwd(drive) Get current working directory (MS-DOS) signal(sig, func) Set trap for interrupt condition brk(addr) Set memory allocation sbrk(incr) Adjust memory allocation malloc(cnt) Dynamic memory allocation free(ptr) Dynamic memory release realloc(ptr, cnt) Dynamic memory reallocation calloc(cnt, size) Dynamic memory allocation zeroed perror(s) Print error message qsort(base, nel, width, func) Quick sort srand(seed) Initialize random number generator rand() Get next random number setjmp(buf) Setup for non-local goto longjmp(buf, val) Non-local goto _getargs(buf, name) Wild card expansion and i/o redirection inp(port) Read port outp(port, data) Write data to port bdos(func, val) Perform bdos call (CP/M) msdos(func, val, val, ...) Perform msdos call msdoscx(func, val, val, ...) Alternate msdos call intdos(ip, op) Execute DOS interrupt HI-TECH C USER'S MANUAL Page 103 intdosx(ip, op, sp) Execute DOS interrupt segread(sp) Get segment register values int86(int, ip, op) Execute software interrupt int86x(int, ip, op, sp) Execute software interrupt bios(n, c) Call bios entry (CP/M) ei() Enable interrupts di() Disable interrupts set_vector(vec, func) Set an interrupt vector assert(e) Run time assertion getenv(s) Get environment string (MS-DOS) ACOS, ASIN, ATAN, ATAN2 SYNOPSIS #include double acos(double f) double asin(double f) double atan(double f) double atan2(double x, double y) DESCRIPTION These functions are the converse of the trignometric functions cos, sin and tan. Acos and asin are undefined for arguments whose absolute value is greater than 1.0. The returned value is in radians, and always in the range -pi/2 to +pi/2, except for cos(), which returns a value in the range 0 to pi. Atan2() returns the inverse tan of x/y but uses the signs of its arguments to return a value in the range -pi to +pi. SEE ALSO sin, cos, tan Page 104 HI-TECH C USER'S MANUAL ATEXIT SYNOPSIS #include int atexit(void (*func)(void)); DESCRIPTION The atexit() function registers the function pointed to by func, to be called without arguments at normal pro- gram termination. Ateixt() returns zero if the regis- tration succeeds, nonzero if it fails. On program ter- mination, all functions registered by atexit() are called, in the reverse order of their registration. SEE ALSO exit ASCTIME SYNOPSIS #include char * asctime(time_t t) DESCRIPTION Asctime() takes the broken down time pointed to by its argument, and returns a 26 character string describing the current date and time in the format Sun Sep 16 01:03:52 1973\n\0 Note the newline at the end of the string. The width of each field in the string is fixed. SEE ALSO ctime, time, gmtime, localtime HI-TECH C USER'S MANUAL Page 105 ASSERT SYNOPSIS #include void assert(int e) DESCRIPTION This macro is used for debugging purposes; the basic method of usage is to place assertions liberally throughout your code at points where correct operation of the code depends upon certain conditions being true initially. An assert() may be used to ensure at run time that that assumption holds. For example, the fol- lowing statement asserts that the pointer tp is non- null: assert(tp); If at run time the expression evaluates to false, the program will abort with a message identifying the source file and line number of the assertion, and the expression used as an argument to it. A fuller discus- sion of the uses of assert is impossible in limited space, but it is closely linked to methods of proving program correctness. ATOF, ATOI, ATOL SYNOPSIS #include double atof(char * s) int atoi(char * s) #include long atol(char * s) DESCRIPTION These routines convert a decimal number in the argument string s into a double float, integer or long integer respectively. Leading blanks are skipped over. In the case of atof(), the number may be in scientific nota- tion. Page 106 HI-TECH C USER'S MANUAL BDOS (CP/M only) SYNOPSIS #include char bdos(int func, int arg) short bdoshl(int func, int arg)(CP/M-80 only) DESCRIPTION Bdos() calls the CP/M BDOS with func in register C (CL for CP/M-86) and arg in register DE (DX). The return value is the byte returned by the BDOS in register A (AX). Bdoshl() is the same, except that the return value is the value returned by the BDOS in HL. Con- stant values for the various BDOS function values are defined in cpm.h. These functions should be avoided except in programs which are not intended to be used on an operating sys- tem other than CP/M. The standard I/O routines are to be preferred, since they are portable. SEE ALSO bios, msdos BIOS (CP/M only) SYNOPSIS #includ char bios(int n, int a1, int a2) DESCRIPTION This function will call the n'th bios entry point (cold boot = 0, warm boot = 1, etc.) with register BC (CX) set to the argument a1 and DE (DX) set to the argument a2. The return value is the contents of register A (AX) after the bios call. On CP/M-86, bdos function 50 is used to perform the bios call. This function should not be used unless unavoidable, since it is highly non-portable. There is even no guarantee of portability of bios calls between differing CP/M systems. SEE ALSO bdos HI-TECH C USER'S MANUAL Page 107 CALLOC SYNOPSIS #include char * calloc(size_t cnt, size_t size) DESCRIPTION Calloc() attempts to obtain a contiguous block of dynamic memory which will hold cnt objects, each of length size. The block is filled with zeroes. A pointer to the block is returned, or 0 if the memory could not be allocated. SEE ALSO brk, sbrk, malloc, free CGETS, CPUTS SYNOPSIS #include char * cgets(char * s) void cputs(char * s) DESCRIPTION Cputs() will read one line of input from the console into the buffer passed as an argument. It does so by repeated calls to getche(). Cputs() writes its argu- ment string to the console, outputting carriage returns before each newline in the string. It calls putch() repeatedly. SEE ALSO getch, getche, putch Page 108 HI-TECH C USER'S MANUAL CHDIR SYNOPSIS #include int chdir(char * s) DESCRIPTION This function is availble only under MS-DOS. It changes the current working directory to the path name supplied as argument. This path name be be absolute, as in A:\FRED, or relative, as in ..\SOURCES. A return value of -1 indicates that the requested change could not be performed. SEE ALSO mkdir, rmdir, getcwd CHMOD SYNOPSIS #include int chmod(char * name, int ) char * name; int mode; DESCRIPTION This function changes the file attributes (or modes) of the named file. The argument name may be any valid file name. The mode argument may include all bits defined in stat.h except those relating to the type of the file, e.g. S_IFDIR. Note however that not all bits may be changed under all operating systems, e.g. nei- ther DOS nor CP/M permit a file to be made unreadable, thus even if mode does not include S_IREAD the file will still be readable (and stat() will still return S_IREAD in flags). SEE ALSO stat, creat HI-TECH C USER'S MANUAL Page 109 CLOSE SYNOPSIS #include int close(int fd) DESCRIPTION This routine closes the file associated with the file descriptor fd, which will have been previously obtained from a call to open(). Close() returns 0 for a success- ful close, or -1 otherwise. SEE ALSO open, read, write, seek CLRERR, CLREOF SYNOPSIS #include void clrerr(FILE * stream) void clreof(FILE * stream) DESCRIPTION These are macros, defined in stdio.h, which reset the error and end of file flags respectively for the speci- fied stream. They should be used with care; the major valid use is for clearing an EOF status on input from a terminal-like device, where it may be valid to continue to read after having seen an end-of-file indication. SEE ALSO fopen, fclose Page 110 HI-TECH C USER'S MANUAL COS SYNOPSIS #include double cos(double f) DESCRIPTION This function yields the cosine of its argument. SEE ALSO sin, tan, asin, acos, atan COSH, SINH, TANH SYNOPSIS #include double cosh(double f) double sinh(double f) double tanh(double f) DESCRIPTION These functions implement the hyperbolic trig func- tions. HI-TECH C USER'S MANUAL Page 111 CREAT SYNOPSIS #include int creat(char * name, int mode) DESCRIPTION This routine attempts to create the file named by name. If the file exists and is writeable, it will be removed and re-created. The return value is -1 if the create failed, or a small non-negative number if it succeeded. This number is a valuable token which must be used to write to or close the file subsequently. Mode is used to initialize the attributes of the created file. The allowable bits are the same as for chmod(), but for Unix compatibility it is recommended that a mode of 0666 or 0600 be used. Under CP/M the mode is ignored - the only way to set a files attributes is via the chmod() function. SEE ALSO open, close, read, write, seek, stat, chmod CTIME SYNOPSIS #include char * ctime(time_t t) DESCRIPTION Ctime() converts the time in seconds pointed to by its argument to a string of the same form as described for asctime. Thus the following program prints the current time and date: #include main() { time_t t; time(&t); printf("%s", ctime(&t)); } Page 112 HI-TECH C USER'S MANUAL SEE ALSO gmtime, localtime, asctime, time DIV, LDIV SYNOPSIS #include div_t div(int numer, int denom) ldiv_t ldiv(long numer, long denom) DESCRIPTION The div() function computes the quotient and remainder of the divison of numer by denom. The div() function returns a structure of type div_t, containing both the quotient and remainder. ldiv() is similar to div() except it takes arguments of type long and returns a structure of type ldiv_t. The types div_t and ldiv_t are defined in as follows: typedef struct { intquot, rem; } div_t; typedef struct { longquot, rem; } ldiv_t; HI-TECH C USER'S MANUAL Page 113 DI, EI SYNOPSIS void ei(void); void di(void); DESCRIPTION Ei() and di() enable and disable interrupts respec- tivly. DUP SYNOPSIS #include int dup(int fd) DESCRIPTION Given a file descriptor, such as returned by open(), this routine will return another file descriptor which will refer to the same open file. -1 is returned if the fd argument is a bad descriptor or does not refer to an open file. SEE ALSO open, close, creat, read, write Page 114 HI-TECH C USER'S MANUAL EXECL, EXECV SYNOPSIS #include int execl(char * name, pname, ...) int execv(char * name, ppname) DESCRIPTION Execl() and execv() load and execute the program speci- fied by the string name. Execl() takes the arguments for the program from the zero-terminated list of string arguments. Execv() is passed a pointer to an array of strings. The array must be zero-terminated. If the named program is found and can be read, the call does not return. Thus any return from these routines may be treated as an error. SEE ALSO spawnl, spawnv, system EXIT SYNOPSIS #include void exit(int status) DESCRIPTION This call will close all open files and exit from the program. On CP/M, this means a return to CCP level. Status will be stored in a known place for examination by other programs. This is only useful if the program executing was actually invoked by another program which is trapping warm boots. The status value will be stored on CP/M at 80H. This call will never return. SEE ALSO atexit HI-TECH C USER'S MANUAL Page 115 _EXIT SYNOPSIS #include void _exit(int status) DESCRIPTION This function will cause an immediate exit from the program, without the normal flushing of stdio buffers that is performed by exit(). SEE ALSO exit EXP, LOG, LOG10, POW SYNOPSIS #include double exp(double f) double log(double f) double log10(double f) double pow(double x, y) DESCRIPTION Exp() returns the exponential function of its argument, log() the natural logarithm of f, and log10() the loga- rithm to base 10. Pow() returns the value of x raised to the y'th power. Page 116 HI-TECH C USER'S MANUAL FABS, CEIL, FLOOR SYNOPSIS #include double fabs(double f) double ceil(double f) double floor(double f) DESCRIPTION These routines return respectively the absolute value of f, the smallest integral value not less than f, and the largest integral value not greater than f. FCLOSE SYNOPSIS #include int fclose(FILE * stream) DESCRIPTION This routine closes the specified i/o stream. Stream should be a token returned by a previous call to fopen(). NULL is returned on a successful close, EOF otherwise. SEE ALSO fopen, fread, fwrite HI-TECH C USER'S MANUAL Page 117 FEOF, FERROR SYNOPSIS #include feof(FILE * stream) ferror(FILE * stream) DESCRIPTION These macros test the status of the EOF and ERROR bits respectively for the specified stream. Each will be true if the corresponding flag is set. The macros are defined in stdio.h. Stream must be a token returned by a previous fopen() call. SEE ALSO fopen, fclose FFLUSH SYNOPSIS #include int fflush(FILE * stream) DESCRIPTION Fflush() will output to the disk file or other device currently open on the specified stream the contents of the associated buffer. This is typically used for flushing buffered standard output in interactive appli- cations. SEE ALSO fopen, fclose Page 118 HI-TECH C USER'S MANUAL FGETC SYNOPSIS #include int fgetc(FILE * stream) DESCRIPTION Fgetc() returns the next character from the input stream. If end-of-file is encountered EOF will be returned instead. It is for this reason that the func- tion is declared as int. The integer EOF is not a valid byte, thus end-of-file is distinguishable from reading a byte of all 1 bits from the file. Fgetc() is the non-macro version of getc(). SEE ALSO fopen, fclose, fputc, getc, putc FGETS SYNOPSIS #include char * fgets(char * s, size_t n, char * stream) DESCRIPTION Fgets() places in the buffer s up to n-1 characters from the input stream. If a newline is seen in the input before the correct number of characters is read, then fgets() will return immediately. The newline will be left in the buffer. The buffer will be null ter- minated in any case. A successful fgets() will return its first argument; NULL is returned on end-of-file or error. HI-TECH C USER'S MANUAL Page 119 FILENO SYNOPSIS fileno(FILE * stream) DESCRIPTION Fileno() is a macro from stdio.h which yields the file descriptor associated with stream. It is mainly used when it is desired to perform some low-level operation on a file opened as a stdio stream. SEE ALSO fopen, fclose, open, close FOPEN SYNOPSIS #include FILE * fopen(char * name, char * mode); DESCRIPTION DESCRIPTION Fopen() attempts to open file for reading or writing (or both) according to the mode string supplied. The mode string is interpreted as follows: r The file is opend for reading if it exists. If the file does not exist the call fails. r+ If the file exists it is opened for reading and writ- ing. If the file does not already exist the call fails. w The file is created if it does not exist, or truncated if it does. It is then opened for writing. w+ The file is created if it does not already exist, or truncated if it does. The file is opened for reading and writing. a The file is created if it does not already exist, and opened for writing. All writes will be dynamically forced to the end of file, thus this mode is known as append mode. a+ The file is created if it does not already exist, and opened for reading and writing. All writes to the file will be dynamically forced to the end of the file, i.e. while any portion of the file may be read, all writes Page 120 HI-TECH C USER'S MANUAL will take place at the end of the file and will not overwrite any existing data. Calling fseek() in an attempt to write at any other place in the file will not be effective. The "b" modifier may be appended to any of the above modes, e.g. "r+b" or "rb+" are equivalent. Adding the "b" modifier will cause the file to be opened in binary rather than ASCII mode. Opening in ASCII mode ensures that text files are read in a manner compatible with the Unix-derived conventions for C programs, i.e. that text files contain lines delimited by newline characters. The special treat- ment of read or written characters varies with the operating system, but includes some or all of the following: NEWLINE (LINE FEED) Converted to carriage return, line feed on output. RETURN Ignored on input, inserted before NEWLINE on output. CTRL-Z Signals EOF on input, appended on fclose on output if necessary on CP/M. Opening a file in binary mode will allow each character to be read just as written, but because the exact size of a file is not known to CP/M, the file may contain more bytes than were written to it. See open() for a description of what constitutes a file name. When using one of the read/write modes (with a '+' character in the string), although they permits reading and writing on the same stream, it is not possible to arbi- trarily mix input and output calls to the same stream. At any given time a stream opened with a "+" mode will be in either an input or output state. The state may only be changed when the associated buffer is empty, which is only guaranteed immediately after a call to fflush() or one of the file positioning functions fseek() or rewind(). The buffer will also be empty after encountering EOF while read- ing a binary stream, but it is recommended that an explicit call to fflush() be used to ensure this situation. Thus after reading from a stream you should call fflush() or fseek() before attempting to write on that stream, and vice versa. SEE ALSO fclose, fgetc, fputc, freopen HI-TECH C USER'S MANUAL Page 121 FPRINTF SYNOPSIS #include fprintf(FILE * stream, char * fmt, ...); vfprintf(FILE * stream, va_list va_arg); DESCRIPTION Fprintf() performs formatted printing on the specified stream. Refer to printf() for the details of the avail- able formats. Vfprintf() is similar to fprintf() but takes a variable argument list pointer rather than a list of arguments. See the description of vastart() for more information on variable argument lists. SEE ALSO printf, fscanf, sscanf FPUTC SYNOPSIS #include int fputc(int c, FILE * stream) DESCRIPTION The character c is written to the supplied stream. This is the non-macro version of putc(). The character is returned if it was successfully written, EOF is returned otherwise. Note that "written to the stream" may mean only placing the character in the buffer asso- ciated with the stream. SEE ALSO putc, fgetc, fopen, fflush Page 122 HI-TECH C USER'S MANUAL FPUTS SYNOPSIS #include int fputs(char * s, FILE * stream) DESCRIPTION The null-terminated string s is written to the stream. No newline is appended (cf. puts() ). The error return is EOF. SEE ALSO puts, fgets, fopen, fclose FREAD SYNOPSIS #include int fread(void * buf, size_t size, size_t cnt, FILE * stream) DESCRIPTION Up to cnt objects, each of length size, are read into memory at buf from the stream. The return value is the number of objects read. If none is read, 0 will be returned. Note that a return value less than cnt, but greater than 0, may not represent an error (cf. fwrite() ). No word alignment in the stream is assumed or necessary. The read is done via successive getc()'s. SEE ALSO fwrite, fopen, fclose, getc HI-TECH C USER'S MANUAL Page 123 FREE SYNOPSIS #include void free(void * ptr) DESCRIPTION Free() deallocates the block of memory at ptr, which must have been obtained from a call to malloc() or cal- loc(). SEE ALSO malloc, calloc FREOPEN SYNOPSIS #include FILE * freopen(char * name, char * mode, FILE * stream) DESCRIPTION Freopen() closes the given stream (if open) then re- opens the stream attached to the file described by name. The mode of opening is given by mode. It either returns the stream argument, if successful, or NULL if not. See fopen() for more information. SEE ALSO fopen, fclose Page 124 HI-TECH C USER'S MANUAL FREXP, LDEXP SYNOPSIS #include double frexp(double f, int * p) double ldexp(double f, int i) DESCRIPTION Frexp() breaks a floating point number into a normal- ized fraction and an integral power of 2. The integer is stored into the int object pointed to by p. Its return value x is in the interval [0.5, 1.0) or zero, and f equals x times 2 raised to the power stored in *p. If f is zero, both parts of the result are zero. Ldexp() performs the reverse operation; the integer i is added to the exponent of the floating point f and the resultant value returned. FSCANF SYNOPSIS #include int fscanf(FILE * stream, char * fmt, ...) DESCRIPTION This routine performs formatted input from the speci- fied stream. See scanf() for a full description of the behaviour of the routine. Vfscanf() is similar to fscanf() but takes a variable argument list pointer rather than a list of arguments. See the description of va_start() for more information on variable argument lists. SEE ALSO scanf, sscanf, fopen, fclose HI-TECH C USER'S MANUAL Page 125 FSEEK SYNOPSIS #include int fseek(FILE * stream, long offs, int wh) DESCRIPTION Fseek() positions the "file pointer" (i.e. a pointer to the next character to be read or written) of the speci- fied stream as follows: _____________________________ |_wh|____resultant_location__| | 0 | offs | | 1 | offs+previous location| | 2 | offs+length of file | |___|________________________| It should be noted that offs is a signed value. Thus the 3 allowed modes give postioning relative to the beginning of the file, the current file pointer and the end of the file respectively. EOF is returned if the positioning request could not be satisfied. Note how- ever that positioning beyond the end of the file is legal, but will result in an EOF indication if an attempt is made to read data there. It is quite in order to write data beyond the previous end of file. Fseek() correctly accounts for any buffered data. SEE ALSO lseek, fopen, fclose Page 126 HI-TECH C USER'S MANUAL FTELL SYNOPSIS #include long ftell(FILE * stream) DESCRIPTION This function returns the current position of the con- ceptual read/write pointer associated with stream. This is the position relative to the beginning of the file of the next byte to be read from or written to the file. SEE ALSO fseek FWRITE SYNOPSIS #include int fwrite(void * buf, size_t size, size_t cnt, FILE * stream) DESCRIPTION Cnt objects of length size bytes will be written from memory at buf, to the specified stream. The number of whole objects written will be returned, or 0 if none could be written. Any return value not equal to cnt should be treated as an error (cf. fread() ). SEE ALSO fread, fopen, fclose HI-TECH C USER'S MANUAL Page 127 _GETARGS SYNOPSIS #include char ** _getargs(char * buf, char * name) extern int _argc_; DESCRIPTION This routine performs I/O redirection (CP/M only) and wild card expansion. Under MS-DOS I/O redirection is performed by the operating system. It is called from startup code to operate on the command line if the -R option is used to the C command, but may also be called by user-written code. If the buf argument is null, it will read lines of text from standard input. If the standard input is a terminal (usually the console) the name argument will be written to the standard error stream as a prompt. If the buf argument is not null, it will be used as the source of the string to be pro- cessed. The returned value is a pointer to an array of strings, exactly as would be pointed to by the argv argument to the main() function. The number of strings in the array may be obtained from the global _argc_. For example, a typical use of this function would be: #include main(argc, argv) char ** argv; { extern char ** _getargs(); extern int _argc_; if(argc == 1) {/* no arguments */ argv = _getargs(0, "myname"); argc = _argc_; } . . . } There will be one string in the array for each word in the buffer processed. Quotes, either single (') or double (") may be used to include white space in "words". If any wild card characters (? or *) appear in a non-quoted word, it will be expanded into a string of words, one for each file matching the word. The usual CP/M conventions are followed for this expansion. On CP/M any occurence of the redirection characters > and < outside quotes will be handled in the following manner: > name will cause standard output to be redirected to the file name. Page 128 HI-TECH C USER'S MANUAL < name will cause standard input to be redirected from the file name. >> name will cause standard output to append to file name. White space is optional between the > or < character and the file name, however it is an error for a redirection character not to be followed by a file name. It is also an error if a file cannot be opened for input or created for output. An append redirection (>>) will create the file if it does not exist. If the source of text to be processed is standard input, several lines may be supplied by ending each line (except the last) with a backslash (\). This serves as a continuation character. Note that the newline follow- ing the backslash is ignored, and not treated as white space. GETC SYNOPSIS #include int getc(FILE * stream) FILE * stream; DESCRIPTION One character is read from the specified stream and returned. EOF will be returned on end-of-file or error. This is the macro version of fgetc(), and is defined in stdio.h. HI-TECH C USER'S MANUAL Page 129 GETCH, GETCHE, UNGETCH, PUTCH SYNOPSIS #include char getch(void) char getche(void) void putch(int c) DESCRIPTION Getch() reads a single character from the console key- board and returns it without echoing. Getche() is similar but does echo the character typed. Ungetch() will push back one character such that the next call to getch() or getche() will return that character. Putch() outputs the character c to the console screen, prepending a carriage return if the character is a new- line. SEE ALSO cgets, cputs GETCHAR SYNOPSIS #include int getchar(void) DESCRIPTION Getchar() is a getc(stdin) operation. It is a macro defined in stdio.h. Note that under normal cir- cumstances getchar() will NOT return unless a carriage return has been typed on the console. To get a single character immediately from the console, use the routine getch(). SEE ALSO getc, fgetc, freopen, fclose Page 130 HI-TECH C USER'S MANUAL GETCWD (MS-DOS only) SYNOPSIS #include char * getcwd(int drive) DESCRIPTION Getcwd() returns the path name of the current working directory on the specified drive, where drive == 0 represents the current drive, drive == 1 represents A:, drive == 2 represents B: etc. The return value is a pointer to a static area of memory which will be overwritten on the next call to getcwd(). SEE ALSO chdir GETENV SYNOPSIS #include char * getenv(char * s) extern char ** environ; DESCRIPTION Getenv() will search the vector of environment strings for one matching the argument supplied, and return the value part of that environment string. For example, if the environment contains the string COMSPEC=A:\COMMAND.COM then getenv("COMSPEC") will return A:\COMMAND.COM. The global variable environ is a pointer to an array of pointers to environment strings, terminated by a null pointer. This array is initialized at startup time under MS-DOS from the environment pointer supplied when the program was executed. Under CP/M no such environ- ment is supplied, so the first call to getenv() will attempt to open a file in the current user number on the current drive called ENVIRON. This file should con- tain definitions for any environment variables desired to be accessible to the program, e.g. HITECH=0:C: Each variable definition should be on a separate line, consisting of the variable name (conventionally all in upper case) followed without intervening white space by HI-TECH C USER'S MANUAL Page 131 an equal sign ('=') then the value to be assigned to that variable. GETS SYNOPSIS #include char * gets(char * s) DESCRIPTION Gets() reads a line from standard input into the buffer at s, deleting the newline (cf. fgets() ). The buffer is null terminated. It returns its argument, or NULL on end-of-file. SEE ALSO fgets, freopen GETUID (CP/M only) SYNOPSIS #include int getuid(void) DESCRIPTION Getuid() returns the current user number. On CP/M, the current user number determines the user number associ- ated with an opened or created file, unless overridden by an explicit user number prefix in the file name. SEE ALSO setuid, open Page 132 HI-TECH C USER'S MANUAL GETW SYNOPSIS #include int getw(FILE * stream) DESCRIPTION Getw() returns one word (16 bits for the Z80 and 8086) from the nominated stream. EOF is returned on end-of- file, but since this is a perfectly good word, the feof() macro should be used for testing for end-of- file. When reading the word, no special alignment in the file is necessary, as the read is done by two con- secutive getc()'s. The byte ordering is however unde- fined. The word read should in general have been writ- ten by putw(). SEE ALSO putw, getc, fopen, fclose GMTIME, LOCALTIME SYNOPSIS #include struct tm * gmtime(time_t * t) struct tm * localtime(time_t * t) DESCRIPTION These functions convert the time pointed to by t which is in seconds since 00:00:00 on Jan 1, 1970, into a broken down time stored in a structure as defined in time.h. Gmtime() performs a straight conversion, while localtime() takes into account the contents of the glo- bal integer time_zone. This should contain the number of minutes that the local time zone is WESTWARD of Greenwich. Since there is no way under MS-DOS of actu- ally pre-determining this value, by default localtime() will return the same result as gmtime(). SEE ALSO ctime, asctime, time HI-TECH C USER'S MANUAL Page 133 INP, OUTP SYNOPSIS char inp(unsigned port) void outp(unsigned, unsigned data) DESCRIPTION These routines read and write bytes to and from I/O ports. Inp() returns the data byte read from the specified port, and outp() outputs the data byte to the specified port. INT86, INT86X, INTDOS, INTDOSX SYNOPSIS #include int int86(int intno, union REGS * inregs, union REGS * outregs) int int86x(int intno, union REGS inregs, union REGS outregs, struct SREGS * segregs) int intdos(union REGS * inregs, union REGS * outregs) int intdosx(union REGS * inregs, union REGS * outregs, struct SREGS * segregs) DESCRIPTION These functions allow calling of software interrupts from C programs. Int86() and int86x() execute the software interrupt specified by intno while intdos() and intdosx() execute interrupt 21(hex), which is the MS-DOS system call interrupt. The inregs pointer should point to a union containing values for each of the general purpose registers to be set when executing the interrupt, and the values of the registers on return are copied into the union pointed to by outregs. The x versions of the calls also take a pointer to a union defining the segment register values to be set on execution of the interrupt, though only ES and DS are actually set from this structure. SEE ALSO segread Page 134 HI-TECH C USER'S MANUAL ISALNUM, ISALPHA, ISDIGIT, ISLOWER et. al. SYNOPSIS #include isalnum(char c) isalpha(char c) isascii(char c) iscntrl(char c) isdigit(char c) islower(char c) isprint(char c) isgraph(char c) ispunct(char c) isspace(char c) isupper(char c) char c; DESCRIPTION These macros, defined in ctype.h, test the supplied character for membership in one of several overlapping groups of characters. Note that all except isascii are defined for c iff isascii(c) is true. isalnum(c) c is alphanumeric isalpha(c) c is in A-Z or a-z isascii(c) c is a 7 bit ascii character iscntrl(c) c is a control character isdigit(c) c is a decimal digit islower(c) c is in a-z isprint(c) c is a printing char isgraph(c) c is a non-space printable character ispunct(c) c is not alphanumeric isspace(c) c is a space, tab or newline isupper(c) c is in A-Z isxdigit(c) c is in 0-9 or a-f or A-F SEE ALSO toupper, tolower, toascii HI-TECH C USER'S MANUAL Page 135 ISATTY SYNOPSIS #include int isatty(int fd) DESCRIPTION This tests the type of the file associated with fd. It returns true if the file is attached to a tty-like dev- ice. This would normally be used for testing if stan- dard input is coming from a file or the console. For testing STDIO streams, use isatty(fileno(stream)). KBHIT SYNOPSIS #include int kbhit(void) DESCRIPTION This function returns 1 if a character has been pressed on the console keyboard, 0 otherwise. Normally the character would then be read via getch(). SEE ALSO getch, getche Page 136 HI-TECH C USER'S MANUAL LONGJMP SYNOPSIS #include void longjmp(jmp_buf buf, int val) DESCRIPTION Longjmp(), in conjunction with setjmp(), provides a mechanism for non-local gotos. To use this facility, setjmp() should be called with a jmp_buf argument in some outer level function. The call from setjmp() will return 0. To return to this level of execution, longjmp() may be called with the same jmp_buf argument from an inner level of execution. Note however that the function which called setjmp() must still be active when longjmp() is called. Breach of this rule will cause disaster, due to the use of a stack containing invalid data. The val argument to longjmp() will be the value apparently returned from the setjmp(). This should normally be non-zero, to distinguish it from the genuine setjmp() call. For example: #include static jmp_buf jb_err; main() { if(setjmp(jb_err)) { printf("An error occured0); exit(1); } a_func(); } a_func() { if(do_whatever() != 0) longjmp(jb_err, 1); if(do_something_else() != 0) longjmp(jb_err, 2); } The calls to longjmp() above will never return; rather the call to setjmp() will appear to return, but with a return value equal to the argument supplied to longjmp(). SEE ALSO setjmp HI-TECH C USER'S MANUAL Page 137 LSEEK SYNOPSIS #include long lseek(int fd, long offs, int wh) DESCRIPTION This function operates in an analogous manner to fseek(), however it does so on unbuffered low-level i/o file descriptors, rather than on STDIO streams. It also returns the resulting pointer location. Thus lseek(fd, 0L, 1) returns the current pointer location without moving it. -1 is returned on error. SEE ALSO open, close, read, write MALLOC SYNOPSIS #include void * malloc(size_t cnt) DESCRIPTION Malloc() attempts to allocate cnt bytes of memory from the "heap", the dynamic memory allocation area. If suc- cessful, it returns a pointer to the block, otherwise 0 is returned. The memory so allocated may be freed with free(), or changed in size via realloc(). Malloc() calls sbrk() to obtain memory, and is in turn called by calloc(). Malloc() does not clear the memory it obtains. SEE ALSO calloc, free, realloc Page 138 HI-TECH C USER'S MANUAL MEMSET, MEMCPY, MEMCMP, MEMMOVE SYNOPSIS #include void memset(void s, char c, size_t n) void * memcpy(void * d, void * s, size_t n) int memcmp(void * s1, void * s2, size_t n) void * memmove(void * s1, void * s2, size_t n) void * memchr(void * s, int c, size_t n) DESCRIPTION Memset() initializes n bytes of memory starting at the location pointed to by s with the character c. Memcpy() copies n bytes of memory starting from the location pointed to by s to the block of memory pointed to by d. The result of copying overlapping blocks is undefined. Memcmp() compares two blocks of memory, of length n, and returns a signed value similar to strncmp(). Unlike strncmp() the comparision does not stop on a null char- acter. The ascii collating sequence is used for the comparision, but the effect of including non-ascii characters in the memory blocks on the sense of the return value is indeterminate. Memmove() is similar to memcpy() except copying of overlapping blocks is han- dled correctly. The memchr() function locates the first occurence of c (converted to unsigned char) in the ini- tial n characters of the object pointed to by s. SEE ALSO strncpy, strncmp, strchr HI-TECH C USER'S MANUAL Page 139 MKDIR, RMDIR SYNOPSIS #include int mkdir(char * s) int rmdir(char * s) DESCRIPTION These functions allow the creation (mkdir()) and dele- tion (rmdir()) of sub-directories under the MS-DOS operating system. The argument s may be an arbitrary pathname, and the return value will be -1 if the crea- tion or removal was unsuccessful. SEE ALSO chdir MSDOS, MSDOSCX SYNOPSIS #include long msdos(int ax, int dx, int cx, int bx, int si, int di) long msdoscx(int ax, int dx, int cx, int bx, int si, int di) DESCRIPTION These functions allow direct access to MS-DOS system calls. The arguments will be placed in the registers implied by their names, while the return value will be the contents of AX and DX (for msdos()) or the contents of DX and CX (for msdoscx()). Only as many arguments as necessary need be supplied, e.g. if only AH and DX need have specified valued, then only 2 argument would be required. The following piece of code outputs a form-feed to the printer. msdos(0x500, '\f'); Note that the system call number (in this case 5) must be multiplied by 0x100 since MS-DOS expects the call number in AH, the high byte of AX. SEE ALSO intdos, intdosx, int86, int86x Page 140 HI-TECH C USER'S MANUAL OPEN SYNOPSIS #include int open(char * name, int mode) DESCRIPTION Open() is the fundamental means of opening files for reading and writing. The file specified by name is sought, and if found is opened for reading, writing or both. Mode is encoded as follows: Mode Meaning 0 Open for reading only 1 Open for writing only 2 Open for both reading and writing The file must already exist - if it does not, creat() should be used to create it. On a successful open, a file descriptor is returned. This is a non-negative integer which may be used to refer to the open file subsequently. If the open fails, -1 is returned. The syntax of a CP/M filename is: [uid:][drive:]name.type where uid is a decimal number 0 to 15, drive is a letter A to P or a to p, name is 1 to 8 characters and type is 0 to 3 characters. Though there are few inherent restrictions on the characters in the name and type, it is recommended that they be restricted to the alphanumerics and standard printing characters. Use of strange characters may cause problems in accessing and/or deleting the file. One or both of uid: and drive: may be omitted; if both are supplied, the uid: must come first. Note that the [ and ] are meta-symbols only. Some examples are: fred.dat file.c 0:xyz.com 0:a:file1.p a:file2. If the uid: is omitted, the file will be sought with uid equal to the current user number, as returned by getuid(). If drive: is omitted, the file will be sought on the currently selected drive. The following special file names are recognized: HI-TECH C USER'S MANUAL Page 141 lst: Accesses the list device - write only pun: Accesses the punch device - write only rdr: Accesses the reader device - read only con: Accesses the system console - read/write File names may be in any case - they are converted to upper case during processing of the name. MS-DOS filenames may be any valid MS-DOS 2.xx filename, e.g. fred.nrk A:\HITECH\STDIO.H The special device names (e.g. CON, LST) are also recognized. These do not require (and should not have) a trailing colon. SEE ALSO close, fopen, fclose, read, write, creat PERROR SYNOPSIS #include void perror(char * s) DESCRIPTION This routine will print on the stderr stream the argu- ment s, followed by a descriptive message detailing the last error returned from an open, close read or write call. Unfortunately CP/M does not provide definitive information relating to the error, except in the case of a random read or write. Thus this routine is of lim- ited usefulness under CP/M. MS-DOS provides much more information however, and use of perror() after MS-DOS file handling calls will certainly give useful diagnos- tics. SEE ALSO open, close, read, write Page 142 HI-TECH C USER'S MANUAL PRINTF, VPRINTF SYNOPSIS #include int printf(char * fmt, ...) int vprintf(char * fmt, va_list va_arg) DESCRIPTION Printf() is a formatted output routine, operating on stdout. There are corresponding routines operating on a given stream (fprintf()) or into a string buffer (sprintf()). Printf() is passed a format string, fol- lowed by a list of zero or more arguments. In the for- mat string are conversion specifications, each of which is used to print out one of the argument list values. Each conversion specification is of the form %m.nc where the percent symbol % introduces a conversion, followed by an optional width specification m. n is an optional precision specification (introduced by the dot) and c is a letter specifying the type of the conversion. A minus sign ('-') preceding m indicates left rather than right adjustment of the converted value in the field. Where the field width is larger than required for the conversion, blank padding is per- formed at the left or right as specified. Where right adjustment of a numeric conversion is specified, and the first digit of m is 0, then padding will be per- formed with zeroes rather than blanks. If the character * is used in place of a decimal con- stant, e.g. in the format %*d, then one integer argu- ment will be taken from the list to provide that value. The types of conversion are: f Floating point - m is the total width and n is the number of digits after the decimal point. If n is omitted it defaults to 6. e Print the corresponding argument in scientific nota- tion. Otherwise similar to f. g Use e or f format, whichever gives maximum precision in minimum width. o x X u d Integer conversion - in radices 8, 16, 10 and 10 respectively. The conversion is signed in the case of d, unsigned otherwise. The precision value is the total number of digits to print, and may be used to force leading zeroes. E.g. %8.4x will print at least 4 hex digits in an 8 wide field. Preceding the key letter with an l indicates that the value argument is a long integer or unsigned value. The letter X prints out hexadecimal numbers using the upper case letters A-F rather than a-f as would be printed when using x. HI-TECH C USER'S MANUAL Page 143 s Print a string - the value argument is assumed to be a character pointer. At most n characters from the string will be printed, in a field m characters wide. c The argument is assumed to be a single character and is printed literally. Any other characters used as conversion specifications will be printed. Thus %% will produce a single percent sign. Some examples: printf("Total = %4d%%", 23) yields 'Total =23%' printf("Size is %lx" , size) where size is a long, prints size as hexadecimal. printf("Name = %.8s", "a1234567890") yields 'Name = a1234567' printf("xx%*d", 3, 4) yields 'xx 4' Printf returns EOF on error, 0 otherwise. Vprintf() is similar to printf() but takes a variable argument list pointer rather than a list of arguments. See the description of va_start() for more information on vari- able argument lists. SEE ALSO fprintf, sprintf Page 144 HI-TECH C USER'S MANUAL PUTC SYNOPSIS #include int putc(int c, FILE * stream) DESCRIPTION Putc() is the macro version of fputc() and is defined in stdio.h. See fputc() for a description of its behaviour. SEE ALSO fputc, getc, fopen, fclose PUTCHAR SYNOPSIS #include int putchar(int c) DESCRIPTION Putchar() is a putc() operation on stdout, defined in stdio.h. SEE ALSO putc, getc, freopen, fclose HI-TECH C USER'S MANUAL Page 145 PUTS SYNOPSIS #include int puts(char * s) DESCRIPTION Puts() writes the string s to the stdout stream, appending a newline. The null terminating the string is not copied. EOF is returned on error. SEE ALSO fputs, gets, freopen, fclose PUTW SYNOPSIS #include int putw(int w, FILE * stream) DESCRIPTION Putw() copies the word w to the given stream. It returns w, except on error, in which case EOF is returned. Since this is a good integer, ferror() should be used to check for errors. SEE ALSO getw, fopen, fclose Page 146 HI-TECH C USER'S MANUAL QSORT SYNOPSIS #include void qsort(void * base, size_t nel, size_t width, int (*func)()) DESCRIPTION Qsort() is an implementation of the quicksort algo- rithm. It sorts an array of nel items, each of length width bytes, located contiguously in memory at base. Func is a pointer to a function used by qsort() to com- pare items. It calls func with pointers to two items to be compared. If the first item is considered to be greater than, equal to or less than the second then func() should return a value greater than zero, equal to zero or less than zero respectively. static short array[100]; #define SIZE sizeof array/sizeof array[0] a_func(p1, p2) short * p1, * p2; { return *p1 - *p2; } sort_em() { qsort(array, SIZE, sizeof array[0], a_func); } This will sort the array into ascending values. Note the use of sizeof to make the code independent of the size of a short, or the number of elements in the array. HI-TECH C USER'S MANUAL Page 147 RAND SYNOPSIS #include int rand(void) DESCRIPTION Rand() is a pseudo-random number generator. It returns an integer in the range 0 to 32767, which changes in a pseudo-random fashion on each call. SEE ALSO srand READ SYNOPSIS #include int read(int fd, void * buf, size_t cnt) DESCRIPTION Read() will read from the file associated with fd up to cnt bytes into a buffer located at buf. It returns the number of bytes actually read. A zero return indicates end-of-file. A negative return indicates error. Fd should have been obtained from a previous call to open(). It is possible for read() to return less bytes than requested, e.g. when reading from the console, in which case read() will read one line of input. SEE ALSO open, close, write Page 148 HI-TECH C USER'S MANUAL REALLOC SYNOPSIS void * realloc(void * ptr, size_t cnt) DESCRIPTION Realloc() frees the block of memory at ptr, which should have been obtained by a previous call to mal- loc(), calloc() or realloc(), then attempts to allocate cnt bytes of dynamic memory, and if successful copies the contents of the block of memory located at ptr into the new block. At most, realloc() will copy the number of bytes which were in the old block, but if the new block is smaller, will only copy cnt bytes. If the block could not be allocated, 0 is returned. SEE ALSO malloc, calloc, realloc REMOVE SYNOPSIS #include int remove(char * s) DESCRIPTION Remove() will attempt to remove the file named by the argument s from the directory. A return value of -1 indicates that the attempt failed. SEE ALSO unlink HI-TECH C USER'S MANUAL Page 149 RENAME SYNOPSIS #include int rename(char * name1, char * name2) DESCRIPTION The file named by name1 will be renamed to name2. -1 will be returned if the rename was not successful. Note that renames across user numbers or drives are not per- mitted. SEE ALSO open, close, unlink REWIND SYNOPSIS #include int rewind(FILE * stream) DESCRIPTION This function will attempt to re-position the read/write pointer of the nominated stream to the beginning of the file. A return value of -1 indicates that the attempt was not successful, perhaps because the stream is associated with a non-random access file such as a character device. SEE ALSO fseek, ftell Page 150 HI-TECH C USER'S MANUAL SBRK SYNOPSIS char * sbrk(int incr) DESCRIPTION Sbrk() increments the current highest memory location allocated to the program by incr bytes. It returns a pointer to the previous highest location. Thus sbrk(0) returns a pointer to the current highest location, without altering its value. If there is insufficient memory to satisfy the request, -1 is returned. SEE ALSO brk, malloc, calloc, realloc, free SCANF SYNOPSIS #include int scanf(char * fmt, ...) int vscanf(char *, va_list ap); DESCRIPTION Scanf() performs formatted input ("de-editing") from the stdin stream. Similar functions are available for streams in general, and for strings. The function vscanf() is similar, but takes a pointer to an argument list rather than a series of additional arguments. This pointer should have been initialized with va_start(). The input conversions are performed according to the fmt string; in general a character in the format string must match a character in the input; however a space character in the format string will match zero or more "white space" characters in the input, i.e. spaces, tabs or newlines. A conversion specification takes the form of the character %, optionally followed by an assignment suppression character ('*'), optionally fol- lowed by a numerical maximum field width, followed by a conversion specification character. Each conversion specification, unless it incorporates the assignment suppression character, will assign a value to the vari- able pointed at by the next argument. Thus if there are two conversion specifications in the fmt string, there should be two additional pointer arguments. The conversion characters are as follows: o x d Skip white space, then convert a number in base 8, 16 or 10 radix respectively. If a field width was HI-TECH C USER'S MANUAL Page 151 supplied, take at most that many characters from the input. A leading minus sign will be recognized. f Skip white space, then convert a floating number in either conventional or scientific notation. The field width applies as above. s Skip white space, then copy a maximal length sequence of non-white-space characters. The pointer argument must be a pointer to char. The field width will limit the number of characters copied. The resultant string will be null-terminated. c Copy the next character from the input. The pointer argument is assumed to be a pointer to char. If a field width is specified, then copy that many characters. This differs from the s format in that white space does not terminate the character sequence. The conversion characters o, x, u, d and f may be pre- ceded by an l to indicate that the corresponding pointer argument is a pointer to long or double as appropriate. A preceding h will indicate that the pointer argument is a pointer to short rather than int. Scanf() returns the number of successful conversions; EOF is returned if end-of-file was seen before any conversions were performed. Some examples are: scanf("%d %s", &a, &s) with input "12s" will assign 12 to a, and "s" to s. scanf("%4cd %lf", &c, &f) with input " abcd -3.5" will assign " abc" to c, and -3.5 to f. SEE ALSO fscanf, sscanf, printf, va_arg Page 152 HI-TECH C USER'S MANUAL SEGREAD SYNOPSIS #include int segread(struct SREGS * segregs) DESCRIPTION Segread() copies the values of the segment registers into the structure pointed to by segregs. SEE ALSO int86, int86x, intdos, intdosx SETJMP SYNOPSIS #include int setjmp(jmp_buf buf) DESCRIPTION Setjmp() is used with longjmp() for non-local gotos. See longjmp() for further information. SEE ALSO longjmp HI-TECH C USER'S MANUAL Page 153 SETUID (CP/M only) SYNOPSIS #include void setuid(int uid) DESCRIPTION Setuid() will set the current user number to uid. Uid should be a number in the range 0-15. SEE ALSO getuid SETVBUF, SETBUF SYNOPSIS #include int setvbuf(FILE * stream, char * buf, int mode, size_t size); void setbuf(FILE * stream, char * buf) DESCRIPTION The setvbuf() function allows the buffering behaviour of a STDIO stream to be altered. It supersedes the function setbuf() which is retained for backwards com- patibility. 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 . 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. Page 154 HI-TECH C USER'S MANUAL SEE ALSO fopen, freopen, fclose SET_VECTOR SYNOPSIS #include typedef interrupt void (*isr)(); isr set_vector(isr * vector, isr func); DESCRIPTION This routine allows an interrupt vector to be initial- ized. The first argument should be the address of the interrupt vector (not the vector number but the actual address) cast to a pointer to isr, which is a typedef'd pointer to an interrupt function. The second argument should be the function which you want the interrupt vector to point to. This must be declared using the interrupt type qualifier. The return value of set_vector() is the previous contents of the vector. SEE ALSO di(), ei() HI-TECH C USER'S MANUAL Page 155 SIGNAL SYNOPSIS #include void (* signal)(int sig, void (*func)()); DESCRIPTION Signal() provides a mechanism for catching control-C's (ctrl-BREAK for MS-DOS) typed on the console during I/O. Under CP/M the console is polled whenever an I/O call is performed, while for MS-DOS the polling depends on the setting of the BREAK command. If a control-C is detected certain action will be performed. The default action is to exit summarily; this may be modified with signal(). The sig argument to signal may at the present time be only SIGINT, signifying an interrupt condition. The func argument may be one of SIG_DFL, representing the default action, SIG_IGN, to ignore control-C's com- pletely, or the address of a function which will be called with one argument, the number of the signal caught, when a control-C is seen. As the only signal supported is SIGINT, this will always be the value of the argument to the called function. SEE ALSO exit SIN SYNOPSIS #include double sin(double f); DESCRIPTION This function returns the sine function of its argu- ment. SEE ALSO cos, tan, asin, acos, atan Page 156 HI-TECH C USER'S MANUAL SPAWNL, SPAWNV, SPAWNVE SYNOPSIS int spawnl(char * n, char * argv0, ...); int spawnv(cahr * n, char ** v) int spawnve(char * n, char ** v, char ** e) DESCRIPTION These functions will load and execute a sub-program, named by the argument n. The calling conventions are similar to the functions execl() and execv(), the difference being that the spawn functions return to the calling program after termination of the sub-program, while the exec functions return only if the program could not be executed. Spawnve() takes an environment list in the same format as the argument list which will be supplied to the executed program as its environment. SEE ALSO execl, execv SPRINTF SYNOPSIS #include int sprintf(char * buf, char * fmt, ...); int vsprintf(char * buf, char * fmt, va_list ap); DESCRIPTION Sprintf() operates in a similar fashion to printf(), except that instead of placing the converted output on the stdout stream, the characters are placed in the buffer at buf. The resultant string will be null- terminated, and the number of characters in the buffer will be returned. Vsprintf takes an argument pointer rather than a list of arguments. SEE ALSO printf, fprintf, sscanf HI-TECH C USER'S MANUAL Page 157 SQRT SYNOPSIS #include double sqrt(double f) DESCRIPTION Sqrt() implements a square root function using Newton's approximation. SEE ALSO exp SSCANF SYNOPSIS #include int sscanf(char * buf, char * fmt, ...); int vsscanf(char * buf, char * fmt, va_list ap); DESCRIPTION Sscanf() operates in a similar manner to scanf(), except that instead of the conversions being taken from stdin, they are taken from the string at buf. SEE ALSO scanf, fscanf, sprintf Page 158 HI-TECH C USER'S MANUAL SRAND SYNOPSIS #include void srand(int seed) DESCRIPTION Srand() initializes the random number generator accessed by rand() with the given seed. This provides a mechanism for varying the starting point of the pseudo-random sequence yielded by rand(). On the z80, a good place to get a truly random seed is from the refresh register. Otherwise timing a response from the console will do. SEE ALSO rand STAT SYNOPSIS #include int stat(char * name, struct stat * statbuf) DESCRIPTION This routine returns information about the file by name. The information returned is operating system dependent, but may include file attributes (e.g. read only), file size in bytes, and file modification and/or access times. The argument name should be the name of the file, and may include path names under DOS, user numbers under CP/M, etc. The argument statbuf should be the address of a structure as defined in stat.h which will be filled in with the information about the file. The structure of struct stat is as follows: struct stat { short st_mode; /* flags */ long st_atime; /* access time */ long st_mtime; /* modification time */ long st_size; /* file size */ }; The access and modification times (under DOS these are both set to the modification time) are in seconds since 00:00:00 Jan 1 1970. The function ctime() may be used to convert this to a readable HI-TECH C USER'S MANUAL Page 159 value. The file size is self explanatory. The flag bits are as follows: Flag Meaning ____________________________________ S_IFMT mask for file type S_IFDIR file is a directory S_IFREG file is a regular file S_IREAD file is readable S_IWRITE file is writeable S_IEXEC file is executable S_HIDDEN file is hidden S_SYSTEM file is marked system S_ARCHIVE file has been written to Stat returns 0 on success, -1 on failure, e.g. if the file could not be found. SEE ALSO ctime, creat, chmod STRCAT, STRCMP, STRCPY, STRLEN et. al. SYNOPSIS #include char * strcat(char * s1, char * s2); int strcmp(char * s1, char * s2); char * strcpy(char * s1, char * s2); int strlen(char * s); char * strncat(char * s1, char * s2, size_t n); int strncmp(char * s1, char * s2, size_t n); char * strncpy(char * s1, char * s2, size_t n); DESCRIPTION These functions provide operations on null-terminated strings. Strcat() appends the string s2 to the end of the string s1. The string at s1 will be null ter- minated. Needless to say the buffer at s1 must be big enough. Strcmp() compares the two strings and returns a number greater than 0, 0 or a number less than 0 according to whether s1 is greater than, equal to or less than s2. The comparision is via the ascii collat- ing order, with the first character the most signifi- cant. Strcpy() copies s2 into the buffer at s1, null terminating it. Strlen() returns the length of s1, not including the terminating null. Strncat(), strncmp() and strncpy() will catenate, compare and copy s2 and s1 in the same manner as their similarly named counter- parts above, but involving at most n characters. For strncpy(), the resulting string may not be null ter- minated. Page 160 HI-TECH C USER'S MANUAL STRCHR, STRRCHR SYNOPSIS #include char * strchr(char * s, int c) char * strrchr(char * s, int c) DESCRIPTION These functions locate an instance of the character c in the string s. In the case of strchr() a pointer will be returned to the first instance of the character found be searching from the beginning of the string, while strrchr() searches backwards from the end of the string. A null pointer is returned if the character does not exist in the string. SEE ALSO SYSTEM SYNOPSIS #include int system(char * s) DESCRIPTION When executed under MS-DOS system() will pass the argu- ment string to the command processor, located via the environment string COMSPEC, for execution. The exit status of the command processor will be returned from the call to system(). For example, to set the baud rate on the serial port on an MS-DOS machine: system("MODE COM1:96,N,8,1,P"); This function will not work on CP/M-86 since it does not have an invokable command interpreter. Under Con- current CP/M the CLI system call is used. SEE ALSO spawnl, spawnv HI-TECH C USER'S MANUAL Page 161 TAN SYNOPSIS #include double tan(double f); DESCRIPTION This is the tangent function. SEE ALSO sin, cos, asin, acos, atan TIME SYNOPSIS #include time_t time(time_t * t) DESCRIPTION This function returns the current time in seconds since 00:00:00 on Jan 1, 1970. If the argument t is non- null, the same value is stored into the object pointed to by t. The accuracy of this function is naturally dependent on the operating system having the correct time. This function does not work under CP/M-86 or CP/M 2.2 but does work under Concurrent-CP/M and CP/M+. SEE ALSO ctime, gmtime, localtime, asctime Page 162 HI-TECH C USER'S MANUAL TOUPPER, TOLOWER, TOASCII SYNOPSIS #include char toupper(int c); char tolower(int c); char toascii(int c); char c; DESCRIPTION Toupper() converts its lower case alphabetic argument to upper case, tolower() performs the reverse conver- sion, and toascii() returns a result that is guaranteed in the range 0-0177. Toupper() and tolower return their arguments if it is not an alphabetic character. SEE ALSO islower, isupper, isascii et. al. UNGETC SYNOPSIS #include int ungetc(int c, FILE * stream) DESCRIPTION Ungetc() will attempt to push back the character c onto the named stream, such that a subsequent getc() opera- tion will return the character. At most one level of pushback will be allowed, and if the stream is not buf- fered, even this may not be possible. EOF is returned if the ungetc() could not be performed. SEE ALSO getc HI-TECH C USER'S MANUAL Page 163 UNLINK SYNOPSIS int unlink(char * name) DESCRIPTION Unlink() will remove (delete) the named file, that is erase the file from its directory. See open() for a description of the file name construction. Zero will be returned if successful, -1 if the file did not exist or it could not be removed. SEE ALSO open, close, rename, remove VA_START, VA_ARG, VA_END SYNOPSIS #include void va_start(va_list ap, parmN); type va_arg(ap, type); void va_end(va_list ap); DESCRIPTION These macros are provided to give access in a portable way to parameters to a function represented in a proto- type by the ellipsis symbol (...), where type and number of arguments supplied to the function are not known at compile time. The rightmost parameter to the function (shown as parmN) plays an important role in these macros, as it is the starting point for access to further parameters. In a function taking variable numbers of arguments, a variable of type va_list should be declared, then the macro va_start invoked with that variable and the name of parmN. This will initialize the variable to allow subsequent calls of the macro va_arg to access successive parameters. Each call to va_arg requires two arguments; the variable previously defined and a type name which is the type that the next parameter is expected to be. Note that any arguments thus accessed will have been widened by the default conventions to int, unsigned int or double. For exam- ple if a character argument has been passed, it should be accessed by va_arg(ap, int) since the char will have been widened to int. An example is given below of a function taking one integer parameter, followed by a number of other parameters. In this example the func- tion expects the subsequent parameters to be pointers to char, but note that the compiler is not aware of this, and it is the programmers responsibility to Page 164 HI-TECH C USER'S MANUAL ensure that correct arguments are supplied. #include prf(int n, ...) { va_list ap; va_start(ap, n); while(n--) puts(va_arg(ap, char *)); va_end(ap); } WRITE SYNOPSIS #include int write(int fd, void * buf, size_t cnt) DESCRIPTION Write() will write from the buffer at buf up to cnt bytes to the file associated with the file descriptor fd. The number of bytes actually written will be returned. EOF or a value less than cnt will be returned on error. In any case, any return value not equal to cnt should be treated as an error (cf. read() ). SEE ALSO open, close, read HI-TECH C USER'S MANUAL Page 165 INDEX 8086 70 CP/M 26,106,131,155 absolute value 116 CP/M-80 compiler 2 acos() 103 cputs() 107 address creat() 111 link 73 creating a library 76 load 73 CREF 83 ANSI Standard 13,17 cross compilers 3 array cross reference 36,83 dimension 16 ctime() 111 index 16 ctrl-Z 26,120 size 16 date and time 104 ASCII 26 debugging 10,105 asctime() 104 device name as file 23 asin() 103 device assembler as file 141 in C programs 20 di() 113 assert() 105 directory 108,139 atan() 103 current 130 atan2() 103 disk changing on floppy disk Atari ST 3 systems 3 atexit() 104 disk space 33 atof() 105 div() 112 atoi() 105 div_t 112 atol() 105 dup() 113 bdos() 106 editor 3,33 binary output file 8 ei() 113 bios() 106 entering long commands 7 braces Enumerated Types 16 omission of 16 environment 130 byte ordering 21 error message: C command 3,7 Can't generate code 33 C reference books 2 Error closing file 33 calloc() 107 No room 33 carriage return 26,120 out of memory 33 ceil() 116 Undefined symbol 33 cgets() 107 Write error 33 change file attributes 108 error messages 23,33 character testing 134 format of 23 chdir() 108 LIBR 78 checksum 79,80 list of 23,85 chmod() 108 redirection of 23 class name 70 execl() 114 close() 109 executing a sub-program 156 clreof() 109 executing system commands clrerr() 109 160 command line 7,12,77,160 execution profiling 10 Compatibility 25 execv() 114 compiler driver 3 exit() 114 Compiler Structure 5 exp() 115 console I/O 107,129,135 exponentional functions 115 control-C handling 155 Extern Declarations 30 converting ascii to binary fabs() 116 105 fclose() 116 cos() 110 feof() 117 cosh() 110 ferror() 117 Page 166 HI-TECH C USER'S MANUAL fflush() 117 getw() 132 fgetc() 118 global variables 30 fgets() 118 gmtime() 132 FILE 99 hex output file 8 file descriptor 27,111,119 I/O redirection 127 duplicating 113 I/O FILE pointer 27 ASCII 26 file Binary 26 access time 158 standard 25,99 attributes 108,158 in-line assembler 20 closing a 109,116 Initialization Syntax 16 creating a 111 initializer 16 deleting a 148,163 inp() 133 flushing buffer to a 117 int86() 133 information about a 158 int86x() 133 modification time 158 intdos() 133 opening a 119,123,140 intdosx() 133 random access to a Intel hex format 79 125,137 interrupt 133 reading from a 122,147 interrupt handling 155 renaming a 149 interrupt vector size 158 setting 154 type of a 135 isalnul() 134 writing to a 126,164 isalnum() 134 fileno() 119 isalpha() 134 floating point isascii() 134 library 27 isatty() 135 options required to use iscntrl() 134 4 isdigit() 134 floor() 116 isgraph() 134 fopen() 26,119 islower() 134 formatted input 124,150 ispunct() 134 formatted printing 121,142 isspace() 134 fprintf() 121 isupper() 134 fputc() 121 kbhit() 135 fputs() 122 Kernighan and Ritchie 2,16 fread() 122 large model 70,80 free() 123 ldexp() 124 freopen() 123 ldiv() 112 frexp() 124 LIBR 75 fscanf() 124 librarian 75 fseek() 125 libraries 7 ftell() 126 library manager 75 function parameter 163 library ordering 77 function library declaration 17 creating 76 large 33 floating point 33 parameters 17 ordering 33 prototype 17,163 line number symbols 10 fwrite() 126 linker 69 getc() 128 LINT 16 getch() 129 localtime 132 getchar() 25,129 log() 115 getche() 129 log10() 115 getcwd() 130 logarithmic functions 115 getenv() 130 long 30 gets() 131 longjmp() 136 getuid() 131 lseek() 137 HI-TECH C USER'S MANUAL Page 167 Machine Dependencies 21 pack pragma 20 macros parameter predefined 21 type 17 malloc() 137 perror() 141 Member Names 13,29 portable code 21 memcmp() 138 pow() 115 memcpy() 138 pragma 20,21 memory allocation printf 33 107,148,150 printf() 142 releasing 123 program execution 156 memory model 31 psect memory requirements 2 linking 69 memset() 138 local 70 mkdir() 139 putc() 144 Motorola hex format 80 putch() 129 MS-DOS 108,133,139,155 putchar() 144 msdos() 139 puts() 145 msdoscx() 139 putw() 145 multiple definitions 30 qsort() 146 newline 26 rand() 147 Newton's approximation 157 random numbers 147,158 non-local goto 136,152 read() 147 objtohex 72,79 realloc() 148 open() 140 relocation 69 Operating Details 7 remove() 148 options 7 rename() 149 -1 10 return 26,120 -11 11 rewind() 149 -2 11 rmdir() 139 -6301 11 S format hex 80 -A 8 sbrk() 150 -B 9 scanf 33 -C 7 scanf() 150 -CPM 7 segment registers 152 -CR 7 segread() 152 -D 8 self relocation 72 -E 10 setbuf() 153 -F 8 setjmp() 152 -G 10 setuid() 153 -H 10 setvbuf() 153 -I 8 set_vector() 154 -LF 4,27,33 shift -M 8 signed 14 -O 8 unsigned 14 -Ooutfile 8 short 21,30 -P 10 signal() 155 -R 8 sin() 155 -S 7 sinh() 110 -U 8 size of data types 21 -V 3,8 sorting 146 -W 10 source file naming 3 -X 8 source level debugging 10 -Z 10 spawnl() 156 linker 71 spawnv() 156 outp() 133 spawnve() 156 pack 21 Specific Features 13 sprintf() 156 sqrt() 157 Page 168 HI-TECH C USER'S MANUAL square root function 157 Unsigned Types 14 srand() 158 user ID 131,153 sscanf() 157 V3.09 2 Standard Libraries 25 va_arg 18,163 Standard Library Functions va_end 163 99 va_start 163 stat() 158 void 18 stdarg.h 18,163 Pointer to 18 STDIO 25,27,99 warning level 10 storage allocator 18 warning messages strcat() 159 suppressing 10 strchr() 160 wild card expansion 127 strcmp() 159 Wordstar 33 strcpy() 159 write() 164 stream 27,99 Z180 MMU 68 string manipulation 159 Bank Base Register 68 strlen() 159 BBR 68 strncat() 159 CBAR 68 strncmp() 159 CBR 68 strncpy() 159 Common Base Register 68 strrchr() 160 Common/Bank Area Regis- Structure Operations 15 ter 68 structure packing 20 Z180 Registers 68 structures ASCI 68 as function argument 15 Bank Base Register 68 assignment 15 BBR 68 functions returning 15 BCR0H 68 Stylistic Considerations 29 BCR0L 68 symbol file 10,80 BCR1H 68 symbols BCR1L 68 cross reference 83 CBAR 68 global 70,76 CBR 68 System Requirements 2 CNTLA0 68 system() 160 CNTLA1 68 tan() 161 CNTLB0 68 tanh() 110 CNTLB1 68 temporary files 4 CNTR 68 text editor 3 Common Base Register 68 time and date 104 Common/Bank Area Regis- time() 161 ter 68 toascii() 162 CSI/0 68 tolower() 162 DAR0B 68 toupper() 162 DAR0H 68 trigonometric functions DAR0L 68 103,110 DCNTL 68 hyperbolic 110 DMA 68 Type Checking 13 DMA Byte Count 68 type qualifiers 19 DMA Desitination Address typecast 13 68 typecasting 18 DMA Mode Register 68 ungetc() 162 DMA Source Address 68 ungetch() 129 DMA Status Register 68 Unix DMODE 68 C compiler 16 DSTAT 68 V7 25 FRC 68 unlink() 163 Free Running Counter 68 unsigned 23 IAR1H 68 unsigned char 21 IAR1L 68 HI-TECH C USER'S MANUAL Page 169 ICR 68 INC 55 IL 68 IND 55 Interrupt Vector Regis- INDR 56 ter 68 INI 56 ITC 68 INIR 56 MAR1B 68 JP 56 MAR1H 68 JR 56 MAR1L 68 LD 56,57,58,59 MMU 68 LDD 59 OMCR 68 LDDR 59 RCR 68 LDI 59 Refresh Control Register LDIR 59 68 MLT 59 RLDR0H 68 NEG 59 RLDR0L 68 NOP 59 RLDR1H 68 OR 59,60 RLDR1L 68 OTDM 61 SAR0B 68 OTDMR 60 SAR0H 68 OTDR 60 SAR0L 68 OTIM 61 STAT0 68 OTIMR 60 STAT1 68 OTIR 60 TCR 68 OUT 60 TDR0 68 OUT0 60 TDR1 68 OUTD 60 TIMER 0 68 OUTI 61 TIMER 1 68 POP 61 TMDR0H 68 PUSH 61 TMDR0L 68 RES 61,62,63 TMDR1H 68 RET 63 TMDR1L 68 RETI 63 TRDR 68 RETN 63 TSR0 68 RL 63 TSR1 68 RLA 63 Z80 Instructions 50 RLC 63 ADC 51 RLCA 63 ADD 51 RLD 63 AND 51 RR 63,64 BIT 52,53 RRA 64 CALL 53 RRC 64 CCF 53 RRCA 64 CP 53,54 RRD 64 CPD 54 RST 64 CPDR 54 SBC 64 CPI 54 SCF 64 CPIR 54 SET 64,65,66 CPL 54 SLA 66 DAA 54 SLP 66 DEC 54 SRA 66 DI 54 SRL 67 DJNZ 54 SUB 67 EI 54 TST 67 EX 55 TSTIO 67 EXX 55 XOR 67 HALT 55 Z80 pseudo ops IM 55 IRP 47 IN 55 IRPC 47 IN0 55 ZAS directives 48 Page 170 HI-TECH C USER'S MANUAL title 48 operators 38 ZAS options program sections 39 -J 35 PSECT 43 -L 36 psects 39,43 -N 35 pseudo ops 40 -O 36 relocatable object code -U 35 39 -W 36 temporary labels 37 ZAS psect flags Z180 35 ABS 43 Zilog 35 GLOBAL 43 _exit() 115 LOCAL 43 _getargs() 127 OVRLD 43 PURE 43 ZAS pseudo ops 40 COND 42 DB 40 DEFB 40 DEFF 41 DEFL 41 DEFM 42 DEFS 41 DEFW 41 ELSE 42 END 42 ENDC 42 ENDM 44 EQU 41 GLOBAL 43 IF 42 LOCAL 45 MACRO 44 ORG 44 PSECT 43 REPT 46 ZAS 64180 35 arithmetic overflow 35 binary constants 37 character constants 38 condition codes 48 conditional assembly 42 constants 37 directives 48 extended condition codes 48 external symbols 35 floating point constants 38 hexadecimal constants 37 jump optimization 35 jumps 35 labels 36 listing 36 macros 44 mnemonics 35 octal constants 37 opcode constants 38  ================================================ FILE: doc/OBJCODE.TXT ================================================ HI-TECH Software Object Code Format 1. Introduction This describes the format of the object code recognized by the linker "link". Note that later versions of the object code have identifying version numbers in IDENT records. Early version of the object code did not have these version numbers. The presence of the version number can be determined from the length of the ident record. Certain features will be identified as being present in versions greater than some value by the notation (>=m.n) where m is the major version number and n is the minor version number, e.g. (>=2.1). 2. Object Code Structure The object code (OCODE) is essentially binary, comprising a sequence of records, each with an outer envelope thus: | Length (16 bits) | Record type (8 bits) | Data (Length*8 bits) | i.e. a 16 bit length, followed by an 8 bit type, then a sequence of 8 bit bytes. The length is the number of bytes, exluding the length and type. In practice, the length of the data portion of any record will not exceed 512 bytes. This places an upper limit on the size of the buffer required to hold any record. 2.1. TEXT Record The major record type is TEXT (== 1). Its format (i.e. the data part of the basic record envelope) is thus: | Offset (32 bits) | Psect name (null term.) | data bytes | The Offset is the offset (in bytes) within the named psect (i.e. program section) at which the data bytes are to be placed. The name, like all names in this OCODE, is null terminated. The number of data bytes is found by subtracting the length of the name + 4 from the record length in the outer envelope. 2.2. PSECT Record The PSECT (== 2) record is used to define program sections. Each PSECT record describes one psect. | Psect flags (16 bits) | psect name (null terminated) | Note that as a consistency check, the null byte terminating the name must be the last byte in the record. The flag bits are: GLOBAL 020 Psect is global PURE 040 Psect is to be read-only OVRLD 0100 Each modules data for this psect starts at relative location 0. The default is concatenation. ABS 0200 This psect is to be loaded at absolute 0. BIGSEG 0400 Means the relocatibility of this psect is multiplied by 65535 BPAGE 01000 This is a base page psect - ignore overflows in relocations 2.3. RELOC Record The RELOC (== 3) type record contains relocation information relating to the last TEXT record. It consists of a sequence of offset/descriptor pairs, the offset being a 16 bit offset within the last TEXT record, and the descriptor providing the relocation information. The type of the relocation may be simple relocation within a psect, relocation by the value of an external name, or whatever. Complex relocations may also appear, which are a sequence of operators and operands, to be evaluated by a stack machine. Each simple relocation record will appear as: | Offset (16 bits) | Reloc. type (8 bits) | Psect or external name | The name is, as usual, null terminated. The actual RELOC record consists of an arbitrary number of these entries. The relocation type byte is interpreted as follows: bits |7 4|3 0| | type | size | The size is the size in bytes of the quantity to be relocated. The type is one of: RABS 0 Absolute - no relocation (i.e. no change) RPSECT 1 Relocation within named psect RNAME 2 Relocation by value of name RRPSECT 5 Relocation within psect, less the current pc. This is required for machines using relative addressing. val = val + psect.base - code.location RRNAME 6 As for RRPSECT, but relative to a symbol rather than a psect. RSPSECT 9 Relocation by the segment value for the psect RSNAME 10 Relocation by the segment value for the symbol RCPLX 48 Complex relocation follows A complex relocation entry has, in place of the name, a sequence of operator bytes and operand bytes with further information. Where binary operations are performed, the top stack entry is the left hand operand, and the next to top stack value is the right hand operand. Both values are removed from the stack and the result pushed back on. Unary operators act on the top stack value. Operands like RC_VAL and RPSECT push their value onto the stack. The possible type bytes are as follows: RC_END 0 End of complex relocations RC_LOW 1 And with 0xFF RC_HI 2 Right shift 8 bits, and with 0xFF RC_VAL 3 32 bit constant follows RC_ADD 4 Addition RC_SUB 5 Subtraction RC_MUL 6 Multiplication RC_DIV 7 Division RC_SHL 8 Shift left RC_SHR 9 Shift right RC_AND 10 Bitwise AND RC_OR 11 Bitwise OR RC_XOR 12 Bitwise XOR RC_CPL 13 Bitwise complement RC_NEG 14 Negate RC_BITF 15 Bitfield extract - operands are value, bit offset, and length RPSECT 16 Value of psect - null-terminated name follows RC_MOD 17 Modulus RNAME 32 Value of symbol - null-terminated name follows RSPSECT 144 Segment selector of psect RSNAME 160 Segment selector of symbol 2.4. SYM Record The SYM (== 4) record defines external and internal names. It consists of a sequence of name definitions. Note that it is not essential to mention an external name here if it is referenced in a RELOC record. Each entry is as follows: | Value (32 bits) | flags (16 bits) | psect name | symbol name | Note that the psect name will be null if the symbol is not being defined. That is, the psect name will be a single null byte. The flag word contains the same flags as defined above for PSECT records. In the low order 4 bits is one of the following values: NULL 0 The normal case when defining local or global symbols STACK 1 Symbol is a stack (auto variable) symbol COMM 2 Symbol is a common symbol - if it is defined elsewhere then this is the same as EXTERN, otherwise the linker will allocate space in the psect named, of size equal to the maximum value of any instance of this symbol encountered. REGNAM 3 Symbol refers to a register LINENO 4 This is a line number in the source code FILNAM 5 This is the name of a source file EXTERN 6 This is a reference to an externally defined symbol The psect name must be null. STACK, REGNAM, FILNAM and LINENO symbols are purely for use by a debugger. These symbols are not handled by the linker at all (other than to correctly relocate their values) but will be passed through to a symbol table unless suppressed with a -x option. 2.5. START Record The START (== 5) record defines a start address. Only one START record may appear in a module. | offset (32 bits) | psect name (null term) | This defines the start address to be at the specified offset in the named psect. 2.6. END Record The END (== 6) record is as follows: | flags (16 bits) | The flag value is currently unused. 2.7. IDENT Record The IDENT (= 7) record identifies the target machine and specifies the ordering of bytes in 32 and 16 bit quantities. This affects both offset and symbol values as well as relocatable values in TEXT records. The IDENT record is optional, and the default ordering is strictly low byte first. If the IDENT record is present, it must be the first record in the file. The length field in every record's outer envelope is always stored low byte first, irrespective of the content of any IDENT record. | byte order (32 bits) | byte order (16 bits) | machine name | version number (16 bits) | The byte order fields list the relative position of successively more significant bytes within fields of 32 and 16 bits respectively. For example, the ident record for a PDP11 would look like this: | 02 03 00 01 | 00 01 | PDP11 | The machine name is null terminated. The ident record need not be present, if more than one ident record is encountered, all records must have identical byte ordering. The version number (>=2.0) occupies 2 bytes after the machine name. This is present only if the record length is long enough to contain these extra 2 bytes. If absent, the version number may be assumed to be 1.0. If present, the first byte is the major version number, and the second the minor version number. 2.8. XPSECT Record The XPSECT (==8) record contains further information about a psect. Some object files may not contain any XPSECT records. The layout is as follows: | max size (32 bits) | relocatability (16 bits) | selector (16 bits) | reserved (24 bits) | type (8 bits) | psect name | The max size field is a long integer specifying the maximum size of this psect. The relocatability field, if non-zero, specifies a boundary on which the psect must start, e.g. for the 8086 this field is usually 16, since 8086 segment must start on a 16 byte boundary. The reserved field should be all zeros. The psect name is the null terminated name of the psect. The selector (>=2.0) is non-zero if there is a segment selector to be associated with this psect. This feature is normally only used with segmented architecture processors like the 8086. In object code versions prior to 2.0 this field was always zero. The type field (>=2.1) allows the linker to verify that all module's contributions to a given psect are of the same type. This field must match in all modules for this psect. This is typically used by the 8086 assembler to encode the state of the USE32 flag for a psect. 2.9. SEGMENT Record The SEGMENT (== 9) record (>= 2.0) is present in fully linked object files only, i.e. those produced by the linker. This defines a segment, which is a contiguous set of psects. The record structure is as follows: | size (32 bits) | base address (32 bits) | selector (16 bits) | reserved (16 bits) | origin (32 bits) | segment name | The size field is the size of the segment in bytes. The base address is the physical base address of the segment. This is not necessarily the same as the origin, which is the addresse used when references to this segment were relocated. These correspond to the load and link addresses respectively of the psects comprising the segment. The selector is the segment selector value used in referring to this segment. This is of relevance mainly for 8086 family processors. The segment name is the name of the first psect comprising this segment. 2.10. XSYM Record The XSYM (== 10) record (>= 2.1) is similar to the SYM record but also defines a selector value for the symbol. The record layout is as follows: | value (32 bits) | flags (16 bits) | selector (16 bits) | name | The selector value is the selector of the segment within which the symbol is located. 2.11. SIGNAT Record The SIGNAT (== 11) record (>=2.1) defines a signature for a symbol. At link time all signatures for a symbol are compared and must be identical. If a signature is not the same, an error message is issued. The record layout is as follows: | signature (16 bits) | symbol name | 2.12. FNINFO Record The FNINFO (== 12) record (>= 2.3) provides information necessary for call-graphing and local data allocation for non-reentrant functions. Within a record are concatenated one or more instances of the following layouts. Each instance is variable length, depending on name lengths. | FNCALL (1) | caller name | callee name | | FNARG (2) | caller name | callee name | | FNINDIR (3) | caller name | callee signature (16 bits) | | FNADDR (4) | function name | signature (16 bits) | | FNSIZE (5) | func name | local size (32 bits) | arg size (32 bits) | | FNROOT (6) | func name | The FNCALL instance specifies that one function directly calls another. The FNARG instance specifies that one function will have arguments built while another is called. The FNINDIR instance specifies that a function calls indirectly another (unknown) function, whose signature is as specified. The FNADDR instance specifies that the function has its address taken (and is thus a candidate for being called indirectly) and its signature. The FNSIZE instance specifies the local variable block size and the argument block size for a function. The FNROOT instance specifies that this function is the root of a call graph (either the main function or an interrupt function). 2.13. FNCONF Record The FNCONF (== 13) record (>=2.3) provides environmental information for call-graphing and local data allocation purposes. The layout comprises three null-terminated strings as follows: | psect name | local data prefix | argument prefix | The psect name is the name of the psect in which local data and argument blocks should be allocated by the linker. The local data and argument prefixes are the strings which should be prepended to a function name to derive the names for the local data and argument blocks for a given function. 3. NOTES No padding or fill bytes are stored in the object file, i.e. no alignment of the records is done. Do not attempt to read or write object files using structures, i.e. all records must be built up byte-by-byte in a char array. ================================================ FILE: doc/SYMFILE.TXT ================================================ HI-TECH C Symbol File Format Introduction The symbol files produced by the HI-TECH linker using the -h option are ascii files, organized as one symbol per line. Other lines provide information about modules etc. Global Symbols The first part of the file comprises global symbols, i.e symbols visible throughout the entire program. Each line has the symbol name, a space then one or two hex numbers separated by a space. The first hex number is the link value of the symbol, i.e. the value that will be substituted whenever the symbol is referenced in the code. If the symbol is absolute, this will be the only number on the line. If a second value appears, this is the difference between the link and load addresses of the symbol. The load address of a symbol is the address at which it appears in the code image produced by the linker. If the link and load addresses are the same, this value will be zero. Some examples: _main 100 0 This line defines a symbol _main (note that the C compiler prepends an underscore to all C symbols) with a link address of 100 hex and the same load address. _bios_ram 0 400 This symbol has a link address of 0, and a load address of 400 hex. In the context of an 8086 processor this would be interpreted as a segemented address of 40:0 (the load address is a linear address). Psect Limits Within the global symbols will appear some symbols generated by the linker which give information about the limits of psects (program sections, sometimes called segments). Every psect in the program will have at least two symbols defined for it. The names of these symbols are formed by prepending the strings __L and __H to the psect name. The values of these are the low and high bounds of the psect respectively. For example, the psect "text" would have the symbols __Ltext and __Htext defined. These may appear as follows: __Ltext 100 0 __Htext 157 0 This specifies that the text psect starts at 100 hex and has a length of 57 hex bytes. Its load and link addresses are the same. Another example: __Lbss 560 270 __Hbss 840 270 This indicates that the bss psect starts at 560 hex and extends to 83F hex. Note the non-zero second number. This means that the link and load addresses are different. In 8086 real mode the segmented address 27:560 could be used to refer to the base of this bss psect (though numerous other addresses would also refer to the same location). If the link and load addresses for a psect are different, there will also be another symbol defined, formed by prefixing __B to the psect name. This symbol will be given a value equal to the load address of the psect less the base of the psect. In the above example, __Bbss would be set to 270. Local Symbols The end of the global symbol list is flagged by the line %locals All symbols after this line are local symbols, i.e. they are visible only to the module in which they are defined. Symbol lines will generally be the same in form as global symbols, i.e. a name followed by one or two hex numbers. In addition, lines will appear with a file name and no hex numbers, e.g. fred.obj would appear immediately before the symbols defined in the module fred. Within the module fred there will be one or more source files. The names of these source files may also appear, e.g. fred.obj fred.c _fred 0 A0 _bill 140 A0 george.c _george 276 A0 This example indicates that the source file fred.c defined the two symbols _fred and _bill, then included another file george.c which defined the symbol _george. Absolute symbols may also appear in the local symbol area. The order of symbols and modules is preserved. Line Numbers If line numbers are included in the object code, these appear in the same form as described above, but the symbol name is a number, e.g. fred.obj fred.c 10 4 D0 11 8 D0 12 10 D0 defines a module fred.obj, derived from the file fred.c, and with lines 10, 11 and 12 producing code. The addresses are the addresses of the first executable code from that line. A Full Example An example is given here of a small C source file, and the resultant symbol file and link map. The C source is test.c, as follows: #include #include static int fred; main() { fred = 23; putch('x'); return 1; } The resultant symbol file is: _main E01C 0 _exit E019 0 start E000 0 __Hbss 8006 0 __Lbss 8004 0 _getch E06D 0 _kbhit E063 0 _putch E047 0 __Hdata E093 0 __Ldata E093 0 __Htemp 8004 0 __Ltemp 8000 0 __Htext E093 0 _getche E084 0 __Ltext E000 0 __Hstack 8800 0 __Lstack 8800 0 __Hvectors 10000 0 __Lvectors 0 0 _init_uart E031 0 %locals test.c 6 E01C 0 7 E01E 0 8 E024 0 9 E029 0 10 E02E 0 _fred 8004 0 ctemp 8000 0 The link map generated at the same time is: Linker command line: -w80 -z -H -Mmap -ptext=0e000h,data,temp=08000h,bss,stack=08800h \ -o/usr/tmp/eaaa20022 /usr/hitech/lib/crt09.obj \ test.obj \ /usr/hitech/lib/09libc.lib Machine type is 6809 /usr/hitech/lib/crt09.obj vectors 0 0 10000 text E000 E000 1C test.obj text E01C E01C 15 bss 8004 8004 2 temp 8000 8000 4 /usr/hitech/lib/09libc.lib getch.obj text E031 E031 62 temp 8000 8000 4 TOTAL Name Link Load Length vectors 0 0 10000 text E000 E000 93 bss 8004 8004 2 temp 8000 8000 4 SEGMENTS Name Load Length Selector text 00E000 000093 E000 temp 008000 000006 8000 stack 008800 000000 8800 Symbol Table __Hbss bss 08006 __Hdata data 0E093 __Hstack stack 08800 __Htemp temp 08004 __Htext text 0E093 __Hvectors vectors 10000 __Lbss bss 08004 __Ldata data 0E093 __Lstack stack 08800 __Ltemp temp 08000 __Ltext text 0E000 __Lvectors vectors 00000 _exit text 0E019 _getch text 0E06D _getche text 0E084 _init_uart text 0E031 _kbhit text 0E063 _main text 0E01C _putch text 0E047 start text 0E000 ================================================ FILE: float/ACOS.C ================================================ #include #define PI 3.14159265358979 #define TWO_PI 6.28318530717958 #define HALF_PI 1.570796326794895 double acos(x) double x; { return HALF_PI - asin(x); } ================================================ FILE: float/ASFLOAT.AS ================================================ global asfladd, asflsub, asflmul, asfldiv global fladd, flsub, flmul, fldiv global iregset, iregstore psect text asfladd: call iregset call fladd jp iregstore asflsub: call iregset call flsub jp iregstore asflmul: call iregset call flmul jp iregstore asfldiv: call iregset call fldiv jp iregstore ================================================ FILE: float/ASIN.C ================================================ #include #define PI 3.14159265358979 #define TWO_PI 6.28318530717958 #define HALF_PI 1.570796326794895 double asin(x) double x; { double y; double sgn; if(fabs(x) > 1.0) return 0.0; sgn = 1.0; y = sqrt(1.0 - x*x); if(fabs(x) < 0.71) return atan(x/y); if(x < 0.0) return -(HALF_PI - atan(-y/x)); return (HALF_PI - atan(y/x)); } ================================================ FILE: float/ATAN.C ================================================ #include #define PI 3.14159265358979 #define TWO_PI 6.28318530717958 #define HALF_PI 1.570796326794895 double atan(f) double f; { static /* const */ double coeff_a[] = { 33.058618473989548, 58.655751569001961, 32.390974856200445, 5.8531952112628600, 0.19523741936234277, -.0024346033004411264 }; static /* const */ double coeff_b[] = { 33.058618473992416, 69.675291059524653, 49.004348218216250, 12.975578862709239, 1.0 }; int recip; extern double eval_poly(), fabs(); double val, val_squared; if((val = fabs(f)) == 0.0) return 0.0; if(recip = (val > 1.0)) val = 1.0/val; val_squared = val * val; val *= eval_poly(val_squared, coeff_a, 5)/eval_poly(val_squared, coeff_b, 4); if(recip) val = HALF_PI - val; return f < 0.0 ? -val : val; } ================================================ FILE: float/ATAN2.C ================================================ #include #define PI 3.14159265358979 #define TWO_PI 6.28318530717958 #define HALF_PI 1.570796326794895 double atan2(x, y) double x, y; { double v; if(fabs(y) >= fabs(x)) { v = atan(x/y); if( y < 0.0) if(x >= 0.0) v += PI; else v -= PI; return v; } v = -atan(y/x); if(x < 0.) v -= HALF_PI; else v += HALF_PI; return v; } ================================================ FILE: float/ATOF.C ================================================ #include double atof(s) register char * s; { char sign; double l; short exp; short eexp; char expsign; double ten; ten = 10.0; while(isspace(*s)) s++; expsign = sign = 0; if(*s == '-') { s++; sign = 1; } l = 0; exp = 0; while(isdigit(*s)) l = ten*l + (double)(*s++ - '0'); if(*s == '.') while(isdigit(*++s)) { exp--; l = ten*l + (double)(*s - '0'); } eexp = 0; if(*s == 'e' || *s == 'E') { if(*++s == '-') { expsign = 1; s++; } if(*s == '+') s++; while(isdigit(*s)) eexp = eexp*10 + *s++ - '0'; if(expsign) eexp = -eexp; } exp += eexp; while(exp < 0) { l = l / ten; exp++; } while(exp > 0) { l = l * ten; exp--; } if(sign) return -l; return l; } ================================================ FILE: float/CEIL.C ================================================ #include extern double _frndint(); double ceil(x) double x; { double i; i = _frndint(x); if(i < x) return i + 1.0; return i; } ================================================ FILE: float/COS.C ================================================ #include #define PI 3.14159265358979 #define TWO_PI 6.28318530717958 #define HALF_PI 1.570796326794895 double cos(f) double f; { /* cos is pi/2 out of phase with sin, so ... */ if(f > PI) return sin(f - (PI+HALF_PI)); return sin(f + HALF_PI); } ================================================ FILE: float/COSH.C ================================================ #include double cosh(x) double x; { x = exp(x); return 0.5*(x+1.0/x); } ================================================ FILE: float/DOPRNT.C ================================================ #include #include /* * doprnt for 8086 */ static uchar ival; static char * x; static FILE * ffile; extern int atoi(char *); extern int strlen(char *); static pputc(c) int c; { putc(c, ffile); } static char * icvt(cp) register char * cp; { ival = atoi(cp); while(isdigit((unsigned)*cp)) cp++; return cp; } _doprnt(file, f, a) FILE * file; register char * f; int * a; { char c, prec; uchar fill, left; unsigned int i, len; uchar base, width, sign; uchar ftype; extern short _pnum(), _fnum(); ffile = file; while(c = *f++) if(c != '%') pputc(c); else { base = 10; width = 0; sign = 0; left = 0; ftype = 0; len = sizeof(int)/sizeof *a; if(*f == '-') { f++; left++; } fill = *f == '0'; if(isdigit((unsigned)*f)) { f = icvt(f); width = ival; } else if(*f == '*') { width = *a++; f++; } if(*f == '.') if(*++f == '*') { prec = *a++; f++; } else { f = icvt(f); prec = ival; } else prec = fill ? width : -1; if(*f == 'l') { f++; len = sizeof(long)/sizeof *a; } switch(c = *f++) { case 0: return; case 'o': case 'O': base = 8; break; case 'd': case 'D': sign = 1; break; case 'x': case 'X': base = 16; break; case 's': x = *(char **)a; a += sizeof(char *)/sizeof *a; if(!x) x = "(null)"; i = strlen(x); dostring: if(prec < 0) prec = 0; if(prec && prec < i) i = prec; if(width > i) width -= i; else width = 0; if(!left) while(width--) pputc(' '); while(i--) pputc(*x++); if(left) while(width--) pputc(' '); continue; case 'c': c = *a++; default: x = &c; i = 1; goto dostring; case 'u': case 'U': break; case 'e': case 'E': sign++; case 'g': case 'G': sign++; case 'f': case 'F': if(prec < 0) prec = 6; ftype = 1; break; } if(left) { left = width; width = 0; } if(isupper(c)) len = sizeof(long)/sizeof *a; if(prec < 0) prec = 0; if(ftype) { width = _fnum(*(double *)a, prec, width, sign, pputc); a += sizeof(double)/sizeof(*a); } else { width = _pnum((len == sizeof(int)/sizeof *a ? (sign ? (long)*a : (unsigned long)*a) : *(long *)a), prec, width, sign, base, pputc); a += len; } while(left-- > width) pputc(' '); } } ================================================ FILE: float/DOSCAN.C ================================================ /* * _doscan - implement scanf, fscanf, sscanf */ #include #include static FILE * fp; extern double atof(char *); extern int atoi(char *); static range(c, base) int c; uchar base; { if(isdigit(c)) c -= '0'; else { if (isupper(c)) c = tolower(c) ; if (isalpha(c)) c = c - 'a' + 10 ; else return -1 ; } if (c >= base) return -1 ; return c ; } static wspace() { int c; while(isspace(c = getc(fp))) continue; if(c != EOF) ungetc(c, fp); } _doscan(file, fmt, args) FILE * file; register char * fmt; int ** args; { uchar c, sign, base, n, noass,len; char width ; char * sptr; int ch; long val; char buf[60]; fp = file; n = 0; while(c = *fmt++) { len = 0 ; if(isspace(c)) { wspace(); continue; } if(c == '%') { noass = 0; width = 0; loop: switch(c = *fmt++) { case '\0': return n ? n : feof(fp) ? EOF : 0; case '*': noass++; goto loop; case 'F': len++; case 'f': wspace(); sptr = buf; if(width == 0) width = sizeof buf - 1; sign = 0; /* really decimal point seen */ ch = getc(fp); if(ch == '-') { *sptr++ = ch; ch = getc(fp); width--; } while(width && isdigit(ch) || !sign && ch == '.') { *sptr++ = ch; if(ch == '.') sign++; ch = getc(fp); width--; } if(width && (ch == 'e' || ch == 'E')) { *sptr++ = ch; ch = getc(fp); width--; if(width && (ch == '-' || ch == '+')) { *sptr++ = ch; ch = getc(fp); width--; } while(width && isdigit(ch)) { *sptr++ = ch; ch = getc(fp); width--; } } *sptr = 0; if(ch != EOF) ungetc(ch, fp); if(sptr == buf) return n ? n : feof(fp) ? EOF : 0; n++; if(!noass) if(len) *(double *)*args++ = atof(buf); else *(float *)*args++ = atof(buf); continue; case 'l': len++; goto loop; case 'D': len++; case 'd': base = 10; break; case 'O': len++; case 'o': base = 8; break; case 'X': len++; case 'x': base = 16; break ; case 's': wspace(); if ( !noass ) sptr = (char *)*args++; if ((ch = getc(fp)) == EOF ) return n ? n : EOF; while(ch && ch != EOF && !isspace(ch)) { if(ch == *fmt) { fmt++; break; } if ( !noass ) *sptr++ = ch; if(--width == 0) break; ch = getc(fp); } n++; if(!noass) *sptr = 0; continue; case 'c': if ( !noass ) sptr = (char *)*args++; do { if ((ch = getc(fp)) == EOF) return n ? n : EOF; if ( !noass ) *sptr++ = ch; } while(--width > 0); n++; continue; default: if(isdigit(c)) { width = atoi(fmt-1); while(isdigit(*fmt)) fmt++; goto loop; } if(c != (ch = getc(fp))) if(ch == EOF) return n ? n : EOF; else { ungetc(ch, fp); return n; } continue; } wspace(); val = 0; sign = 0; ch = getc(fp); if(ch == '-') { sign++; ch = getc(fp); } if(range(ch, base) == -1) { ungetc(ch, fp); return n ? n : feof(fp) ? EOF : 0; } do { val = val * base + range(ch, base); } while (( --width != 0 ) && ( range(ch = getc(fp),base) != -1 )) ; n++; if (range(ch,base) == -1) ungetc(ch, fp); if(sign) val = -val; if ( !noass ) if(len) *(long *)*args++ = val; else **args++ = val; continue; } else if(c != (ch = getc(fp))) { if(ch != EOF) { ungetc(ch, fp); return n; } else return n ? n : EOF; } } return n; } ================================================ FILE: float/EVALPOLY.C ================================================ double eval_poly(x, d, n) double x; /* const */ double * d; int n; { int i; double res; res = d[i = n]; while(i) res = x * res + d[--i]; return res; } ================================================ FILE: float/EXP.C ================================================ #include extern double eval_poly(); double exp(x) double x; { int exp; char sign; /* const */ static double coeff[] = { 1.0000000000e+00, 6.9314718056e-01, 2.4022650695e-01, 5.5504108945e-02, 9.6181261779e-03, 1.3333710529e-03, 1.5399104432e-04, 1.5327675257e-05, 1.2485143336e-06, 1.3908092221e-07, }; if(x == 0.0) return 1.0; sign = x < 0.0; if(sign) x = -x; x *= 1.4426950409; /* convert to log2 */ exp = (int)floor(x); x -= (double)exp; x = ldexp(eval_poly(x, coeff, sizeof coeff/sizeof coeff[0] - 1), exp); if(sign) return 1.0/x; return x; } double pow(x, y) double x, y; { unsigned char sign = 0; unsigned long yi; if(x == 0.0) return 0.0; if(y == 0.0) return 1.0; if(x < 0.0) { yi = (unsigned long)y; if(yi != y) return 0.0; sign = yi & 1; x = -x; } x = exp(log(x) * y); if(sign) return -x; return x; } ================================================ FILE: float/FABS.C ================================================ double fabs(d) double d; { if(d < 0.0) return -d; return d; } ================================================ FILE: float/FBCD.AS ================================================ ; long _fbcd(x, exp, buf) ; double x; ; int * exp; ; char * buf; ; split x into mantissa and decimal exponent parts ; return value is the (long) mantissa part, exponent part is ; stored in *exp as two's complement. Mantissa is stored into buf ; as an ascii string. argx equ 6 ;offset of x argument argexp equ 10 ;offset of exp argument argbuf equ 12 ;offset of buf argument exptmp equ -1 ;offset of exp temp byte sgntmp equ -2 ;offset of sign byte NDIG equ 8 ;number of decimal digits global __fbcd, rcsv, cret, flmul, negmant,lldiv,llmod psect text hasfrac: ld c,0 ;zero number ld a,e ;check low 8 bits or a jr nz,1f ;non zero bit in low 8 bits ld c,8 ;bump count ld a,d ;check next 8 bits or a ;is there a bit there? jr nz,1f ;yup ld c,16 ld a,h ;now check next 8 bits 1: rra ;shift bottom bit out jr c,2f ;found a bit! inc c ;increment count jr 1b ;and loop 2: ld a,h ;get exponent res 7,a ;clear sign bit - should be zero anyway sub 64+24 ;normalize - remove bias add a,c ;add in bit position ret ;return with value in a and flags set __fbcd: call rcsv ;get x into hlde, exp into bc dec sp ;make room for exponent dec sp ;and sign flag xor a ld (ix+exptmp),a ;zero it ld (ix+sgntmp),a ld (bc),a ;and the returned exp value ex de,hl ;put hi word into hl as required ld a,h ;check for zero exponent and 7Fh ;zero exponent means 0.0 jp nz,1f ;return if x == 0.0 ld l,a ;zero mantissa just in case ld e,a ld d,a ld h,a ;and sign/exponent jp sbcd ;return with mantissa = 0, exponent = 0 1: res 7,h ;test mantissa sign 2: call hasfrac ;any fractional part? jp m,1f ;negative if there is fractional part push hl ;put x on stack push de ld hl,(tenth+2) ld de,(tenth) call flmul ;returns with value in hlde inc (ix+exptmp) ;increment exponent jr 2b ;now check again 1: push hl push de ;pass x as argument ld hl,(ten+2) ld de,(ten) call flmul ;multiply it dec (ix+exptmp) ;and decrement exponent call hasfrac ;check for fractional part jp m,1b ;loop if still fractional ld a,h ;get exponent ld h,0 ;zero top byte sub 64+24 ;offset exponent 2: or a ;check for zero jr z,3f ;return if finished jp p,4f srl l ;shift l down rr d ;rotate the rest rr e inc a ;increment count jr 2b 4: sla e rl d rl l rl h dec a jr 2b 3: ld a,(ix+exptmp) ld c,(ix+argexp) ;get exp pointer ld b,(ix+argexp+1) ld (bc),a ;store exponent inc bc rla sbc a,a ld (bc),a ;sign extend it bit 0,(ix+sgntmp) ;test sign jp z,sbcd ;return if no negation needed push hl ;push hi word ld hl,0 ;get a zero or a ;reset carry sbc hl,de ;do low subtraction ex de,hl ;put into de again ld hl,0 ;get another zero pop bc ;get hi word sbc hl,bc ;subtract again sbcd: ;now store as ascii ld c,(ix+argbuf) ld b,(ix+argbuf+1) push bc pop iy ld bc,NDIG add iy,bc ;point to end of buffer ld b,c ld (iy+0),0 ;null terminate push hl push de ;save return value 1: push bc ;save count push hl ;save value push de ld bc,0 push bc ;pass 10 on stack ld bc,10 push bc call llmod ld a,e ;get remainder add a,'0' ;asciize dec iy ld (iy+0),a pop de pop hl ;restore value ld bc,0 ;now divide by 10 push bc ld bc,10 push bc call lldiv pop bc ;restore count djnz 1b ;loop if more to do pop de pop hl jp cret ;all done psect data ten: deff 10.0 tenth: deff 0.1 ================================================ FILE: float/FINC.AS ================================================ ; lfinc - floating increment ; lfdec - floating decrement psect text global lfinc, lfdec, asfladd lfinc: exx ld hl,one incdec: exx ;restore original hl ld e,(hl) ;get left operand original value inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) push bc push de ;save on the stack for 'ron dec hl ;restore pointer value dec hl dec hl exx ;now pointer to right op ld e,(hl) inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) push bc ;hi order word first push de ;low order word second exx ;restore pointer to left op call asfladd ;perform the addition pop de ;pop original lo word pop hl ;and high word ret ;and return with it in the right place lfdec: exx ld hl,mone ;get a minus one jp incdec psect data one: deff 1.0 mone: deff -1.0 ================================================ FILE: float/FLOAT.AS ================================================ ; This is a set of routines for floating point handling for C ; The format of a floating point number is as follows: ; ; ------------ ; * sign * 1 bit ; *----------* ; * exponent * 7 bits ; *----------* ; * mantissa * 24 bits, normalized ; ------------ ; ; Note that the number is stored with the mantissa in the ; low order bytes, i.e. the sign is the most significant ; bit of the most significant byte. global fpnorm, fladd, flsub, flmul, fldiv, negmant psect text ; fpnorm - passed a floating point number in HLDE (sign and exponent ; in H) - returns with it normalized. ; ; Points to note: ; Normalization consists of shifting the mantissa until there ; is a 1 bit in the MSB of the mantissa. ; fpnorm: ld a,l ;check for zero mantissa or d or e jp z,fpzero ;make it a clean zero push hl ;save exponent and sign pop bc ;get the exponent into b ld c,b ;copy into c res 7,c ;reset the sign bit 2: bit 7,l ;test the MSB of the mantissa jr nz,3f ;set, no more shifting required dec c ;decrement exponent jp m,fpovrflw ;underflow - set flag and return 0 ex de,hl ;get low word in hl add hl,hl ;shift left ex de,hl ;hi word back again adc hl,hl ;shift bit in jr 2b ;loop and test again 3: bit 7,b ;test sign jr z,4f ;skip if clear set 7,c ;set the new sign bit 4: ld h,c ;put exponent and sign back where it belongs ret ;finished ; Set the floating overflow flag and return zero. Floating execptions ; may be caught in which case the appropriate routine will be called. fpovrflw: ld a,1 ld (fperr),a fpzero: ld hl,0 ld e,l ld d,h ret ; Negate the mantissa in LDE. negmant: push hl ;save hi byte and sign ld hl,0 ld a,l ;zero a as well or a ;reset carry sbc hl,de ;negate low word ex de,hl ;put back in de pop hl ;restore hi byte sbc a,l ;negate the hi byte ld l,a ;put back ret ;and return ; Floating subtraction. The value on the stack is subtracted from the ; value in HLDE. To simplify matters, we do it thus: ; ; A-B == A+-B flsub: pop bc ;return address exx ;get some other regs pop de ;low word pop hl ;hi word ld a,h ;get sign/exponent or a jr z,1f xor 80h ;toggle sign ld h,a ;put back 1: push hl ;put back on stack push de exx ;get other operand back push bc ;and return address ;fall through to fladd ; Floating addition: ; Add the value in HLDE to the value on the stack (under the ; return address, and return with the argument removed from ; the stack. fladd: ld a,l ;check 1st operand for zero or d or e ;only need to check mantissa exx ;get some spare registers pop bc ;return address pop de ;low word of 2nd operand pop hl ;hi word push bc ;put return address back on stack ret z ;if 1st operand 0, just return 2nd ld a,l ;check for zero 2nd arg or d or e ;if zero, just return the 1st operand ld a,h ;put exponent in a exx ;restore 1st operand ret z res 7,a ;clear sign ld c,h ;get exponent res 7,c ;and clear sign sub c ;find difference jr nc,1f ;if negative, exx ; switch operands neg ;and make it positive 1: cp 24 ;if less than 24 bits difference, jr c,2f ;we can do the add exx ;otherwise just return the larger value ret 2: or a ;check for zero difference call nz,fpadjust ;adjust till equal ld c,h ;save exponent of result bit 7,h ;test sign, do we need to negate? ld h,0 ;zero fill in case +ve jr z,1f ;no call negmant ;yes ld h,0ffh ;1 fill top byte 1: push de ;get low word exx ;select other bank bit 7,h ;test sign, do we need to negate? ld h,0 ;zero fill in case +ve jr z,1f ;no call negmant ;yes ld h,0ffh ;1 fill top byte 1: pop bc ;get low word of other operand ex de,hl ;exchange hi/low add hl,bc ex de,hl ;restore exx ;get other bank again push hl ;and hi word ld a,c ;and exponent exx pop bc adc hl,bc ;add it in res 7,a ;clear sign from exponent jr c,hm3 inc h dec h ;zero in h? jr z,hm2 hm3: sra h ;now shift down 1 bit to compensate rr l ;propogate the shift rr d rr e inc a ;increment to compensate for shift above hm2: push af ;save carry flag ld c,a ;save exponent ld a,h and 80h ;mask off low bits or c ;or in exponent ld h,a ;now have it! call m,negmant ;restore mantissa to positive if required pop af ;restore carry flag call c,round ;round up if necessary jp fpnorm ;normalize and return!! ; Round the number in HLDE up by one, because of a shift of bits out ; earlier round: ld bc,1 ;add in 1 extra bit ex de,hl add hl,bc ex de,hl push hl ;save exponent/sign ld h,0 ld c,h adc hl,bc ;add in carry pop bc ;get exponent/sign back bit 0,h ;did it cause carry out of l? jr z,2f srl h rr l rr d rr e ld a,b ;get exponent/sign and 7fh ;get exponent only inc a ;add one ld c,a ld a,b and 80h or c ;now exponent and sign again ld b,a 2: ld h,b ;restore sign/exponent ret ; Adjust the floating number in HLDE by increasing the exponent by the ; contents of A. The mantissa must be shifted right to compensate. fpadjust: and 31 ;mask of hi bits - irrelevant ld b,a ;put in a suitable register for loop count 1: srl l rr d rr e inc h ;increment exponent - it will not overflow djnz 1b ;loop if more ret ;finito ; Get the right operand into HLDE', leave the left operand ; where it is in HLDE, but make both of them +ve. The original ; exponents/signs are left in C and B, left and right operands ; respectively. fsetup: pop bc ;top return address exx pop bc ;outer return address pop de ;low word pop hl ;hi word of right operand push bc ;put return address back ld c,h ;get exponent res 7,h ;clear sign ld a,c ;exponent again exx push bc ;inner return address ld b,a ;other exponent ld c,h ;this exponent res 7,h ;make positive ret ; Floating multiplication. The number in HLDE is multiplied by the ; number on the stack under the return address. The stack is cleaned ; up and the result returned in HLDE. flmul: call fsetup ;get operands, make them +ve. push bc ;save exponents etc. ld h,0 ;zero top byte push hl ;push hi word ld hl,0 ;zero product exx ld h,0 ;zero top byte push hl ;push hi word pop bc ;put it into bc pop hl ;hi word of multplicand ex de,hl ;get it into de push hl ;low word of multiplier ld hl,0 ;zero product exx pop bc ;low word of multiplier ld a,c ;get low 8 bits of multiplier ld c,b ;save next 8 bits call mult26 ;do 8 bits of multiply ld a,c call mult8 ;next 8 bits exx ld a,c ;next 8 bits exx call mult8 ;do next chunk exx ;get hi words push hl ;product hi word exx pop de ex de,hl ;hi word in hl, lo in de ld a,h ;get hi byte ld h,0 ld c,h ;zero lower byte jr 1f ;skip forward 2: srl a rr l rr d rr e rr c ;save carry bit in c inc h 1: or a ;hi byte zero yet? jr nz,2b ;no, keep shifting down ex af,af' ld a,c ;copy shifted-out bits ex af,af' pop bc ;get exponents bit 7,l ;check for zero mantissa jp z,fpzero ;return a clean zero if so ld a,c res 7,a ;mask off sign sub 41h ;remove bias, allow one bit shift add a,h ;add in shift count sub 6 ;compensate for shift up earlier ld h,b ;the other res 7,h ;mask off signs add a,h ;add them together jp m,fpovrflw ;overflow in exponent ld h,a ;put exponent in ld a,c ;now check signs xor b jp p,1f set 7,h ;set sign flag 1: ex af,af' rla ;shift top bit out ret nc ;return if no carry jp round ;round it mult26: ld b,6 3: srl a ;shift LSB of multiplier into carry jp nc,1f add hl,de exx adc hl,de exx 1: ex de,hl add hl,hl ex de,hl exx ex de,hl adc hl,hl ex de,hl exx ;shift multiplicand up one bit djnz 3b ;more? ld b,2 ;do remaining two bits jr 4f mult8: ld b,8 3: exx srl h rr l ;shift product down 1 bit exx rr h rr l 4: srl a ;shift LSB into carry jp nc,1f add hl,de exx adc hl,de exx 1: djnz 3b ;more? ret ;no, return as is ; Floating division. The number in HLDE is divided by the ; number on the stack under the return address. The stack is cleaned ; up and the result returned in HLDE. fldiv: call fsetup ;get operands, make them +ve. push bc ;save exponents etc. ld h,0 ;zero top byte of dividend push de ;push lo word ld bc,0 ;zero quotient exx ld h,0 ;zero top byte of divisor ex (sp),hl ;get lo word of dividend into hl ld bc,0 ;zero low word of quotient exx pop de ;hi word of divisor ld a,24+6 ;number of bits in dividend and then some 3: push hl ;save dividend exx push hl ;low word or a ;reset carry sbc hl,de ;try a subtraction exx sbc hl,de ;now the hi word exx jr nc,4f ;skip if no carry pop hl ;restore dividend exx pop hl exx jr 5f 4: inc sp ;unjunk stack inc sp inc sp inc sp 5: ccf ;complement carry bit rl c ;shift into quotient rl b exx rl c rl b exx ;low words again add hl,hl ;shift dividend left exx adc hl,hl ;upper shift dec a ;decrement loop count jr nz,3b exx push bc ;get low word of quotient exx pop de push bc ;hi word pop hl ld a,h ;get hi byte ld h,0 ld c,h ;zero lower byte jr 1f ;skip forward 2: srl a rr l rr d rr e rr c ;save carry bit in c inc h 1: or a ;hi byte zero yet? jr nz,2b ;no, keep shifting down ex af,af' ld a,c ;copy shifted-out bits ex af,af' pop bc ;restore exponents push bc ;save signs ld a,c res 7,a res 7,b sub b add a,41h-6 ;compensate add a,h ld h,a pop bc jp m,fpovrflw ;PMO catch under/overflow ld a,c xor b ;get sign jp p,1f set 7,h 1: ex af,af' ;get shifted out bit back again rla call c,round ;round if necessary jp fpnorm ;normalize it and return psect bss fperr: defs 1 ;floating over/underflow flag ================================================ FILE: float/FLOOR.C ================================================ #include extern double _frndint(); double floor(x) double x; { double i; i = _frndint(x); if(i > x) return i - 1.0; return i; } ================================================ FILE: float/FNUM.C ================================================ /* * _fnum() - converts floating numbers to ascii decimal * representations. */ #define uchar unsigned char #define putc(c) (*pputc)(c) #define buf (xbuf+2) extern double _frndint(); extern int strlen(char *); extern int abs(int); _fnum(val, prec, width, efmt, pputc) double val; char width, prec, efmt; void (* pputc)(); { register char * cp, * xp; int exp; char digs; short twid; uchar sign; char xbuf[60]; if(prec < 0) prec = 6; twid = 0; if(val < 0.0) { val = -val; sign = 1; } else sign = 0; exp = 0; /* if(efmt == 0 && prec == 0) val = _frndint(val); /* round to integer */ _fbcd(val, &exp, buf); cp = buf; while(*cp == '0') cp++; if(*cp == 0) /* all zero */ cp--; if(strlen(cp) > 1) { xp = cp+strlen(cp)-1; while(*xp == '0') { /* remove traiing zeros */ *xp-- = 0; exp++; } } else if(*cp == '0') exp = 0; cp[-1] = '0'; digs = strlen(cp); /* number of significant digits */ if(efmt == 0 && prec == 0 || efmt == 1 && exp >= 0 && exp <= 5+prec) { /* use d format */ if(exp < 0) { /* too much precision */ char c; xp = cp+digs+exp; c = *xp; *xp = 0; if(c >= '5') for(;;) if((*--xp += 1) == '9'+1) *xp = '0'; else break; if(xp < cp) cp = xp; digs = strlen(cp); exp = 0; } width -= (twid = digs + exp + sign); while(width > 0) { putc(' '); width--; twid++; } if(sign) putc('-'); while(*cp) putc(*cp++); while(exp > 0) { putc('0'); exp--; } return twid; } if(efmt == 1 && exp >= 5 || exp + digs < -4) efmt++; if(efmt >= 2) { /* use e format */ width -= (twid = sign + prec + 6); if(digs > prec+1) { /* need to round it */ char c; loop: xp = cp+prec+1; exp += digs-(prec+1); c = *xp; *xp = 0; if(c >= '5') for(;;) if((*--xp += 1) == '9'+1) *xp = '0'; else break; if(xp < cp) cp = xp; digs = strlen(cp); if(digs > prec+1) goto loop; } exp += digs - 1; /* allow for moving dec. pt. */ if(abs(exp) >= 100) /* 3 digit exponent */ width--; prec -= digs - 1; while(width > 0) { putc(' '); width--; twid++; } if(sign) putc('-'); putc(*cp++); putc('.'); while(*cp) putc(*cp++); while(prec > 0) { putc('0'); prec--; } putc('e'); if(exp < 0) { exp = -exp; putc('-'); } else putc('+'); if(exp >= 100) { putc(exp / 100 + '0'); exp %= 100; } putc(exp / 10 + '0'); putc(exp % 10 + '0'); return twid; } /* here for f format */ if(exp + prec < 0) { /* too much precision */ char c; xp = cp+digs+exp+prec; c = *xp; *xp = 0; if(c >= '5') for(;;) if((*--xp += 1) == '9'+1) *xp = '0'; else break; if(xp < cp) cp = xp; digs = strlen(cp); exp = -prec; } prec += exp; twid = 1 + prec + sign + digs; digs = -digs; if(exp <= digs) twid += digs - exp + 1; width -= twid; while(width > 0) { putc(' '); width--; } if(sign) putc('-'); if(exp <= digs) { putc('0'); putc('.'); while(exp < digs) { putc('0'); exp++; } } while(*cp) { putc(*cp++); if(++digs == exp) putc('.'); } while(exp > 0) { putc('0'); prec--; if(--exp == 0) putc('.'); } while(prec > 0) { putc('0'); prec--; } return twid; } ================================================ FILE: float/FPRINTF.C ================================================ #include extern int _doprnt(); fprintf(file, f, a) FILE * file; char * f; int a; { return(_doprnt(file, f, &a)); } ================================================ FILE: float/FREXP.AS ================================================ ; These functions allow the mantissa and exponent of floating ; numbers to be manipulate separately. psect text global _frexp, _ldexp ; double frexp(value, eptr) ; double value; ; int * eptr; _frexp: push ix ld ix,0 add ix,sp ld a,(ix+7) ;get old exponent ld b,a ;save sign bit and 80h ;mask it out add a,64 ;add in bias ld d,a ;store new exponent back ld a,b ;now get exponent and 7Fh ;clea sign bit sub 64 ;remove bias ld l,(ix+8) ;get pointer ld h,(ix+9) ld (hl),a inc hl rla sbc a,a ld (hl),a ;store upper byte ld l,(ix+4) ;now get value to return ld h,(ix+5) ld e,(ix+6) ex de,hl ;already have sign in d pop ix ret _ldexp: push ix ld ix,0 add ix,sp ld a,(ix+8) and 7Fh ld c,a ld a,(ix+7) ld h,a and 80h ld b,a ld a,h add a,c and 7Fh or b ld h,a ld l,(ix+6) ld d,(ix+5) ld e,(ix+4) pop ix ret ================================================ FILE: float/FRNDINT.AS ================================================ psect text ; double frndint(val) ; double val; ; Round the argument to an integral value, return as a double global __frndint, altof, ftol __frndint: pop bc ;return addr pop de pop hl ;float val push hl push de push bc call ftol jp altof ================================================ FILE: float/FSCANF.C ================================================ /* * Stdio fscanf */ #include extern int _doscan(); fscanf(file, fmt, args) FILE * file; char * fmt; int args; { return _doscan(file, fmt, &args); } ================================================ FILE: float/FTOL.AS ================================================ ; ftol - convert floating to long, by using lower bits can also ; be used to convert from float to int or char psect text global ftol global alrsh, allsh, negmant ftol: bit 7,h ;test sign call nz,negmant ;negate mantissa if required ld a,h ;get exponent res 7,a ;mask sign off sub 64+24 ;remove offset ld b,a ;save shift count ld a,h ;get exponent, sign rla sbc a,a ;sign extend ld h,a ;put back bit 7,b ;test sign jp z,allsh ;shift it left ld a,b ;get the count neg ;make +ve dec a ;and reduce it one ld b,a ;put back in b call nz,alrsh ;shift right ex de,hl ld bc,1 ;add one for rounding add hl,bc ld b,c ex de,hl jp nc,alrsh ;and shift down one more inc hl ;add in carry first jp alrsh ================================================ FILE: float/LIBFVER.C ================================================ #include char *_libfver = #ifdef Z280 "LIB280F " _HTC_VERSION; #else "LIBF " _HTC_VERSION; #endif ================================================ FILE: float/LOG.C ================================================ #include extern double eval_poly(); double log(x) double x; { int exp; static /* const */ double coeff[] = { 0.0000000000, /* a0 */ 0.9999964239, /* a1 */ -0.4998741238, /* a2 */ 0.3317990258, /* a3 */ -0.2407338084, /* a4 */ 0.1676540711, /* a5 */ -0.0953293897, /* a6 */ 0.0360884937, /* a7 */ -0.0064535442, /* a8 */ }; /* zero or -ve arguments are not defined */ if(x <= 0.0) return 0.0; x = frexp(x, &exp) * 2.0 - 1.0; exp--; x = eval_poly(x, coeff, sizeof coeff/sizeof coeff[0] - 1); return x + 0.69314718055995 * exp; } double log10(x) double x; { return log(x) * 0.4342944819; } ================================================ FILE: float/LTOF.AS ================================================ ; Conversion of integer type things to floating. Uses routines out ; of float.as. psect text global altof, lltof, aitof, litof, abtof, lbtof global fpnorm lbtof: ld l,a ld h,0 litof: ex de,hl ;put arg in de ld l,0 ;zero top byte b3tof: ld h,64+24 jp fpnorm abtof: ld l,a rla sbc a,a ld h,a aitof: bit 7,h ;negative? jp z,litof ;no, treat as unsigned ex de,hl ld hl,0 or a sbc hl,de ;negate it call litof set 7,h ;set sign flag ret lltof: ld a,h ;anything in top byte? or a jr z,b3tof ;no, just do 3 bytes ld c,0 ; Do it the hard way slop: ld a,h cp 1 ;last shift coming up? jr z,slop2 srl h rr l rr d rr e inc c jr slop slop2: inc e jr nz,slop3 inc d jr nz,slop3 inc l jr nz,slop3 inc h slop3: srl h rr l rr d rr e ld a,h or a jr z,slop4 srl h rr l rr d rr e inc c slop4: ld a,c add a,64+25 ld h,a jp fpnorm ;and normalize it altof: bit 7,h ;negative? jr z,lltof ;no, treat as unsigned push hl ;negate it now ld hl,0 or a sbc hl,de ex de,hl pop bc ld hl,0 sbc hl,bc call lltof set 7,h ;set sign flag ret ================================================ FILE: float/M280LIBF.LOG ================================================ 10D>date A:DATE COM (User 0) Mon 01/09/2025 13:28:32 10D>;---------- M280LIBF.SUB ---------- 10D>; Assumes DEHUFF -X FLOAT.HUF has extracted 10D>; all sources to the default drive 10D>;------------------------------------ 10D>m: 10M>era m:*.obj ERASE M:*.OBJ (Y/N)? Y 10M>; 10M>c280 A:C280 COM (User 0) 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 c> -v -c -o2 \ c> d:LIBFVER.C \ c> d:PRINTF.C \ c> d:FPRINTF.C \ c> d:SPRINTF.C \ c> d:SCANF.C \ c> d:FSCANF.C \ c> d:SSCANF.C \ c> d:DOPRNT.C \ c> d:DOSCAN.C \ c> d:ATOF.C \ c> d:FNUM.C \ c> d:FBCD.AS \ c> d:TAN.C \ c> d:ACOS.C \ c> d:ASIN.C \ c> d:ATAN2.C \ c> d:ATAN.C \ c> d:COS.C \ c> d:SIN.C \ c> d:SINH.C \ c> d:COSH.C \ c> d:TANH.C \ c> d:EXP.C \ c> d:LOG.C \ c> d:EVALPOLY.C \ c> d:SQRT.C \ c> d:FREXP.AS \ c> d:FABS.C \ c> d:CEIL.C \ c> d:FLOOR.C \ c> d:FINC.AS \ c> d:ASFLOAT.AS \ c> d:FRNDINT.AS \ c> d:FTOL.AS \ c> d:LTOF.AS \ c> d:FLOAT.AS D:LIBFVER.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:LIBFVER.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OLIBFVER.OBJ $CTMP5.$$$ D:PRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:PRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 5 bytes size optimised away 6 bytes replaced 0:A:ZAS -J -N -OPRINTF.OBJ $CTMP5.$$$ D:FPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:FPRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 7 bytes size optimised away 10 bytes replaced 0:A:ZAS -J -N -OFPRINTF.OBJ $CTMP5.$$$ D:SPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:SPRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -OSPRINTF.OBJ $CTMP5.$$$ D:SCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:SCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 5 bytes size optimised away 6 bytes replaced 0:A:ZAS -J -N -OSCANF.OBJ $CTMP5.$$$ D:FSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:FSCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 7 bytes size optimised away 10 bytes replaced 0:A:ZAS -J -N -OFSCANF.OBJ $CTMP5.$$$ D:SSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:SSCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 18 bytes size optimised away 28 bytes replaced 0:A:ZAS -J -N -OSSCANF.OBJ $CTMP5.$$$ D:DOPRNT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:DOPRNT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 51 bytes size optimised away 122 bytes replaced 0:A:ZAS -J -N -ODOPRNT.OBJ $CTMP5.$$$ D:DOSCAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:DOSCAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 201 bytes size optimised away 410 bytes replaced 0:A:ZAS -J -N -ODOSCAN.OBJ $CTMP5.$$$ D:ATOF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:ATOF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 92 bytes size optimised away 185 bytes replaced 0:A:ZAS -J -N -OATOF.OBJ $CTMP5.$$$ D:FNUM.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:FNUM.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 187 bytes size optimised away 420 bytes replaced 0:A:ZAS -J -N -OFNUM.OBJ $CTMP5.$$$ D:FBCD.AS 0:A:OPTIMH D:FBCD.AS $CTMP5.$$$ 5 bytes size optimised away 10 bytes replaced 0:A:ZAS -J -OFBCD.OBJ $CTMP5.$$$ D:TAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:TAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 8 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -OTAN.OBJ $CTMP5.$$$ D:ACOS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:ACOS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 4 bytes size optimised away 8 bytes replaced 0:A:ZAS -J -N -OACOS.OBJ $CTMP5.$$$ D:ASIN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:ASIN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 40 bytes size optimised away 80 bytes replaced 0:A:ZAS -J -N -OASIN.OBJ $CTMP5.$$$ D:ATAN2.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:ATAN2.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 45 bytes size optimised away 108 bytes replaced 0:A:ZAS -J -N -OATAN2.OBJ $CTMP5.$$$ D:ATAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:ATAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 55 bytes size optimised away 106 bytes replaced 0:A:ZAS -J -N -OATAN.OBJ $CTMP5.$$$ D:COS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:COS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 12 bytes size optimised away 24 bytes replaced 0:A:ZAS -J -N -OCOS.OBJ $CTMP5.$$$ D:SIN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:SIN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 57 bytes size optimised away 102 bytes replaced 0:A:ZAS -J -N -OSIN.OBJ $CTMP5.$$$ D:SINH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:SINH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 16 bytes size optimised away 32 bytes replaced 0:A:ZAS -J -N -OSINH.OBJ $CTMP5.$$$ D:COSH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:COSH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 12 bytes size optimised away 24 bytes replaced 0:A:ZAS -J -N -OCOSH.OBJ $CTMP5.$$$ D:TANH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:TANH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 16 bytes size optimised away 32 bytes replaced 0:A:ZAS -J -N -OTANH.OBJ $CTMP5.$$$ D:EXP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:EXP.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 70 bytes size optimised away 132 bytes replaced 0:A:ZAS -J -N -OEXP.OBJ $CTMP5.$$$ D:LOG.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:LOG.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 27 bytes size optimised away 60 bytes replaced 0:A:ZAS -J -N -OLOG.OBJ $CTMP5.$$$ D:EVALPOLY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:EVALPOLY.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 32 bytes size optimised away 68 bytes replaced 0:A:ZAS -J -N -OEVALPOLY.OBJ $CTMP5.$$$ D:SQRT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:SQRT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 95 bytes size optimised away 186 bytes replaced 0:A:ZAS -J -N -OSQRT.OBJ $CTMP5.$$$ D:FREXP.AS 0:A:OPTIMH D:FREXP.AS $CTMP5.$$$ 4 bytes size optimised away 8 bytes replaced 0:A:ZAS -J -OFREXP.OBJ $CTMP5.$$$ D:FABS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:FABS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 8 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -OFABS.OBJ $CTMP5.$$$ D:CEIL.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:CEIL.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 24 bytes size optimised away 48 bytes replaced 0:A:ZAS -J -N -OCEIL.OBJ $CTMP5.$$$ D:FLOOR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: D:FLOOR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 20 bytes size optimised away 40 bytes replaced 0:A:ZAS -J -N -OFLOOR.OBJ $CTMP5.$$$ D:FINC.AS 0:A:OPTIMH D:FINC.AS $CTMP5.$$$ 0 bytes size optimised away 8 bytes replaced 0:A:ZAS -J -OFINC.OBJ $CTMP5.$$$ D:ASFLOAT.AS 0:A:OPTIMH D:ASFLOAT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASFLOAT.OBJ $CTMP5.$$$ D:FRNDINT.AS 0:A:OPTIMH D:FRNDINT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OFRNDINT.OBJ $CTMP5.$$$ D:FTOL.AS 0:A:OPTIMH D:FTOL.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OFTOL.OBJ $CTMP5.$$$ D:LTOF.AS 0:A:OPTIMH D:LTOF.AS $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OLTOF.OBJ $CTMP5.$$$ D:FLOAT.AS 0:A:OPTIMH D:FLOAT.AS $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OFLOAT.OBJ $CTMP5.$$$ ERA $CTMP1.$$$ ERA $CTMP2.$$$ ERA $CTMP3.$$$ ERA $CTMP5.$$$ ERA $$EXEC.$$$ 10M>; 10M>era m:lib280f.lib No File 10M>; 10M>LIBR A:LIBR COM (User 0) libr> R m:lib280f.LIB \ libr> LIBFVER.OBJ \ libr> PRINTF.OBJ \ libr> FPRINTF.OBJ \ libr> SPRINTF.OBJ \ libr> SCANF.OBJ \ libr> FSCANF.OBJ \ libr> SSCANF.OBJ \ libr> DOPRNT.OBJ \ libr> DOSCAN.OBJ \ libr> ATOF.OBJ \ libr> FNUM.OBJ \ libr> FBCD.OBJ \ libr> TAN.OBJ \ libr> ACOS.OBJ \ libr> ASIN.OBJ \ libr> ATAN2.OBJ \ libr> ATAN.OBJ \ libr> COS.OBJ \ libr> SIN.OBJ \ libr> SINH.OBJ \ libr> COSH.OBJ \ libr> TANH.OBJ \ libr> EXP.OBJ \ libr> LOG.OBJ \ libr> EVALPOLY.OBJ \ libr> SQRT.OBJ \ libr> FREXP.OBJ \ libr> FABS.OBJ \ libr> CEIL.OBJ \ libr> FLOOR.OBJ \ libr> FINC.OBJ \ libr> ASFLOAT.OBJ \ libr> FRNDINT.OBJ \ libr> FTOL.OBJ \ libr> LTOF.OBJ \ libr> FLOAT.OBJ 10M>; 10M>pip d:=m:lib280f.lib A:PIP COM (User 0) 10M>; 10M>dir m:*.obj[fu,length=65535] A:DIR COM (User 0) Scanning Directory... Sorting Directory... Directory For Drive M: User 10 Name Bytes Recs Attributes Prot Update Create ------------ ------ ------ ------------ ------ -------------- -------------- ACOS OBJ 4k 3 Dir RW None 01/09/25 13:32 01/09/25 13:32 ASFLOAT OBJ 4k 3 Dir RW None 01/09/25 13:35 01/09/25 13:35 ASIN OBJ 4k 8 Dir RW None 01/09/25 13:32 01/09/25 13:32 ATAN OBJ 4k 8 Dir RW None 01/09/25 13:33 01/09/25 13:33 ATAN2 OBJ 4k 8 Dir RW None 01/09/25 13:33 01/09/25 13:33 ATOF OBJ 4k 10 Dir RW None 01/09/25 13:31 01/09/25 13:31 CEIL OBJ 4k 3 Dir RW None 01/09/25 13:35 01/09/25 13:35 COS OBJ 4k 5 Dir RW None 01/09/25 13:33 01/09/25 13:33 COSH OBJ 4k 3 Dir RW None 01/09/25 13:34 01/09/25 13:34 DOPRNT OBJ 4k 20 Dir RW None 01/09/25 13:30 01/09/25 13:30 DOSCAN OBJ 4k 31 Dir RW None 01/09/25 13:31 01/09/25 13:31 EVALPOLY OBJ 4k 3 Dir RW None 01/09/25 13:34 01/09/25 13:34 EXP OBJ 4k 13 Dir RW None 01/09/25 13:34 01/09/25 13:34 FABS OBJ 4k 3 Dir RW None 01/09/25 13:35 01/09/25 13:35 FBCD OBJ 4k 6 Dir RW None 01/09/25 13:32 01/09/25 13:32 FINC OBJ 4k 2 Dir RW None 01/09/25 13:35 01/09/25 13:35 FLOAT OBJ 4k 9 Dir RW None 01/09/25 13:36 01/09/25 13:36 FLOOR OBJ 4k 3 Dir RW None 01/09/25 13:35 01/09/25 13:35 FNUM OBJ 4k 29 Dir RW None 01/09/25 13:32 01/09/25 13:32 FPRINTF OBJ 4k 2 Dir RW None 01/09/25 13:29 01/09/25 13:29 FREXP OBJ 4k 2 Dir RW None 01/09/25 13:35 01/09/25 13:35 FRNDINT OBJ 4k 1 Dir RW None 01/09/25 13:35 01/09/25 13:35 FSCANF OBJ 4k 2 Dir RW None 01/09/25 13:29 01/09/25 13:29 FTOL OBJ 4k 2 Dir RW None 01/09/25 13:35 01/09/25 13:35 LIBFVER OBJ 4k 1 Dir RW None 01/09/25 13:28 01/09/25 13:28 LOG OBJ 4k 7 Dir RW None 01/09/25 13:34 01/09/25 13:34 LTOF OBJ 4k 4 Dir RW None 01/09/25 13:35 01/09/25 13:35 PRINTF OBJ 4k 2 Dir RW None 01/09/25 13:28 01/09/25 13:28 SCANF OBJ 4k 2 Dir RW None 01/09/25 13:29 01/09/25 13:29 SIN OBJ 4k 10 Dir RW None 01/09/25 13:33 01/09/25 13:33 SINH OBJ 4k 3 Dir RW None 01/09/25 13:33 01/09/25 13:33 SPRINTF OBJ 4k 3 Dir RW None 01/09/25 13:29 01/09/25 13:29 SQRT OBJ 4k 9 Dir RW None 01/09/25 13:35 01/09/25 13:35 SSCANF OBJ 4k 2 Dir RW None 01/09/25 13:29 01/09/25 13:29 TAN OBJ 4k 2 Dir RW None 01/09/25 13:32 01/09/25 13:32 TANH OBJ 4k 4 Dir RW None 01/09/25 13:34 01/09/25 13:34 Total Bytes = 144k Total Records = 228 Files Found = 36 Total 1k Blocks = 49 Used/Max Dir Entries For Drive M: 101/ 512 10M>era d:libf2obj.lbr 10M>nulu d:libf2obj.lbr -a m:*.obj -x A:NULU COM (User 0) ^Z NULU 1.52 (07/12/87) Copyright (C) 1984, 1985 & 1987 by Martin Murray Bug fixes in version 1.52 by Mick Waters TYPE -H FOR HELP SYSIN58 .$$$ | STDIO .I | LIB280F .LIB | LIBFVER .OBJ | PRINTF .OBJ FPRINTF .OBJ | SPRINTF .OBJ | SCANF .OBJ | FSCANF .OBJ | SSCANF .OBJ DOPRNT .OBJ | DOSCAN .OBJ | ATOF .OBJ | FNUM .OBJ | FBCD .OBJ TAN .OBJ | ACOS .OBJ | ASIN .OBJ | ATAN2 .OBJ | ATAN .OBJ COS .OBJ | SIN .OBJ | SINH .OBJ | COSH .OBJ | TANH .OBJ EXP .OBJ | LOG .OBJ | EVALPOLY.OBJ | SQRT .OBJ | FREXP .OBJ FABS .OBJ | CEIL .OBJ | FLOOR .OBJ | FINC .OBJ | ASFLOAT .OBJ FRNDINT .OBJ | FTOL .OBJ | LTOF .OBJ | FLOAT .OBJ | LIB280C .LIB Drive M: Total 1520k, Used 268k, Free 1252k Library D10:LIBF2OBJ.LBR^G not found. To make it, enter the number of entries to allow. Press RETURN now to abort making the library. Allow how many entries: 36 Library D10:LIBF2OBJ.LBR open. (Buffer size: 281 sectors) Active entries: 1, Deleted: 0, Free: 39, Total: 40. Adding: M10:LIBFVER .OBJ Adding: M10:PRINTF .OBJ Adding: M10:FPRINTF .OBJ Adding: M10:SPRINTF .OBJ Adding: M10:SCANF .OBJ Adding: M10:FSCANF .OBJ Adding: M10:SSCANF .OBJ Adding: M10:DOPRNT .OBJ Adding: M10:DOSCAN .OBJ Adding: M10:ATOF .OBJ Adding: M10:FNUM .OBJ Adding: M10:FBCD .OBJ Adding: M10:TAN .OBJ Adding: M10:ACOS .OBJ Adding: M10:ASIN .OBJ Adding: M10:ATAN2 .OBJ Adding: M10:ATAN .OBJ Adding: M10:COS .OBJ Adding: M10:SIN .OBJ Adding: M10:SINH .OBJ Adding: M10:COSH .OBJ Adding: M10:TANH .OBJ Adding: M10:EXP .OBJ Adding: M10:LOG .OBJ Adding: M10:EVALPOLY.OBJ Adding: M10:SQRT .OBJ Adding: M10:FREXP .OBJ Adding: M10:FABS .OBJ Adding: M10:CEIL .OBJ Adding: M10:FLOOR .OBJ Adding: M10:FINC .OBJ Adding: M10:ASFLOAT .OBJ Adding: M10:FRNDINT .OBJ Adding: M10:FTOL .OBJ Adding: M10:LTOF .OBJ Adding: M10:FLOAT .OBJ Active entries: 37, Deleted: 0, Free: 3, Total: 40. Closing D10:LIBF2OBJ.LBR... 10M>d: 10D>;---------- done ---------- 10D>put console to console A:PUT COM (User 0) ================================================ FILE: float/M280LIBF.SUB ================================================ era m280libf.log put console output to file m280libf.log [system] date ;---------- M280LIBF.SUB ---------- ; Assumes DEHUFF -X FLOAT.HUF has extracted ; all sources to the default drive ;------------------------------------ m: era m:*.obj float.pak huff: -rm float.huf $(ENHUFF) -a float.huf Makefile $(SRCS) print: print Makefile *.h *.c *.i *.as ================================================ FILE: float/MAKELIBF.LOG ================================================ 10D>date A:DATE COM (User 0) Mon 01/09/2025 12:08:16 10D>;---------- MAKELIBF.SUB ---------- 10D>; Assumes DEHUFF -X FLOAT.HUF has extracted 10D>; all sources to the default drive 10D>;------------------------------------ 10D>m: 10M>era *.obj ERASE *.OBJ (Y/N)? Y No File 10M>; 10M>C A:C COM (User 0) Hi-Tech Z80 C Compiler (CP/M-80) V3.09-19 Copyright (C) 1984-87 HI-TECH SOFTWARE Updated from https://github.com/agn453/HI-TECH-Z80-C c> -O -V -C d:LIBFVER.C \ c> d:PRINTF.C \ c> d:FPRINTF.C \ c> d:SPRINTF.C \ c> d:SCANF.C \ c> d:FSCANF.C \ c> d:SSCANF.C \ c> d:DOPRNT.C \ c> d:DOSCAN.C \ c> d:ATOF.C \ c> d:FNUM.C \ c> d:FBCD.AS \ c> d:TAN.C \ c> d:ACOS.C \ c> d:ASIN.C \ c> d:ATAN2.C \ c> d:ATAN.C \ c> d:COS.C \ c> d:SIN.C \ c> d:SINH.C \ c> d:COSH.C \ c> d:TANH.C \ c> d:EXP.C \ c> d:LOG.C \ c> d:EVALPOLY.C \ c> d:SQRT.C \ c> d:FREXP.AS \ c> d:FABS.C \ c> d:CEIL.C \ c> d:FLOOR.C \ c> d:FINC.AS \ c> d:ASFLOAT.AS \ c> d:FRNDINT.AS \ c> d:FTOL.AS \ c> d:LTOF.AS \ c> d:FLOAT.AS D:LIBFVER.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:LIBFVER.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OLIBFVER.OBJ $CTMP2.$$$ D:PRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:PRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OPRINTF.OBJ $CTMP2.$$$ D:FPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:FPRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OFPRINTF.OBJ $CTMP2.$$$ D:SPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:SPRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OSPRINTF.OBJ $CTMP2.$$$ D:SCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:SCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OSCANF.OBJ $CTMP2.$$$ D:FSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:FSCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OFSCANF.OBJ $CTMP2.$$$ D:SSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:SSCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OSSCANF.OBJ $CTMP2.$$$ D:DOPRNT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:DOPRNT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -ODOPRNT.OBJ $CTMP2.$$$ D:DOSCAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:DOSCAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -ODOSCAN.OBJ $CTMP2.$$$ D:ATOF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:ATOF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OATOF.OBJ $CTMP2.$$$ D:FNUM.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:FNUM.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OFNUM.OBJ $CTMP2.$$$ D:FBCD.AS 0:A:ZAS -J -OFBCD.OBJ D:FBCD.AS D:TAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:TAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OTAN.OBJ $CTMP2.$$$ D:ACOS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:ACOS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OACOS.OBJ $CTMP2.$$$ D:ASIN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:ASIN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OASIN.OBJ $CTMP2.$$$ D:ATAN2.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:ATAN2.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OATAN2.OBJ $CTMP2.$$$ D:ATAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:ATAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OATAN.OBJ $CTMP2.$$$ D:COS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:COS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OCOS.OBJ $CTMP2.$$$ D:SIN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:SIN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OSIN.OBJ $CTMP2.$$$ D:SINH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:SINH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OSINH.OBJ $CTMP2.$$$ D:COSH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:COSH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OCOSH.OBJ $CTMP2.$$$ D:TANH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:TANH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OTANH.OBJ $CTMP2.$$$ D:EXP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:EXP.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OEXP.OBJ $CTMP2.$$$ D:LOG.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:LOG.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OLOG.OBJ $CTMP2.$$$ D:EVALPOLY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:EVALPOLY.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OEVALPOLY.OBJ $CTMP2.$$$ D:SQRT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:SQRT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OSQRT.OBJ $CTMP2.$$$ D:FREXP.AS 0:A:ZAS -J -OFREXP.OBJ D:FREXP.AS D:FABS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:FABS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OFABS.OBJ $CTMP2.$$$ D:CEIL.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:CEIL.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OCEIL.OBJ $CTMP2.$$$ D:FLOOR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: D:FLOOR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:ZAS -J -N -OFLOOR.OBJ $CTMP2.$$$ D:FINC.AS 0:A:ZAS -J -OFINC.OBJ D:FINC.AS D:ASFLOAT.AS 0:A:ZAS -J -OASFLOAT.OBJ D:ASFLOAT.AS D:FRNDINT.AS 0:A:ZAS -J -OFRNDINT.OBJ D:FRNDINT.AS D:FTOL.AS 0:A:ZAS -J -OFTOL.OBJ D:FTOL.AS D:LTOF.AS 0:A:ZAS -J -OLTOF.OBJ D:LTOF.AS D:FLOAT.AS 0:A:ZAS -J -OFLOAT.OBJ D:FLOAT.AS ERA $CTMP1.$$$ ERA $CTMP2.$$$ ERA $CTMP3.$$$ ERA $CTMP5.$$$ ERA $$EXEC.$$$ 10M>; 10M>era m:libf.lib No File 10M>libr A:LIBR COM (User 0) libr> r m:LIBF.LIB \ libr> LIBFVER.OBJ \ libr> PRINTF.OBJ \ libr> FPRINTF.OBJ \ libr> SPRINTF.OBJ \ libr> SCANF.OBJ \ libr> FSCANF.OBJ \ libr> SSCANF.OBJ \ libr> DOPRNT.OBJ \ libr> DOSCAN.OBJ \ libr> ATOF.OBJ \ libr> FNUM.OBJ \ libr> FBCD.OBJ \ libr> TAN.OBJ \ libr> ACOS.OBJ \ libr> ASIN.OBJ \ libr> ATAN2.OBJ \ libr> ATAN.OBJ \ libr> COS.OBJ \ libr> SIN.OBJ \ libr> SINH.OBJ \ libr> COSH.OBJ \ libr> TANH.OBJ \ libr> EXP.OBJ \ libr> LOG.OBJ \ libr> EVALPOLY.OBJ \ libr> SQRT.OBJ \ libr> FREXP.OBJ \ libr> FABS.OBJ \ libr> CEIL.OBJ \ libr> FLOOR.OBJ \ libr> FINC.OBJ \ libr> ASFLOAT.OBJ \ libr> FRNDINT.OBJ \ libr> FTOL.OBJ \ libr> LTOF.OBJ \ libr> FLOAT.OBJ 10M>; 10M>pip d:=m:LIBF.LIB A:PIP COM (User 0) 10M>; 10M>dir m:*.obj[fu,length=65535] A:DIR COM (User 0) Scanning Directory... Sorting Directory... Directory For Drive M: User 10 Name Bytes Recs Attributes Prot Update Create ------------ ------ ------ ------------ ------ -------------- -------------- ACOS OBJ 4k 3 Dir RW None 01/09/25 12:11 01/09/25 12:11 ASFLOAT OBJ 4k 3 Dir RW None 01/09/25 12:14 01/09/25 12:14 ASIN OBJ 4k 9 Dir RW None 01/09/25 12:11 01/09/25 12:11 ATAN OBJ 4k 9 Dir RW None 01/09/25 12:12 01/09/25 12:12 ATAN2 OBJ 4k 9 Dir RW None 01/09/25 12:12 01/09/25 12:12 ATOF OBJ 4k 11 Dir RW None 01/09/25 12:10 01/09/25 12:10 CEIL OBJ 4k 4 Dir RW None 01/09/25 12:14 01/09/25 12:14 COS OBJ 4k 5 Dir RW None 01/09/25 12:12 01/09/25 12:12 COSH OBJ 4k 4 Dir RW None 01/09/25 12:12 01/09/25 12:12 DOPRNT OBJ 4k 21 Dir RW None 01/09/25 12:09 01/09/25 12:09 DOSCAN OBJ 4k 32 Dir RW None 01/09/25 12:10 01/09/25 12:10 EVALPOLY OBJ 4k 3 Dir RW None 01/09/25 12:13 01/09/25 12:13 EXP OBJ 4k 14 Dir RW None 01/09/25 12:13 01/09/25 12:13 FABS OBJ 4k 3 Dir RW None 01/09/25 12:13 01/09/25 12:13 FBCD OBJ 4k 6 Dir RW None 01/09/25 12:11 01/09/25 12:11 FINC OBJ 4k 2 Dir RW None 01/09/25 12:14 01/09/25 12:14 FLOAT OBJ 4k 9 Dir RW None 01/09/25 12:14 01/09/25 12:14 FLOOR OBJ 4k 4 Dir RW None 01/09/25 12:14 01/09/25 12:14 FNUM OBJ 4k 31 Dir RW None 01/09/25 12:11 01/09/25 12:11 FPRINTF OBJ 4k 2 Dir RW None 01/09/25 12:08 01/09/25 12:08 FREXP OBJ 4k 2 Dir RW None 01/09/25 12:13 01/09/25 12:13 FRNDINT OBJ 4k 1 Dir RW None 01/09/25 12:14 01/09/25 12:14 FSCANF OBJ 4k 2 Dir RW None 01/09/25 12:09 01/09/25 12:09 FTOL OBJ 4k 2 Dir RW None 01/09/25 12:14 01/09/25 12:14 LIBFVER OBJ 4k 1 Dir RW None 01/09/25 12:08 01/09/25 12:08 LOG OBJ 4k 8 Dir RW None 01/09/25 12:13 01/09/25 12:13 LTOF OBJ 4k 4 Dir RW None 01/09/25 12:14 01/09/25 12:14 PRINTF OBJ 4k 2 Dir RW None 01/09/25 12:08 01/09/25 12:08 SCANF OBJ 4k 2 Dir RW None 01/09/25 12:08 01/09/25 12:08 SIN OBJ 4k 10 Dir RW None 01/09/25 12:12 01/09/25 12:12 SINH OBJ 4k 4 Dir RW None 01/09/25 12:12 01/09/25 12:12 SPRINTF OBJ 4k 3 Dir RW None 01/09/25 12:08 01/09/25 12:08 SQRT OBJ 4k 10 Dir RW None 01/09/25 12:13 01/09/25 12:13 SSCANF OBJ 4k 3 Dir RW None 01/09/25 12:09 01/09/25 12:09 TAN OBJ 4k 2 Dir RW None 01/09/25 12:11 01/09/25 12:11 TANH OBJ 4k 4 Dir RW None 01/09/25 12:13 01/09/25 12:13 Total Bytes = 144k Total Records = 244 Files Found = 36 Total 1k Blocks = 52 Used/Max Dir Entries For Drive M: 52/ 512 10M>era d:libf-obj.lbr 10M>nulu d:libf-obj.lbr -a m:*.obj -x A:NULU COM (User 0) ^Z NULU 1.52 (07/12/87) Copyright (C) 1984, 1985 & 1987 by Martin Murray Bug fixes in version 1.52 by Mick Waters TYPE -H FOR HELP SYSIN58 .$$$ | LIBF .LIB | LIBFVER .OBJ | PRINTF .OBJ | FPRINTF .OBJ SPRINTF .OBJ | SCANF .OBJ | FSCANF .OBJ | SSCANF .OBJ | DOPRNT .OBJ DOSCAN .OBJ | ATOF .OBJ | FNUM .OBJ | FBCD .OBJ | TAN .OBJ ACOS .OBJ | ASIN .OBJ | ATAN2 .OBJ | ATAN .OBJ | COS .OBJ SIN .OBJ | SINH .OBJ | COSH .OBJ | TANH .OBJ | EXP .OBJ LOG .OBJ | EVALPOLY.OBJ | SQRT .OBJ | FREXP .OBJ | FABS .OBJ CEIL .OBJ | FLOOR .OBJ | FINC .OBJ | ASFLOAT .OBJ | FRNDINT .OBJ FTOL .OBJ | LTOF .OBJ | FLOAT .OBJ | Drive M: Total 1520k, Used 180k, Free 1340k Library D10:LIBF-OBJ.LBR^G not found. To make it, enter the number of entries to allow. Press RETURN now to abort making the library. Allow how many entries: 36 Library D10:LIBF-OBJ.LBR open. (Buffer size: 281 sectors) Active entries: 1, Deleted: 0, Free: 39, Total: 40. Adding: M10:LIBFVER .OBJ Adding: M10:PRINTF .OBJ Adding: M10:FPRINTF .OBJ Adding: M10:SPRINTF .OBJ Adding: M10:SCANF .OBJ Adding: M10:FSCANF .OBJ Adding: M10:SSCANF .OBJ Adding: M10:DOPRNT .OBJ Adding: M10:DOSCAN .OBJ Adding: M10:ATOF .OBJ Adding: M10:FNUM .OBJ Adding: M10:FBCD .OBJ Adding: M10:TAN .OBJ Adding: M10:ACOS .OBJ Adding: M10:ASIN .OBJ Adding: M10:ATAN2 .OBJ Adding: M10:ATAN .OBJ Adding: M10:COS .OBJ Adding: M10:SIN .OBJ Adding: M10:SINH .OBJ Adding: M10:COSH .OBJ Adding: M10:TANH .OBJ Adding: M10:EXP .OBJ Adding: M10:LOG .OBJ Adding: M10:EVALPOLY.OBJ Adding: M10:SQRT .OBJ Adding: M10:FREXP .OBJ Adding: M10:FABS .OBJ Adding: M10:CEIL .OBJ Adding: M10:FLOOR .OBJ Adding: M10:FINC .OBJ Adding: M10:ASFLOAT .OBJ Adding: M10:FRNDINT .OBJ Adding: M10:FTOL .OBJ Adding: M10:LTOF .OBJ Adding: M10:FLOAT .OBJ Active entries: 37, Deleted: 0, Free: 3, Total: 40. Closing D10:LIBF-OBJ.LBR... 10M>d: 10D>;---------- done ---------- 10D>put console to console A:PUT COM (User 0) ================================================ FILE: float/MAKELIBF.SUB ================================================ era makelibf.log put console output to file makelibf.log [system] date ;---------- MAKELIBF.SUB ---------- ; Assumes DEHUFF -X FLOAT.HUF has extracted ; all sources to the default drive ;------------------------------------ m: era *.obj extern int _doprnt(); printf(f, a) char * f; int a; { return(_doprnt(stdout, f, &a)); } ================================================ FILE: float/SCANF.C ================================================ /* * Stdio scanf */ #include extern int _doscan(); scanf(fmt, args) char * fmt; int args; { return _doscan(stdin, fmt, &args); } ================================================ FILE: float/SIN.C ================================================ #include #define PI 3.14159265358979 #define TWO_PI 6.28318530717958 #define HALF_PI 1.570796326794895 double sin(f) double f; { /* const */ static double coeff_a[] = { 207823.68416961012, -76586.415638846949, 7064.1360814006881, -237.85932457812158, 2.8078274176220686 }; /* const */ static double coeff_b[] = { 132304.66650864931, 5651.6867953169177, 108.99981103712905, 1.0 }; double x2; int sgn; extern double eval_poly(); sgn = 0; if(f < 0.0) { f = -f; sgn = 1; } f *= 1.0/TWO_PI; f = 4.0 * (f - floor(f)); if(f > 2.0) { f -= 2.0; sgn = !sgn; } if( f > 1.0) f = 2.0 - f; x2 = f * f; f *= eval_poly(x2, coeff_a, 4) / eval_poly(x2, coeff_b, 3); if(sgn) return -f; return f; } ================================================ FILE: float/SINH.C ================================================ #include double sinh(x) double x; { x = exp(x); return 0.5*(x-1.0/x); } ================================================ FILE: float/SPRINTF.C ================================================ #include static FILE spf; sprintf(wh, f, a) char * wh; char * f; int a; { spf._size = 32767; spf._cnt = 0; spf._base = spf._ptr = wh; spf._flag = _IOWRT|_IOBINARY|_IOSTRG; _doprnt(&spf, f, &a); *spf._ptr = 0; return spf._ptr - wh; } ================================================ FILE: float/SQRT.C ================================================ #include double sqrt(x) double x; { double og, ng; short niter; int exp; if(x <= 0.0) return 0.0; og = x; if(og < 1.0) og = 1.0/og; og = frexp(og, &exp); og = ldexp(og, exp/2); /* make an educated guess */ if(x < 1.0) og = 1.0/og; for(niter = 0 ; niter < 20 ; niter++) { ng = (x/og + og)/2.0; if(ng == og) break; og = ng; } return og; } ================================================ FILE: float/SSCANF.C ================================================ /* * Stdio sscanf */ #include #include extern int _doscan(); sscanf(str, fmt, args) char * str; char * fmt; int args; { FILE file; file._base = file._ptr = str; file._size = file._cnt = strlen(str); file._flag = _IOSTRG|_IOBINARY|_IOREAD; return _doscan(&file, fmt, &args); } ================================================ FILE: float/TAN.C ================================================ #include double tan(x) double x; { return sin(x)/cos(x); } ================================================ FILE: float/TANH.C ================================================ #include double tanh(x) double x; { x = exp(x); return (x-1.0/x)/(x+1.0/x); } ================================================ FILE: gen/ABS.AS ================================================ ; abs(i) returns the absolute value of i global _abs psect text _abs: pop de ;Return address pop hl push hl push de bit 7,h ;Negative? ret z ;no, leave alone ex de,hl ld hl,0 or a ;Clear carry sbc hl,de ret ================================================ FILE: gen/ALLSH.AS ================================================ ; arithmetic long left shift ; value in HLDE, count in B global allsh, lllsh psect text allsh: lllsh: ld a,b ;check for zero shift or a ret z cp 33 jr c,1f ;limit shift to 32 bits ld b,32 1: ex de,hl add hl,hl ex de,hl adc hl,hl djnz 1b ret ================================================ FILE: gen/ALRSH.AS ================================================ ; arithmetic long right shift ; value in HLDE, count in B global alrsh psect text alrsh: ld a,b ;check for zero shift or a ret z cp 33 jr c,1f ;limit shift to 32 bits ld b,32 1: sra h rr l rr d rr e djnz 1b ret ================================================ FILE: gen/ASALLSH.AS ================================================ ; ASsign Arithmetic Long Left SHift ; ASsign Logical Long Left SHift psect text global asallsh, aslllsh, allsh, iregstore asallsh: aslllsh: push bc ;save the count ld e,(hl) inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) ex (sp),hl ;save pointer, restore count push bc ;hi word ex (sp),hl pop bc call allsh ;do the shift jp iregstore ;go store the value and return ================================================ FILE: gen/ASALRSH.AS ================================================ ; ASsign Arithmetic Long Right SHift psect text global asalrsh, alrsh, iregstore asalrsh: push bc ;save the count ld e,(hl) inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) ex (sp),hl ;save pointer, restore count push bc ;hi word ex (sp),hl pop bc call alrsh ;do the shift jp iregstore ;go store the value and return ================================================ FILE: gen/ASAR.AS ================================================ ; Shift operations - the count is always in B, ; the quantity to be shifted is in HL, except for the assignment ; type operations, when it is in the memory location pointed to by ; HL global asar ;assign shift arithmetic right psect text global shar asar: ld e,(hl) inc hl ld d,(hl) push hl ;save for the store ex de,hl call shar ex de,hl pop hl ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret ================================================ FILE: gen/ASDIV.AS ================================================ ; Assign versions of divide global asadiv, asldiv, adiv, ldiv psect text asadiv: ld c,(hl) inc hl ld b,(hl) push bc ex (sp),hl call adiv ex (sp),hl pop de ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret asldiv: ld c,(hl) inc hl ld b,(hl) push bc ex (sp),hl call ldiv ex (sp),hl pop de ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret ================================================ FILE: gen/ASLADD.AS ================================================ psect text global iregset, iregstore, asaladd, aslladd, aladd asaladd: aslladd: call iregset call aladd jp iregstore ================================================ FILE: gen/ASLAND.AS ================================================ psect text global iregset, iregstore, asaland, aslland, aland asaland: aslland: call iregset call aland jp iregstore ================================================ FILE: gen/ASLL.AS ================================================ ; Shift operations - the count is always in B, ; the quantity to be shifted is in HL, except for the assignment ; type operations, when it is in the memory location pointed to by ; HL global asll,asal ;assign shift left (logical or arithmetic) psect text global shal asll: asal: ld e,(hl) inc hl ld d,(hl) push hl ;save for the store ex de,hl call shal ex de,hl pop hl ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret ================================================ FILE: gen/ASLLRSH.AS ================================================ ; ASsign Logical Long Right SHift psect text global asllrsh, llrsh, iregstore asllrsh: push bc ;save the count ld e,(hl) inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) ex (sp),hl ;save pointer, restore count push bc ;hi word ex (sp),hl pop bc call llrsh ;do the shift jp iregstore ;go store the value and return ================================================ FILE: gen/ASLMUL.AS ================================================ psect text global iregset, iregstore, asalmul, asllmul, almul asalmul: asllmul: call iregset call almul jp iregstore ================================================ FILE: gen/ASLOR.AS ================================================ psect text global iregset, iregstore, asalor, asllor, alor asalor: asllor: call iregset call alor jp iregstore ================================================ FILE: gen/ASLR.AS ================================================ ; Shift operations - the count is always in B, ; the quantity to be shifted is in HL, except for the assignment ; type operations, when it is in the memory location pointed to by ; HL global aslr ;assign shift logical right psect text global shlr aslr: ld e,(hl) inc hl ld d,(hl) push hl ;save for the store ex de,hl call shlr ex de,hl pop hl ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret ================================================ FILE: gen/ASLSUB.AS ================================================ psect text global iregset, iregstore, asalsub, asllsub, alsub asalsub: asllsub: call iregset call alsub jp iregstore ================================================ FILE: gen/ASLXOR.AS ================================================ psect text global iregset, iregstore, asalxor, asllxor, alxor asalxor: asllxor: call iregset call alxor jp iregstore ================================================ FILE: gen/ASMOD.AS ================================================ ; Assign versions of modulus global asamod, aslmod, amod, lmod psect text asamod: ld c,(hl) inc hl ld b,(hl) push bc ex (sp),hl call amod ex (sp),hl pop de ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret aslmod: ld c,(hl) inc hl ld b,(hl) push bc ex (sp),hl call lmod ex (sp),hl pop de ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret ================================================ FILE: gen/ASMUL.AS ================================================ ; Assign versions of multiply global asamul, aslmul, amul psect text asamul: aslmul: ld c,(hl) inc hl ld b,(hl) push bc ex (sp),hl call amul ex (sp),hl pop de ld (hl),d dec hl ld (hl),e ex de,hl ;return value in hl ret ================================================ FILE: gen/ATOI.AS ================================================ psect text digit: sub '0' ret c cp 10 ccf ret global _atoi _atoi: pop bc ;return address pop de push de push bc ld hl,0 1: ld a,(de) inc de cp ' ' jr z,1b cp ' ' ;tab jr z,1b dec de ;point to 1st non blank char cp '-' jr z,3f cp '+' jr nz,2f or a ;reset zero flag 3: inc de 2: ex af,af' 1: ld a,(de) inc de call digit jr c,3f add hl,hl ld c,l ld b,h add hl,hl add hl,hl add hl,bc ld c,a ld b,0 add hl,bc jr 1b 3: ex af,af' ret nz ex de,hl ld hl,0 sbc hl,de ret ================================================ FILE: gen/ATOL.C ================================================ #include long atol(s) register char * s; { long a; unsigned char sign; while(*s == ' ' || *s == '\t') s++; a = 0; sign = 0; if(*s == '-') { sign++; s++; } else if(*s == '+') s++; while(isdigit(*s)) a = a*10L + (*s++ - '0'); if(sign) return -a; return a; } ================================================ FILE: gen/BITFIELD.AS ================================================ ; Functions to implement bitfields: ; the width and offset (in bits) of the bitfield concerned ; appear in the code immediately after the call, packed into one byte ; like this: ; bit |7 4|3 0| ; |offset|width| ; bfext: called with a value in HL, returns with extracted ; bitfield value in HL psect text global bfext, bfins bfext: pop bc ;get return address ld a,(bc) ;pick up width and offset inc bc push bc push af rra rra rra rra and 0Fh ;get offset jr z,1f ;skip if zero ld b,a 2: srl h rr l djnz 2b 1: pop af push de ;don't touch de ld de,1 ;start with a 1 and 0Fh ;get width ld b,a ;put in counter 2: sll e rl d ;shift up one bit djnz 2b dec de ;decrement by one ld a,l and e ;mask appropriately ld l,a ld a,h and d ld h,a ;all done! pop de ret ; Insert the data in de into the data at (hl). Size and offset ; are in the following byte as usual bfins: pop bc ;get return address ld a,(bc) ;get info byte inc bc push bc push hl ;save address push af ;save for ron ld hl,1 and 0Fh ld b,a 2: sll l rl h ;shift up one bit djnz 2b dec hl ;convert to a mask ld a,e and l ld e,a ld a,d and h ld d,a ;masked it pop af ;get byte again push de ;save value rra rra rra rra and 0Fh ;mask out offset jr z,1f ;skip if zero ld b,a 2: sll l ;shift it up rl h sll e rl d djnz 2b ;loop for more 1: ex (sp),hl ;save mask, get value pop bc ;mask in bc ex (sp),hl ;address in hl, save value ld a,c ;complement mask cpl and (hl) ;and with memory data or e ;or with shifted value ld (hl),a ;put back inc hl ld a,b cpl and (hl) or d ld (hl),a pop hl ;get value back ret ;finito! ================================================ FILE: gen/BLKCLR.AS ================================================ ; blkclr(ptr, size) ; char * ptr; unsigned short size; ; Fills memory with size null bytes psect text global _blkclr _blkclr: pop de ;return address pop hl ;pointer pop bc ;count push bc ;adjust stack push hl push de ld e,0 1: ld a,c ;check for finished or b ret z ld (hl),e inc hl dec bc jr 1b ================================================ FILE: gen/BLKCPY.C ================================================ blkcpy(dp, sp, n) register char *dp, *sp; register unsigned n; { while (n--) *dp++ = *sp++; } ================================================ FILE: gen/BMOVE.AS ================================================ ; bmove(from, to, count) global _bmove, _movmem psect text _movmem: _bmove: pop hl ;return address exx pop hl ;from pop de ;to pop bc ;count ld a,b or c jr z,1f ldir 1: push bc ;stack is as it was push de push hl exx jp (hl) ================================================ FILE: gen/BRELOP.AS ================================================ ; byte relational operation - returns flags correctly for ; comparision of words in a and b psect text global brelop brelop: push de ld e,a xor b ;compare signs jp m,1f ;if different, return sign of lhs ld a,e sbc a,b pop de ret 1: ld a,e ;get sign of lhs and 80h ;mask out sign flag ld d,a ld a,e sbc a,b ;set carry flag if appropriate ld a,d inc a ;set sign flag as appropriate and reset Z flag pop de ret ================================================ FILE: gen/BUILDGEN.SUB ================================================ c <-o -c \ = '0' && c <= '9'); } ================================================ FILE: gen/CTYPE_.C ================================================ #include unsigned char _ctype_[] = { 0, _C, _C, _C, _C, _C, _C, _C, _C, _C, _S, _S, _S, _S, _S, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _S, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _N, _N, _N, _N, _N, _N, _N, _N, _N, _N, _P, _P, _P, _P, _P, _P, _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _P, _P, _P, _P, _P, _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _P, _P, _P, _P, _C }; ================================================ FILE: gen/FRELOP.AS ================================================ ; floating relational operation - returns flags as though ; a floating subtract was done. psect text global frelop frelop: exx ;select alternate reg set pop hl ;return address exx ;get other set again pop bc ;low word of 2nd arg ex de,hl ;put hi word of 1st in de ex (sp),hl ;get hi word of 2nd in hl ex de,hl ;hi word of 1st back in hl ld a,h ;test for differing signs xor d jp p,2f ;the same, so ok ld a,h ;get the sign of the LHS or 1 ;ensure zero flag is reset, set sign flag pop bc ;unjunk stack jr 1f ;return with sign of LHS 2: ld a,d ;preserve sign flag res 7,d ;clear sign flag res 7,h ;and the other and 80h ;mask out sign flag sbc hl,de ;set the flags pop hl ;low word of 1st into hl again jr nz,togs ;go fixup sign flag if different sbc hl,bc ;now set flags on basis of low word jr z,1f ;if zero, all ok togs: rr h ;rotate carry into sign xor h ;toggle sign if necessary or 1 ;reset zero flag 1: exx ;get return address jp (hl) ;and return with stack clean ================================================ FILE: gen/GETSP.AS ================================================ ; Return value of the stack pointer psect text global __getsp __getsp: ld hl,0 add hl,sp ret ================================================ FILE: gen/IDIV.AS ================================================ ; 16 bit divide and modulus routines ; called with dividend in hl and divisor in de ; returns with result in hl. ; adiv (amod) is signed divide (modulus), ldiv (lmod) is unsigned global adiv,ldiv,amod,lmod psect text amod: call adiv ex de,hl ;put modulus in hl ret lmod: call ldiv ex de,hl ret ldiv: xor a push af ex de,hl jr dv1 adiv: ld a,h xor d ;set sign flag for quotient ld a,h ;get sign of dividend push af call negif ex de,hl call negif dv1: ld b,1 ld a,h or l jr nz,dv8 pop af ret dv8: push hl add hl,hl jr c,dv2 ld a,d cp h jr c,dv2 jp nz,dv6 ld a,e cp l jr c,dv2 dv6: pop af inc b jp dv8 dv2: pop hl ex de,hl push hl ld hl,0 ex (sp),hl dv4: ld a,h cp d jr c,dv3 jp nz,dv5 ld a,l cp e jr c,dv3 dv5: sbc hl,de dv3: ex (sp),hl ccf adc hl,hl srl d rr e ex (sp),hl djnz dv4 pop de ex de,hl pop af call m,negat ex de,hl or a ;test remainder sign bit call m,negat ex de,hl ret negif: bit 7,h ret z negat: ld b,h ld c,l ld hl,0 or a sbc hl,bc ret ================================================ FILE: gen/IMUL.AS ================================================ ; 16 bit integer multiply ; on entry, left operand is in hl, right operand in de psect text global amul,lmul amul: lmul: ld a,e ld c,d ex de,hl ld hl,0 ld b,8 call mult8b ex de,hl jr 3f 2: add hl,hl 3: djnz 2b ex de,hl 1: ld a,c mult8b: srl a jp nc,1f add hl,de 1: ex de,hl add hl,hl ex de,hl ret z djnz mult8b ret ================================================ FILE: gen/INDEX.AS ================================================ psect text global rcsv, cret, _index _index: call rcsv jr 3f 1: inc hl 3: ld a,(hl) or a jr z,2f cp e jr nz,1b 4: jp cret 2: ld hl,0 jp 4b ================================================ FILE: gen/INOUT.AS ================================================ global _in, _out, _inp, _outp psect text _in: _inp: pop hl ;return address pop bc ;port address push bc push hl in l,(c) ;read port ld h,0 ;zero extend it ret _out: _outp: pop hl ;return address pop bc ;port address pop de ;data push de push bc push hl out (c),e ;output the data ld l,c ;return value in hl also ld h,0 ret ================================================ FILE: gen/IREGSET.AS ================================================ ; routines to support the assignment versions of the long operations psect text global iregset, iregstore iregset: ld e,(hl) ;pick up arg inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) ex (sp),hl ;save pointer, get return address push bc ;now put the hi word into hl ex (sp),hl ;saving return address on stack again pop bc ;now return address in bc exx pop hl ;the pointer pop bc ;the final return address pop de ;now the low word of arg2 ex (sp),hl ;get the hi word, save pointer push bc ;this is the return address again ex (sp),hl ;into hl again pop bc ;hi word now in bc ex (sp),hl ;AHA! got return address on stack, ptr in hl push hl ;now its easy, save pointer push bc ;hi word push de ;low word exx push bc ;immediate return address ret ;finito iregstore: ex (sp),hl ;get pointer into hl pop bc ;hi word in bc ld (hl),b dec hl ld (hl),c dec hl ld (hl),d dec hl ld (hl),e ;all done push bc ;restore to hl pop hl ret ;and return with value in hl ================================================ FILE: gen/ISALPHA.AS ================================================ global _isalpha psect text _isalpha: pop de ;return address pop hl push hl push de ld a,h ;check for a char or a jr nz,nix ld a,l cp 'A' jr c,nix cp 'z'+1 jr nc,nix cp 'a' cp 'Z'+1 jr c,yes cp 'a' jr c,nix yes: ld hl,1 ;yes ret nix: ld hl,0 ret ================================================ FILE: gen/ISDIGIT.AS ================================================ global _isdigit, _isdig psect text _isdigit: _isdig: pop de ;return address pop hl push hl push de ld a,h ;check for a char or a jr nz,nix ld a,l cp '0' jr c,nix cp '9'+1 jr nc,nix ld hl,1 ;yes ret nix: ld hl,0 ret ================================================ FILE: gen/ISLOWER.AS ================================================ global _islower psect text _islower: pop de ;return address pop hl push hl push de ld a,h ;check for a char or a jr nz,nix ld a,l cp 'a' jr c,nix cp 'z'+1 jr nc,nix ld hl,1 ;yes ret nix: ld hl,0 ret ================================================ FILE: gen/ISSPACE.AS ================================================ global _isspace psect text _isspace: pop de ;return address pop hl push hl push de ld a,h ;check for a char or a jr nz,nix ld a,l cp ' ' jr z,yes cp 12 ;newline jr z,yes cp 9 ;tab jr nz,nix yes: ld hl,1 ;yes ret nix: ld hl,0 ret ================================================ FILE: gen/ISUPPER.AS ================================================ global _isupper psect text _isupper: pop de ;return address pop hl push hl push de ld a,h ;check for a char or a jr nz,nix ld a,l cp 'A' jr c,nix cp 'Z'+1 jr nc,nix ld hl,1 ;yes ret nix: ld hl,0 ret ================================================ FILE: gen/LADD.AS ================================================ psect text global aladd, lladd aladd: lladd: exx pop hl exx pop bc ex de,hl add hl,bc ex de,hl pop bc adc hl,bc exx push hl exx ret ================================================ FILE: gen/LAND.AS ================================================ psect text global aland, lland aland: lland: exx pop hl exx pop bc ld a,c and e ld e,a ld a,b and d ld d,a pop bc ld a,c and l ld l,a ld a,b and h ld h,a exx push hl exx ret ================================================ FILE: gen/LDIV.AS ================================================ ; Long division routines for Z80 global lldiv,aldiv,almod,llmod,aslldiv,asaldiv,asllmod,asalmod psect text ; Called with dividend in HLDE, divisor on stack under 2 return ; addresses. Returns with dividend in HL/HL', divisor in DE/DE' ; on return the HIGH words are selected. lregset: pop bc ;get top return address exx ;select other bank pop bc ;return address of call to this module pop de ;get low word of divisor exx ;select hi bank ex de,hl ;dividend.low -> hl ex (sp),hl ;divisor.high -> hl ex de,hl ;dividend.high -> hl exx ;back to low bank push bc ;put outer r.a. back on stack pop hl ;return address ex (sp),hl ;dividend.low -> hl exx push bc ;top return address ret ; Much the same as lregset, except that on entry the dividend ; is pointed to by HL. ; The pointer is saved in iy for subsequent updating of memory iregset: pop de ;immediate return address call lregset ;returns with hi words selected push hl ;save a copy for 'ron ex (sp),iy ;get it in iy, saving old iy ld h,(iy+3) ;high order byte ld l,(iy+2) ;byte 2 exx ;back to low bank push hl ;return address ld h,(iy+1) ;byte 1 ld l,(iy+0) ;and LSB exx ;restore hi words ret ;now return ; Called with hi words selected, performs division on the absolute ; values of the dividend and divisor. Quotient is positive sgndiv: call negif ;make dividend positive exx ex de,hl ;put divisor in HL/HL' exx ex de,hl call negif ;make divisor positive ex de,hl ;restore divisor to DE/DE' exx ex de,hl exx ;select high words again jp divide ;do division asaldiv: call iregset call dosdiv store: ld (iy+0),e ld (iy+1),d ld (iy+2),l ld (iy+3),h pop iy ;restore old iy ret aldiv: call lregset ;get args ; Called with high words selected, performs signed division by ; the rule that the quotient is negative iff the signs of the dividend ; and divisor differ ; returns quotient in HL/DE dosdiv: ld a,h xor d ex af,af' ;sign bit is now sign of quotient call sgndiv ;do signed division ex af,af' ;get sign flag back push bc ;high word exx pop hl ld e,c ;low word of quotient ld d,b jp m,negat ;negate quotient if necessary ret lldiv: call lregset ; Called with high words selected, performs unsigned division ; returns with quotient in HL/DE doudiv: call divide ;unsigned division push bc ;high word of quotien exx pop hl ld e,c ;low word ld d,b ret aslldiv: call iregset call doudiv jp store almod: call lregset ; Called with high words selected, performs signed modulus - the rule ; is that the sign of the remainder is the sign of the dividend dosrem: ld a,h ;get sign of dividend ex af,af' ;save it call sgndiv ;do signed division push hl ;high word exx pop de ex de,hl ;put high word in hl ex af,af' ;get sign bit back or a jp m,negat ;negate if necessary ret asalmod: call iregset call dosrem jp store llmod: call lregset ; Called with high words selected, perform unsigned modulus dourem: call divide push hl ;high word of remainder exx pop de ex de,hl ;high word in hl ret asllmod: call iregset call dourem jp store ; Negate the long in HL/DE negat: push hl ;save high word ld hl,0 or a sbc hl,de ex de,hl pop bc ;get high word back ld hl,0 sbc hl,bc ret ;finito negif: ;called with high word in HL, low word in HL' ;returns with positive value bit 7,h ;check sign ret z ;already positive exx ;select low word ld c,l ld b,h ld hl,0 or a sbc hl,bc exx ld c,l ld b,h ld hl,0 sbc hl,bc ret ;finito ; Called with dividend in HL/HL', divisor in DE/DE', high words in ; selected register set ; returns with quotient in BC/BC', remainder in HL/HL', high words ; selected divide: ld bc,0 ;initialize quotient ld a,e ;check for zero divisor or d exx ld bc,0 or e or d exx ;restor high words ret z ;return with quotient == 0 ld a,1 ;loop count jp 3f ;enter loop in middle 1: push hl ;save divisor exx push hl ;low word or a ;clear carry sbc hl,de ;subtract low word exx sbc hl,de ;sbutract hi word exx pop hl ;restore dividend exx pop hl ;and hi word jr c,2f ;finished - divisor is big enough exx inc a ;increment count ex de,hl ;put divisor in hl - still low word add hl,hl ;shift left ex de,hl ;put back in de exx ;get hi word ex de,hl adc hl,hl ;shift with carry ex de,hl 3: bit 7,d ;test for max divisor jp z,1b ;loop if msb not set 2: ;arrive here with shifted divisor, loop count in a, and low words ;selected 3: push hl ;save dividend exx push hl ;low word or a ;clear carry sbc hl,de exx sbc hl,de exx ;restore low word jp nc,4f pop hl ;restore low word of dividend exx pop hl ;hi word exx ;restore low word jr 5f 4: inc sp ;unjunk stack inc sp inc sp inc sp 5: ccf ;complement carry bit rl c ;shift in carry bit rl b ;next byte exx ;hi word rl c rl b srl d ;now shift divisor right rr e exx ;get low word back rr d rr e exx ;select hi word again dec a ;decrement loop count jr nz,3b ret ;finished ================================================ FILE: gen/LIBCVER.C ================================================ #define VERSION "3.09-18" char *_libcver = #ifdef Z280 "LIB280C " VERSION; #else "LIBC " VERSION; #endif ================================================ FILE: gen/LINC.AS ================================================ ; Long increment psect text global lainc, llinc, ladec, lldec gval: exx pop hl ;return address exx ld e,(hl) inc hl ld d,(hl) inc hl ld c,(hl) inc hl ld b,(hl) push de ;lo word push bc ;hi word push bc ex (sp),hl exx push hl ;return address exx ret lainc: llinc: call gval ld bc,1 ex de,hl add hl,bc ex de,hl ld c,0 adc hl,bc sval: ex (sp),hl pop bc ld (hl),b dec hl ld (hl),c dec hl ld (hl),d dec hl ld (hl),e pop hl ;restore original value pop de ret lldec: ladec: call gval ld bc,-1 ex de,hl add hl,bc ex de,hl adc hl,bc jr sval ================================================ FILE: gen/LLRSH.AS ================================================ ; logical long right shift ; value in HLDE, count in B global llrsh psect text llrsh: ld a,b ;check for zero shift or a ret z cp 33 jr c,1f ;limit shift to 32 bits ld b,32 1: srl h rr l rr d rr e djnz 1b ret ================================================ FILE: gen/LMUL.AS ================================================ ; Long multiplication for Z80 ; Called with 1st arg in HLDE, 2nd arg on stack. Returns with ; result in HLDE, other argument removed from stack global almul, llmul psect text almul: llmul: ex de,hl ex (sp),hl ;return address now in hl exx pop de ;low word in de pop bc ;low word of multiplier in bc exx pop bc ;hi word of multiplier push hl ;restore return address ld hl,0 ;initialize product exx ;get lo words back ld hl,0 ld a,c ld c,b call mult8b ld a,c call mult8b exx ld a,c exx call mult8b exx ld a,b exx call mult8b push hl ;low word exx pop de ret mult8b: ld b,8 3: srl a jp nc,1f add hl,de exx adc hl,de exx 1: ex de,hl add hl,hl ex de,hl exx ex de,hl adc hl,hl ex de,hl exx djnz 3b ret ================================================ FILE: gen/LONGJMP.AS ================================================ ; setjump, longjump - non local goto psect text global _longjmp, _setjmp _setjmp: pop bc ;return address ex (sp),iy ;jmp_buf ptr to IY pop de ;old IY to DE push de ;keep stack balanced for return ld hl,0 add hl,sp ld (iy+0),l ;save SP in jmp_buf ld (iy+1),h push ix pop hl ld (iy+2),l ;save IX (frame ptr) in jmp_buf ld (iy+3),h ld (iy+4),c ;return address to jmp_buf ld (iy+5),b ld (iy+6),e ;save IY in jmp_buf ld (iy+7),d ld hl,0 ;setjmp returns 0 push de ;restore IY pop iy push bc ;return address -> BC ret _longjmp: pop bc ; return address - junk now pop iy ;jmp_buf ptr to IY pop de ; return val in de as stack will change ld l,(iy+0) ;restore SP from jmp_buf ld h,(iy+1) ld sp,hl ld l,(iy+2) ;restore IX (frame ptr) from jmp_buf ld h,(iy+3) push hl pop ix ld l,(iy+4) ;return address ld h,(iy+5) push hl ld c,(iy+6) ;restore IY from jmp_buf ld b,(iy+7) push bc pop iy ex de,hl ;get arg into hl ld a,l or h ret nz ;not allowed to return 0 inc l ret ================================================ FILE: gen/LOR.AS ================================================ psect text global alor, llor alor: llor: exx pop hl exx pop bc ld a,c or e ld e,a ld a,b or d ld d,a pop bc ld a,c or l ld l,a ld a,b or h ld h,a exx push hl exx ret ================================================ FILE: gen/LRELOP.AS ================================================ ; long relational operation - returns flags as though ; a long subtract was done. psect text global lrelop,arelop arelop: lrelop: exx ;select alternate reg set pop hl ;return address exx ;get other set again pop bc ;low word of 2nd arg ex de,hl ;put hi word of 1st in de ex (sp),hl ;get hi word of 2nd in hl ex de,hl ;hi word of 1st back in hl ld a,h ;test for differing signs xor d jp p,2f ;the same, so ok ld a,h ;get the sign of the LHS or 2 ;ensure zero flag is reset, set sign flag ld a,d ;get RHS rla ;rotate hi bit into carry - Z and S unchanged pop hl ;unjunk stack jp 1f ;return with sign of LHS 2: or a sbc hl,de ;set the flags pop hl ;low word of 1st into hl again jr nz,1f ;go return if not zero sbc hl,bc ;now set flags on basis of low word jr z,1f ;if zero, all ok ld a,2 ;make non-zero rra ;rotate carry into sign or a ;set minus flag rlca ;put carry flag back 1: exx ;get return address jp (hl) ;and return with stack clean ================================================ FILE: gen/LSUB.AS ================================================ psect text global alsub, llsub alsub: llsub: exx pop hl exx pop bc ex de,hl or a sbc hl,bc ex de,hl pop bc sbc hl,bc exx push hl exx ret ================================================ FILE: gen/LXOR.AS ================================================ psect text global alxor, llxor alxor: llxor: exx pop hl exx pop bc ld a,c xor e ld e,a ld a,b xor d ld d,a pop bc ld a,c xor l ld l,a ld a,b xor h ld h,a exx push hl exx ret ================================================ FILE: gen/MAKEFILE ================================================ .SUFFIXES: .c .as .obj CC = /usr/hitech/bin/zc AS = /usr/hitech/bin/zas LIBR = /usr/hitech/bin/libr CFLAGS = -O -x ASFLAGS = -j -x LIB = ../../lib ENHUFF = /usr/hitech/bin/enhuff .c.obj: $(CC) -c $(CFLAGS) $*.c .as.obj: $(AS) $(ASFLAGS) $*.as SRCS = 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 \ calloc.c csv.as ctype.c ctype_.c brelop.as wrelop.as 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 linc.as llrsh.as lmul.as \ longjmp.as lor.as lrelop.as lsub.as lxor.as malloc.c \ max.as memcmp.c memcpy.c memset.c pnum.c \ qsort.c swap.as rand.c rcsv.as rindex.as sbrk.as shar.as \ shll.as shlr.as strcat.as strchr.as strcmp.as strcpy.as \ strlen.as strncat.as strncmp.as strncpy.as strrchr.as \ tolower.as toupper.as xtoi.as OBJS = memcpy.obj memcmp.obj memset.obj \ abs.obj asallsh.obj allsh.obj asalrsh.obj asar.obj \ asdiv.obj asladd.obj asland.obj asll.obj asllrsh.obj \ aslmul.obj aslor.obj aslsub.obj aslxor.obj asmod.obj \ atoi.obj atol.obj bitfield.obj blkclr.obj blkcpy.obj calloc.obj \ asmul.obj ctype_.obj getsp.obj index.obj strchr.obj \ inout.obj iregset.obj isalpha.obj isdigit.obj \ islower.obj isspace.obj isupper.obj ladd.obj land.obj \ linc.obj llrsh.obj longjmp.obj lor.obj lrelop.obj frelop.obj \ brelop.obj wrelop.obj lsub.obj lxor.obj malloc.obj idiv.obj max.obj \ pnum.obj ldiv.obj qsort.obj swap.obj aslr.obj bmove.obj \ imul.obj rand.obj alrsh.obj lmul.obj rindex.obj strrchr.obj \ sbrk.obj shar.obj shll.obj shlr.obj strcat.obj \ strcmp.obj strcpy.obj strlen.obj strncat.obj strncmp.obj \ strncpy.obj csv.obj rcsv.obj sys.obj tolower.obj \ toupper.obj xtoi.obj zlibc.lib: $(OBJS) -rm -f zlibc.lib $(LIBR) r zlibc.lib $(OBJS) install: $(LIB)/zlibc.lib $(LIB)/zlibc.lib: zlibc.lib cp zlibc.lib $(LIB)/zlibc.lib huff: -rm gen.huf $(ENHUFF) -a gen.huf Makefile $(SRCS) ================================================ FILE: gen/MALLOC.C ================================================ #ifdef debug #define ASSERT(p) if(!(p))botch("p");else botch(s) char *s; { printf("assertion botched: %s\n",s); abort(); } #else #define ASSERT(p) #endif /* C storage allocator for Z80 and other 8 bit machines * circular first-fit strategy * works with noncontiguous, but monotonically linked, arena * each block is preceded by a ptr to the (pointer of) * the next following block and a busy flag * bit in flag is 1 for busy, 0 for idle * gaps in arena are merely noted as busy blocks * last block of arena (pointed to by alloct) is empty and * has a pointer to first * idle blocks are coalesced during space search * */ #define BLOCK (85*sizeof(struct store)) /* 255 bytes */ #define BUSY 1 #define NULL 0 #define testbusy(p) ((p).flag & BUSY) #define sbusy(p) (p).flag |= BUSY #define cbusy(p) (p).flag &= ~BUSY struct store { struct store * ptr; char flag; }; static struct store allocs[2]; /*initial arena*/ static struct store * allocp; /*search ptr*/ static struct store * alloct; /*arena top*/ static struct store allocx; /* for realloc */ char * sbrk(); char * malloc(nw) unsigned nw; { register struct store *p, *q; static unsigned temp; /*coroutines assume no auto*/ if(allocs[0].ptr==(struct store *)0) { /*first time*/ alloct = allocs[0].ptr = &allocs[1]; allocp = allocs[1].ptr = &allocs[0]; sbusy(allocs[0]); sbusy(allocs[1]); } nw = ((nw - 1 + sizeof(struct store)*2)/sizeof(struct store)) * sizeof(struct store); ASSERT(allocp>=allocs && allocp<=alloct); ASSERT(allock()); for(p=allocp; ; ) { for(temp=0; ; ) { if(!testbusy(*p)) { while(!testbusy(*(q=p->ptr))) { ASSERT(q>p&&qptr = q->ptr; } if(q>=(struct store *)((char *)p+nw) && (struct store *)((char *)p+nw)>=p) goto found; } q = p; p = p->ptr; if(p>q) ASSERT(p<=alloct); else if(q!=alloct || p!=allocs) { ASSERT(q==alloct&&p==allocs); return(NULL); } else if(++temp>1) break; } temp = ((nw+sizeof(struct store)-1+BLOCK)/BLOCK)*BLOCK; q = (struct store *)sbrk(0); if((struct store *)((char *)q+temp) < q) { return(NULL); } q = (struct store *)sbrk(temp); if((int)q == -1) { return(NULL); } ASSERT(q>alloct); alloct->ptr = q; if(q!=alloct+1) sbusy(*alloct); else cbusy(*alloct); alloct = q->ptr = (struct store *)((char *)q+temp-sizeof(struct store));; alloct->ptr = allocs; sbusy(*alloct); cbusy(*q); } found: allocp = (struct store *)((char *)p + nw); ASSERT(allocp<=alloct); if(q>allocp) { allocx = *allocp; allocp->ptr = p->ptr; allocp->flag = 0; } p->ptr = allocp; sbusy(*p); return((char *)(p+1)); } /* freeing strategy tuned for LIFO allocation */ free(ap) char *ap; { register struct store *p; p = ((struct store *)ap)-1; ASSERT(p>allocs[1].ptr&&p<=alloct); ASSERT(allock()); allocp = p; ASSERT(testbusy(*p)); cbusy(*p); ASSERT(p->ptr > allocp && p->ptr <= alloct); } char * realloc(p, nbytes) char * p; unsigned short nbytes; { register struct store * xp, * q; unsigned short ons; unsigned short ns; xp = (struct store *)p; ns = (nbytes + sizeof(struct store) - 1)/sizeof(struct store); ons = xp[-1].ptr - xp; if(testbusy(xp[-1])) free((char *)xp); if(!(q = (struct store *)malloc(nbytes)) || q == xp) return (char *)q; ns = q[-1].ptr - q; if(ons > ns) ons = ns; bmove((char *)xp, (char *)q, ons * sizeof(struct store)); if(q < xp && q+ns > xp) q[q+ns-xp] = allocx; return (char *)q; } #ifdef debug showall() { struct store *p, *q; int i, used = 0, free = 0; for(p = &allocs[0] ; p && p!= alloct ; p = q) { q = p->ptr; printf("%4.4x %5d %s\n", p, i = (unsigned)q - (unsigned)p, testbusy(*p) ? "BUSY" : "FREE"); if(testbusy(*p)) used += i; else free += i; } printf("%d used, %d free, %4.4x end\n", used, free, alloct); } #endif ================================================ FILE: gen/MAX.AS ================================================ global _max psect text _max: pop bc ;return address pop de ;arg 1 pop hl ;arg 2 push hl push de push bc push hl ;save it or a ;clear carry sbc hl,de ;compare pop hl ;restore ret nc ;return if greater or equal ex de,hl ;otherwise returnt the other ret ================================================ FILE: gen/MEMCMP.C ================================================ memcmp(s1, s2, n) register char * s1, * s2; register int n; { short i; while(n--) if(i = *s1++ - *s2++) return i; return 0; } ================================================ FILE: gen/MEMCPY.C ================================================ memcpy(d, s, n) register char * d, * s; register int n; { while(n--) *d++ = *s++; } ================================================ FILE: gen/MEMSET.C ================================================ /*------------------------------------------------------------------------*\ | memset() | | This is the original Hi-Tech code for memset(): | | memset(p, n, c) | register char * p; | register int n; | char c; | { | while(n--) | *p++ = c; | } | | The declaration of memset() in string.h is: | | void *memset(void *, int, size_t); | | which is correct but which does not agree with the implementation. | The problem with the Hi-Tech code is that the parameters are in the | wrong order and that causes serious problems. | | Herewith an implementation which matches the declaration and which | conforms to the standard definition for memset(). | | Jon Saxton | September 2012 \*-------------------------------------------------------------------------*/ #include void *memset(void *mem, int fill, size_t bytes) { unsigned char *v = (unsigned char *)mem; while (bytes--) *v++ = fill; return mem; } ================================================ FILE: gen/PNUM.C ================================================ /* * Formatted number printing for Z80 printf and debugger */ #define NDIG 30 /* max number of digits to be printed */ #define putch(x) (*pputch)(x) _pnum(i, f, w, s, base, pputch) unsigned long i; unsigned char base; void (*pputch)(); unsigned char s; char f, w; { register char * cp; unsigned char fw; char buf[NDIG]; if(f > NDIG) f = NDIG; if(s && (long)i < 0) i = -i; else s = 0; if(f == 0 && i == 0) f++; cp = &buf[NDIG]; while(i || f > 0) { *--cp = "0123456789ABCDEF"[i%base]; i /= base; f--; } fw = f = (&buf[NDIG] - cp) + s; if(fw < w) fw = w; while(w-- > f) putch(' '); if(s) { putch('-'); f--; } while(f--) putch(*cp++); return fw; } ================================================ FILE: gen/QSORT.C ================================================ /* * Quicksort based on the algorithm given in * "Algorithms + Data Structures = Programs" by N. Wirth. */ qsort(base, nel, width, compar) char *base; int (*compar)(); unsigned width,nel; { register char * x; extern char * malloc(); register int i,j,l,r; struct { int l,r; } stack[20]; int s; char xbuf[800]; if(width < sizeof xbuf) x = xbuf; else if(!(x = malloc(width+1))) return; /* can't do much */ x[width] = 0; s = 0; stack[0].l = 0; stack[0].r = nel-1; do { /* take top request from stack */ l = stack[s].l; r = stack[s--].r; do { i = l; j = r; bmove(base+width*((i+j)/2), x, width); do { while((*compar)(base+i*width, x) < 0) i++; while((*compar)(x, base+j*width) < 0) j--; if(i <= j) { _swap(width, base+i*width, base+j*width); i++; j--; } } while(i <= j); if(j-l < r-i) { if(i < r) { /* stack right partition */ stack[++s].l = i; stack[s].r = r; } r = j; /* continue with left */ } else { if(l < j) { stack[++s].l = l; stack[s].r = j; } l = i; } } while(l < r); } while(s >= 0); if(x != xbuf) free(x); } ================================================ FILE: gen/RAND.C ================================================ static long randx = 1; srand(x) unsigned x; { randx = x; } rand() { return(((randx = randx*1103515245L + 12345)>>16) & 077777); } ================================================ FILE: gen/RCSV.AS ================================================ global rcsv ARG equ 6 ;offset of 1st arg psect text rcsv: ex (sp),iy ;save iy, get return address push ix ld ix,0 add ix,sp ;new frame pointer ld l,(ix+ARG+0) ld h,(ix+ARG+1) ld e,(ix+ARG+2) ld d,(ix+ARG+3) ld c,(ix+ARG+4) ld b,(ix+ARG+5) jp (iy) ================================================ FILE: gen/RINDEX.AS ================================================ psect text global rcsv, cret, _rindex _rindex: call rcsv ld bc,0 jr 5f 6: inc hl inc bc 5: ld a,(hl) or a jr nz,6b 1: dec hl ld a,c or b jr z,2f dec bc ld a,(hl) cp e jr nz,1b 4: jp cret 2: ld hl,0 jp 4b ================================================ FILE: gen/SBRK.AS ================================================ psect text global _sbrk,__Hbss, _brk, _checksp ; NB This brk() does not check that the argument is reasonable. _brk: pop hl ;return address pop de ;argument ld (memtop),de ;store it push de ;adjust stack jp (hl) ;return _sbrk: pop bc pop de push de push bc ld hl,(memtop) ld a,l or h jr nz,1f ld hl,__Hbss ld (memtop),hl 1: add hl,de jr c,2f ;if overflow, no room ld bc,1024 ;allow 1k bytes stack overhead add hl,bc jr c,2f ;if overflow, no room sbc hl,sp jr c,1f 2: ld hl,-1 ;no room at the inn ret 1: ld hl,(memtop) push hl add hl,de ld (memtop),hl pop hl ret _checksp: ld hl,(memtop) ld bc,128 add hl,bc sbc hl,sp ld hl,1 ;true if ok ret c ;if carry, sp > memtop+128 dec hl ;make into 0 ret psect bss memtop: defs 2 ================================================ FILE: gen/SHAR.AS ================================================ ; Shift operations - the count is always in B, ; the quantity to be shifted is in HL, except for the assignment ; type operations, when it is in the memory location pointed to by ; HL global shar ;shift arithmetic right psect text shar: ld a,b ;check for zero shift or a ret z cp 16 ;16 bits is maximum shift jr c,1f ;is ok ld b,16 1: sra h rr l djnz 1b ret ================================================ FILE: gen/SHLL.AS ================================================ ; Shift operations - the count is always in B, ; the quantity to be shifted is in HL, except for the assignment ; type operations, when it is in the memory location pointed to by ; HL global shll,shal ;shift left, arithmetic or logical psect text shll: shal: ld a,b ;check for zero shift or a ret z cp 16 ;16 bits is maximum shift jr c,1f ;is ok ld b,16 1: add hl,hl ;shift left djnz 1b ret ================================================ FILE: gen/SHLR.AS ================================================ ; Shift operations - the count is always in B, ; the quantity to be shifted is in HL, except for the assignment ; type operations, when it is in the memory location pointed to by ; HL global shlr ;shift logical right psect text shlr: ld a,b ;check for zero shift or a ret z cp 16 ;16 bits is maximum shift jr c,1f ;is ok ld b,16 1: srl h rr l djnz 1b ret ================================================ FILE: gen/STRCAT.AS ================================================ psect text global _strcat _strcat: pop bc pop de pop hl push hl push de push bc ld c,e ;save destination pointer ld b,d 1: ld a,(de) or a jr z,2f inc de jr 1b 2: ld a,(hl) ld (de),a or a jr z,3f inc de inc hl jr 2b 3: ld l,c ;restore destination ld h,b ret ================================================ FILE: gen/STRCHR.AS ================================================ ; strchr(char *s, int c) ; version that can find the closing \0 by Arnold M psect text global rcsv, cret, _strchr ; also equivalent to _index _strchr: pop bc pop hl pop de push de push hl push bc jr 3f 1: inc hl 3: ld a,(hl) cp e ; check for a match first, e may be zero ret z or a jr nz,1b ld hl,0 ret ================================================ FILE: gen/STRCMP.AS ================================================ psect text global _strcmp _strcmp: pop bc pop de pop hl push hl push de push bc 1: ld a,(de) cp (hl) jr nz,2f inc de inc hl or a jr nz,1b ld hl,0 ret 2: ld hl,1 ret nc dec hl dec hl ret ================================================ FILE: gen/STRCPY.AS ================================================ psect text global _strcpy _strcpy: pop bc pop de pop hl push hl push de push bc ld c,e ld b,d ;save destination pointer 1: ld a,(hl) ld (de),a inc de inc hl or a jr nz,1b ld l,c ld h,b ret ================================================ FILE: gen/STRDUP.C ================================================ #include extern char *malloc(); char * strdup(char * str) { char *dup; if ( (dup = malloc(strlen(str)+1)) ) /* add one for the closing \0 */ return strcpy(dup, str); return (dup); } ================================================ FILE: gen/STRFTIME.C ================================================ /** * * strftime.c * * implements the ansi c function strftime() * * written 6 september 1989 by jim nutt * released into the public domain by jim nutt * * modified 21-Oct-89 by Rob Duff * **/ #ifndef TZNAME #define TZNAME "GMT" /* define TZNAME to override to your timezone */ #endif #include /* for size_t */ #include /* for va_arg */ #include /* for struct tm */ /* ** The following line should be appended to TIME.H. ** Also copy size_t define from STRING.H. */ /* extern size_t strftime(char *s, size_t maxs, char *f, struct tm *t); */ static char *aday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char *day[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static char *amonth[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *month[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static char buf[26]; static void strfmt(char *str, char *fmt, ...); /** * * size_t strftime(char *str, * size_t maxs, * const char *fmt, * const struct tm *t) * * this functions acts much like a sprintf for time/date output. * given a pointer to an output buffer, a format string and a * time, it copies the time to the output buffer formatted in * accordance with the format string. the parameters are used * as follows: * * str is a pointer to the output buffer, there should * be at least maxs characters available at the address * pointed to by str. * * maxs is the maximum number of characters to be copied * into the output buffer, included the '\0' terminator * * fmt is the format string. a percent sign (%) is used * to indicate that the following character is a special * format character. the following are valid format * characters: * * %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 \0, or zero if more * than maxs characters were produced. * **/ size_t strftime(char *s, size_t maxs, char *f, struct tm *t) { int w; char *p, *q, *r; p = s; q = s + maxs - 1; while ((*f != '\0')) { if (*f++ == '%') { r = buf; switch (*f++) { case '%' : r = "%"; break; case 'a' : r = aday[t->tm_wday]; break; case 'A' : r = day[t->tm_wday]; break; case 'b' : r = amonth[t->tm_mon]; break; case 'B' : r = month[t->tm_mon]; break; case 'c' : strfmt(r, "%0 %0 %2 %2:%2:%2 %4", aday[t->tm_wday], amonth[t->tm_mon], t->tm_mday,t->tm_hour, t->tm_min, t->tm_sec, t->tm_year+1900); break; case 'd' : strfmt(r,"%2",t->tm_mday); break; case 'H' : strfmt(r,"%2",t->tm_hour); break; case 'I' : strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12); break; case 'j' : strfmt(r,"%3",t->tm_yday+1); break; case 'm' : strfmt(r,"%2",t->tm_mon+1); break; case 'M' : strfmt(r,"%2",t->tm_min); break; case 'p' : r = (t->tm_hour>11)?"PM":"AM"; break; case 'S' : strfmt(r,"%2",t->tm_sec); break; case 'U' : w = t->tm_yday/7; if (t->tm_yday%7 > t->tm_wday) w++; strfmt(r, "%2", w); break; case 'W' : w = t->tm_yday/7; if (t->tm_yday%7 > (t->tm_wday+6)%7) w++; strfmt(r, "%2", w); break; case 'w' : strfmt(r,"%1",t->tm_wday); break; case 'x' : strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday], amonth[t->tm_mon], t->tm_mday, t->tm_year+1900); break; case 'X' : strfmt(r, "%2:%2:%2", t->tm_hour, t->tm_min, t->tm_sec); break; case 'y' : strfmt(r,"%2",t->tm_year%100); break; case 'Y' : strfmt(r,"%4",t->tm_year+1900); break; case 'Z' : r = TZNAME; break; default: buf[0] = '%'; /* reconstruct the format */ buf[1] = f[-1]; buf[2] = '\0'; if (buf[1] == 0) f--; /* back up if at end of string */ } while (*r) { if (p == q) { *q = '\0'; return 0; } *p++ = *r++; } } else { if (p == q) { *q = '\0'; return 0; } *p++ = f[-1]; } } *p = '\0'; return p - s; } /* * stdarg.h * typedef void *va_list; #define va_start(vp,v) (vp=((char*)&v)+sizeof(v)) #define va_arg(vp,t) (*((t*)(vp))++) #define va_end(vp) * */ static int pow[5] = { 1, 10, 100, 1000, 10000 }; /** * static void strfmt(char *str, char *fmt); * * simple sprintf for strftime * * each format descriptor is of the form %n * where n goes from zero to four * * 0 -- string %s * 1..4 -- int %?.?d * **/ static void strfmt(char *str, char *fmt, ...) { int ival, ilen; char *sval; va_list vp; va_start(vp, fmt); while (*fmt) { if (*fmt++ == '%') { ilen = *fmt++ - '0'; if (ilen == 0) /* zero means string arg */ { sval = va_arg(vp, char*); while (*sval) *str++ = *sval++; } else /* always leading zeros */ { ival = va_arg(vp, int); while (ilen) { ival %= pow[ilen--]; *str++ = (char)('0' + ival / pow[ilen]); } } } else *str++ = fmt[-1]; } *str = '\0'; va_end(vp); } #ifdef TEST #include /* for printf */ #include /* for strftime */ char test[80]; int main(int argc, char *argv[]) { int len; char *fmt; time_t now; time(&now); fmt = (argc == 1) ? "%I:%M %p\n%c\n" : argv[1]; len = strftime(test,sizeof test, fmt, localtime(&now)); printf("%d: %s\n", len, test); return !len; } #endif /* TEST */ ================================================ FILE: gen/STRICMP.AS ================================================ ; int strcasecmp(const char *s1, const char *s2) ; return a value less than 0, 0 or greater than 0 if s1 is found, respectively, ; to be less than equal or greater than s2 ignoring case ; by Arnold M psect text macro tolower cp 'A' jr c, 10f cp 'Z'+1 jr nc, 10f add a, 'a'-'A' 10: endm global _strcasecmp _strcasecmp: pop bc pop hl ; s1 pop de ; s2 push de push hl push bc 1: ld a,(de) ;*s2 tolower ld c,a ld a,(hl) ;*s1 tolower cp c jr nz,2f inc hl inc de or a jp nz,1b ld h,a ld l,a ret 2: sbc hl,hl ret c inc hl ret ================================================ FILE: gen/STRISTR.C ================================================ /* * char * strcasestr (char *t, char *s) * * Find string s in string t, disregarding the case of letters. * * Return * - The smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p, or * - NULL if there is no such pointer. */ #include char * strcasestr (char *t, char *s) { char *t1; char *s1; do { t1 = t; s1 = s; while(*s1) { if (toupper(*s1) != toupper(*(t1++))) break; else ++s1; } if (!*s1) return t; } while (*(t++)); return (char *) 0; } ================================================ FILE: gen/STRLEN.AS ================================================ psect text global _strlen _strlen: pop hl pop de push de push hl ld hl,0 1: ld a,(de) or a ret z inc hl inc de jr 1b ================================================ FILE: gen/STRNCAT.AS ================================================ psect text global _strncat, rcsv, cret _strncat: call rcsv push hl jr 3f 4: inc hl 3: ld a,(hl) or a jr nz,4b 1: ld a,c or b jr z,3f dec bc ld a,(de) ld (hl),a inc hl or a jr z,2f inc de jr 1b 3: ld (hl),0 2: pop hl jp cret ================================================ FILE: gen/STRNCMP.AS ================================================ psect text global _strncmp, rcsv, cret _strncmp: call rcsv 1: ld a,c or b jp z,3f dec bc ld a,(de) cp (hl) jr nz,2f inc de inc hl or a jr nz,1b 3: ld hl,0 jp cret 2: ld hl,1 jp c,cret dec hl dec hl jp cret ================================================ FILE: gen/STRNCPY.AS ================================================ psect text global _strncpy, rcsv, cret _strncpy: call rcsv push hl 1: ld a,c or b jr z,2f dec bc ld a,(de) ld (hl),a inc hl or a jr z,1b inc de jr 1b 2: pop hl jp cret ================================================ FILE: gen/STRNICMP.AS ================================================ ; int strncasecmp(const char *s1, const char *s2, size_t n) ; return a value less than 0, 0 or greater than 0 if s1 is found, respectively, ; to be less than equal or greater than s2 ignoring case ; by Arnold M psect text macro tolower cp 'A' jr c, 10f cp 'Z'+1 jr nc, 10f add a, 'a'-'A' 10: endm global _strncasecmp, rcsv, cret _strncasecmp: call rcsv ; hl=s1, de=s2, bc=n ld b,c ; keep low part of n in reg b, reg c is used as scratch ld a,b or a jr z,bzero loop: ld a,(de) ;*s2 tolower ld c,a ld a,(hl) ;*s1 tolower cp c jr nz,diff or a jr z, equal inc hl inc de djnz loop bzero: dec (ix+6+5) ; n / 0x100 jp p,loop ; dec m does not affect the carry flag ld a,(ix+6+5) inc a jr nz,loop equal: ld h,a ld l,a jp cret diff: sbc hl,hl jp c,cret inc hl jp cret ================================================ FILE: gen/STRNISTR.C ================================================ /* * char * strncasestr (char *t, char *s, unsigned int n) * * Find string s in string t, disregarding the case of letters. * At most n characters from t are used. * * Returns * - A smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p and strictly before t+n, or * - NULL if there is no such pointer. */ #include char * strncasestr (char *t, char *s, unsigned int n) { char *t1; char *s1; unsigned int n1; if (!*s) return t; while (*t && n) { t1 = t; n1 = n; s1 = s; while (*s1) { if (toupper(*s1) != toupper(*(t1++))) break; else { ++s1; if (!--n1) break; } } if (!*s1) return t; --n; ++t; } return (char *) 0; } ================================================ FILE: gen/STRNSTR.C ================================================ /* * char * strnstr (char *t, char *s, unsigned int n) * * Find string s in string t, using at most n characters from t. * * Returns * - A smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p and strictly before t+n, or * - NULL if there is no such pointer. */ char * strnstr (char *t, char *s, unsigned int n) { char *t1; char *s1; unsigned int n1; if (!*s) return t; while (*t && n) { t1 = t; n1 = n; s1 = s; while (*s1) { if (*s1 != *(t1++)) break; else { ++s1; if (!--n1) break; } } if (!*s1) return t; --n; ++t; } return (char *) 0; } ================================================ FILE: gen/STRRCHR.AS ================================================ ; strrchr(char *s, int c) ; version that can find the closing \0 by Arnold M psect text global rcsv, cret, _strrchr ; also equivalent to _rindex _strrchr: pop bc pop hl pop de push de push hl push bc ld bc,1 ; the closing nul is considered part of the string here jr 5f 6: inc hl inc bc 5: ld a,(hl) or a jr nz,6b 1: ld a,e cpdr inc hl ret z ld l,c ld h,b ret ================================================ FILE: gen/STRSTR.C ================================================ /* * char * strstr (char *t, char *s) * * Find string s in string t. * * Return * - The smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p, or * - NULL if there is no such pointer. */ char * strstr (char *t, char *s) { char *t1; char *s1; do { t1 = t; s1 = s; while(*s1) { if (*s1 != *(t1++)) break; else ++s1; } if (!*s1) return t; } while (*(t++)); return (char *) 0; } ================================================ FILE: gen/STRTOK.C ================================================ /* ** strtok() -- public domain by Ray Gardner, modified by Bob Stout ** not modified for Hi-Tech C by Pierre Gielen :-) ** comment corrected by Arnold Metselaar ** ** You pass this function a string to parse, a buffer to receive the ** "token" that gets scanned, the length of the buffer, and a string of ** "break" characters that stop the scan. It will copy the string into ** the buffer up to any of the break characters, or until the buffer is ** full, and will always leave the buffer null-terminated. It will ** return a pointer to the first character from s that was not copied to ** tok. */ #include char *strtok(char *s, char *tok, size_t toklen, char *brk) { char *lim, *b; if (!*s) return NULL; lim = tok + toklen - 1; while (*s && (tok #include "huff.h" char cl[ALFSIZ]; short alfused; static short clidx; static short g_bit; static short g_char; node * root; void bld_tree(void); node * get_tree(void); void align(void); int get_bit(void); int gethch(void); extern void error(char *fmt, ...); void bld_tree(void) { short i; for(i = 0 ; i < alfused ; i++) cl[i] = getchar(); align(); clidx = 0; root = get_tree(); } node * get_tree(void) { register node * tp; if(!(tp = (node *)calloc(sizeof(node), 1))) error("Out of memory"); if(get_bit()) { tp->n_left = get_tree(); tp->n_right = get_tree(); } else tp->n_c = cl[clidx++]; return tp; } void align(void) { g_char = 0; g_bit = CHAR_BIT; } int get_bit(void) { if(g_bit == CHAR_BIT) if((g_char = getchar()) == EOF) error("Read error or EOF on huf file"); else g_bit = 0; return g_char & (1 << g_bit++); } int gethch(void) { register node * tp; tp = root; while(tp->n_left) tp = get_bit() ? tp->n_left : tp->n_right; return tp->n_c & 0xFF; } ================================================ FILE: huff/DEHUF.C ================================================ #include #include "huff.h" hdr hd; static short indent; static uchar listflg; static uchar xtractflg; static uchar debug; static char ** av; extern void align(void); extern void bld_tree(void); extern void error(char *fmt, ...); extern int casecmp(register char *, char *); extern int gethch(void); int isarg(char * s); char * getname(short i); void list(short i); void extract(short i); void prtree(register node * np); #if !unix extern char ** _getargs(); extern int _argc_; #endif /* unix */ /* * */ int main(int argc, char ** argv) { short i; #if !unix if(argc == 1) { argv = _getargs(0, "dehuff"); argc = _argc_; } #endif /* unix */ argc--; argv++; while(argc && **argv == '-') { switch(argv[0][1]) { case 'l': case 'L': listflg++; break; case 'x': case 'X': xtractflg++; break; case 'd': case 'D': debug++; break; default: fprintf(stderr, "Unrecognized flag %s ignored\n", argv[0]); break; } argc--; argv++; } if(argc < 1) { printf("Usage of dehuff:\n\nTo list the contents of a .HUF file:\n"); printf("\n dehuff file.huf\n\nTo extract files from a .HUF file:\n"); printf("\n dehuff -x file.huf\n\nIf no extra arguments are supplied, then the entire contents\n"); printf("of the .HUF file will be listed or extracted, otherwise only files\n"); printf("matching an argument will be listed or extracted, e.g.\n\n"); printf(" dehuff -x xyz.huf afile.c\n\nwould extract only the file afile.c.\n"); printf("The number reported for each file is its length in bytes\n"); exit(1); } av = argv+1; if(!freopen(*argv, "rb", stdin)) error("Can't open file %s", *argv); hd.hd_magic = get2(); if(hd.hd_magic != MAGIC) error("%s is not a huf file", *argv); hd.hd_nfiles = get2(); alfused = hd.hd_alfsiz = get2(); hd.hd_hpos = get4(); bld_tree(); if(debug) prtree(root); for(i = 0 ; i < hd.hd_nfiles ; i++) if(isarg(getname(i))) if(xtractflg) extract(i); else list(i); } /* * */ int isarg(char * s) { register char ** p; if(*av == 0) /* default is all members */ return 1; for(p = av ; *p ; p++) if(casecmp(*p, s) == 0) return 1; return 0; } /* * */ char * getname(short i) { static char fbuf[100]; register char * cp; filent hf; fseek(stdin, hd.hd_hpos+i*FSIZE, 0); hf.f_npos = get4(); hf.f_nchrs = get4(); hf.f_pos = get4(); hf.f_asc = getchar(); fseek(stdin, hf.f_npos, 0); align(); for(cp = fbuf ; (*cp++ = gethch()) ; ) continue; return fbuf; } /* * */ void list(short i) { register char * cp; filent hf; char fbuf[100]; fseek(stdin, hd.hd_hpos+i*FSIZE, 0); hf.f_npos = get4(); hf.f_nchrs = get4(); hf.f_pos = get4(); hf.f_asc = getchar(); fseek(stdin, hf.f_npos, 0); align(); for(cp = fbuf ; (*cp++ = gethch()) ; ) continue; fprintf(stderr, "%-20.20s %ld\n", fbuf, hf.f_nchrs); } /* * */ void extract(short i) { register char * cp; filent hf; FILE * fp; char fbuf[100]; fseek(stdin, hd.hd_hpos+i*FSIZE, 0); hf.f_npos = get4(); hf.f_nchrs = get4(); hf.f_pos = get4(); hf.f_asc = getchar(); fseek(stdin, hf.f_npos, 0); align(); for(cp = fbuf ; (*cp++ = gethch()) ; ) continue; if(!(fp = fopen(fbuf, hf.f_asc ? "w" : "wb"))) { fprintf(stderr, "Can't create %s\n", fbuf); return; } fprintf(stderr, "%-20.20s %ld\n", fbuf, hf.f_nchrs); fseek(stdin, hf.f_pos, 0); align(); while(hf.f_nchrs--) putc(gethch(), fp); fclose(fp); } /* * */ void prtree(register node * np) { short i; for(i = indent ; i-- ; ) fputc(' ', stderr); if(np->n_left) { fprintf(stderr, "X\n"); indent += 4; prtree(np->n_left); prtree(np->n_right); indent -= 4; } else if(np->n_c >= ' ' && np->n_c <= 0176) fprintf(stderr, "'%c'\n", np->n_c); else fprintf(stderr, "%03o\n", np->n_c); } ================================================ FILE: huff/DEHUFF.C ================================================ #include #include "huff.h" hdr hd; static short indent; static uchar listflg; static uchar xtractflg; static uchar debug; static char ** av; extern void align(void); extern void bld_tree(void); extern void error(char *fmt, ...); extern int casecmp(register char *, char *); extern int gethch(void); int isarg(char * s); char * getname(short i); void list(short i); void extract(short i); void prtree(register node * np); #if !unix extern char ** _getargs(); extern int _argc_; #endif /* unix */ /* * */ int main(int argc, char ** argv) { short i; #if !unix if(argc == 1) { argv = _getargs(0, "dehuff"); argc = _argc_; } #endif /* unix */ argc--; argv++; while(argc && **argv == '-') { switch(argv[0][1]) { case 'l': case 'L': listflg++; break; case 'x': case 'X': xtractflg++; break; case 'd': case 'D': debug++; break; default: fprintf(stderr, "Unrecognized flag %s ignored\n", argv[0]); break; } argc--; argv++; } if(argc < 1) { printf("Usage of dehuff:\n\nTo list the contents of a .HUF file:\n"); printf("\n dehuff file.huf\n\nTo extract files from a .HUF file:\n"); printf("\n dehuff -x file.huf\n\nIf no extra arguments are supplied, then the entire contents\n"); printf("of the .HUF file will be listed or extracted, otherwise only files\n"); printf("matching an argument will be listed or extracted, e.g.\n\n"); printf(" dehuff -x xyz.huf afile.c\n\nwould extract only the file afile.c.\n"); printf("The number reported for each file is its length in bytes\n"); exit(1); } av = argv+1; if(!freopen(*argv, "rb", stdin)) error("Can't open file %s", *argv); hd.hd_magic = get2(); if(hd.hd_magic != MAGIC) error("%s is not a huf file", *argv); hd.hd_nfiles = get2(); alfused = hd.hd_alfsiz = get2(); hd.hd_hpos = get4(); bld_tree(); if(debug) prtree(root); for(i = 0 ; i < hd.hd_nfiles ; i++) if(isarg(getname(i))) if(xtractflg) extract(i); else list(i); } /* * */ int isarg(char * s) { register char ** p; if(*av == 0) /* default is all members */ return 1; for(p = av ; *p ; p++) if(casecmp(*p, s) == 0) return 1; return 0; } /* * */ char * getname(short i) { static char fbuf[100]; register char * cp; filent hf; fseek(stdin, hd.hd_hpos+i*FSIZE, 0); hf.f_npos = get4(); hf.f_nchrs = get4(); hf.f_pos = get4(); hf.f_asc = getchar(); fseek(stdin, hf.f_npos, 0); align(); for(cp = fbuf ; (*cp++ = gethch()) ; ) continue; return fbuf; } /* * */ void list(short i) { register char * cp; filent hf; char fbuf[100]; fseek(stdin, hd.hd_hpos+i*FSIZE, 0); hf.f_npos = get4(); hf.f_nchrs = get4(); hf.f_pos = get4(); hf.f_asc = getchar(); fseek(stdin, hf.f_npos, 0); align(); for(cp = fbuf ; (*cp++ = gethch()) ; ) continue; fprintf(stderr, "%-20.20s %ld\n", fbuf, hf.f_nchrs); } /* * */ void extract(short i) { register char * cp; filent hf; FILE * fp; char fbuf[100]; fseek(stdin, hd.hd_hpos+i*FSIZE, 0); hf.f_npos = get4(); hf.f_nchrs = get4(); hf.f_pos = get4(); hf.f_asc = getchar(); fseek(stdin, hf.f_npos, 0); align(); for(cp = fbuf ; (*cp++ = gethch()) ; ) continue; if(!(fp = fopen(fbuf, hf.f_asc ? "w" : "wb"))) { fprintf(stderr, "Can't create %s\n", fbuf); return; } fprintf(stderr, "%-20.20s %ld\n", fbuf, hf.f_nchrs); fseek(stdin, hf.f_pos, 0); align(); while(hf.f_nchrs--) putc(gethch(), fp); fclose(fp); } /* * */ void prtree(register node * np) { short i; for(i = indent ; i-- ; ) fputc(' ', stderr); if(np->n_left) { fprintf(stderr, "X\n"); indent += 4; prtree(np->n_left); prtree(np->n_right); indent -= 4; } else if(np->n_c >= ' ' && np->n_c <= 0176) fprintf(stderr, "'%c'\n", np->n_c); else fprintf(stderr, "%03o\n", np->n_c); } ================================================ FILE: huff/ENCODE.C ================================================ #include "huff.h" #include #include typedef struct { node * np_node; uchar np_len; } np; node * root; chent clist[ALFSIZ]; filent flist[MAXFILENT]; short alfused; chent * cptrs[ALFSIZ]; static np nptrs[ALFSIZ]; static uchar p_bit; static uchar p_char; static uchar level; static short nidx; /* extern char * calloc(); */ extern void error(char *fmt, ...); void make_tree(char **); node * newnode(void); node * bld(short, short); int cmpr(chent **, chent **); int cmpnp(np *, np *); void bld_bits(node *, h_char); void pinit(void); void align(void); void put_bit(int); void puthch(uchar); void put_tchrs(node *); void walk_tree(node *); void put_tree(void); /* * */ void make_tree(char ** namlist) { FILE * fp; int c, fno; h_char tch; register char * cp; fno = 0; while(*namlist) { if(**namlist == '-') switch(namlist[0][1]) { case 'a': case 'A': ascii = 1; namlist++; continue; case 'b': case 'B': ascii = 0; namlist++; continue; default: break; } if(!(fp = fopen(*namlist, ascii ? "r" : "rb"))) { fprintf(stderr, "Can't open %s\n", *namlist++); continue; } flist[fno].f_name = *namlist; flist[fno].f_asc = ascii; while((c = getc(fp)) != EOF) { clist[c & (ALFSIZ-1)].c_freq++; flist[fno].f_nchrs++; } fclose(fp); for(cp = *namlist ; *cp ; ) clist[*cp++ & (ALFSIZ-1)].c_freq++; clist[0].c_freq++; namlist++; fno++; } for(c =0 ; c < ALFSIZ ; c++) { cptrs[c] = clist+c; clist[c].c_chr = c; } qsort(cptrs, ALFSIZ, sizeof cptrs[0], cmpr); for(alfused = 0 ; alfused < ALFSIZ && cptrs[alfused]->c_freq ; alfused++) continue; level = 0; nidx = 0; root = bld(0, alfused-1); qsort(nptrs, alfused, sizeof nptrs[0], cmpnp); for(c = 0 ; c < alfused ; c++) nptrs[c].np_node->n_c = cptrs[c]->c_chr; tch.h_nbits = 0; bld_bits(root, tch); } /* * */ node * newnode(void) { register node * np; if(!(np = (node *)calloc(1, sizeof(node)))) error("Out of memory"); return np; } /* * */ node * bld(short first, short last) { int i; long tot, run; register node * l, * np; if(first == last) { l = newnode(); nptrs[nidx].np_node = l; nptrs[nidx++].np_len = level+1; l->n_left = l->n_right = (node *)0; return l; } level++; for(i = first, tot = 0 ; i <= last ; i++) tot += cptrs[i]->c_freq; tot /= factor; run = cptrs[i = first]->c_freq; while(run < tot && i != last) run += cptrs[++i]->c_freq; if(i == last) i = (first+last)/2; if(i == first) { l = newnode(); nptrs[nidx].np_node = l; nptrs[nidx++].np_len = level+1; l->n_left = l->n_right = (node *)0; } else l = bld(first, i); np = newnode(); np->n_left = l; np->n_right = bld(i+1, last); level--; return np; } /* * */ int cmpr(register chent ** p1, chent ** p2) { long i; i = (*p2)->c_freq - (*p1)->c_freq; if(i > 0) return 1; if(i < 0) return -1; return 0; } /* * */ int cmpnp(np * p1, np * p2) { return p1->np_len - p2->np_len; } /* * */ void bld_bits(register node * nodep, h_char tch) { if(!nodep->n_left) { /* leaf node */ clist[nodep->n_c].c_bits = tch; return; } SET(tch.h_cbits, tch.h_nbits); tch.h_nbits++; bld_bits(nodep->n_left, tch); CLR(tch.h_cbits, tch.h_nbits-1); bld_bits(nodep->n_right, tch); } /* * */ void pinit(void) { p_char = 0; p_bit = 0; } /* * */ void align(void) { if(p_bit) putchar(p_char); pinit(); } /* * */ void put_bit(int i) { if(i) p_char |= 1 << p_bit; if(++p_bit == CHAR_BIT) { putchar(p_char); p_char = 0; p_bit = 0; } } /* * */ void puthch(uchar c) { h_char tch; short i; tch = clist[c].c_bits; for(i = 0 ; i < tch.h_nbits ; i++) { if(TST(tch.h_cbits, i)) p_char |= 1 << p_bit; if(++p_bit == CHAR_BIT) { putchar(p_char); p_char = 0; p_bit = 0; } } } /* * */ void put_tchrs(register node * tp) { if(tp->n_left) { put_tchrs(tp->n_left); put_tchrs(tp->n_right); } else putchar(tp->n_c); } /* * */ void walk_tree(register node * tp) { if(tp->n_left) { put_bit(1); walk_tree(tp->n_left); put_bit(0); walk_tree(tp->n_right); } } /* * */ void put_tree(void) { put_tchrs(root); walk_tree(root); put_bit(0); /* a safeguard */ } ================================================ FILE: huff/ENHUFF.C ================================================ #include #include "huff.h" uchar ascii; short factor; static int indent; static uchar debug; static char * outfile; static short filecnt; static long totchrs; static long totsize; static hdr hd; extern long ftell(); extern void error(char *fmt, ...); extern void make_tree(char **); void putnames(void); void putfiles(void); void puthdr(void); void prtree(register node *); void prchars(void); void putbch(h_char); extern void put_tree(void); #if !unix extern char ** _getargs(); extern int _argc_; #endif /* unix */ extern void align(void); extern void puthch(uchar); extern void put2(unsigned short); extern void put4(unsigned long); int main(int argc, char ** argv) { long pc; char buf[10]; #if !unix if(argc == 1) { argv = _getargs(0, "enhuff"); argc = _argc_; } #endif argc--; argv++; while(argc && **argv == '-') { switch(argv[0][1]) { case 'f': case 'F': factor = atoi(&argv[0][2]); break; case 'a': case 'A': ascii = 1; break; case 'b': case 'B': ascii = 0; break; case 'd': case 'D': debug++; break; default: fprintf(stderr, "Unrecognized flag %s ignored\n", *argv); break; } argv++; argc--; } if(factor == 0) factor = 2; if(argc < 2) error("USAGE: enhuff [options] outfile file1 file2 ..."); outfile = *argv++; if(freopen(outfile, "r", stdout)) { fprintf(stderr, "File %s exists; want to overwrite it? ", outfile); fgets(buf, sizeof buf, stdin); if(buf[0] != 'y' && buf[0] != 'Y') exit(1); } if(!freopen(outfile, "wb", stdout)) error("Can't create %s", outfile); make_tree(argv); if(debug) prchars(); if(debug > 1) prtree(root); for(filecnt = 0 ; flist[filecnt].f_name ; filecnt++) continue; fseek(stdout, (long)HSIZE, 0); put_tree(); hd.hd_alfsiz = alfused; align(); hd.hd_hpos = ftell(stdout); putnames(); putfiles(); puthdr(); if(fclose(stdout) == EOF) error("Error closing output file - out of disk space?"); pc = (totchrs-totsize)*100; pc /= totchrs; fprintf(stderr, "Source bytes %ld, enhuff'ed bytes %ld, compression %d%%\n", totchrs, totsize, (int)pc); } /* * */ void putnames(void) { register filent * fp; register char * cp; fseek(stdout, (long)FSIZE * filecnt + hd.hd_hpos, 0); for(fp = flist ; fp->f_name ; fp++) { fp->f_npos = ftell(stdout); for(cp = fp->f_name ; *cp ;) puthch(*cp++); puthch(0); align(); } } /* * */ void putfiles(void) { int c; register filent * fp; for(fp = flist ; fp->f_name ; fp++) { fprintf(stderr, "%-20.20s %ld\n", fp->f_name, fp->f_nchrs); fp->f_pos = ftell(stdout); totchrs += fp->f_nchrs; if(!freopen(fp->f_name, fp->f_asc ? "r" : "rb", stdin)) error("Can't re-open file %s", fp->f_name); while((c = getchar()) != EOF) puthch(c); align(); } totsize = ftell(stdout); } /* * */ void puthdr(void) { register filent * fp; hd.hd_magic = MAGIC; hd.hd_nfiles = filecnt; fseek(stdout, 0L, 0); put2(hd.hd_magic); put2(hd.hd_nfiles); put2(hd.hd_alfsiz); put4(hd.hd_hpos); fseek(stdout, hd.hd_hpos, 0); for(fp = flist ; fp->f_name ; fp++) { put4(fp->f_npos); put4(fp->f_nchrs); put4(fp->f_pos); putchar(fp->f_asc); } } /* * */ void prtree(register node * np) { short i; for(i = indent ; i-- ; ) fputc(' ', stderr); if(np->n_left) { fprintf(stderr, "X\n"); indent += 4; prtree(np->n_left); prtree(np->n_right); indent -= 4; } else if(np->n_c >= ' ' && np->n_c <= 0176) fprintf(stderr, "'%c'\n", np->n_c); else fprintf(stderr, "%03o\n", np->n_c); } /* * */ void prchars(void) { short i; long nchars, nbits, xx; nchars = nbits = 0; for(i = 0 ; i < alfused ; i++) { nchars += cptrs[i]->c_freq; nbits += cptrs[i]->c_freq * cptrs[i]->c_bits.h_nbits; if(cptrs[i]->c_chr >= ' ' && cptrs[i]->c_chr <= 0176) fprintf(stderr, "'%c'\t", cptrs[i]->c_chr); else fprintf(stderr, "%03o\t", cptrs[i]->c_chr); fprintf(stderr, "%7ld\t", cptrs[i]->c_freq); putbch(cptrs[i]->c_bits); fputc('\n', stderr); } nbits /= CHAR_BIT; xx = (nchars - nbits)*100; i = xx/nchars; fprintf(stderr, "%ld chars reduced to %ld - %d%% compression\n", nchars, nbits, i); } /* * */ void putbch(h_char tch) { short i; for(i = 0 ; i < tch.h_nbits ; i++) if(TST(tch.h_cbits, i)) putc('1', stderr); else putc('0', stderr); } ================================================ FILE: huff/HUFF.H ================================================ /* * Definitions for the Huffman encoded file structure */ #include #ifndef uchar #define uchar unsigned char #endif #ifndef CHAR_BIT #define CHAR_BIT 8 #endif /* CHAR_BIT */ #define ALFSIZ (1< #include #include #if ! unix /* this is a kludge for a bug in the Venix cpp */ #endif void error(char *fmt, ...); void put2(unsigned short i); void put4(unsigned long i); unsigned long get4(void); unsigned short get2(void); #if ! unix #include int casecmp(register char *, char *); int casecmp(register char * s1, char * s2) { char a, b; while((a = *s1++)) { b = *s2++; if(isupper(a)) a = tolower(a); if(isupper(b)) b = tolower(b); if(a != b) return 1; } return 0; } #endif /* unix */ /*======================================== void error(char *s, char* a1, char* a2) { fprintf(stderr, "huff: fatal error: "); fprintf(stderr, s, a1, a2); fputc('\n', stderr); exit(1); } ========================================*/ void error(char *fmt, ...) { va_list ap; /* points to the next unnamed argument */ char *p, *sval; fprintf(stderr, "huff: fatal error: "); va_start(ap, fmt); /* set ap to 1st unnamed argument */ for(p=fmt; *p; p++) { if(*p !='%') { putchar(*p); continue; } switch(*++p) { case 's': for(sval = va_arg(ap, char *); *sval; sval++) fputc(*sval, stderr); break; default: fputc(*p, stderr); break; } } va_end(ap); /* cleaning when done */ fputc('\n', stderr); exit(1); } /* * */ void put2(unsigned short i) { putchar(i & 0xFF); putchar(i >> 8); } /* * */ void put4(unsigned long i) { put2(i & 0xFFFFL); put2(i >> 16); } /* * */ unsigned long get4(void) { unsigned long i; i = (unsigned long)getchar(); i += (unsigned long)getchar() << 8; i += (unsigned long)getchar() << 16; i += (unsigned long)getchar() << 24; if(feof(stdin)) error("EOF on input file"); return i; } /* * */ unsigned short get2(void) { unsigned short i; i = (unsigned short)getchar(); i += (unsigned short)getchar() << 8; if(feof(stdin)) error("EOF on input file"); return i; } ================================================ FILE: msx2dist/cc_01/CC.C ================================================ /* * Copyright (C) 1984-1987 HI-TECH SOFTWARE * * MSXDOS modifications by Pierre Gielen 1993: * * - Replaced EXECL routines (C produces a batch file now) * - Added -Q switch to write batch file without executing * - Changed object file types to .O and temporary file * types to .T to allow more commands per line (note: * crt.o = crtcpm.obj). Changed library types back to .LIB. * - Commented out calls to GETENV (for now) because it locks up * the computer (still to be changed in the standard library) * * Modifications by Arnold Metselaar: * * - Append ".C" _only_ if no filetype at all * - Fixed bug with "-R" switch * - Put object and program files in the same place as their sources * - Switched back from producing $exec.bat to _spawn * - removed -Q switch * - Use APPEND environment item to find include files (and libs) * - Added -N switch to link without crt.o , the user should provide * * HITECH C is almost ANSI C compatible, but it does not recognize * the '#pragma nonrec' directive. * * * HITECH SOFTWARE has given kind permission to copy this * software for personal use. * */ #include #include #include void stack_trace(); /* * CC command MSX-DOS2 version * * CC [-C] [-O] [-I] [-F] [-U] [-D] [-S] [-X] [-P] [-W] [-M] [-N] files {-Llib} */ #define MAXLIST 60 /* max arg list */ #define BIGLIST 120 /* room for much more */ #define HITECH "HITECH" #define PROMPT "c" #define TEMP "TMP" #define DEFPATH "" #define DEFTMP "" #define LIBSUFF ".LIB" /* library suffix */ #define LFLAGS "-Z" #define STDLIB "C" /* originally "-U__getargs", but the -u option to link is broken, so I made * a small object file with the same effect */ #define REDIR_O "redir.obj" 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 */ redir, /* AM - link code for redirectioning and globbing */ nocrto; /* AM - do not link standard crt.o */ 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 iuds[] */ obj_idx, /* " " objs[] */ flg_idx, /* " " flgs[] */ lib_idx, /* " " libs[] */ c_as_idx; /* " " c_as[] */ static char * paths[] = { "~LINK", "OBJTOHEX", "~CGEN", "~OPTIM", "~CPP", "~ZAS", "LIB", "~P1", "~CREF", "CRT.O", }; #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 cref paths[8] #define strtoff paths[9] #define RELSTRT strtoff[plen] static char * temps[] = { "$C1.T", "$C2.T", "$C3.T", "$C4.T", "L.O", "CREF.T" }; #define tmpf1 temps[0] #define tmpf2 temps[1] #define tmpf3 temps[2] #define redname temps[3] #define l_dot_obj temps[4] #define crtmp temps[5] static char * cppdef[] = { "-DCPM", "-DHI_TECH_C", "-Dz80" }; static char * cpppath = "-I"; static char * old_append, * new_append; 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 short plen; /* length of path */ static char ebuf[22]; /* error listing file */ static char * xrname; /*static struct stat statbuf;*/ extern char * malloc(), * getenv(), * rindex(); * realloc(char *, int); extern char ** _getargs(); extern int dup(int); static char * xalloc(short); void setup(); int doit(); int main(argc, argv) char ** argv; { register char * cp, * xp; short i; fprintf(stderr, "HI-TECH C COMPILER (MSXDOS) V3.09\n"); fprintf(stderr, "Copyright (C) 1993 HI-TECH SOFTWARE\n"); 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 'N': /* AM */ nocrto = 1; break; case 'R': redir=1; break; case 'V': verbose = 1; break; case 'S': keepas = 1; keep = 1; break; 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': if (strlen(argv[0])>3) outfile=argv[0]+2; else { optimize = 1; if(argv[0][2] == 'F' || argv[0][2] == 'f') speed = 1; } break; case 'I': /* APPEND does not work as desired * if (strlen(new_append)+strlen(argv[0]+1)<256) { * cp=(char*)realloc(new_append, * strlen(new_append)+strlen(argv[0]+1)); * if (cp) { * strcat(strcat(cp,"; "),argv[0]+2); * new_append=cp; * } * else * fprintf(stderr, "Excessive -I options\n"); * } * else * fprintf(stderr, "Excessive -I options\n"); * break; */ 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++; } /* PG: */ if (strchr(argv[0],'.')==NULL) /* if no filetype at all */ argv[0]=strcat(strcpy(xalloc(strlen(argv[0])+3),argv[0]),".C"); /* make it .C */ /* */ cp = rindex(argv[0], '.'); if(cp && (strcmp(cp, ".C") == 0 || strcmp(cp, ".AS") == 0)) { c_as[c_as_idx++] = argv[0]; /* AM: put object files in the same place as their sources * maybe there should be an option controlling this * if(xp = rindex(argv[0], ':')) * xp++; * else */ xp = argv[0]; *cp = 0; strcat(strcpy(tmpbuf, xp), ".O"); addobj(tmpbuf); strcpy(single, tmpbuf); *cp = '.'; } else addobj(argv[0]); } if (outfile && keep && (c_as_idx>1)) { fprintf(stderr, "-Oname used while keeping more than one %sfile. (Error)\n", keepas?"assembly language ":"object"); exit(2); } if (redir) addobj(REDIR_O); setenv("APPEND", new_append); i=doit(); setenv("APPEND", old_append); return i; } void setup() { register char * cp; short i, len; if (!(cp = getenv("PROGRAM"))) cp=DEFPATH; else if (strrchr(cp,'\\')) strrchr(cp,'\\')[1]='\0'; old_append = getenv("APPEND"); if (!old_append) old_append=""; new_append = strcpy(xalloc(strlen(cp)+1), cp); plen=strlen(cp); for (i = 0 ; i < sizeof paths/sizeof paths[0] ; i++) if (paths[i][0]=='~') paths[i] = strcat(strcat(strcpy(xalloc(plen+strlen(paths[i])+4), cp), paths[i]+1), ".COM"); if (cp!=DEFPATH) free(cp); 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]); free(cp); } 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; outfile = NULL; } int compile(char *, char *); int assemble(char *, char *); int doexec(char *, char **); char * set_ext(char*, char*, char*, int); int doit() { register char * cp; register uchar i; char *outf, buf[20]; int res; if(xref) close(creat(crtmp, 0600)); iuds[iud_idx++] = cpppath; for(i = res = 0 ; (i < c_as_idx) && (res == 0) ; i++) { if ( verbose && (c_as_idx > 1) ) printf("Working on: '%s'.\n",c_as[i]); cp = rindex(c_as[i], '.'); if(strcmp(cp, ".C") == 0) { outf=(keep && outfile) ? outfile : set_ext(buf, c_as[i], keepas?".AS":".O", 20); res = compile(c_as[i], outf); } else { outf=(keep && outfile) ? outfile : set_ext(buf, c_as[i], ".O", 20); res = assemble(c_as[i], outf); } } remove(tmpf1); remove(tmpf2); remove(tmpf3); if (!keep && !res && (obj_idx>1)) { if (!outfile) outfile=set_ext(buf,objs[nocrto?2:1],".COM",20); 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); } /* skip standard startoff file if desired - AM */ for (i = (nocrto?1: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; res = doexec(linker, flgs); if (reloc && !res) { flgs[0] = "-R"; flgs[1] = "-B100H"; flgs[2] = l_dot_obj; flgs[3] = outfile; flgs[4] = (char *)0; res = doexec(objto, flgs); remove(l_dot_obj); } if (c_as_idx == 1 && nfiles == 1) remove(single); } if (xref && !res) 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; res = doexec(cref, flgs); remove(crtmp); } else fprintf(stderr, "Cross reference info left in %s:\ run CREF to produce listing\n", crtmp); return res; } addobj(s) char * s; { char * cp; 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; } void error(s, a) char * s; { fprintf(stderr, s, a); stack_trace(); 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++; } } int _spawn(char *, char *, char fds[3]); int doexec(name, vec) char * name; char ** vec; { uchar len; int res; char ** pvec; char * redir[2]; FILE * cfile; char redbuf[20]; char xbuf[130]; static char fds[3] = { 0, 1, 2 }; pvec = vec; len = 0; redbuf[0] = 0; while (*pvec) len += strlen(*pvec++)+1; if (len > 124) { if(!(cfile = fopen(redname, "w"))) { perror(redname); fputs(", can't create file to pass options.\n",stderr); return 1; } len = 0; while(*vec) { len += strlen(*vec)+1; if (len > 126) { len = strlen(*vec)+1; fprintf(cfile, "\\\n"); } if (verbose) printf("%s ",*vec); fprintf(cfile, "%s ", *vec++); } fputc('\n', cfile); putchar('\n'); fclose(cfile); redir[1] = (char *)0; sprintf(redbuf, "<%s", redname); redir[0] = redbuf; vec = redir; } xbuf[0] = 0; while(*vec) strcat(strcat(xbuf, " "), *vec++); if (verbose) printf("[CC] %s %s\n", name, xbuf); res=_spawn(name, xbuf, fds); if (*redbuf) remove(redbuf+1); return res; } int assemble(s,d) char * s; char * d; { char * vec[5]; char buf[80]; uchar i; i = 0; if (optimize && !speed) vec[i++] = "-J"; if (nolocal) vec[i++] = "-X"; /* AM: put object files in the same place as their sources * maybe there should be an option controlling this * if(cp = rindex(s, ':')) * cp++; * else * cp = d; */ strcat(strcpy(buf, "-O"), d); vec[i++] = buf; vec[i++] = s; vec[i] = (char *)0; return doexec(assem, vec); } int compile(s,d) char * s; char * d; { register char * cp; uchar i, j; int res; char * vec[MAXLIST]; char cbuf[50]; for(j = 0; j < iud_idx ; j++) vec[j] = iuds[j]; vec[j++] = s; vec[j++] = tmpf1; vec[j] = (char *)0; res=doexec(cpp, vec); if (res) { fprintf(stderr,"CPP failed on '%s'.\n",s); return res; } /* AM: put object files in the same place as their sources * maybe there should be an option controlling this * 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; res=doexec(pass1, vec); if (res) { fprintf(stderr,"Pass1 failed while processing '%s'.\n",s); return res; } vec[0] = tmpf2; vec[1] = keepas && !optimize ? d : tmpf1; vec[2] = (char *)0; res=doexec(cgen, vec); if (res) { fprintf(stderr,"Code generator failed while processing '%s'.\n",s); return res; } if(keepas && !optimize) return res; cp = tmpf1; if(optimize) { i = 0; if (speed) vec[i++] = "-F"; vec[i++] = tmpf1; if (keepas) vec[i++] = d; else vec[i++] = tmpf2; vec[i] = (char *)0; res=doexec(optim, vec); if (res) { fprintf(stderr,"Optimiser failed while processing '%s'.\n",s); return res; } if (keepas) return res; cp = tmpf2; } i = 0; if (nolocal) vec[i++] = "-X"; if (optimize && !speed) vec[i++] = "-J"; vec[i++] = "-N"; vec[i++] = strcat(strcpy(tmpbuf, "-o"), d); vec[i++] = cp; vec[i] = (char *)0; res=doexec(assem, vec); if (res) fprintf(stderr,"Assembler failed while processing '%s'.\n",s); return res; } char * set_ext(char *buf, char *nm, char *ex, int len) { char *p; strncpy(buf, nm, len-strlen(ex)-2); buf[len-strlen(ex)-1]=0; p=strrchr(buf, '.'); if (p) *p=0; strcat(buf, ex); return buf; } /* printf debugging: */ typedef struct sf { struct sf * up; int iy; char * pc; } frame ; void stack_trace() { int i; frame *fp; fp=(frame *)((&i)+1); while ( (unsigned int) (fp->up)>(unsigned int) fp ) { fprintf(stderr, "Called from %04x (fp=%04x),\n", fp->pc-3, fp); fp = fp->up; } fprintf(stderr, "Called from %04x.\n", fp->pc-3); } /* end of source *****************************************************/  ================================================ FILE: msx2dist/cc_01/CC.TXT ================================================ *** CC - improved control program for HiTech-C and msx-dos2 The program cc.com executes the passes to compile a C-program with HiTech-C automatically. The c.com from Hi-Tech does the same, but cc.com has the following advantages: - cc.com does not use a batchfile and stops if a pass has failed - cc.com sets the append-variable so that your source can be in a different directory than the compiler. * How to install First you need to install MSX-DOS2. Then get the HI-TECH Z80 CP/M C Compiler from ftp://ftp.funet.fi/pub/msx/programming/c/hitech-?.pma and unpack with pmext. HiTech has been so kind to grant permission to use their C-compiler free of charge, see also http://www.htsoft.com/products/CPM.php . Unpack cc.lzh to the directory that contains the C-compiler. You should get the following files: cc.com - replacement for c.com libdos2.lib - IO-library using msx-dos2, source is in libdos.lzh vsh1.o ) variants of crt.o for vsh2.o ) - programs executing other programs vsh3.o ) see vsh.txt for details vsh.txt - text about vsh?.o redir.obj - used in a work-around for -U bug in link.com cc.txt - this text cc.c - source for cc.com vshrt.as - source for vsh?.o redir.as - source for redir.obj makefile pack.bat * Using cc You can invoke CC with: cc The following options are recognised: -C : keep the object file; do not link -CR[file] : produce cross refenerence file -O : optimise assembly code generated by CGEN with OPTIM -O : put output in -I : passed to CPP as extra search-path for include files, only works for drives, the directory where cc.com is stored is always searched via APPEND environment variable -V : verbose mode, print out commands of subprocesses -F : write symbol file -U : undefine symbol for CPP -D[=]: define symbol for CPP -S : keep assembly file; do not assemble or link -X : strip local symbols, also passed to LINK -P : define order of psect (not normally needed) -M : write map file -W : width for map file -l : pass lib.lib to LINK, order is important All options are case insensitive. files: Files with no extension get the extension ".c". Files with extension ".c" are treated as C language sourcefiles. Files with extension ".as" are treated as assembly assembly language source files. All other files are passed directly to the linker. * Environment item VSHTOP: If set, VSHTOP specifies the first page of video memory that will not be used or probed by CC. Pages 0..7 are ordinary video memory, pages 8..11 are the extended video memory. Legal values are 2..12, default is 12. Other values are silently ignored. If VSHTOP is 2, CC will not work. You can use this to protect data in higher pages. Some emulators may need vshtop=8. * Notes CC.COM uses video memory for temporary storage, so it will corrupt the contents of a ramdisk that also uses video memory. The screen will flash between the compilation steps, this is to improve reliability of reading/writing from/to video memory and should not be cause for concern. HiTech-C cannot handle large C-files. This is not a real problem; just split your program in to C-files of about 6 or 7 kB. The MAKE program by Arnold metselaar can be used with CC.com to compile only those modules that need to be recompiled. * See also: The documantation that comes with HiTech-C Documentation about the C language in general vsh.txt * Authors CC.C is based on work by HiTech and Pierre Gielen. Arnold Metselaar added the code to execute a subprogram and then continue the main program.  ================================================ FILE: msx2dist/cc_01/MAKEFILE ================================================ # makefile for a:\hitech DIST = cc_01.lzh SRC = cc.c vshrt.as redir.as makefile BIN = cc.com vsh1.o vsh2.o vsh3.o redir.obj XTRA = cc.txt vsh.txt libdos2.lib ..all : cc.com vsh1.o vsh2.o vsh3.o redir.obj cc_new.com : cc.o vsh2.o libdos2.lib cc -Occ_new.com -R -Mcc.map -N vsh2.o cc.o libdos2.lib cc.o : cc.c cc -c -o -v cc vsh1.o : vshrt.as echo mypages equ 1 > mypages.as zas -N -Ovsh1.o vshrt.as :del mypages.as vsh2.o : vshrt.as echo mypages equ 2 > mypages.as zas -N -Ovsh2.o vshrt.as :del mypages.as vsh3.o : vshrt.as echo mypages equ 3 > mypages.as zas -N -Ovsh3.o vshrt.as :del mypages.as redir.obj : redir.as zas -N -Oredir.obj redir.as distribution : $(DIST) $(DIST) : $(SRC) $(BIN) $(XTRA) echo del $(DIST) > pack.bat xargs >>pack.bat < pages ld sp,mypages * 4000h ; the rest is standard ld de,__Lbss ;Start of BSS segment scf ;set carry ld hl,__Hbss sbc hl,de ;-1 ld c,l ld b,h 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 push hl ld hl,(__argc_) push hl call _main push hl call _exit jp 0 psect data nularg: defb 0 psect text noram: ld de,noramm ld hl,0DEh ; .NORAM push hl jr 1f nodos2: ld de,nodos2m ld hl,085h ; .BADVER push hl 1: ld c,9 ; _STROUT call bDos jp _exit psect data noramm: defm '*** Not enough memory; need 48KiB in TPA' defb 13,10,'$' nodos2m: defm '*** Wrong version of MSX-DOS' defb 13,10,'$' ;De onderstaande code is gebaseerd op code uit MCCM 65, pp 12--15 ;ipv MemMan wordt echter video RAM (en evt EXT. RAM) gebruikt ; int _spawn (char * program, char *args, char fds[3]) psect text __spawn: global csv, cret, indir, __spawn, _errno call csv ld e,(ix+6) ld d,(ix+7) ; program push ix ld bc,0640h ; _FFIRST, attr hidden/system ld ix,80h call bDos ; DOS2 jr z,1f pop ix ld (_errno),a ld hl,-1 jp cret 1: ld a,(ix+25) ; drive nr. add a,'A'-1 ld hl,mypages*4000h ld (hl),a inc hl ld (hl),':' inc hl ld (hl),'\' inc hl ex de,hl ld c,5Eh ; _WPATH call bDos ; DOS2 dec de dec de dec de ld hl, program ld c,6Ch ; _SENV call bDos ; DOS2 pop ix ld hl,81h ld (hl),' ' inc hl ex de,hl ld l,(ix+8) ld h,(ix+9) ; args ld bc,7eh 12: ld a,(hl) ldi jp po, 11f or a jr nz, 12b 11: dec de xor a ld (de),a ld a,e sub 81h ld (80h),a ld (lenp),a ld de,81h ld hl,param ld c,6Ch ; _SENV call bDos ; DOS2 psect data program: defm 'PROGRAM' defb 0 param: defm 'PARAMETERS' defb 0 psect text call is_vsh ; is de vshell opgezet ? call nz, setvsh ; zo niet neerzetten, ; vshell is nu opgezet en iy is exitcode - 9 ld c,60h ; _FORK call bDos jr z,2f 1: ld (_errno),a ld hl,-1 jp cret 2: ld a,b ld (ppidp),a ; The handles in fds[] are used for the stdin/stdout/stderr of the program we ; start, works only if these handles are inheritable! ld (ixp),ix ld l,(ix+10) ld h,(ix+11) ; fds xor a 4: cp (hl) ld b,a jr z,5f push af ld c,45h ; _CLOSE push hl call bDos pop hl ld b,(hl) ld c,47h ; _DUP push hl call bDos pop hl ld e,a pop af 5: cp b jr nz,reopen_err inc hl inc a cp 3 jr c,4b ld c,43h ; _OPEN ld de,mypages * 4000h ld a,1 ; no write call bDos jr nz,open_err ; unlikely, file is known to exist ; handle in b ld c,mypages ; # pages ld de,vramcode ld hl,(6) inc hl inc hl inc hl call indir ; do_push, only returns on faillure ; jr c, novram novram: ld e,0DEh reopen_err: ld a,e open_err: ld (_errno),a ld bc,(ppidp-1) ; pid in b ld c,061h ; _JOIN call bDos ; DOS2 ld ix,(ixp) ld hl,-1 jp cret psect text ; kijkt of de exitcode in het geheugen staat ; UIT: Z vlag aan -> de code staat er, iy = exitcode-9 ; Z vlag uit -> de code staat er niet, iy ongewijzigd is_vsh: ld hl,(6) ld l, .low. (magic-exitcode+9) ; jp nn en jr do_push overslaan ld de,magic ld b,3 2: ld a,(de) cp (hl) ret nz ; vshell niet aanwezig inc hl inc de djnz 2b ld l,0 push hl pop iy ret ; zet de code voor een shell aan de top van het TPA ; UIT: iy - adres kopie exitcode - 9 setvsh: ; look for VSHTOP in environment ; if it exists, stop testing for videomemory pages at its value psect data vshtopn: defm 'VSHTOP' defb 0 psect bss vshtopv: defs 4 psect text ld hl, vshtopn ld de, vshtopv ld bc,046Bh ; 4 bytes buffer space, _GENV call bDos ; DOS2 jr nz,3f ; too long push de global _atoi call _atoi pop de ld a,h or a jr nz,3f ; way too high ld a,l cp 12 jr nc,3f ; too high cp 2 jr c,3f ; too small add a,070q ld (topp),a 3: ld hl,6 ld a,(0fcc1h) ; exptbl : slotadres bios call 0Ch ; RDSLT ld (vdprd_),a ; poortnr lezen Vram/Xram inc hl ld a,(0fcc1h) ; exptbl : slotadres bios call 0Ch ; RDSLT inc a ld (vdpcmd_),a ; poortnr vdp commando's ; turn off interrupts while working with jump addresses and the vdp di ld a,(0007h) ld h,a dec a ld (0007h),a ; msB nieuwe top van TPA ld d,a ld bc,09h ld l,b ld e,b push de pop iy ldir ; negen bytes vanaf oude top van TPA ld hl,exitcode ld bc,lenexit ldir ; eigen exitcode kopieren push de ld bc,setvdpoff-lenexit-exitcode ex de,hl add hl,bc ; positie kopie setvdpoff ex de,hl ; naar de ld hl,setoff0+1-setvdpoff add hl,de 12: ld c,(hl) ld (hl),e inc hl ld b,(hl) ld (hl),d add hl,bc jr nc, 12b pop de ld bc,setvdpon-lenexit-exitcode ex de,hl add hl,bc ; positie kopie setvdpon ex de,hl ; naar de ld hl,seton0+1-setvdpon add hl,de 13: ld c,(hl) ld (hl),e inc hl ld b,(hl) ld (hl),d add hl,bc jr nc, 13b ld hl,(0001); pointer naar BIOS-Jump vector inc l ; skip c3h, l wordt 4 ld c,(hl) ld (iy+old_wb),c ld (hl), .low. (new_wb-exitcode+9); nieuwe pos. exitcode inc l ld b,(hl) ld (iy+old_wb+1),b ld (hl),a ; bevat nog steeds msB nieuwe top TPA ; tel het video geheugen ld a,071q 2: call vramtest jr nz, 1f inc a cp 104q topp equ $-1 jr nz,2b 1: ld (iy+top),a ld (iy+shsp),a ld de,0 jp setvdpon ; adresregisters vdp terugzetten, scherm aan vramtest: ld d,a ld e,0 ; lezen call setvdpoff ld c,(iy+vdprd) in l,(c) ld e,40h ; schrijven in h,(c) call setvdpoff dec c ld a,l cpl out (c),a ld a,h cpl out (c),a ld e,0 ; lezen call setvdpoff ld c,(iy+vdprd) in a,(c) cpl sub l ld b,a in a,(c) cpl sub h or b ld e,40h ; schrijven call setvdpoff dec bc ; dec c verandert F, daarom dec bc out (c),l ld a,d out (c),h ret global __cpm_clean __cpm_clean: call is_vsh ret nz ; geen vshell, dan niks weg te halen ld a,(iy+top) cp (iy+shsp) ret nz ; iets op de stack, dan vshell laten staan ; nu hebben we dus iets op te ruimen... di ld hl,0007h inc (hl) ld hl,(0001h) inc l ld a,(iy+old_wb) ld (hl),a inc l ld a,(iy+old_wb+1) ld (hl),a ei ret ; =========================================================================== ; ==== code die in het videogeheugen wordt opgeslagen en door de ==== ; ==== exitcode vlak onder de exitcode wordt in geladen en uitgevoerd ==== ; =========================================================================== vramcode: ; herstel slotselectie en mapper registers ; --- enaslt equ 024h ld a, 08Bh ; slotadres van mapper, wordt overschreven ramsltp equ $-1 push af ld h, 0 call enaslt ld a,3 ; segment in page 0, wordt overschreven map0p equ $-1 call 03050h ; adres van put_p0 komt hier putp0p equ $-2 pop af push af ld h, 40h call enaslt ld a,2 ; segment in page 1, wordt overschreven map1p equ $-1 call 03150h ; adres van put_p1 komt hier putp1p equ $-2 pop af ld h, 80h call enaslt ld a,1 ; segment in page 2, wordt overschreven map2p equ $-1 call 03250h ; adres van put_p2 komt hier putp2p equ $-2 ; lees de inhoud van de eigen pagina's terug ; --- ld a,mypages ld d,(iy+shsp) ld e,3Fh ld hl,100h jr rdblk pglus: call setvdpoff ; e is 0 again -> read ; page 0 has been restored by the time we get here ld e,40h rdblk: ld c,(iy+vdprd) ld b,0 inir dec e jr nz,rdblk inc d dec a jr nz,pglus ld (iy+shsp),d ld d,e ; de wordt 0 call setvdpon ; vdp adresregisters terugzetten, scherm aan ei ld b,1 ; ppid, wordt overschreven ppidp equ $-1 ld ix, 05849h ; ix, wordt overschreven ixp equ $-2 ; -- this part can also be executed while still in page 0 spwnret: ld c,61h ; _JOIN ld a,b ; ppid or a call nz,5 ; DOS2 ld a,b ; primary error code or a ld l,b jr nz,errset ld a,(80h) ; try value at, 80h if none given via DOS cp 04Fh ; old value of (80h), will be filled in by _spawn() lenp equ $-1 jr z,errset ; probably not set by program ld l,a errset: xor a ld h,a jp cret lenvram equ $-vramcode ; =========================================================================== ; ==== code die naar de bovenkant van het TPA in page 3 gekopieerd wordt ==== ; =========================================================================== psect text exitcode: ; --> xx09h jr do_push magic: ; ..b defm 'vsh' jump: defb 0C3h ; jp data: ; ..f defw 0 ; overschreven door hoofdprog. defb 0104q, 0104q vdprd_: defb 98h vdpcmd_: defb 99h old_wb equ data-exitcode+9 shsp equ old_wb+2 top equ shsp+1 vdprd equ shsp+2 vdpcmd equ shsp+3 new_wb: ; --> xx15h ld hl,(0006h) ld l,0 push hl pop iy ld d,(iy+shsp) ld a,(iy+top) cp d jr nz, do_pop ld l, .low. (jump-exitcode+9) jp (hl) do_pop: dec h ld sp,hl di ld e,0 ; lezen in vram, pagenr. in d setoff0:call setoff2-setoff0-1 ; offset naar volgende plek waar het adres ; van de kopie van setvdpoff moet worden ; ingevuld ld c,(iy+vdprd) ld b,0 inir dec h jp (hl) ; bewaart het werkgeheugen in video geheugen en laadt en runt dan ; het programma waarvan de filehandle in D staat. ; Return via new_wb. De stackpointer wordt niet bewaard omdat ; deze toch al wordt hersteld bij een jp cret ; ; IN: ; (sp) - return adres indien vram vol ; iy - adres exitcode -9 ; de - adres van terugkeercode, wordt door new_wb geladen op iy-100h ; en daar uitgevoerd ; b - filehandle voor _READ ; c - aantal pages om op te slaan do_push: ld a,(iy+shsp) sub c cp 071q ret c ; not enough space mem_ok: di ld sp,iy ; switch to new stack push bc ; handle, #pages ld (iy+shsp),a ex de,hl ld d,a ld a,c ; #pages ld e,40h ; schrijven setoff2:call setoff3-setoff2-1 ; nog een stap verder ... dec c ; vdpwr ld b,0 otir ; store 100h bytes with code to restore calling program in vram ld hl,100h ; TPA starts at 100h jr blkdone wpglus: inc d ld e,40h ; schrijven, 40h maal 100h bytes setoff3:call -1 ; de laatste stap dec c wrblk: ld b,0 otir blkdone: dec e jr nz,wrblk dec a jr nz,wpglus ld d,e ; e=0; adresregisters goed te zetten seton0: call -1 ; add hl,-1 geeft carry -> stoppen met invullen ei pop bc ; file handle in b push de ; 0: return adres voor het te laden programma ld de,100h push de ; save load address as start adress push bc ld hl,-500h ; keep at least 1KiB space for stack add hl,sp ld c,48h ; _READ call bDos jp nz,0 ; als het fout gaat, return via new_wb pop bc ld c,45h ; _CLOSE call bDos ld a,1 ld (37h),a ; set load flag; PROGRAM and PARAMETERS set in _spawn ret ; to 100h ; stelt vdp in voor lezen of schrijven ; IN - d= 0xyz octaal ; x=1: external ram, x=0: video ram ; z = bit 17..15 van adres (bit 14..0 zijn nul) ; - e=0h: lezen, e=40h: schrijven, ; - iy = exitcode-9 ; OUT - c=vdp write-adr+1 ; WIJZIGT: bc, af' setvdpon: ex af,af' ld a,(RG1SAV) defb 01h ; ld bc, setvdpoff: ex af,af' ; 0x..08 xor a ; +0xaf.. ld c,(iy+vdpcmd) out (c),a ld a,81h out (c),a ; schrijf reg 1: scherm aan/uit rrca ; a wordt 0300q and d ; a wordt 0100q (ext. ram) of 0 (norm. vram) out (c),a ld a,80h+45 out (c),a ; reg. 45 schrijven ld a,7 and d out (c),a ld a,80h+14 out (c),a ; reg. 14 schrijven xor a out (c),a out (c),e ; stel adres en mode in ex af,af' ret lenexit equ $-exitcode ; ===== eind van gekopieerde code RG1SAV equ 0F3E0h end start  ================================================ FILE: msx2dist/ldos2_04/ACT_FILE.AS ================================================ global __act_file global ncsv, cret, indir, bDos global __flip global amod global _errno, cret psect text ; int _act_file(char * name, short mode, short bc) __act_file: call ncsv defw -67 ld hl,67 push hl ld l,(ix+6) ld h,(ix+7) push hl push ix pop de ld hl,-67 add hl,de push hl call __flip pop bc pop bc pop bc ld a,l or h jp nz,l2 L2: ld hl,-1 jp cret l2: ; #asm global _errno, cret push ix pop hl ld de,-67 add hl,de ex de,hl ; ld a, (ix+8) ld c, (ix+8) ld b,0 ; 8 bits is enough ld hl, modtab add hl,bc ld a,(hl) psect data modtab: defb 1,2,0,3,5,6,4,7, 10h ; translate mode to dos2 conventions psect text ld c, (ix+10) ; bdos function code ld b, (ix+11) ; attributes (for create) ld l,b ; attributes (for chmod) call bDos jr z,1f ld (_errno),a xor a ld (_errno+1),a ld hl,-1 jp cret ; return -1 1: ld hl,0 ld a,(ix+10) ; function code cp 45h jp nc,cret ; return 0 (success) if called by chmod, unlink or rmdir ld l,b ; file handle/descriptor, called by open, creat or mkdir ; #endasm jp cret  ================================================ FILE: msx2dist/ldos2_04/ASSERT.C ================================================ #include #include void _fassert(line, file, exp) char * file, * exp; int line; { fprintf(stderr, "Assertion failed: %s line %d: \"%s\"\n", file, line, exp); abort(); }  ================================================ FILE: msx2dist/ldos2_04/BUF.C ================================================ #include extern char * sbrk(); static union stdbuf { char bufarea[BUFSIZ]; union stdbuf * link; } * freep; char * _bufallo() { register union stdbuf * pp; if(pp = freep) freep = pp->link; else pp = (union stdbuf *)sbrk(BUFSIZ); return pp->bufarea; } _buffree(pp) char * pp; { register union stdbuf * up; up = (union stdbuf *)pp; up->link = freep; freep = up; }  ================================================ FILE: msx2dist/ldos2_04/CGETS.C ================================================ extern int getche(); char * cgets(s) char * s; { char * s1 = s; int c; while((c = getche()) != '\r' && c != '\n') *s++ = c; *s = 0; if(s == s1) return((char *)0); return(s1); }  ================================================ FILE: msx2dist/ldos2_04/CHANGES ================================================ 2013-08-10 Arnold Metselaar (arnold.metselaar@planet.nl) * Include makefile in package. * rename.c: set C register before calling bDos * stat.c: new file * perror.c: slight changes so that we can ... * makefile (stat.c, perror.c, rename.c): ... use optim * stat.h: new file * dirent.h: declare rmdir and mkdir *@utime.c, _utime.as: new files 2006-08-29 Arnold Metselaar (arnold.metselaar@planet.nl) * unixio.h: Added to distribution, define O_INHER and friends. * libdos2.txt: explain constants for open(). 2006-04-15 Arnold Metselaar (arnold.metselaar@planet.nl) * readdir.as: Fully support "." as a shorthand for the current directory, allow to open root directories. 2006-04-15 Arnold Metselaar (arnold.metselaar@planet.nl) * flip.c: Removed and replaced by ... * flip.as: new file. * rmdir.c: New file. * mkdir.c: New file. * dirent.h: New file. * opendir.as: New file. * readdir.as: New file. * closedir.as: New file. * rewnddir.as: New file. * lib.cmd: Removed. * makefile (libdos2.lib): Use a here-document with smart substitutions instead of lib.cmd. * makefile (unlink.obj): enable optimiser. * makefile: Added new files, some reordering. * libdos2.txt: Added documentation for new functions. 2006-04-14 Arnold Metselaar (arnold.metselaar@planet.nl) * libdos2.txt: added a remark about libc.lib still being needed. 2006-01-29 Arnold Metselaar (arnold.metselaar@planet.nl) * doprnt.c(ival, doprnt): Use unsigned int for string lengths, this fixes errors when printing long strings (make.com) * time.c, ctime.c: No longer in libdos2; both work under msxdos1 and are still available as part of the patched libc.lib. * lib.cmd: time.obj and ctime.obj removed. * makefile: Simplified using new features in make. * pack.bat: Removed from the package, generated on demand by make.  ================================================ FILE: msx2dist/ldos2_04/CHDIR.C ================================================ /* * file: chdir.c * author Arnold Metselaar */ int _act_file(char * name, short mode, short bc); int chdir(char * pad) { return _act_file(pad, 0, 0x0059); }  ================================================ FILE: msx2dist/ldos2_04/CHMOD.C ================================================ #include extern int errno; extern int _act_file(char*, short, short); chmod(name, mode) register char * name; { int bc; bc=0x50; if ((mode & S_IWRITE) == 0) bc|=0x100; if (mode & S_HIDDEN) bc|=0x200; if (mode & S_SYSTEM) bc|=0x400; if (mode & S_ARCHIVE) bc|=0x2000; return _act_file (name, 0, bc); }  ================================================ FILE: msx2dist/ldos2_04/CLOSE.C ================================================ #include "cpm.h" close(fd) int fd; { #asm global _errno, cret, bDos ld c,045h ld b,(ix+6) ; fd call bDos ld hl,0 jp z, cret dec hl ld (_errno),a xor a ld (_errno+1),a #endasm /* implicit return hl; */ }  ================================================ FILE: msx2dist/ldos2_04/CLOSEDIR.AS ================================================ ; closedir.as ; int closedir (DIR * dir) ; { ; free(dir); ; return 0; ; } global _closedir global _free psect text _closedir: pop hl pop de ; dir push de push hl push de call _free pop de ld hl,0 ret  ================================================ FILE: msx2dist/ldos2_04/CPUTS.C ================================================ cputs(s) register char * s; { while(*s) putch(*s++); }  ================================================ FILE: msx2dist/ldos2_04/CREAT.C ================================================ /* * creat(name, mode) * * creates a file with the given name, and opens it for reading and writing * mode: ignored * */ extern int _act_file(char*, int, int); creat(name, mode) char * name; { return _act_file(name, 2, 0x0044); }  ================================================ FILE: msx2dist/ldos2_04/DIRENT.H ================================================ /* dirent.h */ /* Declarations for directory access in libdos2. */ #define NAME_MAX 12 struct dirent /* A dos2 file information block. */ { char d_valid; char d_name[NAME_MAX+1]; char d_attribute; unsigned short int d_mtime; unsigned short int d_mdate; unsigned short int d_cluster; unsigned long int d_size; char d_drive; char d_private[64-26]; /* for use by dos2, do not change */ } ; struct _dir { struct dirent dir_dir; struct dirent dir_file; } ; typedef struct _dir DIR; extern DIR * opendir (char * name); extern struct dirent * readdir (DIR * dir); extern int closedir (DIR * dir); extern void rewinddir (DIR * dir); extern int mkdir (char *); extern int rmdir (char *);  ================================================ FILE: msx2dist/ldos2_04/DOPRNT.C ================================================ #include #include #include /* * doprnt for Z80 */ extern int atoi(char *); extern int _pnum(); /* Routines for formatted output must be able to cope with strings longer than 255 bytes. - Arnold M */ static unsigned int ival; static char * x; static FILE * ffile; static pputc(c) char c; { putc(c, ffile); } static char * icvt(cp) register char * cp; { ival = atoi(cp); while(isdigit((unsigned)*cp)) cp++; return cp; } _doprnt(file, f, a) FILE * file; register char * f; int * a; { char c; uchar fill, left; unsigned int i, prec, width; /* Allow for long strings. - Arnold M */ uchar base, sign, len; ffile = file; while(c = *f++) if(c != '%') pputc(c); else { base = 10; width = 0; sign = 0; left = 0; len = sizeof(int)/sizeof *a; if(*f == '-') { f++; left++; } fill = *f == '0'; if(isdigit((unsigned)*f)) { f = icvt(f); width = ival; } else if(*f == '*') { width = *a++; f++; } if(*f == '.') if(*++f == '*') { prec = *a++; f++; } else { f = icvt(f); prec = ival; } else prec = fill ? width : 0; if(*f == 'l') { f++; len = sizeof(long)/sizeof *a; } switch(c = *f++) { case 0: return; case 'o': base = 8; break; case 'd': sign = 1; break; case 'x': sign = 1; /* a-f in lower case */ case 'X': base = 16; break; case 's': x = *(char **)a; a += sizeof(char *)/sizeof *a; if(!x) x = "(null)"; i = strlen(x); dostring: if(prec && prec < i) i = prec; if(width > i) width -= i; else width = 0; if(!left) while(width--) pputc(' '); while(i--) pputc(*x++); if(left) while(width--) pputc(' '); continue; case 'c': c = *a++; default: x = &c; i = 1; goto dostring; case 'u': break; } if(left) { left = width; width = 0; } width = _pnum((len == sizeof(int)/sizeof *a ? (sign ? (long)*a : (unsigned long)*a) : *(long *)a), prec, width, sign, base, pputc); a += len; while(left-- > width) pputc(' '); } }  ================================================ FILE: msx2dist/ldos2_04/DOSCAN.C ================================================ /* * _doscan - implement scanf, fscanf, sscanf */ #include #include extern int atoi(); static FILE * fp; static range(c, base) int c; uchar base; { if(isdigit(c)) c -= '0'; else { if (isupper(c)) c = tolower(c) ; if (isalpha(c)) c = c - 'a' + 10 ; else return -1 ; } if (c >= base) return -1 ; return c ; } static wspace() { int c; while(isspace(c = getc(fp))) continue; if(c != EOF) ungetc(c, fp); } _doscan(file, fmt, args) FILE * file; register char * fmt; int ** args; { uchar c, sign, base, n, noass,len; char width ; char * sptr; int ch; long val; fp = file; n = 0; while(c = *fmt++) { len = 0 ; if(isspace(c)) { wspace(); continue; } if(c == '%') { noass = 0; width = 0; loop: switch(c = *fmt++) { case '\0': return n ? n : feof(fp) ? EOF : 0; case '*': noass++; goto loop; case 'l': len++; case 'h': goto loop; case 'D': len++; case 'd': base = 10; break; case 'O': len++; case 'o': base = 8; break; case 'X': len++; case 'x': base = 16; break ; case 's': wspace(); if ( !noass ) sptr = (char *)*args++; if ((ch = getc(fp)) == EOF ) return n ? n : EOF; while(ch && ch != EOF && !isspace(ch)) { if(ch == *fmt) { fmt++; break; } if ( !noass ) *sptr++ = ch; if(--width == 0) break; ch = getc(fp); } n++; if ( !noass ) *sptr = 0; continue; case 'c': if ( !noass ) sptr = (char *)*args++; do { if ((ch = getc(fp)) == EOF) return n ? n : EOF; if ( !noass ) *sptr++ = ch; } while(--width > 0); n++; continue; default: if(isdigit(c)) { width = atoi(fmt-1); while(isdigit(*fmt)) fmt++; goto loop; } if(c != (ch = getc(fp))) if(ch == EOF) return n ? n : EOF; else { ungetc(ch, fp); return n; } continue; } wspace(); val = 0; sign = 0; ch = getc(fp); if(ch == '-') { sign++; ch = getc(fp); } if(range(ch, base) == -1) return n ? n : feof(fp) ? EOF : 0; do { val = val * base + range(ch, base); } while (( --width != 0 ) && ( range(ch = getc(fp),base) != -1 )) ; n++; if (range(ch,base) == -1) ungetc(ch, fp); if(sign) val = -val; if ( !noass ) if(len) *(long *)*args++ = val; else **args++ = val; continue; } else if(c != (ch = getc(fp))) { if(ch != EOF) { ungetc(ch, fp); return n; } else return n ? n : EOF; } } return n; }  ================================================ FILE: msx2dist/ldos2_04/DUP.C ================================================ /* Duplicate file descriptor */ dup(fd) int fd; { #asm global _errno, bDos ld c,047h ; _DUP ld b,(ix+6) ; fd call bDos jr z,1f ld (_errno), a xor a ld (_errno+1),a 1: ld l,b rl b sbc a,a ld h,a #endasm /* implicit return hl; */ }  ================================================ FILE: msx2dist/ldos2_04/ERRNO.C ================================================ int errno;  ================================================ FILE: msx2dist/ldos2_04/EXIT.AS ================================================ global _exit, __cpm_clean, bDos psect text _exit: call __cpm_clean pop hl ; return address pop hl ; exit status ld (80h),hl ;store exit status ld b,l ld c,062h ; _TERM call bDos ; should not return jp 0 ; Warm boot CP/M  ================================================ FILE: msx2dist/ldos2_04/FAKECPCL.AS ================================================ global __cpm_clean psect text __cpm_clean: ret  ================================================ FILE: msx2dist/ldos2_04/FCLOSE.C ================================================ /* * fclose - for CP/M stdio */ #include extern int close(int); fclose(f) register FILE * f; { if(!(f->_flag & (_IOREAD|_IOWRT))) return(EOF); fflush(f); f->_flag &= ~(_IOREAD|_IOWRT|_IONBF); if(f->_base && !(f->_flag & _IOMYBUF)) { _buffree(f->_base); f->_base = (char *)NULL; } if(close(fileno(f)) == -1 || f->_flag & _IOERR) return EOF; else return 0; }  ================================================ FILE: msx2dist/ldos2_04/FFLUSH.C ================================================ /* * fflush for Zios stdio */ #include extern int write(int, void *, int); fflush(f) register FILE * f; { unsigned cnt; if(!(f->_flag & _IOWRT) || f->_base == (char *)NULL || (cnt = BUFSIZ - f->_cnt) == 0) return 0; if(write(fileno(f), f->_base, cnt) != cnt) f->_flag |= _IOERR; f->_cnt = BUFSIZ; f->_ptr = f->_base; if(f->_flag & _IOERR) return(EOF); return 0; }  ================================================ FILE: msx2dist/ldos2_04/FGETC.AS ================================================ ; /* ; * fgetc for Zios stdio ; */ ; ; #include ; ; #define CPMEOF 032 /* ctrl-Z */ ; ; fgetc(f) ; register FILE * f; ; { ; int c; ; ; if(f->_flag & _IOEOF || !(f->_flag & _IOREAD)) { ; reteof: ; f->_flag |= _IOEOF; ; return EOF; ; } ; loop: ; if(f->_cnt > 0) { ; c = (unsigned)*f->_ptr++; ; f->_cnt--; ; } else if(f->_flag & _IOSTRG) ; goto reteof; ; else ; c = _filbuf(f); ; if(f->_flag & _IOBINARY) ; return c; ; if(c == '\r') ; goto loop; ; if(c == CPMEOF) { ; f->_cnt++; ; f->_ptr--; ; goto reteof; ; } ; return c; ; } ; The assembler version of the above routine *Include stdio.i global _fgetc, __filbuf psect text _fgetc: pop de ;get return address off stack ex (sp),iy ;save iy and get arguement into iy ld a,(iy+flag) ;get flag bits bit _IOREAD_BIT,a jr z,reteof ;return EOF if not open for read bit _IOEOF_BIT,a ;Already seen EOF? jr nz,reteof ;yes, repeat ourselves loop: ld l,(iy+cnt) ld h,(iy+cnt+1) ld a,l or h ;any bytes left? jr z,1f ;no, go get some more dec hl ld (iy+cnt),l ;update count ld (iy+cnt+1),h ld l,(iy+ptr) ;get the pointer ld h,(iy+ptr+1) ld a,(hl) inc hl ld (iy+ptr),l ;update pointer ld (iy+ptr+1),h 2: bit _IOBINARY_BIT,(iy+flag) ;Binary mode? jr z,3f ;no, check for EOF etc retch: ld l,a ;return the character in a ld h,0 ex (sp),iy ;restore iy push de ;put return address back ret ;with char in hl 3: cp RETURN ;carriage return jr z,loop ;yes, get another instead cp CPMEOF ;end of file? jr nz,retch ;no, return it! ld a,(iy+base) ;buffered? or (iy+base+1) jr z,reteof ;yup, leave count alone ld l,(iy+cnt) ld h,(iy+cnt+1) inc hl ;reset count ld (iy+cnt),l ld (iy+cnt+1),h ld l,(iy+ptr) ld h,(iy+ptr+1) dec hl ;reset pointer ld (iy+ptr),l ld (iy+ptr+1),h reteof: set _IOEOF_BIT,(iy+flag) ;note EOF ld hl,EOF ex (sp),iy ;restore iy push de ret ;return with EOF in hl 1: bit _IOSTRG_BIT,(iy+flag) ;end of string? jr nz,reteof ;yes, return EOF push de ;save de push iy ;pass iy as argument call __filbuf ;refill the buffer ld a,l ;the returned value pop bc pop de ;return address in de again bit 7,h jr nz,reteof ;returned EOF jr 2b  ================================================ FILE: msx2dist/ldos2_04/FILBUF.C ================================================ /* * _filbuf for Zios stdio */ extern int read(int, void *, int); #include _filbuf(f) register FILE * f; { f->_cnt = 0; if(!(f->_flag & _IOREAD)) return(EOF); if(f->_base == (char *)NULL) { uchar c; f->_cnt = 0; if(read(fileno(f), &c, 1) == 1) return(c); f->_flag |= _IOEOF; return(EOF); } if((f->_cnt = read(fileno(f), f->_base, BUFSIZ)) <= 0) { if(f->_cnt == 0) f->_flag |= _IOEOF; else f->_flag |= _IOERR; return(EOF); } f->_ptr = f->_base; f->_cnt--; return((unsigned)*f->_ptr++); }  ================================================ FILE: msx2dist/ldos2_04/FLSBUF.C ================================================ /* * _flsbuf for Zios stdio */ #include extern int write(int, void *, int); _flsbuf(c, f) register FILE * f; uchar c; { if(f->_flag & _IOWRT) { if(f->_base == (char *)NULL) { f->_cnt = 0; if(write(fileno(f), &c, 1) == 1) return(c); f->_flag |= _IOERR; return(EOF); } if(write(fileno(f), f->_base, BUFSIZ) != BUFSIZ) f->_flag |= _IOERR; f->_cnt = BUFSIZ-1; *f->_base = c; f->_ptr = f->_base+1; } else { f->_flag |= _IOERR; f->_cnt = 0; } if(f->_flag & _IOERR) return(EOF); return(c); }  ================================================ FILE: msx2dist/ldos2_04/FOPEN.C ================================================ /* * fopen.c - stdio fopen */ #include FILE * fopen(name, mode) char * name, * mode; { register FILE * f; for(f = _iob ; f != &_iob[_NFILE] ; f++) if(!(f->_flag & (_IOREAD|_IOWRT))) break; if(f == &_iob[_NFILE]) return((FILE *)NULL); return freopen(name, mode, f); }  ================================================ FILE: msx2dist/ldos2_04/FPRINTF.C ================================================ #include extern int _doprnt(); fprintf(file, f, a) FILE * file; char * f; int a; { return(_doprnt(file, f, &a)); }  ================================================ FILE: msx2dist/ldos2_04/FREAD.C ================================================ #include /* * fread for Zios */ fread(buf, size, nitems, stream) void * buf; register FILE * stream; unsigned size, nitems; { register char * ptr; register unsigned count; short c; count = size * nitems; ptr = buf; while(count) if((c = getc(stream)) == EOF) break; else { --count; *ptr++ = c; } return(nitems - (count+size-1)/size); }  ================================================ FILE: msx2dist/ldos2_04/FREOPEN.C ================================================ /* * freopen.c - stdio freopen */ #include extern int open(char *, int), creat(char *, int); FILE * freopen(name, mode, iob) char * name, * mode; register FILE * iob; { uchar c; fclose(iob); c = 0; iob->_flag &= _IONBF; switch(*mode) { case 'w': c++; case 'a': c++; case 'r': if(mode[1] == 'b') iob->_flag = _IOBINARY; break; } switch(c) { case 0: iob->_file = open(name, 0); break; case 1: if((iob->_file = open(name, 1)) >= 0) break; /* else fall through */ case 2: iob->_file = creat(name, 0666); break; } if(iob->_file < 0) return (FILE *)NULL; if(!(iob->_flag & (_IONBF|_IOMYBUF))) iob->_base = _bufallo(); if(iob->_base == (char *)-1) { iob->_base = (char *)0; close(iob->_file); iob->_flag = 0; return (FILE *)NULL; } iob->_ptr = iob->_base; iob->_cnt = 0; if(c) iob->_flag |= _IOWRT; else iob->_flag |= _IOREAD; if(iob->_base && c) iob->_cnt = BUFSIZ; if(c == 1) fseek(iob, 0L, 2); return iob; }  ================================================ FILE: msx2dist/ldos2_04/FSCANF.C ================================================ /* * Stdio fscanf */ #include extern int _doscan(); fscanf(file, fmt, args) FILE * file; char * fmt; int args; { return _doscan(file, fmt, &args); }  ================================================ FILE: msx2dist/ldos2_04/FSEEK.C ================================================ #include extern long lseek(int, long, int), ftell(FILE *); fseek(f, offs, ptr) register FILE * f; long offs; int ptr; { return lseek(fileno(f), offs, ptr); } long ftell(FILE * f) { return lseek(fileno(f),0L,1); }  ================================================ FILE: msx2dist/ldos2_04/FWRITE.C ================================================ #include /* * fwrite */ fwrite(buf, size, nitems, stream) void * buf; register FILE * stream; unsigned size, nitems; { register unsigned count; register char * ptr; count = size * nitems; ptr = buf; while(count) if(putc(*ptr++, stream) == EOF) break; else --count; return(nitems - (count+size-1)/size); }  ================================================ FILE: msx2dist/ldos2_04/GETARGS.C ================================================ /* * _getargs(str, name) - process string into argument buffer. * * If str is null, read lines from standard input instead, using name as a * prompt. * Continuation lines are recognized by a \ as the last character on the * line. * * The redirections recognized are: * * > >> < * * Redirections of the form >& and >>& are not yet supported. * Note that the >> redirections depend on fseek working correctly * on text files, when seeking relative to the end of the file. * * Wildcards (? and *) are expanded in the usual way. * * The quotes " and ' may be used to enclose arguments which contain * white space the wild characters and > or <. * * The argument buffer is sbrk'ed and a pointer to it is returned. * The count of arguments is left in the global _argc_. The count * may also be found by counting the arguments; the last one is a null * pointer. * The zero'th argument is set to the name parameter. */ #include #include #include #include #define MAXARGS 200 /* max number of arguments */ #define MAXLEN 100 /* max length of an argument */ #define QUOTE 0x80 /* quoted bit in args */ #define isterminator(c) ((c) == 0) #define look() (*str) extern int _argc_; extern char * sbrk(); extern int isatty(int); static char * name, * str, * bp; static char interactive; static char redone[3]; static void sputs(), error(); static void redirect(); static char * alloc(); static char nxtch(); static char iswild(), isspecial(), isseparator(); extern int _glob(char *, char*); char ** _getargs(_str, _name) char * _str, * _name; { char ** argv; register char * ap; char * cp; short argc; char c, quote; unsigned short i, j; char * argbuf[MAXARGS]; char fibbuf[64]; char buf[MAXLEN]; bp = (char *)0; quote = redone[0] = redone[1] = redone[2] = 0; name = _name; str = _str; if (interactive = (str==(char *)0)) str = "\\"; argbuf[0] = name; argc = 1; /* first step - process arguments and do globbing */ while (look()) { if (argc == MAXARGS) error("too many arguments", 0); while (isseparator(c = nxtch())) continue; if (isterminator(c)) break; ap = buf; if (isspecial(c)) { *ap++ = c; if (c == '>' && look() == '>') *ap++ = nxtch(); } else { /* -- !isspecial(c) */ while (!isterminator(c) && (quote || !isspecial(c) && !isseparator(c))) { if (ap == &buf[MAXLEN]) error("argument too long", 0); if (c == quote) /* end of quoted string */ quote = 0; else if (!quote && (c == '\'' || c == '"')) quote = c; /* start of quoted string */ else { if (quote) c |= QUOTE; *ap++ = c; } if (!quote && isspecial(look())) break; c = nxtch(); } /* -- while (!isterminator(c) ... */ } /* -- else (!isspecial(c)) */ *ap = 0; if (iswild(buf)) { _flip(buf, buf, MAXLEN); cp = strrchr(buf,'\\'); if (!cp) cp=strrchr(buf,':'); if (!cp) cp=buf; else ++cp; fibbuf[0]='\0'; if ( ! _glob(buf, fibbuf) ) do { argbuf[argc]=alloc(cp-buf+strlen(fibbuf)); if (cp-buf) strncpy(argbuf[argc],buf,cp-buf); strcpy(argbuf[argc++]+(cp-buf), fibbuf+1); } while ( ! _glob(buf, fibbuf) ) ; else { perror(buf); fputc('\n', stderr); argbuf[argc++]=strcpy(alloc(strlen(buf)+1),buf); } } /* -- if (iswild(buf)) */ else { /* !iswild(buf) */ argbuf[argc++] = ap = alloc(ap-buf+1); cp = buf; do { *ap++ = *cp & ~QUOTE; } while (*cp++); } } /* -- while (look()) /* now do redirection */ for (i = j = 0 ; j < argc ; j++) if (isspecial(c = argbuf[j][0])) { if (j == argc-1) error("no name after ", argbuf[j], 0); if (c == '<') redirect("input", argbuf[j+1], "r", stdin); else { ap = argbuf[j][1] == '>' ? "a" : "w"; redirect("output", argbuf[j+1], ap, stdout); } j++; } else /* !isspecial() */ argbuf[i++] = argbuf[j]; _argc_ = i; argbuf[i++] = (char *)0; argv = (char **)alloc(i * sizeof *argv); bmove(argbuf, argv, i * sizeof *argv); return argv; } static char nxtch() { if (interactive && *str == '\\' && str[1] == 0) { if (!bp) bp = alloc(256); if (isatty(fileno(stdin))) fprintf(stderr, "%s> ", name); gets(bp); str = bp; } if (*str) return *str++; return 0; } static void error(s) char * s; { register char ** sp; sp = &s; while (*sp) sputs(*sp++); sputs("\n"); exit(-1); } static void sputs(s) register char * s; { while(*s) { if (*s == '\n') bdos(CPMWCON, '\r'); bdos(CPMWCON, *s++); } } static char * alloc(n) short n; { char * bp; if ((bp = sbrk(n)) == (char *)-1) error("no room for arguments", 0); return bp; } static void redirect(str_name, file_name, mode, stream) char * str_name, * file_name, * mode; FILE * stream; { if (redone[stream-_iob]++) error("Ambiguous ", str_name, " redirection", 0); if (freopen(file_name, mode, stream) != stream) error("Can't open ", file_name, " for ", str_name, 0); } static char iswild(buf) char * buf; { return strchr(buf, '*') || strchr(buf, '?'); } static char isspecial(c) char c; { return c == '<' || c == '>'; } static char isseparator(c) char c; { return c == ' ' || c == '\t' || c == '\n'; }  ================================================ FILE: msx2dist/ldos2_04/GETCWD.AS ================================================ ; file: getcwd.as ; author: Arnold Metselaar ; ; implements ; char * getcwd(int drive) ; drive: ; 0 - current ; 1 - A: ; 2 - B: etc. ; global _getcwd, bDos psect text _getcwd: pop hl pop de ; get arg push de push hl ; restore stack ld a,e or a jr nz, 1f ld c,19h ; get default drive call bDos inc a 1: ld b,a add a,'A'-1 ld hl,cwdbuf ld (hl),a inc hl ld (hl),':' inc hl ld (hl),'\' inc hl ex de,hl ld c,59h ; _GETCD, get current directory call bDos ld hl,cwdbuf ret psect bss cwdbuf: defs 67  ================================================ FILE: msx2dist/ldos2_04/GETENV.AS ================================================ ;string.h: 4: typedef int ptrdiff_t; ;string.h: 5: typedef unsigned size_t; ;string.h: 18: extern char * strcpy(char *, char *); ;string.h: 34: extern size_t strlen(char *); ;stdlib.h: 27: extern void * malloc(size_t); ;B:GETENV.C: 9: char * ;B:GETENV.C: 10: getenv(s) ;B:GETENV.C: 11: char * s; ;B:GETENV.C: 12: { psect text global _getenv _getenv: global ncsv, cret, indir, bDos call ncsv defw -255 ;B:GETENV.C: 13: register char *res; ;B:GETENV.C: 14: char val[255]; ld bc,0FF6Bh ; _GENV, buffersize=255 push ix pop hl ld de,-255 add hl,de ; val ld (hl),0 ; make sure val is empty if *s invalid ex de,hl ld l,(ix+6) ; s ld h,(ix+7) call bDos ; out de==val ;B:GETENV.C: 29: res= (strlen(val)==0) ? ((void *)0) : malloc(strlen(val)+1); global _strlen global _malloc push de call _strlen pop bc ld a,l or h jp z,10f push ix pop de ld hl,-255 add hl,de push hl call _strlen pop bc inc hl push hl call _malloc pop bc jp 12f 10: ld hl,0 12: ld C,l ld B,h ;B:GETENV.C: 30: return (res==((void *)0)) ? ((void *)0) : strcpy(res, val); global _strcpy ld a,l or h jp z,10f push ix pop de ld hl,-255 add hl,de push hl push bc call _strcpy pop bc jp 12f 10: ld hl,0 12: ;B:GETENV.C: 31: } jp cret  ================================================ FILE: msx2dist/ldos2_04/GETS.C ================================================ /* * gets and fgets for Zios stdio */ #include #include char * fgets(s, n, f) char * s; register FILE * f; { char * s1 = s; int c; while(n-- && (c = getc(f)) != EOF && (*s++ = c) != '\n') /* VOID */; *s = 0; if(s == s1) return((char *)NULL); return(s1); } char * gets(s) char * s; { if((s = fgets(s, -1, stdin)) == (char *)NULL) return((char *)NULL); s[strlen(s)-1] = 0; return(s); }  ================================================ FILE: msx2dist/ldos2_04/GETW.C ================================================ #include /* * Stdio getw() */ getw(stream) register FILE * stream; { short hi, lo; if((lo = getc(stream)) == EOF || (hi = getc(stream)) == EOF) return EOF; return (hi << 8) + (lo & 0xFF); }  ================================================ FILE: msx2dist/ldos2_04/ISATTY.C ================================================ isatty(f) unsigned char f; { #asm global bDos ld c,04Bh ; _IOCTL ld b,(ix+6) ; f xor a ; 0 => get file handle status call bDos ld a,080h and e rlca ld l,a xor a ld h,a #endasm /* implicit return hl; */ }  ================================================ FILE: msx2dist/ldos2_04/LIBDOS2.TXT ================================================ LIBDOS2 - IO-library for MSX-DOS2 and HiTech-C ---------------------------------------------- HiTech-C comes with a standard library (libc.lib) that does not support subdirectories and environment items under MSX-DOS2. This library (libdos2.lib) is specificly written for MSX-DOS2 and fully supports subdirectories and environment items. Obtaining LIBDOS2 Download libdos2.pma from http://banzai.msx.nu and unpack using lhext.com. The distribution contains the library (libdos2.lib), the sources (*.as, *.c) and some documentation (this file). Using LIBDOS2 To use libdos2 you must first place libdos2.lib in the directory as libc.lib and then invoke the C-compiler with the "-ldos2" option. If you want to link in the support for floating point numbers as well you must make sure libf.lib is scanned before libdos2.lib ("-lf -ldos2"). Note that libdos2.lib is not a complete C-library, you will still need some functions from libc.lib, this is not normally a concern because the compiler driver (e.g. cc.com) automatically instructs the linker to scan libc.lib. Programs linked with libdos2 will only run under MSX-DOS2. Many functions could be rewritten to work under both DOS1 and DOS2, but the DOS2-only versions are more compact. Of course you can easily make two versions of your program. Documentation Most functions are described in the documentation that comes with HiTech-C. A possibly incomplete list of differences between how libdos2 does and what the documentation says it does is below. In functions taking a filename as argument, you can use '/' as a path-separator; libdos2 will perform a substitution before passing a filename to MSX-DOS2. This substitution is also available to applications directly as int _flip(char *d, char *s, unsigned int n); Copy at most n characters from s to d, any occurence of '/' will be replaced by '\\'. The functions _getargs() and _glob() are intended for wildcard expansion in the command-line (-R option), but may be used directly as well, see glob.as and getargs.c for details. The function open() takes the same values for the mode argument as the original in libc.lib. Additionally you may take a bitwise or with O_INHER to make the handle inheritable for child processes created with the DOS2 call _FORK (0x60). The macro O_INHER is defined in unixio.h together with O_RDONLY, O_WRONLY and O_RDWR. The header file dirent.h contains declarations for some funtions to read directories. These functions comply with the POSIX standard. DIR * opendir (char * name); Open the directory with the given name for reading, returns NULL and sets errno if the operation fails, use malloc() to allocate memory. struct dirent * readdir (DIR * dir); Read one entry from directory dir, struct dirent is actually a file information block and defined in dirent.h, but if you want to write a portable program, you should only use char d_name[], a zero-terminated string with at most NAME_MAX characters before the zero. The result of readdir() will be overwritten by the next call to readdir() for the same directory. int closedir (DIR * dir); Close directory dir and release the associated storage with free(). void rewinddir (DIR * dir); Reset the pointer in directory dir, the next call to readdir() for this directory will return the first directory entry. Other functions operating on directories are declared in sys.h: int chdir (char * name); int mkdir (char * name); int getcwd (int drive); int rmdir (char * name); These functions follow the HiTech-C documentation. The functions mkdir() and getcwd() have a different calling convention than their POSIX counterparts. The getenv() function returns a pointer to a freshly malloc()'ed string rather than a pointer to static storage. It is possible to free() the pointer, but this will not be portable to other systems. Libdos2 does not provide a char ** environ. Please send bug reports, comments, suggestions for improvement etc. to Arnold Metselaar.  ================================================ FILE: msx2dist/ldos2_04/MAKEFILE ================================================ # standard IO for MSX-DOS2 ..all : libdos2.lib DIST = ldos2_04 HFILES = dirent.h unixio.h stat.h XFILES = libdos2.txt libdos2.lib changes makefile distribution : $(DIST).lzh # All object files. Ordering does matter ALLOBJ = getargs.obj start1.obj start2.obj assert.obj printf.obj fprintf.obj ALLOBJ += sprintf.obj doprnt.obj puts.obj gets.obj fwrite.obj getw.obj ALLOBJ += putchar.obj perror.obj fputc.obj flsbuf.obj fopen.obj freopen.obj ALLOBJ += rewind.obj fseek.obj fread.obj remove.obj setbuf.obj fscanf.obj ALLOBJ += cgets.obj cputs.obj scanf.obj sscanf.obj doscan.obj ungetc.obj ALLOBJ += fgetc.obj filbuf.obj stdclean.obj fclose.obj chdir.obj unlink.obj ALLOBJ += rmdir.obj fflush.obj buf.obj open.obj chmod.obj creat.obj mkdir.obj ALLOBJ += utime.obj read.obj write.obj seek.obj rename.obj isatty.obj close.obj ALLOBJ += dup.obj opendir.obj readdir.obj stat.obj act_file.obj flip.obj ALLOBJ += _utime.obj errno.obj getenv.obj setenv.obj exit.obj getcwd.obj ALLOBJ += closedir.obj rewnddir.obj fakecpcl.obj glob.obj bdos.obj # sourcefiles in C that cannot, or need not, be optimised with OPTIM # mostly due #asm - constructions : CXSRC = read.c write.c seek.c isatty.c close.c dup.c errno.c CXOBJ = $(CXSRC:.c=.obj) # assembly sourcefiles ASSRC = getenv.as setenv.as exit.as start1.as start2.as getcwd.as ASSRC += opendir.as readdir.as closedir.as rewnddir.as act_file.as ASSRC += fakecpcl.as fgetc.as glob.as flip.as _utime.as bdos.as fputc.as ASOBJ = $(ASSRC:.as=.obj) # The rest are optimizable C sources COBJ = $(ALLOBJ) COBJ -= $(ASOBJ) $(CXOBJ) CSRC = $(COBJ:.obj=.c) ..obj : $(ASOBJ) libdos2.lib : makefile $(ALLOBJ) :del libdos2.lib libr < pack.bat xargs -b >> pack.bat < ; #include ; DIR * opendir(char * name) global _opendir global ncsv, cret, __flip, _malloc, _free, bDos, _errno psect text _opendir: call ncsv defw -69 ld hl, 0 add hl,sp ld (ix-2),l ld (ix-1),h ; address to store slash-flipped name ld bc,67 push bc ld e,(ix+6) ld d,(ix+7) ; name push de push hl call __flip pop hl ; address of slash-flipped name pop bc pop bc ; "." -> getcwd (default drive) ; "x:." -> getcwd (drive x) ld b,0 inc hl ld a,(hl) cp ':' jr nz,1f dec hl ld a,(hl) and 0ffh - ('a'-'A') sub 'A'-1 ld b,a inc hl inc hl inc hl ld a,(hl) 1: or a jr nz,2f dec hl ld a,(hl) cp '.' jr nz,2f ld (hl),'\' inc hl ex de,hl ld c,059h ; _GETCD call bDos 2: ld hl, 128 ; sizeof( DIR ) push hl call _malloc pop bc push hl ld a,l or h jr z,noram ld e,(ix-2) ld d,(ix-1) ; name, flipped push de ; we need to treat a root directory in a special way: call isroot pop de ex (sp),ix ld (ix+14),10h ld bc, 1640h ; 40h : _FFIRST 16h: also hidden, system and directory call nz,bDos ; call the bDos only for non-root directories ld (ix+64),0 ; no entry read so far ld b,(ix+14) ; attribute ex (sp),ix jr nz,error ld a,b and 10h jr z, notdir pop hl jp cret noram: ld bc, 0DEh ; .NORAM ld (_errno),bc jp cret ; return NULL notdir: ld a, 0CFh ; .IATTR error: ld (_errno),a xor a ld (_errno+1),a call _free ; address of allocated block is already on the stack ld hl, 0 jp cret ; return NULL isroot: ; in - DE: pointer to (flipped) pathname ; - HL: pointer to res->dir_dir ; out: * Z: pathname points to a root directory ; *NZ: pathname does not point to a root directory ; if pathname points to a root then drive and path are copied to res->dir_dir ; if the path starts with [d:].\ and the cwd is the root dir, ; then the '.' is removed from the string ld b,0 inc de ld a,(de) cp ':' jr nz, 1f dec de ld a,(de) and 0ffh-('a'-'A') ld b,a inc de inc de inc de ld a,(de) 1: cp '\' jr z,4f or a ret nz dec de ld a,(de) cp '\' ret nz ld a,b or a jr nz, 2f push hl ld c,19h ; _CURDRV call bDos add a,'A' pop hl 2: ld (hl),a inc hl ld (hl),':' inc hl ld (hl),'\' inc hl xor a ld (hl),a ret 4: ; The first component is just one char, check for ".\" with ; the root dir as cwd dec de ld a,(de) cp '.' ret nz ld a,b or a jr z,5f sub 'A'-1 ld b,a 5: push de push hl ex de,hl ld c,59h ; _GETCD call bDos pop hl pop de ld a,(hl) or a ret nz ; DE points to a '.' that we do not want ld l,e ld h,d 6: inc hl ld a,(hl) ld (de),a inc de cp 1 ret c ; look for '\0', but do not set Z-flag jr 6b  ================================================ FILE: msx2dist/ldos2_04/PERROR.C ================================================ #include extern int errno; extern char * sys_err[]; extern int sys_ner; static ps(s) char * s; { while(*s) putc(*s++, stderr); } void perror(char * s) { char err_text[64]; int my_errno; my_errno=errno; ps(s); putc(':', stderr); #asm global bDos push ix pop hl ld de,-64 add hl,de ex de,hl ld c,066h ; _EXPLAIN ld b,(ix+-66) ; my_errno call bDos #endasm ps(err_text); }  ================================================ FILE: msx2dist/ldos2_04/PRINTF.C ================================================ #include extern int _doprnt(); printf(f, a) char * f; int a; { return(_doprnt(stdout, f, &a)); }  ================================================ FILE: msx2dist/ldos2_04/PUTCHAR.C ================================================ /* * Fake routines for getchar and putchar */ #include #undef getchar #undef putchar getchar() { return(getc(stdin)); } putchar(c) { return(putc(c, stdout)); }  ================================================ FILE: msx2dist/ldos2_04/PUTS.C ================================================ /* * puts and fputs for Zios stdio */ #include fputs(s, f) char * s; register FILE * f; { while(*s) putc(*s++, f); } puts(s) char * s; { fputs(s, stdout); putchar('\n'); }  ================================================ FILE: msx2dist/ldos2_04/READ.C ================================================ /* Read bytes from file */ read(fd, buf, nbytes) unsigned char fd; char * buf; unsigned short nbytes; { #asm global _errno, cret, bDos ld c,048h ; _READ ld b,(ix+6) ; fd ld e,(ix+8) ; buf ld d,(ix+9) ld l,(ix+10) ; nbytes ld h,(ix+11) call bDos jp z,cret ; no error, return hl ld (_errno),a xor a ld (_errno+1),a #endasm /* implicit return hl=number of bytes read */ }  ================================================ FILE: msx2dist/ldos2_04/READDIR.AS ================================================ ; readdir.as ; struct dirent * readdir (DIR * dir) psect text global _readdir global csv, cret, _errno, bDos _readdir: call csv ld e,(ix+6) ld d,(ix+7) ld hl,64 add hl,de ld bc, 1640h ; 40h : _FFIRST 16h: also hidden, system and directory ld a,(hl) or a jr z, first inc c ; 41h : _FNEXT first: push hl ex (sp),ix ld hl,nulstr psect data nulstr: defb 0 psect text call bDos ex (sp),ix pop hl jp z,cret ld l,a ld h,0 ld (_errno),hl ld l,h jp cret  ================================================ FILE: msx2dist/ldos2_04/REMOVE.C ================================================ extern int unlink(); remove(s) char * s; { return unlink(s); }  ================================================ FILE: msx2dist/ldos2_04/RENAME.C ================================================ #define BUFLEN 67 extern int _flip(char*, char*, int); int rename(char *n1, char *n2) { char namebuf[BUFLEN]; /* needed for slash-flipping */ if (_flip(namebuf, n1, BUFLEN)) { #asm global _errno, cret, bDos push ix pop hl ld de,-BUFLEN add hl,de ex de,hl ld l,(ix+8) ; n2 ld h,(ix+9) ld c,78 ; _RENAME call bDos ld hl,0 jp z,cret ; return 0 ld (_errno),a ld a,l ld (_errno+1),a 1: #endasm } return -1; }  ================================================ FILE: msx2dist/ldos2_04/REWIND.C ================================================ #include rewind(stream) FILE * stream; { fseek(stream, 0L, 0); }  ================================================ FILE: msx2dist/ldos2_04/REWNDDIR.AS ================================================ ; rewnddir.as ; void rewinddir (DIR * dir) ; { ; dir->dir_file.d_valid = 0; ; } global _rewinddir psect text _rewinddir: pop hl pop de ; dir push de push hl ld hl, 64 add hl,de ld (hl),0 ret  ================================================ FILE: msx2dist/ldos2_04/RMDIR.C ================================================ /* remove directory of given name */ extern int _act_file(char * name, int mode, int bc); extern int errno; rmdir(name) char * name; { return _act_file(name, 8, 0x4D); }  ================================================ FILE: msx2dist/ldos2_04/SCANF.C ================================================ /* * Stdio scanf */ #include extern int _doscan(); scanf(fmt, args) char * fmt; int args; { return _doscan(stdin, fmt, &args); }  ================================================ FILE: msx2dist/ldos2_04/SEEK.C ================================================ /* changes position in file */ long lseek(int fd, long offs, int wh) { #asm global bDos ld c,04Ah ; _SEEK ld b,(ix+6) ; fd ld l,(ix+8) ; offs ld h,(ix+9) ld e,(ix+10) ld d,(ix+11) ld a,(ix+12) ; wh call bDos ; new pointer in de:hl ex de,hl ; Hitech's calling convention requires long in hl:de #endasm /* implicit return hl:de; */ }  ================================================ FILE: msx2dist/ldos2_04/SETBUF.C ================================================ /* * Setbuf for Zios stdio */ #include setbuf(f, c) register FILE * f; char * c; { if(!(f->_flag & _IOMYBUF) && f->_base) _buffree(f->_base); f->_cnt = 0; if(!(f->_base = f->_ptr = c)) { f->_flag &= ~_IOMYBUF; return; } f->_flag |= _IOMYBUF; if(f->_flag & _IOWRT) f->_cnt = BUFSIZ; }  ================================================ FILE: msx2dist/ldos2_04/SETENV.AS ================================================ ; void setenv(char *name, char * val) global csv, cret, bDos psect text global _setenv _setenv: pop bc ; return address pop hl ; name pop de ; val push de push hl push bc ld c,6Ch ; _SENV jp bDos  ================================================ FILE: msx2dist/ldos2_04/SPRINTF.C ================================================ #include static FILE spf; sprintf(wh, f, a) char * wh; char * f; int a; { spf._cnt = 32767; spf._ptr = wh; spf._flag = _IOWRT|_IOBINARY|_IOSTRG; _doprnt(&spf, f, &a); *spf._ptr = 0; return spf._ptr - wh; }  ================================================ FILE: msx2dist/ldos2_04/SSCANF.C ================================================ /* * Stdio sscanf */ #include #include extern int _doscan(); sscanf(str, fmt, args) char * str; char * fmt; int args; { FILE file; file._base = file._ptr = str; file._cnt = strlen(str); file._flag = _IOSTRG|_IOBINARY|_IOREAD; return _doscan(&file, fmt, &args); }  ================================================ FILE: msx2dist/ldos2_04/START1.AS ================================================ psect text global __getargs, startup, __argc_, bDos startup: ; ensure the program is running under msx-dos2 ld c, 06Fh ; _DOSVER (MSX-DOS2) call bDos or a jr nz, nodos2 ld a,b cp 2 jr c, nodos2 ;close AUX and PRN,which are not supposed to be open ; when the program starts, should be harmless under DOS1 ld bc, 0345h ; _CLOSE, handle 3:AUX call bDos ld bc, 0445h ; _CLOSE, handle 4:PRN call bDos jp __getargs nodos2: ld de, errmsg ld c, 09h ; _STROUT call bDos ld c,00h ; _TERM0 call bDos psect data errmsg: defm '*** wrong version of msx-dos.' defb 13,10,'$' psect bss __argc_: defs 2  ================================================ FILE: msx2dist/ldos2_04/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 ex de,hl ;save sp 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 ;end of arguments ex de,hl add hl,bc ;end of space for arguments ld b,c ld c,1 dec hl ld (hl),0 inc b jr 3f 2: ld a,(de) cp ' ' dec de jr nz,1f push hl ; store argument inc c ; arg counter 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: msx2dist/ldos2_04/STAT.C ================================================ /* * int stat(char * s, struct stat * b); * * Fills in the supplied struct stat with modification and * access time and file size. */ #include #include extern int errno; extern int _flip(char *, char *, unsigned int); struct fib /* MSX-DOS2 file info block */ { char magic; /* 0xff */ char name[13]; unsigned char attr; unsigned short mtime; unsigned short mdate; short cluster; long size; char drive; char pad[64-26]; }; #define MAXLEN 67 static time_t seconds(struct tm * tp); int stat(register char * s, register struct stat * b) { /* changes in local variables must be reflected in asm-code */ struct tm td; struct fib info; char name[MAXLEN]; if (! _flip(name,s,MAXLEN)) return -1; else ; #asm global _errno, bDos push ix pop de push de ld ix, -82 ; offset of info in frame add ix,de ; ix= (&info) ld hl,-149 ; offset of name[] in frame add hl,de ex de,hl ; de=name ld bc, 01640h ; 40: _FFIRST, 16: hidden,system,directory call bDos pop ix jr z,1f ld (_errno),a xor a ld (_errno+1),a ld hl,-1 jp cret 1: #endasm b->st_mode = (info.attr & 0x10)?S_IREAD|S_IEXEC|S_IFDIR:S_IREAD|S_IFREG; if ((info.attr & 1)==0) b->st_mode |= S_IWRITE; if (info.attr & 2) b->st_mode |= S_HIDDEN; if (info.attr & 4) b->st_mode |= S_SYSTEM; if (info.attr & 0x20) b->st_mode |= S_ARCHIVE; td.tm_sec = (info.mtime & 0x1f) *2; td.tm_min = (info.mtime >> 5) & 0x3f; td.tm_hour= (info.mtime >> 11) & 0x1f; td.tm_mday= info.mdate & 0x1f; td.tm_mon = (info.mdate >> 5) & 0xf; td.tm_year=((info.mdate >> 9) & 0x7f) + 1980; b->st_mtime=b->st_atime=seconds(& td); b->st_size=info.size; return 0; } /* computes seconds past since 1/1/1970 (ignoring leap seconds) */ static time_t seconds(struct tm * tp) { int yr; unsigned long res; /* som[n] = number of days in first n months of non-leap year */ static int som[12]={ 0, 31, 59, 90,120,151,181,212,243,273,304,334 }; res = (tp->tm_year-1970)*365 + (tp->tm_year-1969)/4; res+= som[tp->tm_mon-1] + tp->tm_mday-1; if ((yr%4==0) && (tp->tm_mon > 2)) res++; /* days past since 1/1/1970 */ /* leap year heuristic is wrong in 2100, > 2^{32} sec after 1/1/1970 */ return ((res*24l + tp->tm_hour)*60l + tp->tm_min)*60l + tp->tm_sec; }  ================================================ FILE: msx2dist/ldos2_04/STAT.H ================================================ struct stat { short st_mode; /* flags */ long st_atime; /* access time */ long st_mtime; /* modification time */ long st_size; /* file size in bytes */ }; /* Flag bits in st_mode */ #define S_IFMT 0x600 /* type bits */ #define S_IFDIR 0x400 /* is a directory */ #define S_IFREG 0x200 /* is a regular file */ #define S_IREAD 0400 /* file can be read */ #define S_IWRITE 0200 /* file can be written */ #define S_IEXEC 0100 /* file can be executed */ #define S_HIDDEN 0x1000 /* file is hidden */ #define S_SYSTEM 0x2000 /* file is marked system */ #define S_ARCHIVE 0x4000 /* file has been written to */ struct utimbuf { long ac_time; long mod_time; }; extern int stat(char *, struct stat *); extern int utime(char *, struct utimbuf *);  ================================================ FILE: msx2dist/ldos2_04/STDCLEAN.C ================================================ #include _cleanup() { uchar i; register struct _iobuf * ip; i = _NFILE; ip = _iob; do { fclose(ip); ip++; } while(--i); } /* * Initial setup for stdio */ char _sibuf[BUFSIZ]; FILE _iob[_NFILE] = { { _sibuf, 0, _sibuf, _IOREAD|_IOMYBUF, 0 /* stdin */ }, { (char *)0, 0, (char *)0, _IOWRT|_IONBF, 1 /* stdout */ }, { (char *)0, 0, (char *)0, _IOWRT|_IONBF, 2 /* stderr */ }, };  ================================================ FILE: msx2dist/ldos2_04/UNGETC.C ================================================ #include /* * ungetc for Zios */ ungetc(c, stream) int c; register FILE * stream; { if(c == EOF || !(stream->_flag & _IOREAD) || stream->_base == (char *)NULL || stream->_cnt == BUFSIZ) return(EOF); if(stream->_ptr == stream->_base) stream->_ptr++; else stream->_cnt++; *--stream->_ptr = c; return(c); }  ================================================ FILE: msx2dist/ldos2_04/UNIXIO.H ================================================ /* * Declarations for Unix style low-level I/O functions. */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #define O_INHER 4 #endif extern int errno; /* system error number */ extern int open(char *, int); extern int close(int); extern int creat(char *, int); extern int dup(int); extern long lseek(int, long, int); extern int read(int, void *, int); extern int unlink(char *); extern int write(int, void *, int); extern int isatty(int); extern int chmod(char *, int);  ================================================ FILE: msx2dist/ldos2_04/UNLINK.C ================================================ /* remove file of given name */ extern int _act_file(char * name, int mode, int bc); extern int errno; unlink(name) char * name; { return _act_file(name, 0, 0x4D); }  ================================================ FILE: msx2dist/ldos2_04/UTIME.C ================================================ /* utime.c */ #include #include extern int _flip(char*, char*, int); extern int _utime(char*, int, int); #define BUFLEN 67 int utime(char * name, struct utimbuf *tb) { register struct tm *tp; int fat_date, fat_time; char buf[BUFLEN]; if (_flip(buf, name, BUFLEN)) { /* '/' to '\\' */ tp=gmtime(tb->mod_time); fat_date= (tp->tm_year-80)<<9 + tp->tm_mon<<5 + tp->tm_mday; fat_time= tp->tm_hour << 11 + tp->tm_min << 5 + tp->tm_sec >>1; return _utime(buf, fat_date, fat_time); } return -1; }  ================================================ FILE: msx2dist/ldos2_04/WRITE.C ================================================ write(fd, buf, nbytes) unsigned char fd; char * buf; unsigned short nbytes; { #asm global _errno, cret, bDos ld c,049h ; _WRITE ld b,(ix+6) ; fd ld e,(ix+8) ; buf ld d,(ix+9) ld l,(ix+10) ; nbytes ld h,(ix+11) call bDos jp z,cret ld (_errno),a xor a ld (_errno+1),a #endasm /* implicit return hl=number of bytes written */ }  ================================================ FILE: msx2dist/libfix01/CONVTIME.C ================================================ /* * This routine converts the date and time in MS(X)DOS format to * Unix style date and time - seconds since 00:00:00 Jan 1 1970. * Pierre Gielen 10/93 * * Public Domain for Hitech-C standard MSXDOS library */ #include long convtime(dostime,dosdate) unsigned int dosdate,dostime; { unsigned int cday = 0; unsigned int cnt,year,month; time_t t; static unsigned char dpermo[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; year = ((dosdate >> 9) & (int)0x7f)+10; /* bits 15..9 */ month = ((dosdate >> 5) & (int)0xf)-1; /* bits 8..5 */ for (cnt=0;cnt1) /* if past february */ ++cday; for (cnt=0;cnt> 11) & (int)0x1f); /* hours, bits 15..11 */ t *= 60; t += ((dostime >> 5) & (int)0x3f); /* minutes, bits 10..5 */ t *= 60; t += ((dostime << 1) & (int)0x3e); /* seconds, bits 4..0 */ return (long)t; }  ================================================ FILE: msx2dist/libfix01/DOPRNT.C ================================================ #include #include #include /* * doprnt for Z80 */ extern int atoi(char *); extern int _pnum(); /* Routines for formatted output must be able to cope with strings longer than 255 bytes. - Arnold M */ static unsigned int ival; static char * x; static FILE * ffile; static pputc(c) char c; { putc(c, ffile); } static char * icvt(cp) register char * cp; { ival = atoi(cp); while(isdigit((unsigned)*cp)) cp++; return cp; } _doprnt(file, f, a) FILE * file; register char * f; int * a; { char c; uchar fill, left; unsigned int i, prec, width; /* Allow for long strings. - Arnold M */ uchar base, sign, len; ffile = file; while(c = *f++) if(c != '%') pputc(c); else { base = 10; width = 0; sign = 0; left = 0; len = sizeof(int)/sizeof *a; if(*f == '-') { f++; left++; } fill = *f == '0'; if(isdigit((unsigned)*f)) { f = icvt(f); width = ival; } else if(*f == '*') { width = *a++; f++; } if(*f == '.') if(*++f == '*') { prec = *a++; f++; } else { f = icvt(f); prec = ival; } else prec = fill ? width : 0; if(*f == 'l') { f++; len = sizeof(long)/sizeof *a; } switch(c = *f++) { case 0: return; case 'o': base = 8; break; case 'd': sign = 1; break; case 'x': sign = 1; /* a-f in lower case */ case 'X': base = 16; break; case 's': x = *(char **)a; a += sizeof(char *)/sizeof *a; if(!x) x = "(null)"; i = strlen(x); dostring: if(prec && prec < i) i = prec; if(width > i) width -= i; else width = 0; if(!left) while(width--) pputc(' '); while(i--) pputc(*x++); if(left) while(width--) pputc(' '); continue; case 'c': c = *a++; default: x = &c; i = 1; goto dostring; case 'u': break; } if(left) { left = width; width = 0; } width = _pnum((len == sizeof(int)/sizeof *a ? (sign ? (long)*a : (unsigned long)*a) : *(long *)a), prec, width, sign, base, pputc); a += len; while(left-- > width) pputc(' '); } }  ================================================ FILE: msx2dist/libfix01/FDOPRNT.C ================================================ #include #include /* * doprnt for 8086 */ /* Routines for formatted output must be able to cope with strings longer than 255 bytes. - Arnold M */ static unsigned int ival; static char * x; static FILE * ffile; extern int atoi(char *); extern int strlen(char *); static pputc(c) int c; { putc(c, ffile); } static char * icvt(cp) register char * cp; { ival = atoi(cp); while(isdigit((unsigned)*cp)) cp++; return cp; } _doprnt(file, f, a) FILE * file; register char * f; int * a; { char c; uchar fill, left; int prec; unsigned int i, width; /* Allow for long strings. - Arnold M */ uchar base, sign, len; uchar ftype; extern short _pnum(), _fnum(); ffile = file; while(c = *f++) if(c != '%') pputc(c); else { base = 10; width = 0; sign = 0; left = 0; ftype = 0; len = sizeof(int)/sizeof *a; if(*f == '-') { f++; left++; } fill = *f == '0'; if(isdigit((unsigned)*f)) { f = icvt(f); width = ival; } else if(*f == '*') { width = *a++; f++; } if(*f == '.') if(*++f == '*') { prec = *a++; f++; } else { f = icvt(f); prec = ival; } else prec = fill ? width : -1; if(*f == 'l') { f++; len = sizeof(long)/sizeof *a; } switch(c = *f++) { case 0: return; case 'o': base = 8; break; case 'd': sign = 1; break; case 'x': sign = 1; /* a-f in lower case */ case 'X': base = 16; break; case 's': x = *(char **)a; a += sizeof(char *)/sizeof *a; if(!x) x = "(null)"; i = strlen(x); dostring: if(prec < 0) prec = 0; if(prec && prec < i) i = prec; if(width > i) width -= i; else width = 0; if(!left) while(width--) pputc(' '); while(i--) pputc(*x++); if(left) while(width--) pputc(' '); continue; case 'c': c = *a++; default: x = &c; i = 1; goto dostring; case 'u': break; case 'e': sign++; case 'g': sign++; case 'f': if(prec < 0) prec = 6; ftype = 1; break; } if(left) { left = width; width = 0; } if(prec < 0) prec = 0; if(ftype) { width = _fnum(*(double *)a, prec, width, sign, pputc); a += sizeof(double)/sizeof(*a); } else { width = _pnum((len == sizeof(int)/sizeof *a ? (sign ? (long)*a : (unsigned long)*a) : *(long *)a), prec, width, sign, base, pputc); a += len; } while(left-- > width) pputc(' '); } }  ================================================ FILE: msx2dist/libfix01/FIXES.TXT ================================================ Fixes for the libraries provided with HiTech-C. HiTech has given kind permission to use its C-compiler for cp/m without paying a fee. hiTech has also released as freeware some libraries for cp/m and the sources thereof. Pierre Gielen has made adaptations and extensions for msxdos2 and has released as public domain in 1993. I have bundled some of these changes with some fixes, improvements and additions I have written myself. I have deliberately left out the things that work only under msx-dos2 to keep it easy to make programs that work under msxdos1; there is libdos2 for those who want to use the extra possibilities of msx-dos2. To use these patches you can copy the header and library files in this package to the directory where you keep your copy of HiTech-C or type 'make install'. You are free to use, modify and redistribute this package. Please send bug-reports, suggestions etc. to me. Arnold Metselaar The following files are present in this package: fixes.txt this file makefile Use with a recent version of make.com to create object files and update library files. Run make without arguments for a list of possibilities. libc.lib libf.lib Replacements for the equally named libraries that come with HiTech-C. string.h Changed header file that reflects which string functions are actually available in libc.lib. time.h Changed header file declaring some extra functions. SOURCEFILES: memchr.as void * memchr (void * s, int c, size_t n) memmove.as void * memmove (void * dest, void * src, size_t n) Missing in the original libc.lib. memcmp.as int memcmp (void * s1, void * s2, size_t n) memcpy.as void * memcpy (void * dest, void * src, size_t n) More efficient implementations of these functions, the original implementations are in C. memset.as void * memset (void * s, int c, size_t n) The original function written in C has the c and n arguments interchanged, this one follows the standard ordering. strchr.as char * strchr(char * s, int c) char * index (char * s, int c) strrchr.as char * strrchr(char * s, int c) char * rindex (char * s, int c) When c==0 the original functions would return NULL, and these functions will return the address of the closing NUL character. stricmp.as int strcasecmp(char *s1, char *s2) strnicmp.as int strncasecmp(char *s1, char *s2, size_t n) These extra functions are similar to strcmp and strncmp respectively, but letters are converted to lower case before comparison, which leads to a case insensitive comparison. strstr.c char * strstr (char *t, char *s) strnstr.c char * strnstr (char *t, char *s, unsigned int n) stristr.c char * strcasestr (char *t, char *s) strnistr.c char * strncasestr (char *t, char *s, unsigned int n) These extra functions locate the first occurence of string s in string t. The functions strnstr and strcasestr read at most n characters from 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.c char * strdup (char * s) This function allocates a new buffer for and copies the string pointed to by s to it. It returns a pointer to the copy of the string or NULL if memory allocation failed. The memory block can be release with free(). strtok.c char *strtok(char *s, char *tok, size_t toklen, char *brk) This function 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 terminating zero. This function does not conform to the posix standard. time.c time_t time (time_t * tp) time_t timerset (time_t t) int timeup (time_t t) msxtime.as time_t msxtime () The function time gives the time in seconds since 00:00:00, Jan 1st, 1970 (unix style), timerset and timeup are convenience functions that can be used to check a certain time interval has passed. The actual conversion is done in msxtime. getch.as char getch(void); /* get character */ char getche(void); /* get/echo character */ void putch(int); /* output character to console*/ void ungetch(int); /* unget character */ int kbhit(void); /* true if keyboard hit */ void cursor(char onoff) Accelerated versions of these functions declared in conio.h. inout.as byte in(byte io-address) byte out(byte io-address,byte value) void di(); void ei(); The functions in() and out() can be used to access the IO ports of the CPU directly. Interrupts can be disabled and enabled with di() and ei() respectively. These functions disable and enable the generation of interrupts by the VDP rather than the servicing by the CPU, since many MSX-bios routines enable interrupts even when they are called with interrupts disabled. peekpoke.as void poke(word address, byte value) byte peek(word address) These functions are equivalent to the more efficient (*((byte*)address)) = value and (*((byte*)address)) respectively. Programmers with experience in basic will find them more familiar. sleep.c void sleep (unsigned int seconds) This function does nothing until the given number of seconds has passed. strftime.c size_t strftime(char *s, size_t maxs, char *f, struct tm *t) This function takes a broken down time (*t) and converts it to a string, in the way specified by the format string (f). convtime.c long convtime(unsigned int dostime, unsigned int dosdate) This routine converts the date and time in MS(X)DOS format to Unix style date and time - seconds since 00:00:00 Jan 1 1970. fdoprnt.c doprnt(FILE* fp, char* format, ...) doprnt.c doprnt(FILE* fp, char* format, ...) Routines used by printf and similar functions to format data, fdoprnt contains the variant that can also handle floats. The original versions use 8 bit variables to hold string lengths, which fails on strings larger than 255 characters. If you do not use such very long strings, you may prefer to use the original functions, that are somewhat smaller and faster. fbcd.obj Internal routine, used to print floating point numbers, strangely enough the source provided by HiTech is correct, but the object file in libc.lib was not. frelop.as Internal routine, correction for a bug that caused wrong results when comparing negative numbers that have the same exponent. rcsv.as Internal routine, marginal improvement in size@and speed.  ================================================ FILE: msx2dist/libfix01/FRELOP.AS ================================================ ; floating relational operation - returns flags as though ; a floating subtract was done. ; bugfix (-1.5 used to be deemed larger than -1.25) by Arnold M psect text global frelop frelop: exx ;select alternate reg set pop hl ;return address exx ;get other set again pop bc ;low word of 2nd arg ex de,hl ;put hi word of 1st in de ex (sp),hl ;get hi word of 2nd in hl ex de,hl ;hi word of 1st back in hl ld a,h ;test for differing signs xor d jp p,2f ;the same, so ok ld a,h ;get the sign of the LHS or 1 ;ensure zero flag is reset, set sign flag pop bc ;unjunk stack jp 1f ;return with sign of LHS 2: ld a,h ;test for differing exponents sub d ;compare with the other jr z,2f ;the same, go for mantissas xor h ;complement sign flag if operands -ve or 1 ;reset zero flag pop bc ;unjunk stack jp 1f ;and return 2: sbc hl,de ;set the flags (Cy=0 from sub d) pop hl ;low word of 1st into hl again jr nz,3f ;go check sign if not zero sbc hl,bc ;now set flags on basis of low word jr z,1f ;if zero, all ok 3: rra ;carry into sign bit of a xor d ;complement sign flag if operands -ve (AM) or 1 ;reset zero flag 1: exx ;get return address jp (hl) ;and return with stack clean  ================================================ FILE: msx2dist/libfix01/GETCH.AS ================================================ ; Hi-Tech C standard library ; ; Accelerated MSXDOS versions of the following console functions ; (defined in conio.h): ; ; char getch(void); /* get character */ ; char getche(void); /* get/echo character */ ; void putch(int); /* output character to console;/ ; void ungetch(int); /* unget character;/ ; int kbhit(void); /* true if keyboard hit;/ ; ; added new function: ; ; void cursor(int); [ 1 = on, 0 = off ] ; ; Use this file to update the Hitech-C standard library libc.lib. ; ; PGN 10/93 ; Last update 12/93 ;void cursor(char onoff) psect text global _cursor _cursor: ld a,l ld (0fca9h),a ; 0=off else on ld (0fcaah),a ; line style cursor if on ret ;char getch(void) psect text global _getch _getch: ld hl,(pushbk) ld a,h or l ; if pushed back jr z,1f ; none ld de,0 ld (pushbk),de ; else delete pushback ret ; return with hl 1: push ix push iy ld ix,09fh ld iy,(0fcc0h) call 01ch ; chget ld l,a ld h,0 pop iy pop ix ret ;char getche(void) psect text global _getche _getche: ld hl,(pushbk) ld a,h or l ; if pushed back jr z,2f ; none ld de,0 ld (pushbk),de ; else delete pushback ret ; return with hl 2: call 1b ; get character push hl call _putch pop hl ret ;void ungetch(char) psect text global _ungetch _ungetch: ld (pushbk),hl ret psect data pushbk: defw 0 ;void putch(char) psect text global _putch _putch: ld a,l cp 10 ; if newline jr nz,3f ld hl,13 call 3f ld hl,10 3: push ix push iy ld a,l ld ix,0a2h ld iy,(0fcc0h) call 01ch pop iy pop ix ret ;int kbhit() psect text global _kbhit _kbhit: ld hl,(0f3fah) ; getpnt ld a,(0f3f8h) ; putpnt cp l ld hl,1 ret nz ; if NZ then keypressed ld hl,0 ret ; end of file ================================================ FILE: msx2dist/libfix01/INOUT.AS ================================================ global _in, _out global _di, _ei psect text ; byte in(byte io-address) _in: ld c,l ;port address in l,(c) ;read port ld h,0 ;zero extend it ret ; byte out(byte io-address,byte value) _out: pop hl ;return address pop bc ;port address pop de ;data push de push bc push hl out (c),e ;output the data ld l,c ;return value in hl also ld h,0 ret ; void di(); ; void ei(); _di: ld a,(0f3e0h) and 0dfh jr 1f _ei: ld a,(0f3e0h) or 20h 1: ld b,a ld c,1 push ix push iy ld ix,047h ; routine WRTVDP ld iy,(0fcc0h) ; in main bios rom call 01ch pop iy pop ix xor a ld (0fca9h),a ret end  ================================================ FILE: msx2dist/libfix01/MAKEFILE ================================================ # makefile for fixes in HiTech-C's libraries # Directory where the libraries are installed: # Backslashes must be doubled twice here because make will process them twice DIR = a:\\\\hitech # Command to move a library file, # change to copy if the library files are on a different drive or partition: MV = move # Name for distribution package: DIST = libfix01.lzh # Options to pass to the C compiler: # -o : optimise, *strongly recommended*, # -v : be verbose, lets you follow the progress. # CFLAGS = -o -v # if you want another tiomezone than central european time, # you can define TZNAME and recompile strftime.c. For example: # # CFLAGS += '-DTZNAME="GMT"' help : type $$m.t <nul EOF :$$clean.bat del $$clean.bat cleanmore : copy $$m.t $$clean.bat <= src, copy backward dec bc add hl,bc ex de,hl add hl,bc inc bc lddr inc de ex de,hl 1: jp cret 2: ; dest < src, copy forward push hl ex de,hl ldir pop hl 1: jp cret  ================================================ FILE: msx2dist/libfix01/MEMSET.AS ================================================ ; memset.as global _memset, csv, cret ; void * memset (void *s, int c, size_t n) ; fast version with standard argument order by Arnold M psect text _memset: call csv ld l,(ix+6) ld h,(ix+7) ld c,(ix+10) ld b,(ix+11) ld a,c or b jr z,1f ld e,(ix+8) ld (hl),e dec bc ld a,c or b jr z,1f push hl ld e,l ld d,h inc de ldir pop hl 1: jp cret  ================================================ FILE: msx2dist/libfix01/MSXTIME.AS ================================================ ; time_t msxtime(); ; used by time(), timerset() and timeup() functions ; Public domain by Pierre Gielen. psect text global _msxtime _msxtime: push ix push iy ld c,02ah ; get date call 5 ld bc,-1970 ; unix offset add hl,bc ; hl=jaren sinds 1970, d=maanden, e=dag push de ; bewaar e=dag, d=maand ld a,l add a,70 ; *** LEAPYEAR BUGFIX *** push af ; bewaar jaar ld c,d ; c=maand ld b,l ; b jaren sinds 1970 ld hl,0 ; vanaf 0 ld a,1 ; modulo 4 teller ld de,365 ; dagen per jaar 1: add hl,de ; tel 1 jaar in dagen er bij op inc a ; verhoog modulo 4 teller and 3 ; elke 4 jaar jr nz,2f ; nee inc hl ; ja, 1 dag extra voor schrikkeljaar 2: djnz 1b ; en dat b keer achter elkaar ; hl bevat nu het aantal dagen in de jaren sinds 1970 pop af ; het huidige jaar and 3 ; is dit een schrikkeljaar? jr nz,3f ; nee ld a,c ; ja, dan pak maand cp 3 ; als februari voorbij is jr c,3f ; nog niet inc hl ; wel, dan 1 extra voor 29 februari ; 3: ld b,c ; maand in b ld de,17f ; tabel met aantal dagen per maand jr 5f ; bereken dagen ; 4: call 7f ; tel aantal dagen in deze maand bij totaal inc de ; verhoog maandentabel-pointer 5: djnz 4b ; volgende (voor b maanden) pop de ; de dag staat nog in e ld a,e dec a ; offset 0 (niet 1) call 6f ; tel op bij totaal jr 8f ; klaar 7: ld a,(de) ; add day of current month 6: add a,l ld l,a ret nc inc h ret 8: call 9f ld (95f),hl ; zet totaal in long1 buffer ld hl,0 ld (95f+2),hl inc hl ld (96f+2),hl ld hl,05180h ld (96f),hl ; zet 15180h (=seconden per dag) in LONG2 call 10f ; long1 = long1 * long2 call 11f ; long3 = long1 ld c,02ch ; get time call 5 push de ; bewaar d=seconden push hl ; bewaar h=uren, l=minuten call 9f ld l,h ; hl=uren ld h,0 ld (95f),hl ld hl,3600 ld (96f),hl call 10f ld hl,(95f) ld (96f),hl ld hl,(95f+2) ld (96f+2),hl ; verplaats long 1 naar long2 call 12f ; haal jaren in seconden call 13f ; long1=long1+long2 ld hl,0 ; offset 0 pop de ; haal e=minuten (was l) ld a,e or a ; 0? jr z,15f ; dan hebben we dit niet nodig ld d,0 ld b,60 ; seconden per minuut 16: add hl,de djnz 16b ; tel minuten in seconden op in hl 15: ld (96f),hl ; in long2 (long1 nog ok) ld hl,0 ld (96f+2),hl call 13f ; tel minuten op pop hl ; haal h=seconden (was d) ld l,h ; in l ld h,0 ld (96f),hl ld hl,0 ld (96f+2),hl call 13f ; tel seconden op ld de,(95f) ld hl,(95f+2) ; resultaat nu in hlde, zoals Hitech wenst pop iy pop ix ret psect data ; tabel met aantal dagen per maand (geen schrikkeljaar) 17: defb 31,28,31,30,31,30,31,31,30,31,30,31 psect text 11: push hl ld hl,(95f) ld (97f),hl ld hl,(95f+2) ld (97f+2),hl pop hl ret 12: push hl ld hl,(97f) ld (95f),hl ld hl,(97f+2) ld (95f+2),hl pop hl ret 9: push hl ld hl,0 ld (95f),hl ld (95f+2),hl ld (96f),hl ld (96f+2),hl pop hl ret 10: ld hl,95f ld de,96f ld a,4 ld c,4 ld b,0 add hl,bc ex de,hl ld (93f),hl ld hl,94f add hl,bc ld (92f),hl ld l,c ld h,b add hl,hl add hl,hl add hl,hl inc hl ld (91f),hl ld b,c ld hl,94f 18: ld (hl),0 inc hl djnz 18b and a 19: ld b,c ld hl,(92f) 20: dec hl rr (hl) djnz 20b ld l,e ld h,d ld b,c 21: dec hl rr (hl) djnz 21b jp nc,22f push de ld de,(93f) ld hl,94f ld b,c and a 23: ld a,(de) adc a,(hl) ld (hl),a inc de inc hl djnz 23b pop de 22: ld a,(91f) dec a ld (91f),a jp nz,19b push af ld a,(91f+1) and a jp z,24f dec a ld (91f+1),a pop af jp 19b 24: pop af ret 13: ld hl,95f ld de,96f ld b,4 ; lengte 14: ld a,(de) adc a,(hl) ld (hl),a inc hl inc de djnz 14b ret psect data 91: defs 2 ; teller 92: defs 2 93: defs 2 94: defs 8 95: defs 4 ; buffers voor longints 96: defs 4 97: defs 4  ================================================ FILE: msx2dist/libfix01/PEEKPOKE.AS ================================================ ; These routines were previously in inout.as, I've put them in a ; separate file because they can be easiliy rewritten, so they need not ; take up space in a .com file - Arnold M global _peek, _poke psect text ; void poke(word address, byte value) _poke: pop hl ;return address pop de ;address pop bc ;value push bc push de ld a,c ld (de),a jp (hl) ; byte peek(word address) _peek: pop de ;return address pop hl ;peek address push hl push de ld l,(hl) ld h,0 ret  ================================================ FILE: msx2dist/libfix01/RCSV.AS ================================================ ; rcsv, save old iy,ix and get three arguments in hl,de,bc ; return with new framepointer in ix. ; save 2 bytes and 34 T-states compared to HiTech's version - Arnold M. global rcsv ARG equ 6 ;offset of 1st arg macro ldrd reg ld reg,(hl) dec hl endm psect text rcsv: ex (sp),iy ;save iy, get return address push ix ld ix,0 add ix,sp ;new frame pointer ld hl,ARG+5 add hl,sp ;top of args ldrd b ldrd c ldrd d ldrd e ld h,(hl) ld l,(ix+ARG+0) jp (iy)  ================================================ FILE: msx2dist/libfix01/SIGNAL.AS ================================================ ; SIGNAL.C, manually modified for MSXDOS-2 ; ;static void (* where)(); ; ;void (*signal(sig, action))() ;int sig; ;void (* action)(int); ;{ ; void (* prev)(); ; ; if(sig != SIGINT) ; return (void (*)())-1; ; prev = where; ; where = action; ; return prev; ;} global _signal global csv,cret psect text _signal: call csv push hl ld de,1 ld l,(ix+6) ld h,(ix+7) or a sbc hl,de jr z,1f ld hl,-1 jp cret 1: ld hl,(_where) ex de,hl ; de = previous ld l,(ix+8) ld h,(ix+9) ; new _where ld (_where),hl ex de,hl ; return previous jp cret ;void _sigchk() ;{ ; char c; ; ; if (where == SIG_IGN) ; return; ; if (bdos(CONSTAT) != 0) { ; c = bdos(CONIN); ; if (c != CPMRBT) ; return; ; if (where == SIG_DFL) ; exit(0); ; (*where)(); ; } ;} global __sigchk,_exit,indir __sigchk: ld a,(0fc9bh) ; INTFLG cp 3 ; if ctrl-stop pressed jp z,1f ; then ignore all bypasses ld hl,(0f3fah) ; getpnt ld a,(0f3f8h) ; putpnt cp l ; if not keypressed ret z ; then return ld de,1 ; SIG_IGN ld hl,(_where) ; if where == SIG_IGN or a sbc hl,de ret z ; then return push ix push iy ld ix,09fh ld iy,(0fcc0h) call 01ch ; _CHGET pop iy pop ix cp 3 ; if not CTRL-C ret nz ; then return ld hl,(_where) ; else look where to go ld a,l or h jr nz,2f ; not goto 0 ? 1: ld hl,0 push hl call _exit ; default to exit(0) 2: ld hl,(_where) call indir ret psect bss _where: defs 2 end ================================================ FILE: msx2dist/libfix01/SLEEP.C ================================================ /* * Sleep function for Hi-Tech C * PGN 12/93 */ #include void sleep(seconds) unsigned int seconds; { long t0; t0 = (long)time((long *)0)+seconds; while (time((long *)0)<=t0); /* wait seconds */ }  ================================================ FILE: msx2dist/libfix01/STRCHR.AS ================================================ ; strchr(char *s, int c) ; version that can find the closing \0 by Arnold M psect text global rcsv, cret, _strchr, _index _strchr: _index: pop bc pop hl pop de push de push hl push bc jr 3f 1: inc hl 3: ld a,(hl) cp e ; check for a match first, e may be zero ret z or a jr nz,1b ld hl,0 ret  ================================================ FILE: msx2dist/libfix01/STRDUP.C ================================================ #include extern char *malloc(); char * strdup(char * str) { char *dup; if ( (dup = malloc(strlen(str)+1)) ) /* add one for the closing \0 */ return strcpy(dup, str); return (dup); }  ================================================ FILE: msx2dist/libfix01/STRFTIME.C ================================================ /** * * strftime.c * * implements the ansi c function strftime() * * written 6 september 1989 by jim nutt * released into the public domain by jim nutt * * modified 21-Oct-89 by Rob Duff * **/ #ifndef TZNAME #define TZNAME "CET" /* my timezone (PGN) */ #endif #include /* for size_t */ #include /* for va_arg */ #include /* for struct tm */ /* ** The following line should be appended to TIME.H. ** Also copy size_t define from STRING.H. */ /* extern size_t strftime(char *s, size_t maxs, char *f, struct tm *t); */ static char *aday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char *day[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static char *amonth[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *month[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static char buf[26]; static void strfmt(char *str, char *fmt, ...); /** * * size_t strftime(char *str, * size_t maxs, * const char *fmt, * const struct tm *t) * * this functions acts much like a sprintf for time/date output. * given a pointer to an output buffer, a format string and a * time, it copies the time to the output buffer formatted in * accordance with the format string. the parameters are used * as follows: * * str is a pointer to the output buffer, there should * be at least maxs characters available at the address * pointed to by str. * * maxs is the maximum number of characters to be copied * into the output buffer, included the '\0' terminator * * fmt is the format string. a percent sign (%) is used * to indicate that the following character is a special * format character. the following are valid format * characters: * * %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 \0, or zero if more * than maxs characters were produced. * **/ size_t strftime(char *s, size_t maxs, char *f, struct tm *t) { int w; char *p, *q, *r; p = s; q = s + maxs - 1; while ((*f != '\0')) { if (*f++ == '%') { r = buf; switch (*f++) { case '%' : r = "%"; break; case 'a' : r = aday[t->tm_wday]; break; case 'A' : r = day[t->tm_wday]; break; case 'b' : r = amonth[t->tm_mon]; break; case 'B' : r = month[t->tm_mon]; break; case 'c' : strfmt(r, "%0 %0 %2 %2:%2:%2 %4", aday[t->tm_wday], amonth[t->tm_mon], t->tm_mday,t->tm_hour, t->tm_min, t->tm_sec, t->tm_year+1900); break; case 'd' : strfmt(r,"%2",t->tm_mday); break; case 'H' : strfmt(r,"%2",t->tm_hour); break; case 'I' : strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12); break; case 'j' : strfmt(r,"%3",t->tm_yday+1); break; case 'm' : strfmt(r,"%2",t->tm_mon+1); break; case 'M' : strfmt(r,"%2",t->tm_min); break; case 'p' : r = (t->tm_hour>11)?"PM":"AM"; break; case 'S' : strfmt(r,"%2",t->tm_sec); break; case 'U' : w = t->tm_yday/7; if (t->tm_yday%7 > t->tm_wday) w++; strfmt(r, "%2", w); break; case 'W' : w = t->tm_yday/7; if (t->tm_yday%7 > (t->tm_wday+6)%7) w++; strfmt(r, "%2", w); break; case 'w' : strfmt(r,"%1",t->tm_wday); break; case 'x' : strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday], amonth[t->tm_mon], t->tm_mday, t->tm_year+1900); break; case 'X' : strfmt(r, "%2:%2:%2", t->tm_hour, t->tm_min, t->tm_sec); break; case 'y' : strfmt(r,"%2",t->tm_year%100); break; case 'Y' : strfmt(r,"%4",t->tm_year+1900); break; case 'Z' : r = TZNAME; break; default: buf[0] = '%'; /* reconstruct the format */ buf[1] = f[-1]; buf[2] = '\0'; if (buf[1] == 0) f--; /* back up if at end of string */ } while (*r) { if (p == q) { *q = '\0'; return 0; } *p++ = *r++; } } else { if (p == q) { *q = '\0'; return 0; } *p++ = f[-1]; } } *p = '\0'; return p - s; } /* * stdarg.h * typedef void *va_list; #define va_start(vp,v) (vp=((char*)&v)+sizeof(v)) #define va_arg(vp,t) (*((t*)(vp))++) #define va_end(vp) * */ static int pow[5] = { 1, 10, 100, 1000, 10000 }; /** * static void strfmt(char *str, char *fmt); * * simple sprintf for strftime * * each format descriptor is of the form %n * where n goes from zero to four * * 0 -- string %s * 1..4 -- int %?.?d * **/ static void strfmt(char *str, char *fmt, ...) { int ival, ilen; char *sval; va_list vp; va_start(vp, fmt); while (*fmt) { if (*fmt++ == '%') { ilen = *fmt++ - '0'; if (ilen == 0) /* zero means string arg */ { sval = va_arg(vp, char*); while (*sval) *str++ = *sval++; } else /* always leading zeros */ { ival = va_arg(vp, int); while (ilen) { ival %= pow[ilen--]; *str++ = '0' + ival / pow[ilen]; } } } else *str++ = fmt[-1]; } *str = '\0'; va_end(vp); } #ifdef TEST #include /* for printf */ #include /* for strftime */ char test[80]; int main(int argc, char *argv[]) { int len; char *fmt; time_t now; time(&now); fmt = (argc == 1) ? "%I:%M %p\n%c\n" : argv[1]; len = strftime(test,sizeof test, fmt, localtime(&now)); printf("%d: %s\n", len, test); return !len; } #endif /* TEST */  ================================================ FILE: msx2dist/libfix01/STRICMP.AS ================================================ ; int strcasecmp(const char *s1, const char *s2) ; return a value less than 0, 0 or greater than 0 if s1 is found, respectively, ; to be less than equal or greater than s2 ignoring case ; by Arnold M psect text macro tolower cp 'A' jr c, 10f cp 'Z'+1 jr nc, 10f add a, 'a'-'A' 10: endm global _strcasecmp _strcasecmp: pop bc pop hl ; s1 pop de ; s2 push de push hl push bc 1: ld a,(de) ;*s2 tolower ld c,a ld a,(hl) ;*s1 tolower cp c jr nz,2f inc hl inc de or a jp nz,1b ld h,a ld l,a ret 2: sbc hl,hl ret c inc hl ret  ================================================ FILE: msx2dist/libfix01/STRING.H ================================================ /* String functions */ #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #ifndef NULL #define NULL ((void *)0) #endif NULL extern int errno; /* system error number */ extern void * memcpy(void *, void *, size_t); extern void * memmove(void *, void *, size_t); extern void * memset(void *, int, size_t); extern char * strcat(char *, char *); extern char * strncat(char *, char *, size_t); extern char * strcpy(char *, char *); extern char * strncpy(char *, char *, size_t); extern char * strdup(char *); extern int memcmp(void *, void *, size_t); extern int strcmp(char *, char *); extern int strncmp(char *, char *, size_t); extern int strcasecmp(char *, char *); extern int strncasecmp(char *, char *, size_t); extern void * memchr(void *, int, size_t); extern size_t strlen(char *); extern char * strchr(char *, int); extern char * index(char *, int); extern char * strrchr(char *, int); extern char * rindex(char *, int); extern char * strstr(char*, char*); extern char * strcasestr(char*, char*); extern char * strnstr(char*, char*, size_t); extern char * strncasestr(char*, char*, size_t);  ================================================ FILE: msx2dist/libfix01/STRISTR.C ================================================ /* * char * strcasestr (char *t, char *s) * * Find string s in string t, disregarding the case of letters. * * Return * - The smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p, or * - NULL if there is no such pointer. */ #include char * strcasestr (char *t, char *s) { char *t1; char *s1; do { t1 = t; s1 = s; while(*s1) { if (toupper(*s1) != toupper(*(t1++))) break; else ++s1; } if (!*s1) return t; } while (*(t++)); return (char *) 0; }  ================================================ FILE: msx2dist/libfix01/STRNICMP.AS ================================================ ; int strncasecmp(const char *s1, const char *s2, size_t n) ; return a value less than 0, 0 or greater than 0 if s1 is found, respectively, ; to be less than equal or greater than s2 ignoring case ; by Arnold M psect text macro tolower cp 'A' jr c, 10f cp 'Z'+1 jr nc, 10f add a, 'a'-'A' 10: endm global _strncasecmp, rcsv, cret _strncasecmp: call rcsv ; hl=s1, de=s2, bc=n ld b,c ; keep low part of n in reg b, reg c is used as scratch ld a,b or a jr z,bzero loop: ld a,(de) ;*s2 tolower ld c,a ld a,(hl) ;*s1 tolower cp c jr nz,diff or a jr z, equal inc hl inc de djnz loop bzero: dec (ix+6+5) ; n / 0x100 jp p,loop ; dec m does not affect the carry flag ld a,(ix+6+5) inc a jr nz,loop equal: ld h,a ld l,a jp cret diff: sbc hl,hl jp c,cret inc hl jp cret  ================================================ FILE: msx2dist/libfix01/STRNISTR.C ================================================ /* * char * strncasestr (char *t, char *s, unsigned int n) * * Find string s in string t, disregarding the case of letters. * At most n characters from t are used. * * Returns * - A smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p and strictly before t+n, or * - NULL if there is no such pointer. */ #include char * strncasestr (char *t, char *s, unsigned int n) { char *t1; char *s1; unsigned int n1; if (!*s) return t; while (*t && n) { t1 = t; n1 = n; s1 = s; while (*s1) { if (toupper(*s1) != toupper(*(t1++))) break; else { ++s1; if (!--n1) break; } } if (!*s1) return t; --n; ++t; } return (char *) 0; }  ================================================ FILE: msx2dist/libfix01/STRNSTR.C ================================================ /* * char * strnstr (char *t, char *s, unsigned int n) * * Find string s in string t, using at most n characters from t. * * Returns * - A smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p and strictly before t+n, or * - NULL if there is no such pointer. */ char * strnstr (char *t, char *s, unsigned int n) { char *t1; char *s1; unsigned int n1; if (!*s) return t; while (*t && n) { t1 = t; n1 = n; s1 = s; while (*s1) { if (*s1 != *(t1++)) break; else { ++s1; if (!--n1) break; } } if (!*s1) return t; --n; ++t; } return (char *) 0; }  ================================================ FILE: msx2dist/libfix01/STRRCHR.AS ================================================ ; strrchr(char *s, int c) ; version that can find the closing \0 by Arnold M psect text global rcsv, cret, _strrchr, _rindex _strrchr: _rindex: pop bc pop hl pop de push de push hl push bc ld bc,1 ; the closing nul is considered part of the string here jr 5f 6: inc hl inc bc 5: ld a,(hl) or a jr nz,6b 1: ld a,e cpdr inc hl ret z ld l,c ld h,b ret  ================================================ FILE: msx2dist/libfix01/STRSTR.C ================================================ /* * char * strstr (char *t, char *s) * * Find string s in string t. * * Return * - The smallest pointer p between t and t+strlen(t) inclusive, such that * the characters from s upto but not including the first NUL character * can be found starting from p, or * - NULL if there is no such pointer. */ char * strstr (char *t, char *s) { char *t1; char *s1; do { t1 = t; s1 = s; while(*s1) { if (*s1 != *(t1++)) break; else ++s1; } if (!*s1) return t; } while (*(t++)); return (char *) 0; }  ================================================ FILE: msx2dist/libfix01/STRTOK.C ================================================ /* ** strtok() -- public domain by Ray Gardner, modified by Bob Stout ** not modified for Hi-Tech C by Pierre Gielen :-) ** comment corrected by Arnold Metselaar ** ** You pass this function a string to parse, a buffer to receive the ** "token" that gets scanned, the length of the buffer, and a string of ** "break" characters that stop the scan. It will copy the string into ** the buffer up to any of the break characters, or until the buffer is ** full, and will always leave the buffer null-terminated. It will ** return a pointer to the first character from s that was not copied to ** tok. */ #include char *strtok(char *s, char *tok, size_t toklen, char *brk) { char *lim, *b; if (!*s) return NULL; lim = tok + toklen - 1; while (*s && (tok /* moved to msxtime.as: */ extern time_t msxtime(); time_t time(tp) time_t * tp; { time_t t; t = msxtime(); if(tp) *tp = t; return t; } time_t timerset(value) long value; { return (msxtime()+value); } int timeup(timer) long timer; { if(msxtime() < timer) return(0); return(1); }  ================================================ FILE: msx2dist/libfix01/TIME.H ================================================ /* time.h voor hitech-c * aanpassing 01/06 */ #ifndef _TIME typedef long time_t; /* for representing times in seconds */ struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; #define _TIME #endif _TIME #ifndef _STDDEF typedef int ptrdiff_t; /* result type of pointer difference */ typedef unsigned size_t; /* type yielded by sizeof */ #define _STDDEF #define offsetof(ty, mem) ((int)&(((ty *)0)->mem)) #endif _STDDEF #define CLK_TCK 50 /* for 50Hz interrupt frequency */ #define JIFFY (*(unsigned short *)0xfc9e) /* clock tick counter */ #define jtimerset(s) (JIFFY=(0-(s * 5))) /* set timer in 100ms slices */ #define jtimeup() (JIFFY==0) extern int time_zone; /* minutes WESTWARD of Greenwich */ /* this value defaults to 0 since with operating systems like MS-DOS there is no time zone information available */ extern time_t time(time_t *); /* seconds since 00:00:00 Jan 1 1970 */ extern char * asctime(struct tm *); /* converts struct tm to ascii time */ extern char * ctime(); /* current local time in ascii form */ extern struct tm * gmtime(); /* Universal time */ extern struct tm * localtime(); /* local time */ extern time_t timerset(time_t); /* set a timer in seconds */ extern int timeup(time_t); /* check if timer expired */ extern size_t strftime(char *s, size_t maxs, char *f, struct tm *t);  ================================================ FILE: msx2dist/make_004/FILE.C ================================================ #include #include #include /* * The header file string.h should declare * extern int strcasecmp(char * s1, char * s2); * a function that is provided as part of the 'fixes for Hitech libraries'. */ #include "make.h" extern int debug; /* * Return file-node for 'fname'. * If it doesn't exist or fname starts with %, then create one. */ FILENODE *filenode(char *fname) { FILENODE *f, *afnode(), *gfile(); if ( (f = gfile(fname)) == NULL ) f = afnode(fname); return f; } /* * Add a dependency to the node 'fnd'. * 'fnd' will depend on 'fname'. */ addfile(FILENODE *fnd, char *fname) { NODE *n; FILENODE *f; if (fnd == NULL) { /* punt if no root file */ fprintf(stderr, "No current root, can't add dependency '%s'\n", fname); return; } f = filenode(fname); n = (NODE *)xalloc(sizeof(NODE)); /* xalloc checks for out of mem. */ n->nnext = fnd->fnode; fnd->fnode = n; n->nfile = f; } /* * Add a line of method-text to the node 'fnode'. */ addmeth(FILENODE *fnode, char *methtext) { int len; char * p; if (fnode == NULL || methtext == NULL) return; len = strlen(methtext) + 2; if (fnode->fmake == NULL) { p = gmacro(BEFORE); /* xalloc checks for out of mem. */ if (!p) p=""; fnode->fmake = (char *)xalloc((strlen(p)+1)); strcpy(fnode->fmake, p); } len += strlen(fnode->fmake); /* realloc doesn't. */ if ( (fnode->fmake=realloc(fnode->fmake, len)) == NULL) allerr(); strcat(fnode->fmake, methtext); len = strlen(fnode->fmake); if (len && fnode->fmake[len - 1] != '\n') strcat(fnode->fmake, "\n"); } /* * Get a filenode for the file called 'fn'. * Returns NULL if the node doesn't exist. */ FILENODE *gfile(char *fn) { FILENODE *f; for (f = froot ; f != NULL ; f = f->fnext) if (!strcasecmp(fn, f->fname)) return f; return NULL; } /* * Alloc space for a new file node. * To faciiltate %-rules, do not check for * an existing FILENODE with the same name. -AM */ FILENODE *afnode(char *name) { FILENODE *f; /* we need not check for NULL here; xalloc does that for us */ f = (FILENODE *)xalloc(sizeof(FILENODE)); f->fname = (char *)xalloc(strlen(name)+1); strcpy(f->fname, name); f->fmake = NULL; f->fnode = NULL; f->fdate = 0L; f->fflag = 0; f->fnext = froot; froot = f; return f; } /* * Print dependency tree. */ prtree() { FILENODE *f; NODE *n; puts("\ndependency tree"); for (f = froot ; f != NULL ; f = f->fnext) { if ( !(f->fflag&DUMMYP) ) { printf("%s%s%s", f->fname, (f->fflag & ROOTP) ? " (root)" : "", (f->fflag & REBUILT) ? " (rebuilt)" : "", (f->fflag & FAILED) ? " (failed)" : ""); if (f->fdate != 0L) printf("(%lu)\n", f->fdate); else putchar('\n'); if (f->fmake != NULL) printf("%s", f->fmake); for (n = f->fnode ; n != NULL ; n = n->nnext) printf("\t%s\n", (n->nfile)->fname); putchar('\n'); } } }  ================================================ FILE: msx2dist/make_004/MACRO.C ================================================ #include #include #include #include #include "make.h" extern char * strcasestr(char *, char *); extern int debug; /* * Macro processing */ static int emacro(char *name, char * dest); /* * Perform macro substitution from 'orig' to newly allocated string. * Return pointer to the string. * A macro reference is in one of two forms: * (macro-name) * or * * "" expands to a single '' */ char * mexpand(char *orig, char macchar) { int ddi, destsiz; char *s, *d, *dest, mname[STRSIZ]; destsiz=strlen(orig); for (s=orig; *s;) if (*s == macchar) { if (*++s == macchar) { destsiz--; s++; continue; } if (!*s) { destsiz--; break; } d = mname; if (*s != '(') { *d++ = *s++; destsiz-=2; } else { for (++s; *s && *s!=')';) *d++ = *s++; destsiz-=d-mname+3; if (*s != ')') destsiz++; else ++s; } *d = 0; destsiz += emacro(mname, NULL); } else s++; dest=xalloc(destsiz+1); ddi = 0; for (s=orig; *s;) if (*s == macchar) { if (*++s == macchar) { dest[ddi++] = *s++; continue; } if (!*s) break; d = mname; if (*s != '(') *d++ = *s++; else { for (++s; *s && *s!=')';) *d++ = *s++; if (*s != ')') puts("Missed matching ')'"); else ++s; } *d = 0; ddi += emacro(mname, dest+ddi); } else dest[ddi++] = *s++; dest[ddi]=0; if (strlen(dest)!=destsiz) { fprintf(stderr, "strlen(dest)=%d, destsiz=%d.\n",strlen(dest),destsiz); exit(2); } return dest; } /* * Lookup a macro, possible performing * a substitution. * Return number of chars in the expansion. */ static int emacro(char *name, char * dest) { char *end, *pat, *rep, *def; int res, pl, rl; end=strchr(name, ':'); if (end) { *end = 0; def=gmacro(name); if (!def) { if (dest) fprintf(stderr, "Undefined macro: %s\n", name); return 0; } *end = ':'; pat = end+1; rep = strchr(pat, '='); res = 0; if (!rep) { if (dest) fprintf(stderr, "$(%s): missing '=' in macro substitution\n", name); } else { pl = rep-pat; ++rep; rl = strlen(rep); end = def+strlen(def)-pl; while (def <= end) { if ((0 == def[pl] || isspace(def[pl])) && 0 == strncmp(def, pat, pl)) { res += rl; def += pl; if (dest) { strcpy(dest, rep); dest += rl; } } else { if (dest) *(dest++) = *def; res++; def++; } } res += strlen(def); if (dest) strcpy(dest, def); } } else { def = gmacro(name); if (!def) { if (dest) fprintf(stderr, "Undefined macro: %s\n", name); return 0; } res = strlen(def); if (dest) strcpy(dest, def); } return res; } /* * Define a macro. * Give the macro called 'name' the string expansion 'def'. * Old macro-names are superseded, NOT replaced. * exit with error-message if can't define the macro. */ void defmac(char *name, char *def) { MACRO *m; /* we need not check for out of mem. here; xalloc does that for us */ m = (MACRO *)xalloc(sizeof(MACRO)); m->mname = (char *)xalloc(strlen(name)+1); m->mvalue = (char *)xalloc(strlen(def)+1); strcpy(m->mname, name); strcpy(m->mvalue, def); m->mnext = mroot; mroot = m; } /* * Searches tok in lst, * tok must appear as a separate token, * comparison is case insensitive. */ char * tok_find(char * lst, char *tok) { char * srch, c; int toklen; toklen=strlen(tok); for (srch = lst ; ; ) { srch = strcasestr(srch, tok); if (!srch) break; c=srch[toklen]; if (isspace(c)) c=0; if ( !c && (srch == lst || isspace(srch[-1])) ) break; else srch += toklen; } return srch; } /* * diffmac - remove tokens from macro. * * All tokens in the old value the macro that do not appear as token * in del are copied to the new value. * The old value is superseded, NOT replaced. */ void diffmac(char *name, char *del) { MACRO *m; char *cp, * newval; char *next, *last; for ( m=mroot ; (m!=NULL) && (strcmp(name, m->mname)!=0) ; m=m->mnext ) ; if ( m!=NULL ) { cp = m->mvalue; newval = xalloc(strlen(cp)+1); for (next=newval ; *cp ; ) { while (isspace(*cp)) cp++; if (*cp) { last = next; while (*cp && !isspace(*cp)) *next++ = *cp++; *next = 0; if (tok_find(del, last)) next = last; else *next++ = ' '; } } *next = 0; defmac(name, newval); free(newval); } else fprintf(stderr, "%s -= ... ignored because the macro is undefined.\n", name); } /* * Replaces the macro called name with * the concatenation of its value and suf. * If there is no macro called name, a new * macro called name with value suf is created */ void catmac(char * name, char * suf) { MACRO *m; char *cp; for ( m=mroot ; (m!=NULL) && (strcmp(name, m->mname)!=0) ; m=m->mnext ) ; if ( m!=NULL ) { if ( (cp=realloc(m->mvalue, strlen(m->mvalue)+strlen(suf)+2)) == NULL ) allerr(); m->mvalue=strcat(strcat(cp," "), suf); } else { fprintf(stderr, "Macro %s not yet defined.\n", name); defmac(name, suf); } } /* * undefmac - undefine a macro. * Return 0 if macro was succesfully undefined, -1 if not found. */ int undefmac(char * name) { MACRO *m = mroot; MACRO *prev = NULL; while (m != NULL && strcmp(name, m->mname)) { prev = m; m = m->mnext; } if (m == NULL) return -1; if (prev == NULL) mroot = m->mnext; else prev->mnext = m->mnext; free(m->mname); free(m->mvalue); free(m); return 0; } /* * Lookup a macro called 'name'. * Return a pointer to its definition, * or NULL if it does not exist. */ char *gmacro(char *name) { MACRO *m; for (m=mroot; m != NULL; m=m->mnext) if (!strcmp(name, m->mname)) return m->mvalue; return NULL; }  ================================================ FILE: msx2dist/make_004/MAKE.C ================================================ #include #include #define MAXMODS 50 #define DATE unsigned long int fmake(char *); /* * MAKE - Maintain seperate source files * * SYNOPSIS * MAKE [-f file] [-a] [-n] [-d] [-k] [-v] [name] ... * f: use 'file' instead of default makefile * a: assume all modules are obsolete (recompile everything) * n: don't recompile, just list steps to recompile * d: debugging (print tree, file info) * k: keep going after error * v: verbose (display steps before executing) * name: module name to recompile * * AUTHORS * Landon M. Dyer, Atari Inc. * Arnold Metselaar * */ char *mfiles[] = { /* default makefiles */ "MAKEFILE", "MAKEFILE.2", /* e.g. DOS2 makefile */ "MAKEFILE.1", "" }; /* MACRO *mroot = NULL; *//* root of macro-list */ /* FILENODE *froot = NULL; *//* root of filenode-list */ /* FILENODE *firstf = NULL; *//* the very first filenode */ /* FILE *mkfp = NULL; *//* script file */ char *modnames[MAXMODS]; /* module-names mentioned in commandline */ int modcount = 0; /* #of module-names */ int obsolete = 0; /*nonzero: every file should be recompiled */ int debug = 0; /*nonzero: turn on debugging */ int noexec = 0; /*nonzero: no execution of commands */ int keepgoing = 0; /*nonzero: don't give up after first error */ int verbose = 0; /*nonzero: print commands before executing */ #define clower(a) (isupper(a) ? tolower(a) : a) /* * process a simple option */ static void opt_char(char c) { switch (clower(c)) { case 'a': obsolete=1; break; case 'd': debug=1; break; case 'n': noexec=1; break; case 'k': keepgoing=1; break; case 'v': verbose=1; break; default: fprintf(stderr, "Unknown switch: %c\n", c); break; } } int main(int argc, char** argv) { int arg, i; char *mfile = NULL; for (arg = 1; arg < argc; ++arg) if (*argv[arg] == '-') { if ('f'==clower(argv[arg][1])) { if (++arg >= argc) { fprintf(stderr, "-f needs filename argument.\n"); return 1; } mfile = argv[arg]; } else opt_char(argv[arg][1]); } else if (modcount < MAXMODS) { if (argv[arg][0]) /* ignore trailing whitespace */ modnames[modcount++] = argv[arg]; } else { fprintf(stderr, "Too many module names.\n"); return 1; } if (mfile != NULL) { arg = fmake(mfile); if (arg == -1) fprintf(stderr, "\nCannot open makefile\n"); } else { for (i = 0; *mfiles[i]; ++i) if ((arg=fmake(mfiles[i])) != -1) break; if (!*mfiles[i]) fprintf(stderr, "\nCannot open makefile\n"); } if (debug) prtree(); return arg; }  ================================================ FILE: msx2dist/make_004/MAKE.H ================================================ #define ESCCHAR '\\' /* escape char (is one \) */ #define MACCHAR '$' /* macro-definition char */ #define COMCHAR '#' /* comment char */ #define DEFMAC "=" /* macro-definition token */ #define CATMAC "+=" /* macro-concatenation token */ #define DIFFMAC "-=" /* macro-filtering token */ #define DEPEND ":" /* dependency-definition token */ #define INIT "~INIT" /* initialization macro */ #define DEINIT "~DEINIT" /* de-init macro */ #define BEFORE "~BEFORE" /* the per-root 'startup' method */ #define AFTER "~AFTER" /* the per-root 'wrapup' method */ #define DEBUG if(0) #define STRSIZ 512 #define MAXMODS 50 /* file attributes */ #define REBUILT 0x01 /* file has been reconstructed */ #define ROOTP 0x02 /* file was named on left side of DEPEND */ #define FAILED 0x04 /* reconstructing the file failed */ #define DUMMYP 0x08 /* 'file' only exists within %-rule */ #define DATE unsigned long struct node { struct filenode *nfile; /* this node's file */ struct node *nnext; /* the next node */ }; typedef struct node NODE; struct filenode { char *fname; /* the filename */ char *fmake; /* remake string for file */ DATE fdate; /* 32 bit last-modification date */ NODE *fnode; /* files this file depends on */ char fflag; /* magic flag bits */ struct filenode *fnext; /* the next file */ }; typedef struct filenode FILENODE; struct macro { char *mname; /* the macro's name */ char *mvalue; /* the macro's definition */ struct macro *mnext; /* the next macro */ }; typedef struct macro MACRO; extern MACRO *mroot; extern FILENODE *froot; char *gmacro(char *name); FILENODE *filenode(char *fname); FILENODE *gfile(char *fn); char *token(char **strpp); void *xalloc(unsigned len);  ================================================ FILE: msx2dist/make_004/MAKE.MAN ================================================ MAKE(I) 3/10/84 MAKE(I) NAME MAKE - maintain multiple source files SYNOPSIS MAKE [-N] [-A] [-V] [-D] [-K] [-F makefile] [name ...] DESCRIPTION MAKE is a utility inspired by the Unix(tm) command of the same name. MAKE helps maintain programs that are constructed from many files. MAKE processes a "makefile", a file which describes how to build a program from its source files, and executes the the steps in sub-processes. MAKE uses 48 KiB video memory to store its own state. Be careful: this MAKE is NOT compatible with Unix(tm) MAKE! The 'N' option causes MAKE to print out the steps it would follow in order to rebuild the program. The 'A' option tells MAKE to assume that all files are obsolete, and that everything should be recompiled. The 'V' options causes MAKE to print out the commands before executing them. The 'D' tells make print out even more information. MAKE normally stops after the first error (nonzero exit status), the 'K' option instructs MAKE to keep going with other that files that do not depend on a file that caused an error. The 'F' option, followed by a filename, can be used to specify a makefile other than the default one. If no names are specified in the commandline, the first dependency in the makefile is examined. Otherwise, the specified root names are brought up to date. Filenames are not case sensitive. It is possible to use wildcards in the command line to rebuild all all files matching a pattern: MAKE *.o Instructs Make to rebuild all _existing_ object files in the current directory. The default makefiles are: MAKEFILE MAKEFILE.2 MAKEFILE.1 If the first makefile cannot be found, MAKE attempts to use the next one. This way a program can be distributed with makefiles for different compilers or different MSXDOS versions. If no makefile is ever found, MAKE prints a diagnostic and aborts. THE MAKEFILE Comments begin with '#' and extend to the end of the line. A '#' (or almost any other character) may be escaped with the escape character slash backward (\). An escape character may be typed by doubling it (\\). The standard Unix escape codes are recognized (\n, \r, \t, \b, \f). Subdirectories are supported by MAKE through the use of LIBDOS2, but may not be fully supported by the programs used to actually build your program. Use the slash forward (/) as a path separator, like in Unix(tm). A makefile is a list of dependencies. A dependency consists of a root name, a colon, and zero or more names of dependent files. (The colon MUST be surrounded by whitespace.) For instance, in: make.com : make.o utils.o parsedir.o file.o macro.o the file 'make.com' depends on five other files. A root name with an empty dependency, as in: print : is assumed NEVER up to date, and will always be recompiled. The dependency list may be continued on successive lines: bigfile.com : one.o two.o three.o four.o five.o six.o gronk.o freeple.o scuzzy.lnk frog.txt greeble.out Any number of 'method' lines may follow a dependency. Method lines begin with an ascii tab. When a file is to be recompiled, MAKE interprets these lines (minus the tab) as commands. Set commands, which change the environment are handled by MAKE itself, and changes to the environment are reverted when MAKE stops processing a method. It searches for a .com-file in the directories in the PATH environment variable. if that fails, MAKE loads the the program pointed to by the SHELL environment variable to interpret the line. If a method line starts with a colon (:) the colon then the colon is not treated as a part of the command and the exit status of the command is ignored. For example, in: make.com : make.o parsedir.o file.o macro.o mk.h link make, parsedir, file, macro :del scratch echo "Just another version of MAKE ..." the three lines following the dependency make up the method for recompiling (or in this case, re-linking) the file 'make.com'. If there is no file named scratch the error code from del will be ignored because of the colon. If the macro "~INIT" is defined, its text will be executed before any other method. If the macro "~DEINIT" is defined, its text will executed just before MAKE exits. ~INIT = mode 80\ntl msxcalc\n ~DEINIT = $(~DEINIT)tk "JvdM MSXCALC"\ncls will expand to: mode 80 tl msxcalc . . tk "JvdM MSXCALC" cls When a root's method is defined, the value of the macro "~BEFORE" is prefixed to the method, and the value of the macro "~AFTER" is appended to it. Frequently one wants to maintain more than one program with a single makefile. In this case, a "master dependency" can appear first in the file: allOfMyToolsAndHorribleHacks : cat peek poke.com grunge cat : cat.com cat.com : .... (stuff for CAT.COM) peek : peek.com peek.com : (stuff for PEEK.COM) poke.com : (stuff for POKE.COM) grunge : grunge.com grunge.com : (stuff for grunge) In other words, make will bring everything up to date that is somehow connected to the first dependency (its assumed that the incredibly lengthy filename specified in this example won't actually exist). MACROS A macro is defined by a line of the form (the '=' MUST be surrounded by whitespace): = A macro may be deleted by assigning an empty value to it. Macros may be redefined, but old definitions stay around. If a macro is redefined, and the redefinition is later deleted, the first definition will take effect: A way to change a macro is to use the operator +=, which must also be surrounded by whitespace: += In this case the old definition does not stay around. It is useful for building long macro values. One can also remove items from a list using the -= operator, which must also be surrounded by whitespace: -= In this case both the macro value and the delendum is treated as a list of tokens, so it is not possible to delete parts of words. The old macro value stay around like in the case of a normal macro definition. MAC = first ! MAC = "first" MAC = second ! MAC = "second" MAC = $(MAC) third ! MAC = "second third" MAC += fourth ! MAC = "second third fourth" MAC -= third ! MAC = "second fourth" MAC = ! MAC = "second third fourth" MAC = ! MAC = "second" MAC = ! MAC = "first" MAC = ! MAC has no definition A macro may be referenced in two ways: $ or $(macro-name) The first way only works if the macro's name is a single character. If the macro's name is longer than one character, it must be enclosed in parenthesis. ['$' may be escaped by doubling it ("$$".)] For example, in: G = mk.h mk1.h OBJS = make.o file.o parsedir.o macro.o BOTH = $(OBJS) $G make.com : $(OBJS) $G make.com : $(BOTH) make.com : mk.h mk1.h make.o file.o parsedir.o macro.o echo "This is a dollar sign --> $$" after macro expansion, the three dependencies will appear identical and the two '$'s in the last line will turn into one '$'. SUBSITUTION REFERENCES Make can substitute suffices when it expands a macro. Sustitution references have the same form as in GNU make; $(MACRONAME:pattern=relpacement). Note that there are no spaces around the ':' and the '=' here. Each occurence of pattern that immediately precedes whitespace or the end of the macro value, is replaced with the replacement. For example in: OBJ = bar.o foo.o SRC = $(OBJ:o=c) the value of SRC will be 'bar.c foo.c' %-RULES Often many files are build in the same way. %-Rules can be used to describe the build method of several files in one rule. A %-rules consists of a pattern starting with '%', a colon (:), the name of macro, another colon optionally followed by dependencies and methods. For each filename in the value of the macro a new rule is constructed from the %-rule as follows. The stem is what must be substituted for '%' in the pattern to obtain the filename. The macro name and one colon are removed from the %-rules and all occurences of '%' are replaced by the stem. For example: H = PROG.H OBJS = PROG.O PART2.O %.O : OBJS : %.C $H CC -c -o -v %.C PART2.O : EXTRA.H is equivalent to PROG.O : PROG.C PROG.H CC -c -o -v PROG.C PART2.O : PART2.C PROG.H EXTRA.H CC -c -o -v PART2.C REDIRECTIONING Make supports redirectioning of the standard input stream with "<", of standard output with ">" and ">>" and of standard error with "2>" and "2>>". This is done by replacing handles 0,1,2 with the "close file handle" and the "duplicate file handle" msxdos2 bdos calls as appropriate. HERE-DOCUMENTS If a line contains "<<" directly followed by a word, the following lines until a line starting with the word are copied to '$M.T'. The characters "<<" and the word are removed from the line and "$M.T" is opened for input and provided as standard input. This is useful in combination with HiTech-C when one wants to link more object files than would fit on a command line. For example: bigprog.com : $(COBJ) $(ASOBJ) $(LIBS) cc < pack.bat echo lhpack $(DIST) $(FILES) >> pack.bat echo lhpack can not be run from make, please run pack.bat from the command prompt # # end of makefile ENVIRONMENT ITEMS VSHTOP If set, VSHTOP specifies the first page of video memory that will not be used or probed by MAKE. Pages 0..7 are ordinary video memory, pages 8..11 are the extended video memory. Legal values are 2..12, default is 12. Other values are silently ignored. If VSHTOP is 2 or 3, MAKE will not work. You can use this to protect data in higher pages. Some emulators may need VSHTOP=8. PATH The PATH environment specifies a search path for .com-files, it should be a semicolon(;)-separated list of directories, like for COMMAND2.COM It is possible to set environment items with "set" as a part of a targets method. Environment items changed this way will be restored by make when it stops executing the methos of the target. KNOWN BUGS MAKE uses video memory to store its internal state when executing a subprocess. MAKE allocates 48 KiB from the top of the video ram. MAKE and CC recognise the video memory in use by MAKE. Some other programs, like lhpack, overwrite the video memory used by MAKE. Such programs must be run directly from the command prompt or from a batch file. MAKE probes for extended video memory and may not run properly on on emulators that do not emulate extended memory correctly. If that's the case try "set VSHTOP=8". The screen flashes when MAKE reads/writes its state from/to video memory. This is to improve reliability of video memory access. AUTHORS Landon Dyer G.DYER@SU-SCORE.ARPA 175 Calvert Dr. #F-211 BASHFL::DYER (Atari Coinop) Cupertino, CA 95014 - original version Pierre Gielen - adaptations for MSX-DOS2 Arnold Metselaar - code for executing subprocesses and continuing - %-rules - here-documents - additional macro functionality - redirectioning  ================================================ FILE: msx2dist/make_004/MAKEFILE ================================================ # # MSXDOS2 Make utility # Compile with HI-TECH C. # Needs: # - vsh3.o, which belongs to cc.com # - libdos2.lib # - strcasecmp(), addition to libc.lib (get the fixes for HiTech libs) # - strcasestr(), idem # Directory where the libraries and vsh3.o are stored CDIR = A:/HITECH LIBS = $(CDIR)/libdos2.lib $(CDIR)/libc.lib COBJ = make.o utils.o macro.o token.o parsedir.o file.o mspawn.o path.o XOBJ = xargs.o token.o path.o H = make.h FILES = $H $(COBJ:.o=.c) FILES -= $(XOBJ:.o=.c) FILES += $(XOBJ:.o=.c) DIST = make_004.lzh DOCUMENTATION = readme make.man makefile # # update make.com # make.com : $(COBJ) $(CDIR)/VSH3.O $(LIBS) CC -V -OMAKE.COM -MMAKE.MAP -R -N VSH3.O $(COBJ) -lDOS2 # # update xargs.com # xargs.com : $(XOBJ) $(CDIR)/VSH2.O $(LIBS) CC -V -OXARGS.COM -MXARGS.MAP -R -N VSH2.O $(XOBJ) -lDOS2 # # update object files # %.O : COBJ : %.C $H CC -c -o -v %.C xargs.o : xargs.c CC -c -o -v xargs.c # # update distribution archive # distribution : $(DIST) $(DIST) : MAKE.COM xargs.com $(FILES) $(DOCUMENTATION) echo del $(DIST) > pack.bat xargs -b <> pack.bat make.com xargs.com $(DOCUMENTATION) $(FILES) EOF echo lhpack can not be run from make, please run pack.bat from the command prompt # # end of makefile  ================================================ FILE: msx2dist/make_004/MSPAWN.C ================================================ #include #include #include #include #include #include #ifndef O_TRUNC #define O_TRUNC 0 #endif #ifndef O_WRONLY #define O_WRONLY 0 #endif extern int _spawn(char*, char*, char *); extern char *token(char **); int spawnblock(char *); char * pathfind(char *); int spawnline(char *, char *); extern int verbose; extern int noexec; static char * tmpnam = "$M.T"; int mkfile(char *s, char *fds, char **q) { int klen, val; FILE * fp; register char * res; for (klen=0, s+=2 ; isalnum(*s) ; ++s) ++klen; s-=klen; if (noexec) printf("<<%.*s\n", klen, s); for (res=*q ; *res && strncmp(res,s,klen) ; ++res) { if ( !(res=strchr(res,'\n')) ) break; } if (!res) fputs("make: runaway << text\n", stderr); else { fp=noexec ? stdout : fopen(tmpnam,"w"); if (!fp) { val=errno; perror(tmpnam); fputs(" while creating temp. file in make:mkfile()\n",stderr); return val; } *res=0; if ((fputs(*q,fp)==EOF)||(fputs("\32\n",fp)==EOF)) { val=errno; perror(tmpnam); fputs(" while writing temp. file in make:mkfile()\n",stderr); if (!noexec) fclose (fp); return val; } *res=*s; if (!noexec && fclose(fp)) { val=errno; perror(tmpnam); fputs(" while closing temp. file in make:mkfile()\n",stderr); return val; } if (noexec) printf("%.*s\n", klen, s); while ( *res && ('\n'!=*res++) ) /* nix */ ; memmove(s-2, s+klen, strlen(s+klen)+1); } if (noexec) val=0; else { val=open(tmpnam, O_RDONLY|O_INHER); if (val<0) { val=errno; perror(tmpnam); fputs(" while opening for redirectioning.\n", stderr); } else { fds[0]=val; val=0; } } *q=res; return val; } struct env_sav { char * name; char * val; struct env_sav * next; } ; struct env_sav * env_stack; /* * undo changes made by do_set */ void pop_env() { struct env_sav *cur, *nxt; for ( cur=env_stack ; cur ; cur=nxt) { setenv(cur->name, cur->val); free(cur->val); nxt = cur->next; free(cur); } } /* process redirectioning */ int redir(char *p, char *fds) { int mode, append, n, fd; char *s, *t; n=append=0; s=p; switch (*s) { case '2': ++n; ++s; case '>': ++n; ++s; mode=O_WRONLY|O_INHER; if ('>'==*s) { append=1; ++s; } break; case '<': ++s; mode=O_RDONLY|O_INHER; } while (*s && isspace(*s)) ++s; for (t=s ; *t && !isspace(*t) ; ++t) ; if (noexec||verbose) putchar(*p); *p=*t; *t=0; if (noexec||verbose) { printf("%s ",p+1); fd=0; } if (!noexec) { if (n && !append) { fd=creat(s,0666); /* Ensure the file exists. */ close(fd); } fd=open(s,mode); if (fd<0) { perror(s); fputs(" while opening for redirectioning.\n", stderr); } else { fds[n]=fd; if (append) lseek(fd, 0, SEEK_END); } } if (*p) memmove(p+1, t+1, strlen(t+1)+1); return (fd<0)?errno:0; } /* * Executes a subprocess for each line in blok. * Stops when a subprocess returns a nonzero exit-status * If a line starts with ':', the ':' is skipped and the exitstatus is ignored. * return value is exit-status of last subprocess executed, * or zero if the last line processed starts with ':' * * if a line contains "<<" followed by a word, the following lines * until a line starting with the word are copied to '$M.T'. * "<<" and the word are removed from the line and '$M.T' is open for input. */ int spawnblock(char *blok) { int res, i; char *linbuf, *p, *q, *s; char quote, heredoc, fds[3]; env_stack = NULL; linbuf=malloc(strlen(blok)+1); if (!linbuf) { fputs("*** Out of memory\n",stderr); return 0xDE; } heredoc=0; for (p=strcpy(linbuf,blok),res=0 ; (res==0) && (*p) ; p=q) { fds[0]=0; fds[1]=1; fds[2]=2; for (q=p ; (*q)&&(*q!='\n') ; ++q) /* nix */; if (*q=='\n') *q++='\0'; /* messy; obey "" and '' */ for (s=p ; *s && (res==0); ) { switch (*s) { case '"': case '\'': quote=*s++; while (*s && (*s++ != quote)) ; break; case '>': res=redir(((s>p) && ('2'==s[-1])) ? s-1 : s, fds); break; case '<': if ('<'==s[1]) { res=mkfile(s, fds, &q); heredoc=!noexec; } else res=redir(s, fds); break; default: s++; } } if (res) break; res = spawnline(p,fds); for ( i=0 ; i<3 ; ++i) if (fds[i]>2) close(fds[i]); if (heredoc) { unlink(tmpnam); heredoc=0; } } pop_env(); free(linbuf); return res; } /* * change the environment like set would do, but store the old value */ int do_set(char * line) { char * q; struct env_sav * penv; q=token(&line); penv=malloc(sizeof(struct env_sav)); if (penv) { penv->val=getenv(q); penv->next=env_stack; setenv(q,line); return 0; } else { fputs("*** Out of memory\n",stderr); return 0xDE; } } char *shell = NULL; /* * executes one subprocess. * if the first token in line can be found in the command search path, * the file is loaded and executed directly, * otherwise line is interpreted by the program pointed to by the * environment variable SHELL. */ int spawnline(char *line, char *fds) { char *command, *progfile, ignore; static char set[]="set"; int res; if (':' == *line) { ignore=1; ++line; } else ignore=0; command=token(&line); if (0 == strcasecmp(&set, command)) progfile=&set; else progfile=pathfind(command); if (progfile==NULL) { if (!shell) shell=getenv("SHELL"); if (!shell) { fprintf(stderr, "make: '%s' not found in path, and 'SHELL' not in environment\n", command); return 0x8E; /* unrecognised command */ } else { progfile=shell; if (*line) *strchr(command, '\0')=' '; line=command; } } if (progfile!=&set && strlen(line)>126) { fprintf(stderr,"%s %.20s... : Linebuffer overflow\n", progfile, line); res=0x8D; /* BUFUL */ } else { if (verbose||noexec) { printf(noexec ? "%s %s\n": "[MAKE] %s %s\n", progfile, line); } if (progfile==&set) res=do_set(line); else res=noexec ? 0 : _spawn(progfile, line, fds); if (progfile == shell) { if (res==0x8C) res=0; /* internal 'error' code meaning no error */ else command=token(&line); } } if (res && (!ignore || verbose)) fprintf(stderr, "'%s' failed with error code %d%s.\n", command, res, ignore ? " (ignored)" : ""); return (ignore ? 0 : res); }  ================================================ FILE: msx2dist/make_004/PARSEDIR.C ================================================ #include #include #include #include "make.h" static struct stat statbuf; #define endoftime ULONG_MAX /* when i'm old and wise */ /* * Get a file's creation date. */ int getdate(FILENODE *f) { char fnm[65]; strncpy(fnm,f->fname,65); if (!stat(fnm,&statbuf)) f->fdate = statbuf.st_mtime; else { fprintf(stderr, "Can't get date for file '%s'\n", f->fname); f->fdate = endoftime; } return 0; } /* * laterdt - compare two dates. * Return -1, 0 or 1 if date1 < date2, date1 == date2, or date1 > date2 */ int laterdt(DATE date1, DATE date2) { if(date1 > date2) return 1; if (date1 < date2) return -1; return 0; }  ================================================ FILE: msx2dist/make_004/PATH.C ================================================ #include #include #include #include #include extern _flip(char *, char *, int); /* substitute '\\' for '/' */ #define MAXLEN 66 static char **path_elt; static char padbuf[MAXLEN+1]; static char *nopath[]={"", NULL}; /* * Tries to find command s in the search path. * Returns the filename if it is found and * NULL otherwise. */ char * pathfind(char* s) { char *pad,*p; int n,i; struct stat dummy; if (path_elt==NULL) { pad=getenv("PATH"); if ((!pad)||strlen(pad)==0) path_elt=nopath; else { for (p=pad, n=1 ; *p ; ) if (*p++ == ';') ++n; path_elt=malloc((n+1)*sizeof(char*)); if (path_elt) { path_elt[0]=pad; for (i=0,p=pad ; (*p) ; ) switch (*p) { case ';': *p='\0'; path_elt[++i]=++p; break; case ' ': ++path_elt[i]; /* fall through */ default: ++p; } path_elt[++i]=NULL; } else { fputs("Not enough memory, ignoring $PATH\n",stderr); path_elt=nopath; } } } for (i=0,pad=NULL ; path_elt[i] && !pad ; ++i) if (strlen(path_elt[i])+strlen(s)+5<=MAXLEN) { strcpy(padbuf,path_elt[i]); if (*padbuf) switch (padbuf[strlen(padbuf)-1]) { case ':': case '/': case '\\': break; default: strcat(padbuf,"\\"); } strcat(strcat(padbuf,s),".COM"); if (stat(padbuf, &dummy)==0) { _flip(padbuf, padbuf, MAXLEN+1); pad=padbuf; } } return pad; }  ================================================ FILE: msx2dist/make_004/README ================================================ The original version of this make program was written by Landon Dryer. Pierre Gielen has adapted it to msx-dos, and later Arnold Metselaar adapted it further for msx-dos2 and made some important improvements The contents of Readme file that came with the old msx-dos version is below. Last month I wrote a version of the Unix(tm) utility MAKE. It runs under VAX/VMS and MSDOS 2.0. I am placing it in the public domain, and it is yours for the asking. You may copy it, or give it away. You can make any changes you like to it. All I ask is that you DO NOT TRY TO SELL IT. Anyway, there is now a MAKE for MSXDOS. It is free, and it works pretty well. I'm giving it away because it might do the world some good. Who knows? Caveat: this version of MAKE is NOT compatible with the Unix(tm) version. Some differences are explained in the documentation. Most of the problem stems from the fact that I've never had a chance to use the original version of MAKE, and the documentation I've seen on it has been poor. My idea of what a make program should do is almost certainly different from what you Unix(tm) hackers are used to. Well, hell -- the software is worth what you paid for it. Have fun. In order to get MAKE running on your system, you need to: 1. Read the documentation file MAKE.MAN. (Yes, read the directions.) 2. Edit the file MAKE.H to represent your system 3. Recompile the source code 4. Test out MAKE by running it on itself. (Make a backup first!) Good luck, Landon Dyer (G.DYER @ SU-SCORE)  ================================================ FILE: msx2dist/make_004/TOKEN.C ================================================ #include #include #include "make.h" void stripwh(char **strpp); /* * Get next token from the string. Return a pointer to it, or NULL. * Adjust pointer to point to next part of string. * The string is modified. * A token consists of any number of non-white characters. */ char *token(char **strpp) { char *s, *beg; stripwh(strpp); if (!**strpp) return NULL; beg = s = *strpp; while (*s && !isspace(*s)) ++s; if (*s) *s++ = '\0'; *strpp = s; return beg; } /* * Parse character escape-sequences in a line of text. * = * n = newline, and so on * = * The string is truncated at the first non-escaped occurance of 'comchar'. */ escape(char *str, char comchar) { char *d, c; for (d = str; *str && *str != comchar; ++str) if (*str == ESCCHAR && *(str + 1)) switch((c = *++str)) { case ESCCHAR: *d++ = ESCCHAR; break; case 'n': *d++ = '\n'; break; case 'r': *d++ = '\r'; break; case 't': *d++ = '\t'; break; case 'b': *d++ = '\b'; break; case 'f': *d++ = '\f'; break; default: *d++ = c; break; } else *d++ = *str; *d++ = 0; } void stripwh(char **strpp) { char *s; s = *strpp; while(isspace(*s)) ++s; *strpp = s; }  ================================================ FILE: msx2dist/make_004/UTILS.C ================================================ #include #include #include #include #include #include #include "make.h" int fmake(char *); int examine(FILENODE *, DATE); int recomp(FILENODE *); int determ(); extern int laterdt(DATE,DATE); extern void defmac(char *, char *); extern void catmac(char *, char *); extern void diffmac(char *, char *); extern int undefmac(char *); extern int spawnblock(char*); extern int strcasecmp(char*, char*); void finish(FILENODE *f); #define PADLEN 64 /* maximum length of filename */ MACRO *mroot = NULL; /* root of macro-list */ FILENODE *froot = NULL; /* root of filenode-list */ FILENODE *firstf = NULL; /* the very first filenode */ FILE *mkfp = NULL; /* script file */ extern int modcount; extern int debug; extern int obsolete; extern int keepgoing; extern int verbose; extern int noexec; extern char *modnames[MAXMODS]; /* module-names mentioned in commandline */ #define endoftime ULONG_MAX /* a date, the very last possible */ void fparse(FILE *fp); /* * Construct dependency tree from the makefile 'fn'. * Figure out what has to be recompiled, and write a script file to do that. */ int fmake(char * fn) { int res; FILE *fp; if (0 == strcmp("-",fn)) fp = stdin; else if ((fp = fopen(fn, "r")) == NULL) return -1; fparse(fp); res=determ(); fclose(fp); return res; } char * mexpand(char *orig, char macchar); /* * Parse the input file, defining macros and building the dependency tree. */ void fparse(FILE *fp) { char *strp, *tok1, *tok2, *s; FILENODE *lastf = NULL; char *ebuf, ibuf[STRSIZ]; for (;; free(ebuf)) { if (fgets(ibuf, STRSIZ, fp) == NULL) break; /* changed prototype of mexpand() to handle long expansions - AM */ ebuf = mexpand(ibuf, MACCHAR); escape(ebuf, COMCHAR); /* clobber last newline in string */ s = ebuf + strlen(ebuf) - 1; if (s >= ebuf && *s == '\n') *s = '\0'; if (*ebuf == '\t') { addmeth(lastf, ebuf+1); continue; } strp = ebuf; if ((tok1 = token(&strp)) == NULL) continue; if ((tok2 = token(&strp)) != NULL) { if (!strcmp(tok2, DEFMAC)) { if (*strp) defmac(tok1, strp); else if (undefmac(tok1) < 0) fprintf(stderr,"Can't undefine macro '%s'\n", tok1); continue; } else if (!strcmp(tok2, CATMAC)) { if (*strp) catmac(tok1, strp); else fprintf(stderr,"'%s %s' ignored.\n", tok1, CATMAC); continue; } else if (!strcmp(tok2, DIFFMAC)) { if (*strp) diffmac(tok1, strp); else fprintf(stderr,"'%s %s' ignored.\n", tok1, DIFFMAC); continue; } else if (!strcmp(tok2, DEPEND)) { finish(lastf); lastf = filenode(tok1); if (firstf == NULL) firstf = lastf; lastf->fmake = NULL; /* ${~BEFORE} is prepended by addmeth(), * if the file contains a method line for this root. */ lastf->fflag |= ROOTP; while ((tok1 = token(&strp)) != NULL) addfile(lastf, tok1); continue; } else addfile(lastf, tok2); } do { addfile(lastf, tok1); } while((tok1 = token(&strp)) != NULL); } finish(lastf); } int match(char *buf, char *pat, char *name); char *subs(char *x, char *s); /* * Called to finish the parsing of a dependency rule. * The value of AFTER is added to the method. * If the rule is a %-rule then a new rule is generated for each * target in the expansion */ void finish(FILENODE * fnd) { NODE *dep, *rp, *dp; FILENODE *rfp; char *cp, *xp, *fn, *rest; char stem[PADLEN]; if (fnd->fmake) addmeth(fnd, gmacro(AFTER)); if (fnd->fname[0]=='%') { fnd->fflag |= DUMMYP ; for ( rp=fnd->fnode ; rp&&strcmp(rp->nfile->fname,DEPEND) ; rp=rp->nnext) if (strchr(rp->nfile->fname, '%')) rp->nfile->fflag |= DUMMYP ; if ( (dep=rp) ) dep->nfile->fflag |= DUMMYP ; else { fprintf(stderr, "Can't find second '%s' in %%-rule.\n", DEPEND); exit(2); } /* the 'dependencies' in the linked list are in reverse order */ if (dep->nnext == NULL) { fprintf(stderr, "In %%-rule: No macro name given.\n"); exit(2); } fn = dep->nnext->nfile->fname; if ( (cp=gmacro(fn)) == NULL ) { fprintf(stderr, "In %%-rule: macro '%s' not defined.\n", fn); exit(2); } if (debug) { puts("%-rule:"); printf("pattern ='%s'\n",fnd->fname); printf("$(%s)='%s'\n", fn, cp); } dep->nnext->nfile->fflag |= DUMMYP ; xp=xalloc(strlen(cp)+1); /* xalloc checks for out of mem. */ rest=strcpy(xp,cp); while ( (fn=token(&rest)) ) { if (! match(stem, fnd->fname, fn)) fprintf(stderr, "'%s' does not match '%s'.\n", fn, fnd->fname); else { if (debug) printf("\t%s\n",fn); rfp=filenode(fn); rfp->fflag |= ROOTP; for ( dp=fnd->fnode ; dp!=dep ; dp=dp->nnext ) { cp=subs(dp->nfile->fname, stem); addfile(rfp, cp); free(cp); } if (fnd->fmake) rfp->fmake = subs(fnd->fmake, stem); } } free(xp); for ( rp=fnd->fnode ; rp ; rp=dp) { dp=rp->nnext; /* if (rp->nfile->fflag & DUMMYP) frnode(rp->nfile); */ free(rp); } fnd->fnode=NULL; if (fnd->fmake) { free(fnd->fmake); fnd->fmake=NULL; } } /* endif (fnd-->fname[0]=='%') */ } /* * 'matches' name against the pattern; * pat must begin with a '%', and the end of name must * be equal to the second to last characters in pat. * if this is the case then the beginning of name is stored in buf and * returns 1 on success, 0 otherwise */ int match(char *buf, char *pat, char *name) { int len; len=strlen(name)-strlen(pat+1); if (len>=PADLEN) { fprintf(stderr, "'%s' : too long!\n"); return 0; } if (strcasecmp(name+len,pat+1)!=0) return 0; strncpy(buf, name, len); buf[len]='\0'; return 1; } /* * returns a newly malloc()ed string, formed from x by * replacing each occurence of '%' with s. */ char *subs(char *x, char *s) { char *p, *res; int len, slen; slen=strlen(s); for (p=x,len=0 ; (*p) ; ++p) len+=(*p=='%') ? slen : 1; res=xalloc(len+1); /* xalloc() checks for out of mem. */ for (p=res ; (*x) ; ++x) { if (*x=='%') { strcpy(p,s); p+=slen; } else *p++ = *x; } *p='\0'; return res; } /* * Determine sequence of recompiles from the creation dates. * If there is anything to recompile, * then do it by calling recomp(). */ int determ() { FILENODE *f; int i,res; char *m; if (firstf == NULL) { /* empty tree */ printf("No changes\n"); return 0; } res=0; if (modcount == 0) res=(examine(firstf, endoftime)==FAILED)?1:0; else for (i = 0; (i < modcount) && (!res || keepgoing) ; ++i) { if ((f = gfile(modnames[i])) == NULL) { fprintf(stderr, "Can't find root '%s'.\n", modnames[i]); continue; } if ((f->fflag & ROOTP)== 0) { fprintf(stderr, "'%s' is not a root!\n", f->fname); continue; } res=(examine(f,endoftime)==FAILED)||res?1:0; } if (mkfp != NULL) { m=gmacro(DEINIT); if (m) res=(spawnblock(m) || res)?1:0; } else printf("No changes\n"); return res; } /* * Examine filenode 'fnd' and see if it has to be recompiled. * 'date' is the last-touched date of the node's father * (or 'endoftime' if its a root file.) * Returns REBUILT if recompilation was successful, * FAILED if recompilation failed and * 0 otherwise * * Root files with NO dependencies are assumed not to be up to date. */ int examine(FILENODE *fnd, DATE date) { int rebuildp = 0; NODE *n; if (debug) { printf("\n examine(%s, ", fnd->fname); if (endoftime == date) printf("endoftime) {"); else printf("%lu) {", date); } getdate(fnd); if ((fnd->fnode == NULL) && (fnd->fflag & ROOTP)) { if (debug) puts("root w/o dependencies"); rebuildp = REBUILT; } else for ( n=fnd->fnode ; (n!=NULL) && (keepgoing || ((rebuildp&FAILED)==0)) ; n=n->nnext) { if (n->nfile->fflag & FAILED) { rebuildp = FAILED; fnd->fflag |= FAILED; } else rebuildp |= examine(n->nfile, fnd->fdate); } if (rebuildp & FAILED) fprintf(stderr, "'%s' not remade because of errors\n", fnd->fname); if ( REBUILT==(rebuildp&(REBUILT|FAILED)) ) { if (debug) putchar('\n'); if (recomp(fnd)) rebuildp=FAILED; } if (laterdt(fnd->fdate, date) > 0) { if (debug) printf ("newer; %lu ", fnd->fdate); rebuildp |= REBUILT; } if (obsolete || (date==endoftime) ) rebuildp |= REBUILT; if (debug) printf(" %s }", rebuildp ? ( (rebuildp&FAILED) ? "failed" : "rebuilt" ) : "uptodate" ); return (rebuildp&FAILED)?FAILED:rebuildp; } /* * Make sure a filenode gets recompiled. * returns non-zero on faillure */ int recomp(FILENODE *f) { /* FILENODE *sf; */ char *m; int res; res = 0; if (mkfp == NULL) { mkfp = stdout; if ((m = gmacro(INIT)) != NULL) res=spawnblock(m); } if (f->fflag & REBUILT) return res; if (verbose||debug) printf("** (re)compiling %s:\n",f->fname); if (f->fmake != NULL) res=spawnblock(f->fmake); f->fflag |= (res ? FAILED : REBUILT); return res; } /* * Try to allocate memory, and check for NULL */ void *xalloc(unsigned len) { void * res; res=malloc(len); if (!res) allerr(); /* does not return */ return res; } /* * Complain about being out of memory, and then die. */ allerr() { fprintf(stderr, "Can't alloc -- no space left (I give up!)\n"); noexec=1; exit(1); }  ================================================ FILE: msx2dist/make_004/XARGS.C ================================================ /* xargs.c - simple xargs program */ /* xargs [-a file] [-t|--no-exec|-b] [initial-args ...] * read token from stdin and construct/execute subcommands; * each subcommand is of the form * [initial-args ...] * each token read from stdin is passed to one subcommand */ #include #include #include #include char * pathfind(char* s); int _spawn(char*,char*,char*); char *token(char**); /* max. total length of arguments (for cp/m and msxdos(2)): */ #define ARGLEN 126 /* require some margin for the extra arguments */ #define MARGIN 12 #define BUFLEN 512 int verbose, do_exec; void print_help(FILE* fp) { static char *help[]={ "Usage: xargs [options] [command [initial args...]]", "", "Execute command repeatedly with arguments read from standard input.", "Options can be", "--help\t: print this help and exit", "--no-exec\t: do not execute the commands, implies -t", "--\t: marks end of options to xargs, the next item is used as the command", "-a file\t: read arguments from file ratherthan stdin", "-b\t: generate batch file; do not search command in PATH and", "\t do not execute the commands, implies -t", "-t\t: type out commands", NULL }; int i; for (i=0 ; help[i] ; ++i) { fputs(help[i],fp); fputc('\n', fp); } } static char *shell; int parse(int argc, char *argv[], char **name, char **prog, char **iniargs) { int i,batch, rest, res, len; char *p; FILE * help; *name=NULL; help=NULL; batch=verbose=0; do_exec=1; for (i=1, rest=argc ; iARGLEN-MARGIN) { fprintf(stderr,"xargs: the initial arguments take up too much space.\n"); return 0x8D; /* .BUFUL */ } *iniargs=p=malloc(len+1); if (**prog) *p++=' '; for (i=rest ; iARGLEN) { fprintf(stderr, "%.20s... too long, ignored\n", tok); } else { if (q+len>argbuf+ARGLEN) { *q--=0; if (' '==*q) *q=0; res=do_once(prog, argbuf, fds); q=argbuf+inilen; } strcpy(q,tok); q+=len; if (qinbuf+BUFLEN/2)) { len=inbuf+BUFLEN-p; memcpy(inbuf, p, len); ateof=do_read(input,in,inbuf+len,BUFLEN-len); p=inbuf; } } *q--=0; if (' '==*q) *q=0; res=do_once(prog, argbuf, fds); if (fds[0]) close(fds[0]); return res; } int main(int argc, char *argv[]) { char * argfile, * prog, *iniargs; int fd, res; res=parse(argc, argv, &argfile, &prog, &iniargs); if (res) return (0x8C==res) ? 0 : res; if (argfile) { fd=open(argfile, O_RDONLY); if (fd<0) { res=errno; perror(argfile); fprintf(stderr, " while opening to read arguments. \n"); return res; } } else fd=0; res=do_xargs(fd?argfile:"(stdin)", fd, prog, iniargs); if (fd) close(fd); }  ================================================ FILE: overlays/B280OVR.SUB ================================================ c280 <-c -of2 ovrload.c ovrbgn.as ================================================ FILE: overlays/BUILDOVR.SUB ================================================ c <-c -o ovrload.c ovrbgn.as ================================================ FILE: overlays/LIBOVR.SUB ================================================ era libovr.lib libr intptr_t ovrload(char *ovr_name,intptr_t args); #endif ================================================ FILE: overlays/OVRBGN.AS ================================================ ; Fake overlay size equ 05000h ; max overlay size global __ovrbgn, __ovrsize, __ovrstart psect text __ovrsize: defw size ; this should never be overlaid __ovrstart: defw __ovrbgn psect bss ; this goes in the uninit bit __ovrbgn: defs size ; reserve room for overlay end ================================================ FILE: overlays/OVREADME.TXT ================================================ ** Overlays with Hi-Tech C ** The following procedure may be used to create overlays for use with Hi-Tech C. Although messy to compile and link, it results in a smaller TPA being used by a given program. Thus larger programs can be created: the only penalty is the time taken to load the overlay from disk. 1. Creating the source files. An overlay can be called from the main program using [value = ]ovloader(filename,argument); where is a string containing the overlay's filename (without the .ovr extension) and is a single argument to the function. The result of the overlay may optionally be assigned to a value, as in any C function. The overlay may reference functions, global symbols etc. in the main program, but otherwise appears as a normal C program, except that the main function must be called ovmain() instead of main(). 2. Linking and producing the overlays. The main function must be linked first. Ensure that the modules ovloader.c and ovbgn.as (in that order) are linked as well, and request the compiler to produce a symbol table (-F option). Once this has been completed, run the SYM2AS program on the .SYM file (e.g. SYM2AS TEST.SYM), and this will produce a file named MAIN.AS, containing the addresses from the main portion in assembler-source form. Then run ZAS on this (ZAS MAIN.AS), and this will produce a file named MAIN.OBJ. You will need this to link the overlays. You will need to examine the MAIN.AS file, as you need the address of _ovbgn for the following step. Assume this is 01234h for the purposes of this explanation. Compile the overlay(s) with the -C option to result in .OBJ files. Do not invoke the linker as this will result in many errors! When you have done this, make up a small ascii file (with wordstar etc.) to direct the linker. The format of this file should be as follows (NOTE: MUST be in lower case!): -c01234h -ptext=01234h,data -otest1.ovr test1.obj \ main.obj 0:a:libc.lib (assuming the overlay is to be test1.ovr, the source was test1.c). Other modules may be linked in as well. Note the use of the \ character to continue input onto the next line. Naturally, you should replace the '01234h' with the actual value of _ovbgn as obtained from the MAIN.AS file. Assume this file is named TEST.LNK. You are now ready to link the overlay. Use the command LINK #include #include extern unsigned _ovrsize; extern char *_ovrstart; extern intptr_t _ovrbgn(intptr_t args); extern char ovrfilename[15]={0}; /* Overlay loader for Hi-Tech C */ intptr_t ovrload(char *name,intptr_t args) { int fd, size; char ovrname[9]; char filename[15], *p, *index(); strncpy(ovrname,name,8); ovrname[8]=0; strcpy(filename,ovrname); /* Copy the filename */ strcat(filename,".ovr"); /* add the extent */ if ((fd = open(filename, 0)) < 0) { strcpy(filename,"a0:"); /* not there -- see if it's on A0: */ strcat(filename, (p = index(ovrname,':')) ? p+1 : ovrname); strcat(filename,".ovr"); if ((fd = open(filename,0)) < 0) { goto error; /* Not there either */ } } if(!strcmp(filename,ovrfilename) && _ovrbgn) { return _ovrbgn(args); } size = read(fd,_ovrstart,_ovrsize); close(fd); if (size < 0 || !_ovrbgn) { goto error; /* read error */ } strcpy(ovrfilename,filename); return _ovrbgn(args); /* ok, execute the overlay */ error: return -1; } ================================================ FILE: overlays/SYMTOAS.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 #include #include #include #include #include #include #include #include #define MAXLINE (200) #define START ("__ovrbgn") int sym2as(char * fname, char * tmpas); int main(int argc, char ** argv) { int rc=0; if(argc<2) { fprintf(stderr,"SYMTOAS V1.00\n"); fprintf(stderr,"Missing sym file\n"); return -1; } if(argc==2) { rc=sym2as(argv[1],0); } else { rc=sym2as(argv[1],argv[2]); } if(rc==-1) { return -1; } return 0; } int sym2as(char * fname, char * tmpas) { 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; FILE * out; in=fopen(fname,"rt"); if(!in) { fprintf(stderr,"Cannot open %s\n",fname); return -1; } if(0==tmpas) { out=stdout; } else { out=fopen(tmpas,"wt"); if(!out) { fclose(in); return -1; } } fprintf(out,"%31s\n","psect data"); while(!feof(in)&& !ferror(in)) { i=0; while(i4) { addr+=strlen(addr); addr-=4; } for(j=strlen(sym)-1;j>=0;j--) { if(isspace(sym[j])) { sym[j]=0; } } fprintf(out,"%-20s %s 0%sh\n",sym,"defl",addr); } fprintf(out,"%24s\n","end\n"); if(ferror(in)) { fclose(in); if(0!=tmpas) { fclose(out); } return -1; } fclose(in); if(0!=tmpas) { fclose(out); } return base; } ================================================ FILE: pipemgr/MKRSX.SUB ================================================ z80asm pipemgr/m :link pipemgr[op nr] :erase pipemgr.rel :erase pipemgr.rsx rename pipemgr.rsx=pipemgr.prl ================================================ FILE: pipemgr/PIPEMGR.C ================================================ /********************************************************************* * PIPEMGR helper subroutines. One tests if stdin is coming from a * * pipe, and the other shuffles the arguments so that blank arguments * * are dropped. * **********************************************************************/ #include #include #include #include #include #include "pipemgr.h" extern int _piped; struct { char func; char npars; char *txt; } pcb = {0x76, 1, "PIPEMGR "}; int stdin_piped(void) { if (!_piped) return 0; return (bdoshl(0x3C, &pcb) & 0x100); } void init_args(int *argc, char ***argv) { int i,j; for (i = 1; i < (*argc); i++) { if ((*argv)[i][0]) continue; for (j = i; j < ((*argc) - 1); j++) (*argv)[j] = (*argv)[j+1]; --i; --(*argc); } } char safe_toupper(char c) { if (!islower(c)) return c; return toupper(c); } ================================================ FILE: pipemgr/PIPEMGR.DOC ================================================ =============================================================================== PIPEMGR v1.02 Pipe manager for CP/M Plus John Elliott, 3 January 2000. =============================================================================== Recent changes: PIPEMGR 1.00 contained bugs when the output of one program was piped to another. This could result in a "can't open input" error. It also overwrote a file when asked to append to it. These bugs have been fixed in v1.02. This documentation is for programmers who want to use PIPEMGR in their own programs. Hardly any of the information here need be handed on to the users of the programs - just the details of the command line syntax (for example, see EGDOC.TXT). PIPEMGR.RSX (only) is distributed under the GNU Library General Public License, version 2 (see COPYING.LIB). The accompanying utilities may be distributed freely, but no source is provided. Those of us who have used DOS or UNIX computers will be familiar with the idea of the "pipe" - a system by which the output of a program may be sent directly into the input of another. This functionality is not present in CP/M, although there have been some program suites (such as the Van Nuys Tools) which could simulate it. PIPEMGR is another program of this type. It is an RSX module, which should be attached to suitable programs with GENCOM. When it is attached, it adds various system calls designed to make implementation of pipes easier to program. It supports three devices: - Standard input (stdin) - input to the program, either from the keyboard or from a file. - Standard output (stdout) - conventional data output from the program, perhaps to a screen or to a file. - Standard error (stderr) - error messages output by the program. PIPEMGR requires CP/M-80 version 3 (CP/M Plus) and a Z80 processor. PIPEMGR API =========== All calls are made to the BDOS (CALL 5) with C=3Ch and DE pointing to an area of memory (the RSXPB) whose format is described in each function. Note that these functions behave like genuine BDOS functions; they return data in HL = BA and corrupt C, D, E and the flags. What happens to the Z80 registers IX etc. is left to the discretion of the BIOS. - Initialise PIPEMGR. This call should always be made before attempting to use the features of PIPEMGR. RSXPB: DEFB 79h,1 ;Function code DEFW addr ;Address of authentication string addr: DEFB 'PIPEMGR ' ;authentication string This function scans the standard command tail at 80h for any of the following redirection operations: file - Standard output is sent to "file". If "file" exists, it is deleted. >>file - Standard output is appended to "file". >&file - Standard output and standard error are sent to "file". >>&file - Standard output and standard error are appended to "file". |command - Standard output is sent into the standard input of "command" (which is a standard CP/M command) via a file on the temporary file drive (set using SETDEF). |&command - Standard output and standard error are sent into the standard input of the next program. The filenames can be right up against the redirection symbols, or have a space between them (ie, ">file" or " > file" ). Any filename passed to PIPEMGR can include user numbers, for example: 10A:FILE.TXT B5:README.1ST 0:PROFILE.SUB It can also handle four special device names: CON: - The current screen/keyboard device(s) as set by DEVICE CON:=xxx AUX: - The current auxiliary device(s) as set by DEVICE AUX:=xxx LST: - The current printer as set by DEVICE LST:=xxx NUL: - Nothing. Inputting from it returns End-Of-File; output to it is lost. Note that unlike DOS, the : at the end of the device name is mandatory, and you can't prepend \DEV\ to the device name. If any PIPEMGR operator is found, then it will be replaced in the command by spaces - so, when your program is called with: MYPROG tmp.$$$ ! PMPROG1 redirection operator. If the target file ; does not have a drive specifier then the temporary file is created on the ; currently logged-in drive. If the host program logs onto a different drive ; then the RSX loses connection to the temporary and target files. ; ; The solution was simple. A drive number was added to the FCB. ;------------------------------------------------------------------------------ ; 2014-05-21 jrs ; ; Altered > and >> redirection operators to write directly to the output file ; rather than writing to a temporary file and subsequently renaming it. This ; fixed a bug in the >> operator which would never append to a file. ;------------------------------------------------------------------------------ .z80 CR equ 13 LF equ 10 rename equ 0 ; -1 to have > operator write to a temporary ; file and then rename that file on exit; ; 0 to have > operator write to the named ; file directly exact equ 0 ;agn - revert to DOS Plus mode ; 0 Selects the DOS Plus exact file size ; where the last sector byte count ; contains the number of USED bytes ; but 0 means 128 ; -1 Selects the ISX/ISIS convention for ; exact file size where the last sector ; byte count contains the number of ; UNUSED bytes ; BDOS calls ; ========== CONIN equ 1 ; 01 - Input from console (keyboard) CONOUT equ 2 ; 02 - Output to console AUXIN equ 3 ; 03 - Input from auxiliary device AUXOUT equ 4 ; 04 - Output to auxiliary device LSTOUT equ 5 ; 05 - Output to list device (printer) DCONIO equ 6 ; 06 - Direct console I/O COSTR equ 9 ; 09 - Console output of string RDCONBUF equ 10 ; 0A - Read console buffer CONSTAT equ 11 ; 0B - Get console status SELDRV equ 14 ; 0E - Select drive OPENF equ 15 ; 0F - Open file CLOSEF equ 16 ; 10 - Close file DELETEF equ 19 ; 13 - Delete file CURDRV equ 25 ; 19 - Get current drive SETDMA equ 26 ; 1A - Set DMA address READSEQ equ 20 ; 14 - Sequential read WRITESEQ equ 21 ; 15 - Sequential write CREATEF equ 22 ; 16 - Create file RENAMEF equ 23 ; 17 - Rename file SETATTR equ 30 ; 1E - Set file attributes (& length) GSUSER equ 32 ; 20 - Get/set user number READRAN equ 33 ; 21 - Random read WRITERAN equ 34 ; 22 - Random write SIZEF equ 35 ; 23 - Compute file size ERRMODE equ 45 ; 2D - Set error mode CHAIN equ 47 ; 2F - Chain to program ACCSCB equ 49 ; 31 - Access SCB (System Control Block) CALLRSX equ 60 ; 3C - Call RSX CONMODE equ 109 ; 6D - Get/set console mode PARSEFN equ 152 ; 98 - Parse file name ; PIPEMGR functions ; ================= PMSTAT equ 118 ; 76 - Get PIPEMGR status PMINIT equ 121 ; 79 - Initialise PMSTERR equ 122 ; 7A - Write byte to stderr PMVER equ 123 ; 7B - Get PIPEMGR version PMSTINP equ 124 ; 7C - Read byte from stdin PMSTOUT equ 125 ; 7D - Write byte to stdout PMTERM1 equ 126 ; 7E - Emergency termination PMTERM2 equ 127 ; 7F - Emergency termination ;------------------------------------------------------------------------------ ; FCB layout ; ; Note that fields beyond .rr are not part of the standard CP/M file control ; block. Furthermore, the treatment of those fields in this RSX is different ; from that defined in cpm.h and used by Hi-Tech C programs. ;------------------------------------------------------------------------------ ; offset length description ; -- -- ---------------------------------------- .dr equ 0 ; 1 Drive code .fn equ 1 ; 8 File name .ft equ 9 ; 3 File type .ex equ 12 ; 1 Extent .s1 equ 13 ; 1 System use. May hold user number (ZPM3) .s2 equ 14 ; 1 System use. May hold drive number (ZPM3) .rc equ 15 ; 1 Number of records in current extent (.ex) .dm equ 16 ; 16 Disk map (filled in by CP/M) .cr equ 32 ; 1 Current record for sequential read or write .rr equ 33 ; 3 Random record number (24 bit no.) .r0 equ 33 ; 1 Individual offsets for random record .r1 equ 34 ; 1 / .r2 equ 35 ; 1 / ; RSX usage .?? equ 36 ; 1 Not used in the original code .ud equ 37 ; 1 User number or device code ;------------------------------------------------------------------------------ cseg ;------------------------------------------------------------------------------ ; RSX prefix ;------------------------------------------------------------------------------ defs 6 ;CP/M version jump: jp init ;First call is a special case fdos: jp 6 ;FDOS (overwritten by loader)w Prev: defw 7 ;Previous RSX delete: defb 0ffh ;Delete this RSX? banked: defb 0 ;Banked system flag rname: defb 'PIPEMGR ' defb 0,0,0 ;------------------------------------------------------------------------------ ; Initial entry. This code is only executed once. ;------------------------------------------------------------------------------ init: push bc push de sub a jp pe,bypass ;Can't run on an 8080. ld c,CALLRSX ld de,verchk call fdos inc a jr z,nomgr ;No duplicate PIPEMGR loaded bypass: ld hl,fdos ld (jump+1),hl ;Bypass PIPEMGR pop de pop bc jr fdos nomgr: ld hl,catch ld (jump+1),hl pop de pop bc ;------------------------------------------------------------------------------ ; Subsequent entry to this RSX is redirected here ;------------------------------------------------------------------------------ catch: ld a,c cp CONMODE ;Set console mode jr nz,catch0 ld a,h and 3 ld (cpol),a ld a,c catch0: cp SETDMA jr nz,catch1 ld (dma),de catch1: ld a,(PipedI) or a jr z,catch2 ld a,(awake) or a jr nz,catch2 ;RSX asleep, but input is piped. ld a,(cpol) cp 3 jr z,catch2 ;Is keyboard redirection disabled? ld a,c cp CONSTAT jp z,con11 xor a ld (ckey),a ;Last call was not for console status ld a,c cp CONIN jp z,con1 cp DCONIO jp z,con6 cp RDCONBUF jp z,con10 catch2: ld a,c cp CALLRSX jp nz,fdos ld a,(de) ;Sub-function number cp PMVER jp z,chkver cp PMINIT jr z,initrsx ld a,(awake) or a ;0 if RSX asleep jp z,fdos ld a,(de) cp PMSTERR jp z,PipeErr cp PMSTOUT jp z,PipeOut cp PMSTINP jp z,PipeIn call idrsx jr nz,jfdos ld a,(de) cp PMTERM2 ;Kill RSX jp z,killrsx cp PMTERM1 ;Kill RSX jp z,killrsx cp PMSTAT jr z,rxstat jfdos: jp fdos rxstat: ld a,(inflg) ;Return bitmapped flags and 1 ld h,a ld a,(outflg) ;Output via PIPEMGR? and 2 or h ld h,a ld a,(errflg) and 4 or h ld h,a ld a,(PipedI) and 8 or h ld h,a ld a,(PipedO) and 16 or h ld h,a ld b,a xor a ld l,a ret initrsx: call idrsx jr nz,jfdos ;Initialise PIPEMGR. ld a,0ffh ;RSX has been awakened ld (awake),a xor a ld (pclosed),a ;Pipe file does not need opening ld a,(PipedI) or a jr z,initr0 ld a,-1 ld (inflg),a initr0: ld de,80h ld a,(de) inc de ld l,a ld h,0 add hl,de ld (hl),0 ckpipe1: ld a,(de) ld (pstrt),de cp '<' jr z,parsein cp '>' jr z,parseout cp '|' jr z,parsepi cp '\' jr z,parsebk or a jr z,endcall inc de jr ckpipe1 parsebk: inc de ld a,(de) or a jr z,endcall jr ckpipe1 parsein: ld hl,infcb call fparse jr ckpipe1 parseout: inc de ld a,(de) cp '&' jr z,parso1 cp '>' jr z,parsa1 dec de jr parso2 parsa1: inc de ld a,1 ld (oapp),a ld a,(de) cp '&' jr z,parso1 dec de jr parso2 parso1: ld a,-1 ld (errflg),a parso2: ld hl,outfcb ; [2014-05-21 jrs] call fparse jr ckpipe1 parsepi: inc de ld a,(de) cp '&' jr z,parsp1 dec de push de jr parsp2 parsp1: ld a,-1 ld (errflg),a push de parsp2: ; +++ Note to myself ... ; ; This may need to have a drive plugged in to prevent issues when ; the host program logs onto a different drive. However, check ; the usage of the CP/M temporary drive setting a few instructions ; further on. ; ; On the next instruction, why the -1 ??? ld de,pipeo$-1 ld hl,outfcb call fparse call tempdrv ld (outfcb+.dr),a pop hl ;Command after the '|' ld (hl),0 ;End it inc hl ld de,pipenxt ld bc,80h ldir ld a,-1 ld (PipedO),a endcall: ;[20-11-1998] File names parsed. ; ; [jrs 2014-05-18] ; ; The original code wrote redirected output to a temporary file $PIPEMGR.$$$ ; and, on exit, renamed that file to the one specified on the command line as ; the redirection target. ; ; That presented a problem with the append operator (>>) because the output ; really needed to be written to the target file and not to a temporary one. ; ; For the simple redirect operator (>) there seems little point in writing to ; a temporary file and then renaming it. It has the advantage of preserving ; the original output file in the event that something gets screwed up but the ; use of the > operator suggests that the user is prepared to have the file ; overwritten anyway. ;------------------------------------------------------------------------------ ; [2014-04-20 jrs] Ensure that a drive number is included in the FCB in case ; the host program switches to a different drive. ld a,(outfcb) or a ; Is a drive specified on the command line? jr nz,ec0 ; Skip if so ld c,CURDRV ; Get current drive call fdos inc a ; 0-15 -> 1-16 ld (outfcb+.dr),a ec0: ;------------------------------------------------------------------------------ ld a,(inflg) or a call nz,openin call obuf1A ld de,outfcb creat: push iy push de pop iy ld a,(iy-1) or a jp z,fcreat ;No creation required ld a,(iy+.ud) cp 20h jr nc,dcreat ;Character device call clrflds ld a,(oapp) or a jp nz,append rcreat: ld c,DELETEF call fcbdos call clrflds xor a ld (outptr),a ld (iy+.??),a ld c,CREATEF call fcbdos inc a jp z,ecreat dcreat: call hookwb xor a ld (delete),a jp fcreat clrflds: xor a ld (iy+.ex),a ld (iy+.s1),a ld (iy+.s2),a ld (iy+.cr),a ld (iy+.rc),a ret append: ; The original code for appending to an existing output file read the ; entire file from the beginning and scanned for a text file EOF marker ; (1Ah). The PIPEMGR documentation says that the redirector should ; work for binary files and so it is not clear that looking for a text ; EOF marker is a valid exercise. ; ; Assuming that scanning is valid (despite the documentation) then it ; should only be done if the length of the file is a multiple of 128 ; bytes. For such a file the scan only needs to be done in the last ; sector of the file. ; ; I am not sure that scanning is ever necessary. Files created by the ; redirector have their exact lengths set and that information can be ; used to position the file for writing. ; ; Scanning might be useful if it should be desirable to append re- ; directed output to a file created by some other program. ; ; [jrs 2014-05-22] ld (iy+.cr),255 ; Prepare to fetch last sector byte count ld c,OPENF ; Try to open the file call fcbdos inc a jp z,rcreat ; If the file doesn't exist then create it ; Repurpose the unused byte in John Elliott's FCB extension to hold ; the last sector byte count. ld a,(iy+.cr) ; Get LSBC ld (iy+.??),a ; Store it for later use ld (iy+.cr),0 ; Clear CR field for sequential I/O ld de,outbuf ; Establish data address for read call set_dma ; The FCB address is in IY ld c,SIZEF ; Compute file size call fcbdos ld a,(iy+.r0) ; Check for zero-length file or a,(iy+.r1) or a,(iy+.r2) jp z,fcreat dec (iy+.r0) ; Step back to previous record jr nc,at_prev dec (iy+.r1) jr nc,at_prev dec (iy+.r2) at_prev: ld c,READRAN ; Read last record of file call fcbdos or a ; Success? jp nz,rcreat ; Delete and recreate on any error ld a,(iy+.??) ; Get last record byte count and a ; Done if not zero jr nz,hooky ld hl,outbuf ; Scan for EOF marker ld a,1Ah ld bc,128 cpir inc c ld a,c hooky: if exact ;agn UNUSED case (ISIS) neg ; Convert unused bytes to used bytes endif and 7Fh ld (outptr),a ; Ready for the next byte. call hookwb xor a ld (delete),a jp fcreat fcbdos: ld a,(iy+.ud) ; fcb[37] holds user+1 if user number specified or a jr nz,fcbd1 ; Skip if user specified push bc ; Save BDOS function number ld e,0FFh ld c,GSUSER call yfdos ;Get user ld (ousr),a ; Save original user number inc a ; Store user+1 at fcb[37] ld (iy+.ud),a jr fcbd2 fcbd1: cp 32 ; If user < 32 then we have a file, otherwise jr c,fcbd1a ; we have a device in which case we simply xor a ; return 0 (success) and don't do BDOS call! ret fcbd1a: push bc ; Save BDOS function ld e,0FFh ;Get user ld c,GSUSER call yfdos ld (ousr),a ; Save original user fcbd2: ld e,(iy+.ud) ; Get user+1 from fcb[37] dec e ; Normalise ld c,GSUSER call yfdos ;Set user pop bc ; Recover BDOS function push iy ; Copy FCB address to DE pop de call yfdos push af ; Save BDOS results push hl ld a,(ousr) ; Get original user number ld e,a ld c,GSUSER ;Restore old user call yfdos pop hl ; Recover BDOS results pop af ret yfdos: push iy call fdos pop iy ret ecreat: ld de,warn1 ;"Error creating output" call print ld de,warn2a call print pop iy ld (iy-1),0 defb 21h ;Swallow the POP IY ; (Converts it to LD HL,xxxx) fcreat: pop iy ld de,(dma) call set_dma ;Restore user DMA xor a ld b,a ld h,a ld l,a ret udconv: ld b,4 ;Generate uppercase version of DEV: spec. push ix ld de,infcb+32 ;Workspace udc0: ld a,(ix+0) ; Translate to upper case (is this necessary?) cp 'a' jr c,udc1 cp 'z' jr nc,udc1 sub 20h udc1: ld (de),a inc de inc ix djnz udc0 pop ix ld c,4 ; Look through the device names for a match ld hl,cpcon udc2: ld de,infcb+32 ld b,4 call cp$ jr z,udc3 dec c jr nz,udc2 jr uconv ;No match. udc3: ; +++ Here is where device gets into FCB ld a,24h sub c ;A = DEV: id ld hl,(pfcb+2) dec hl ld (hl),-1 ;FCB active, piping. ld de,38 add hl,de ld (hl),a ;Set DEV: in FCB. ld hl,(pfcb) ld de,4 add hl,de ;HL = return value ld a,(hl) or a jr nz,dozap0 ld hl,0 ;EOL dozap0: pop ix jp dozap1 ;Cover up the redirector. uconv: ; IX points at input string. On completion ... ld hl,0 ;L=User number, H=drive letter ld b,2 ;B=1 if user number supplied uconv1: ld a,(ix+0) cp '0' ; Check for a decimal digit jp c,fpendi cp ':' ; '9'+1 = ':' (How convenient!) jr c,numeri jr z,ucend ld h,a ; Not a digit. Perhaps a letter? inc ix jr uconv1 numeri: and 0Fh ;A=digit, 0-9 ld c,a ld a,l ;L=running total add a,a ;*2 add a,a ;*4 add a,l ;*5 add a,a ;*10 add a,c ;*10+c ld l,a inc ix ld b,1 ;user number supplied jr uconv1 ucend: djnz ucend0 ;If B=1, no user number supplied. ld a,l inc a ; Store user+1 (to disambiguate 0) push iy ld iy,(pfcb+2) ; Get FCB pointer ld (iy+.ud),a ; Store user number in FCB pop iy ucend0: ld a,h or a jr z,nodrv ;u:filename ld (ix-1),H ld ix,(pfcb) ucend1: ld a,(ix+1) cp ':' jr z,restq ld (ix+0),' ' inc ix jr ucend1 nodrv: inc ix ;IX -> filename proper ld hl,(pfcb) nodrv1: ld a,(hl) ld (hl),' ' inc hl cp ':' jr nz,nodrv1 restq: ld (pfcb),ix jr restt fparse: inc de ld a,(de) ;[19-11-1998] skip spaces betweeen operator & cp ' ' ;argument. jr z,fparse ld (pfcb),de ; Input string ld (pfcb+2),hl ; FCB push ix push hl ; Copy FCB address to IX pop ix ld (ix+.ud),0 ;No user number ld ix,(pfcb) ; IX := pointer to input string ld a,(ix+1) ; Get 2nd character cp ':' ; If 2nd or 3rd character is a colon then jp z,uconv ; look for a user number ld a,(ix+2) cp ':' jp z,uconv ld a,(ix+3) ; If 4th character is a colon then scan cp ':' ; for user and/or drive device name jp z,udconv restt: ; All parsed, or not specified pop ix ld de,pfcb ld c,PARSEFN call fdos dozap1: ld a,h and l inc a jr z,fpend ld a,h or l jr z,eoln push hl ;HL->next character in line. ld de,(pstrt) and a sbc hl,de ;L=length of redirector ex de,hl ;E=length of redirector zaprd: ld (hl),' ' inc hl dec e jr nz,zaprd pop de ;DE=next character in line ld hl,(pfcb+2) dec hl ld (hl),-1 ;Flag, must be 0 or -1 inc hl ret eoln: ld hl,(pstrt) ld (hl),0 ;Chop redirection off ld a,l and 7Fh dec a ld (80h),a ;Command line ends here. ld de,pfcb ld hl,0 ld (pfcb),hl ld hl,(pfcb+2) dec hl ld (hl),-1 ;Pipe active inc hl ret fpendi: pop ix fpend: ld de,(pfcb) ld hl,(pfcb+2) ret dseg pfcb: ; Parse Filename Control Block defw 0 ; Address of input string defw 0 ; Address of FCB (output) cseg chkver: call idrsx jp nz,fdos ld hl,0103h ;agn bump version to PIPEMGR 1.03 ret con1: call pbytin ld a,h or a jr nz,bahl ld l,1Ah bahl: ld b,h ld a,l ret con6: ld a,e cp 0fdh jp c,fdos jr z,con1 cp 0feh jr z,con11 call pbytin jr con1 dseg defs 20 gsp: defw 0 cseg con11: ld a,(cpol) ;Get console mode, including policy for function 0Bh cp 1 ;True jr z,RetTrue cp 2 jr z,RetFalse ;Return conditional value. Two consecutive calls are necessary to signal a ;keypress - the first always returns 0. ld a,(ckey) ;Was last FDOS call 0Bh? or a jr nz,RetTrue ;No. Return False. dec a ld (ckey),a ;Signal that the last BDOS call was 0Bh. RetFalse: xor a ret RetTrue: xor a ld (ckey),a dec a ret con10: ex de,hl ;HL->buffer ld a,h or l ld c,0 jr nz,con10a ld hl,(dma) inc hl ld c,(hl) dec hl con10a: ld a,(hl) ;HL->buf[0] sub c ld b,a ;B=maximum length ret c inc hl ;HL->buf[1] push hl inc hl push bc ;HL->space for input ld b,0 add hl,bc pop bc con10b: push hl push bc call qbytin pop bc ld a,h or a jr z,con10c ld a,l cp CR jr z,con10c cp LF jr z,con10c pop hl ld (hl),a inc hl inc c djnz con10b defb 3Eh ;Swallow the POP HL ;;; jr con10d ; Converts POP HL to LD A,xx con10c: pop hl con10d: pop hl ld (hl),c ret PipeIn: ld a,(inflg) or a jr nz,pipei1 ld a,(crbuf) or a jr z,nolf cp LF jr z,donelf ld c,CONOUT ld e,LF call fdos donelf: xor a ld (crbuf),a ld hl,010ah jp bahl dseg crbuf: defb 0 cseg crlf: ld (crbuf),a ld c,CONOUT ld e,CR call fdos ld hl,010dh jp bahl nolf: ld c,CONIN call fdos cp CR jr z,crlf cp LF jr z,crlf ld l,a cp 1Ah ld h,0 jp z,bahl inc h jp bahl pipei1: call bytin jp bahl PipeOut: inc de ; Step to the output character inc de ld a,(de) ld e,a ld a,(outflg) ;Output via PIPEMGR? ld c,2 or a jp z,fdos bytout: ld a,(outfcb+.ud) ;E=character cp 20h ;CON: jr c,bytoz1 ld c,2 jp z,fdos cp 21h ;AUX: ld c,4 jp z,fdos cp 22h ;LST: ld c,5 jp z,fdos ;NUL: ret bytoz1: ld a,(outptr) push de cp 80h call nc,wrobuf pop de ld l,a ld h,0 ld bc,outbuf add hl,bc ld (hl),e inc a ld (outptr),a ret PipeErr: inc de inc de ld a,(de) ld e,a ld a,(errflg) ld c,2 or a jp z,fdos jr bytout ret1a: ld hl,1Ah ret qbytin: call pbytin ld a,(lastin) ld c,a ld a,l ld (lastin),a cp LF ret nz ld a,c cp CR ;CR,LF -> CR ret nz ;Fall through to... pbytin: ld a,(pclosed) or a jr z,bytin call openin xor a ld (pclosed),a ld (awake),a ;openin wakes up the RSX. bytin: ld a,(ineof) or a jr nz,ret1a ld a,(infcb+.ud) ;Input from a device? cp 20h jr c,bytiz1 ;CON: ld c,CONIN jr z,hlba cp 21h ;AUX: ld c,AUXIN jr z,hlba ld hl,001Ah ;LST: / NUL: ret hlba: call fdos ld l,a xor 1Ah ;H=0 if EOF ld h,a ret bytiz1: ld hl,(inlen) ld de,(inlen+2) ; DEHL has input length ld a,h or l or d or e jr z,ret1a ; DEHL = 0; send a CP/M text EOF dec hl ; Decrement DEHL ld (inlen),hl ld a,h and l inc a jr nz,byti01 dec de ld (inlen+2),de byti01: ld a,(inptr) cp 80h call nc,rdibuf ld l,a inc a ld (inptr),a ld h,0 ld de,inbuf add hl,de ld l,(hl) ld h,1 ret rdibuf: ld de,inbuf call set_dma push iy ld iy,infcb ld c,READSEQ call fcbdos pop iy ld de,(dma) call set_dma or a jr z,rdib1 ld (ineof),a call ibuf1A rdib1: xor a ld (inptr),a ret wrobuf: ld de,outbuf call set_dma push iy ld iy,outfcb ld c,WRITESEQ call fcbdos ld de,(dma) call set_dma pop iy call obuf1A ld de,(dma) call set_dma xor a ld (outptr),a ret CloseIn: ld a,80h ld (inptr),a ld a,(inflg) or a ret z xor a ld (inflg),a ld iy,infcb ld c,CLOSEF call fcbdos ld a,(PipedI) ;Was input piped? or a ret z ld iy,infcb ld hl,0 ld (infcb+14),hl ld (infcb+12),hl ld c,DELETEF call fcbdos ;Delete the input pipe ret CloseOut: ld a,(outflg) ;Output via PIPEMGR? or a ret z ld a,(outptr) or a push af call nz,wrobuf ld iy,outfcb ld c,CLOSEF call fcbdos pop af if exact ;agn UNUSED last sector byte count ; Next instruction added to change meaning of last sector byte count from ; USED bytes to UNUSED bytes. [jrs 03-04-2014] neg endif and 7fh ;; ld (outfcb+.cr),a ;; ld a,(outfcb+6) ;; set 7,a ;; ld (outfcb+6),a ld (iy+.cr),a ; Taking advantage of the fact that IY set 7,(iy+6) ; holds address of outfcb! ld c,SETATTR ;; ld iy,outfcb call fcbdos ;[20-11-1998] Generate a temp file and rename it when closing. ; ld iy,Xoutfcb ; ld c,DELETEF ; call fcbdos ; ld hl,Xoutfcb ; ld de,outfcb+16 ; ld bc,16 ; ldir ; ; ld c,RENAMEF ;Rename temp file. ; ld iy,outfcb ; call fcbdos ; ; xor a ; ld (outflg),a ; ld (Xoutflg),a ;JCE 1-1-2000 keep these flags in sync ret myboot: ;Called when program terminates ld sp,inbuf+7fh call uhookwb xor a ;RSX is asleep ld (awake),a ld c,ERRMODE ;Can't afford recursive RST 0's ld e,0FFh call fdos call CloseIn ;Close STDIN, STDOUT & STDERR. call CloseOut xor a ld (PipedI),a ld a,(PipedO) ;Was there a pipe? or a jr nz,xferpipe dec a ld (delete),a ;Set to delete RSX rst 0 ;RSX vanishes... xferpipe: xor a ld (PipedO),a dec a ld (PipedI),a ld (inflg),a ; ld hl,Xoutfcb ;JCE 1-1-2000 1.01: Use Xoutfcb not outfcb ; JRS 2014-06-17: No. outfcb is correct. ld hl,outfcb ld de,renfcb ;so the right rename is done ld bc,38 push hl ldir pop hl ld de,renfcb+10h ld bc,10h ldir ld hl,0 ld (renfcb+12),hl ld (renfcb+14),hl ld (renfcb+28),hl ld (renfcb+30),hl ld (renfcb+32),hl ;Zap the rename fcb ld hl,'NI' ;"PIPEIN" ld (renfcb+21),hl ld hl,' ' ld (renfcb+23),hl ld iy,renfcb ld c,RENAMEF call fcbdos ;Rename "PIPEOUT" to "PIPEIN" ld hl,renfcb+16 ld de,infcb ;Make input file FCB. ld bc,12 ldir ld a,(renfcb+.ud) ld (infcb+.ud),a ;Transfer uid as well. xor a ld (delete),a ;Return control to CP/M. RSX stays loaded ;but asleep. ld (awake),a ld hl,pipenxt ld de,80h ld b,d ld c,e ldir call hookwb ;We will need this because the pipe is running ld hl,(1) inc hl ld de,splboot ld (hl),e inc hl ld (hl),d xor a ld (cpol),a ;Console input policy inc a ld (pclosed),a ld c,CHAIN ld e,0 call fdos ;Chain to command given in pipe jp oboot splboot: ld hl,(1) inc hl ld de,myboot ld (hl),e inc hl ld (hl),d jp oboot hookwb: ld a,(wbflag) ; Is warm boot hooked already? or a ret nz ; If so then nothing to do ld hl,(1) ; Get target of JP at address 0 ld a,(hl) ; Get instruction that is there ld (hl),0C3h ; Store a JP inc hl ; Step to address ld bc,myboot ; Load address of local routine ld e,(hl) ; Save current warm boot vector and ld (hl),c ; plug in the address of the local inc hl ; routine. ld d,(hl) ld (hl),b ld (oboot),a ; Store the original vector ld (oboot+1),de ld a,1 ; Flag that the warm boot hook is ld (wbflag),a ; in place. ret uhookwb: ld a,(wbflag) or a ret z ld de,(1) ld hl,oboot ld bc,3 ldir xor a ld (wbflag),a ret idrsx: push de ex de,hl inc hl inc hl ld e,(hl) inc hl ld d,(hl) ld hl,rname ld b,8 call cp$ pop de ret cp$: ld a,(de) ; Compares strings at HL and DE for length B. cp (hl) ; Leaves HL=HL+B and DE = DE+B regardless of jr nz,cp$1 ; the result. Z flag is set and A=0 if the inc de ; strings are identical, otherwise Z flag is inc hl ; reset and A<>0 djnz cp$ xor a ret cp$1: inc hl inc de djnz cp$1 xor a dec a ret tempdrv: ld (gsp),sp ld sp,gsp push bc push de push hl ld de,scb1 ld c,ACCSCB call fdos pop hl pop de pop bc ld sp,(gsp) ret killrsx: xor a dec a ld (delete),a ld hl,fdos ld (fdos-2),hl push bc push de call uhookwb pop de pop bc jp fdos openin: push iy ld hl,0 ld (inlen),hl ld (inlen+2),hl ld c,SIZEF ;Compute size of input file ld iy,infcb call fcbdos inc a jp z,noinp ld de,(infcb+.r1) ; Load file size (sectors) from .rr field ld a,(infcb+21h) ld h,a ld l,0 ; Convert sectors to bytes srl d rr e rr h rr l ;DEHL = size of file, bytes ld (inlen),hl ld (inlen+2),de ld hl,0 ld (infcb+12),hl ld (infcb+14),hl ld a,l dec a ld (infcb+.cr),a ld c,OPENF ld iy,infcb call fcbdos inc a jp z,noinp ld a,(infcb+.cr) and 7fh ;------------------------------------------------------------------------ ; This original code assumed byte count at FCB[32] represents the number ; of USED bytes in the last sector. However this program now interprets ; FCB[32] as the number of UNUSED bytes in the last sector. We don't ; need to test for zero. Instead, we unconditionally subtract the last ; sector byte count from the calculated file length. if not exact ;agn DOS Plus has USED last byte count jr z,nomsb ;No adjustment necessary ld b,a ld a,80h sub b ;A=no. unused bytes endif ;------------------------------------------------------------------------ ld c,a ld b,0 ld hl,(inlen) and a sbc hl,bc ld (inlen),hl jr nc,nomsb ld hl,(inlen+2) ld a,h or l jr z,nomsb dec hl ld (inlen+2),hl nomsb: call hookwb xor a ld (infcb+.cr),a ld (delete),a ;Pipemgr is running ld (pclosed),a ld (ineof),a ld (lastin),a ld (ckey),a dec a ld (inflg),a ;Input is redirected. ld (awake),a ;RSX is awake pop iy ret dseg warn1: defb 13,10,"PIPEMGR: Can't open $" warn1a: defb 'input.',13,10,'$' warn2a: defb 'output.',13,10,'$' cseg set_dma: ld (gsp),sp ld sp,gsp push hl push de push bc push af push iy ld c,SETDMA call fdos pop iy pop af pop bc pop de pop hl ld sp,(gsp) ret noinp: xor a ;Failed to open input ld (inflg),a inc a ld (ineof),a ld de,warn1 call print ld de,warn1a call print pop iy ret print: ld c,COSTR jp fdos ibuf1A: ld hl,inbuf jr fill1A obuf1A: ld hl,outbuf fill1A: ld d,h ld e,l inc de ld bc,127 ld (hl),1Ah ldir ret dseg cpcon: defb 'CON:AUX:LST:NUL:' PipedI: defb 0 ;MUST be either 0 or -1 PipedO: defb 0 ;MUST be either 0 or -1 inflg: defb 0 ;MUST be either 0 or -1 infcb: defs 38 outflg: defb 0 ;MUST be either 0 or -1 outfcb: defb 0,'$PIPEMGR$$$' defs 26 ;Xoutflg:defb 0 ;Xoutfcb:defs 38 errflg: defb 0 ;MUST be either 0 or -1 pipenxt: defs 80h inbuf: defs 80h inptr: defb 80h outbuf: defs 80h outptr: defb 0 renfcb: defs 38 inlen: defw 0,0 ;Bytes in input file. pclosed: defb 0 ;Pipe needs opening? awake: defb 0 oapp: defb 0 ineof: defb 0 ;EOF latch wbflag: defb 0 ;WBOOT vector hooked? oboot: defs 3 ;Original boot routine verchk: defb PMVER,1 defw rname pipeo$: defb '0:PIPEOUT.$$$',0 dma: defw 80h scb1: defw 50h pstrt: defw 0 lastin: defb 0 ckey: defb 0 cpol: defb 0 ousr: defb 0 cseg end ================================================ FILE: pipemgr/TEE.C ================================================ /* %CC1 $1.C -X -E5000 %CLINK $1 DIO -S %DELETE $1.CRL */ /********************************************************************* * TEE * ********************************************************************** * COPYRIGHT 1983 EUGENE H. MALLORY * * Converted to Hi-Tech C by John Elliott, 17 November 1998 * * * * Build using C -O -C PIPEMGR.C * * C -O TEE.C PIPEMGR.OBJ -LC ! GENCOM TEE PIPEMGR * * ERA TEE.OBJ * * ERA PIPEMGR.OBJ * * * *********************************************************************/ #include #include #include #include #include "pipemgr.h" char *version; int main(int argc, char **argv) { FILE *fp; int c; char teeflag; char fname[MAXLINE]; version = "Version 3.0"; init_args(&argc, &argv); if (argc >= 2) { strcpy(fname, *++argv); teeflag = TRUE; fp = fopen(fname, "w"); if (!fp) { fprintf(stderr,"TEE: Unable to create file \'%s\'.",fname); exit(1); } } else teeflag = FALSE; while ((c=getchar()) != EOF) { putchar(c); if (teeflag) putc(c,fp); } fflush(fp); fclose(fp); exit(0); } ================================================ FILE: stdio/ASSERT.C ================================================ #include #include #include void _fassert(line, file, exp) char * file, * exp; int line; { fprintf(stderr, "Assertion failed: %s line %d: \"%s\"\n", file, line, exp); abort(); } ================================================ FILE: stdio/BUF.C ================================================ #include #include static union stdbuf { char bufarea[BUFSIZ]; union stdbuf *link; } *freep; char *_bufallo() { register union stdbuf *pp; if (pp = freep) freep = pp->link; else pp = (union stdbuf *)sbrk(BUFSIZ); return pp->bufarea; } void _buffree(char *pp) { register union stdbuf *up; up = (union stdbuf *)pp; up->link = freep; freep = up; } ================================================ FILE: stdio/BUILDSTD.SUB ================================================ c <-o -c getargs.c getenv.c assert.c printf.c fprintf.c sprintf.c \ date A:DATE COM (User 0) Fri 05/09/2025 12:33:27 10E>; Compile all LIB280C.LIB modules from sources for Z280 10E>; 10E>; Sources are on drive E: 10E>; Z280 object files are created on drive M: 10E>; 10E>m: 10M>pip m:=e:stdio.i A:PIP COM (User 0) 10M>c280 A:C280 COM (User 0) 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 c> -v -o2 -c e:abort.c \ c> e:abs.as \ c> e:allsh.as \ c> e:alrsh.as \ c> e:asallsh.as \ c> e:asalrsh.as \ c> e:asar.as \ c> e:asdiv.as \ c> e:asladd.as \ c> e:asland.as \ c> e:asll.as \ c> e:asllrsh.as \ c> e:aslmul.as \ c> e:aslor.as \ c> e:aslr.as \ c> e:aslsub.as \ c> e:aslxor.as \ c> e:asmod.as \ c> e:asmul.as \ c> e:assert.c \ c> e:atoi.as \ c> e:atol.c \ c> e:bdos.as \ c> e:bios.as \ c> e:bitfield.as \ c> e:blkclr.as \ c> e:blkcpy.c \ c> e:bmove.as \ c> e:brelop.as \ c> e:buf.c \ c> e:calloc.c \ c> e:cgets.c \ c> e:chmod.c \ c> e:cleanup.c \ c> e:close.c \ c> e:convtime.c \ c> e:cputs.c \ c> e:creat.c \ c> e:csv.as \ c> e:ctime.c \ c> e:ctype_.c \ c> e:ctype.c \ c> e:doprnt.c \ c> e:doscan.c \ c> e:dup.c \ c> e:exec.as \ c> e:execl.as \ c> e:_exit.as \ c> e:exit.c \ c> e:fakeclea.c \ c> e:fakecpcl.as \ c> e:fcbname.c \ c> e:fclose.c \ c> e:fflush.c \ c> e:fgetc.c \ c> e:filbuf.c \ c> e:flsbuf.c \ c> e:fopen.c \ c> e:fprintf.c \ c> e:fputc.c \ c> e:fread.c \ c> e:frelop.as \ c> e:freopen.c \ c> e:fscanf.c \ c> e:fseek.c \ c> e:fwrite.c \ c> e:getargs.c \ c> e:getch.c \ c> e:getenv.c \ c> e:getfcb.c \ c> e:gets.c \ c> e:getsp.as \ c> e:getuid.as \ c> e:getw.c \ c> e:idiv.as \ c> e:imul.as \ c> e:index.as \ c> e:inout.as \ c> e:iregset.as \ c> e:isalpha.as \ c> e:isatty.c \ c> e:isdigit.as E:ABORT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:ABORT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OABORT.OBJ $CTMP5.$$$ E:ABS.AS 0:A:OPTIMH E:ABS.AS $CTMP5.$$$ 1 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OABS.OBJ $CTMP5.$$$ E:ALLSH.AS 0:A:OPTIMH E:ALLSH.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OALLSH.OBJ $CTMP5.$$$ E:ALRSH.AS 0:A:OPTIMH E:ALRSH.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OALRSH.OBJ $CTMP5.$$$ E:ASALLSH.AS 0:A:OPTIMH E:ASALLSH.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OASALLSH.OBJ $CTMP5.$$$ E:ASALRSH.AS 0:A:OPTIMH E:ASALRSH.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OASALRSH.OBJ $CTMP5.$$$ E:ASAR.AS 0:A:OPTIMH E:ASAR.AS $CTMP5.$$$ 0 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OASAR.OBJ $CTMP5.$$$ E:ASDIV.AS 0:A:OPTIMH E:ASDIV.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OASDIV.OBJ $CTMP5.$$$ E:ASLADD.AS 0:A:OPTIMH E:ASLADD.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASLADD.OBJ $CTMP5.$$$ E:ASLAND.AS 0:A:OPTIMH E:ASLAND.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASLAND.OBJ $CTMP5.$$$ E:ASLL.AS 0:A:OPTIMH E:ASLL.AS $CTMP5.$$$ 0 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OASLL.OBJ $CTMP5.$$$ E:ASLLRSH.AS 0:A:OPTIMH E:ASLLRSH.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OASLLRSH.OBJ $CTMP5.$$$ E:ASLMUL.AS 0:A:OPTIMH E:ASLMUL.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASLMUL.OBJ $CTMP5.$$$ E:ASLOR.AS 0:A:OPTIMH E:ASLOR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASLOR.OBJ $CTMP5.$$$ E:ASLR.AS 0:A:OPTIMH E:ASLR.AS $CTMP5.$$$ 0 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OASLR.OBJ $CTMP5.$$$ E:ASLSUB.AS 0:A:OPTIMH E:ASLSUB.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASLSUB.OBJ $CTMP5.$$$ E:ASLXOR.AS 0:A:OPTIMH E:ASLXOR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OASLXOR.OBJ $CTMP5.$$$ E:ASMOD.AS 0:A:OPTIMH E:ASMOD.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OASMOD.OBJ $CTMP5.$$$ E:ASMUL.AS 0:A:OPTIMH E:ASMUL.AS $CTMP5.$$$ 1 bytes size optimised away 5 bytes replaced 0:A:ZAS -J -OASMUL.OBJ $CTMP5.$$$ E:ASSERT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:ASSERT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 6 bytes size optimised away 12 bytes replaced 0:A:ZAS -J -N -OASSERT.OBJ $CTMP5.$$$ E:ATOI.AS 0:A:OPTIMH E:ATOI.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OATOI.OBJ $CTMP5.$$$ E:ATOL.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:ATOL.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 15 bytes size optimised away 30 bytes replaced 0:A:ZAS -J -N -OATOL.OBJ $CTMP5.$$$ E:BDOS.AS 0:A:OPTIMH E:BDOS.AS $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OBDOS.OBJ $CTMP5.$$$ E:BIOS.AS 0:A:OPTIMH E:BIOS.AS $CTMP5.$$$ 5 bytes size optimised away 22 bytes replaced 0:A:ZAS -J -OBIOS.OBJ $CTMP5.$$$ E:BITFIELD.AS 0:A:OPTIMH E:BITFIELD.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OBITFIELD.OBJ $CTMP5.$$$ E:BLKCLR.AS 0:A:OPTIMH E:BLKCLR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OBLKCLR.OBJ $CTMP5.$$$ E:BLKCPY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:BLKCPY.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OBLKCPY.OBJ $CTMP5.$$$ E:BMOVE.AS 0:A:OPTIMH E:BMOVE.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OBMOVE.OBJ $CTMP5.$$$ E:BRELOP.AS 0:A:OPTIMH E:BRELOP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OBRELOP.OBJ $CTMP5.$$$ E:BUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:BUF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 4 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OBUF.OBJ $CTMP5.$$$ E:CALLOC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CALLOC.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 9 bytes size optimised away 26 bytes replaced 0:A:ZAS -J -N -OCALLOC.OBJ $CTMP5.$$$ E:CGETS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CGETS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 21 bytes size optimised away 42 bytes replaced 0:A:ZAS -J -N -OCGETS.OBJ $CTMP5.$$$ E:CHMOD.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CHMOD.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 16 bytes size optimised away 24 bytes replaced 0:A:ZAS -J -N -OCHMOD.OBJ $CTMP5.$$$ E:CLEANUP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CLEANUP.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 12 bytes size optimised away 24 bytes replaced 0:A:ZAS -J -N -OCLEANUP.OBJ $CTMP5.$$$ E:CLOSE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CLOSE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 6 bytes size optimised away 13 bytes replaced 0:A:ZAS -J -N -OCLOSE.OBJ $CTMP5.$$$ E:CONVTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CONVTIME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 11 bytes size optimised away 61 bytes replaced 0:A:ZAS -J -N -OCONVTIME.OBJ $CTMP5.$$$ E:CPUTS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CPUTS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -N -OCPUTS.OBJ $CTMP5.$$$ E:CREAT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CREAT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 6 bytes size optimised away 18 bytes replaced 0:A:ZAS -J -N -OCREAT.OBJ $CTMP5.$$$ E:CSV.AS 0:A:OPTIMH E:CSV.AS $CTMP5.$$$ 0 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OCSV.OBJ $CTMP5.$$$ E:CTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CTIME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 160 bytes size optimised away 320 bytes replaced 0:A:ZAS -J -N -OCTIME.OBJ $CTMP5.$$$ E:CTYPE_.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CTYPE_.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OCTYPE_.OBJ $CTMP5.$$$ E:CTYPE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:CTYPE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 4 bytes size optimised away 8 bytes replaced 0:A:ZAS -J -N -OCTYPE.OBJ $CTMP5.$$$ E:DOPRNT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:DOPRNT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 45 bytes size optimised away 108 bytes replaced 0:A:ZAS -J -N -ODOPRNT.OBJ $CTMP5.$$$ E:DOSCAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:DOSCAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 125 bytes size optimised away 270 bytes replaced 0:A:ZAS -J -N -ODOSCAN.OBJ $CTMP5.$$$ E:DUP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:DUP.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 1 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -ODUP.OBJ $CTMP5.$$$ E:EXEC.AS 0:A:OPTIMH E:EXEC.AS $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OEXEC.OBJ $CTMP5.$$$ E:EXECL.AS 0:A:OPTIMH E:EXECL.AS $CTMP5.$$$ 71 bytes size optimised away 122 bytes replaced 0:A:ZAS -J -OEXECL.OBJ $CTMP5.$$$ E:_EXIT.AS 0:A:OPTIMH E:_EXIT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -O_EXIT.OBJ $CTMP5.$$$ E:EXIT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:EXIT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -N -OEXIT.OBJ $CTMP5.$$$ E:FAKECLEA.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FAKECLEA.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OFAKECLEA.OBJ $CTMP5.$$$ E:FAKECPCL.AS 0:A:OPTIMH E:FAKECPCL.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OFAKECPCL.OBJ $CTMP5.$$$ E:FCBNAME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FCBNAME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 57 bytes size optimised away 109 bytes replaced 0:A:ZAS -J -N -OFCBNAME.OBJ $CTMP5.$$$ E:FCLOSE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FCLOSE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 9 bytes size optimised away 18 bytes replaced 0:A:ZAS -J -N -OFCLOSE.OBJ $CTMP5.$$$ E:FFLUSH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FFLUSH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 19 bytes size optimised away 38 bytes replaced 0:A:ZAS -J -N -OFFLUSH.OBJ $CTMP5.$$$ E:FGETC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FGETC.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 32 bytes size optimised away 64 bytes replaced 0:A:ZAS -J -N -OFGETC.OBJ $CTMP5.$$$ E:FILBUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FILBUF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 38 bytes size optimised away 84 bytes replaced 0:A:ZAS -J -N -OFILBUF.OBJ $CTMP5.$$$ E:FLSBUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FLSBUF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 22 bytes size optimised away 40 bytes replaced 0:A:ZAS -J -N -OFLSBUF.OBJ $CTMP5.$$$ E:FOPEN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FOPEN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 4 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OFOPEN.OBJ $CTMP5.$$$ E:FPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FPRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 7 bytes size optimised away 10 bytes replaced 0:A:ZAS -J -N -OFPRINTF.OBJ $CTMP5.$$$ E:FPUTC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FPUTC.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 26 bytes size optimised away 52 bytes replaced 0:A:ZAS -J -N -OFPUTC.OBJ $CTMP5.$$$ E:FREAD.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FREAD.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 71 bytes size optimised away 143 bytes replaced 0:A:ZAS -J -N -OFREAD.OBJ $CTMP5.$$$ E:FRELOP.AS 0:A:OPTIMH E:FRELOP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OFRELOP.OBJ $CTMP5.$$$ E:FREOPEN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FREOPEN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 30 bytes size optimised away 66 bytes replaced 0:A:ZAS -J -N -OFREOPEN.OBJ $CTMP5.$$$ E:FSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FSCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 7 bytes size optimised away 10 bytes replaced 0:A:ZAS -J -N -OFSCANF.OBJ $CTMP5.$$$ E:FSEEK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FSEEK.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 91 bytes size optimised away 173 bytes replaced 0:A:ZAS -J -N -OFSEEK.OBJ $CTMP5.$$$ E:FWRITE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:FWRITE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 76 bytes size optimised away 153 bytes replaced 0:A:ZAS -J -N -OFWRITE.OBJ $CTMP5.$$$ E:GETARGS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:GETARGS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 192 bytes size optimised away 432 bytes replaced 0:A:ZAS -J -N -OGETARGS.OBJ $CTMP5.$$$ E:GETCH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:GETCH.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OGETCH.OBJ $CTMP5.$$$ E:GETENV.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:GETENV.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 115 bytes size optimised away 242 bytes replaced 0:A:ZAS -J -N -OGETENV.OBJ $CTMP5.$$$ E:GETFCB.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:GETFCB.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 139 bytes size optimised away 282 bytes replaced 0:A:ZAS -J -N -OGETFCB.OBJ $CTMP5.$$$ E:GETS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:GETS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 32 bytes size optimised away 64 bytes replaced 0:A:ZAS -J -N -OGETS.OBJ $CTMP5.$$$ E:GETSP.AS 0:A:OPTIMH E:GETSP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OGETSP.OBJ $CTMP5.$$$ E:GETUID.AS 0:A:OPTIMH E:GETUID.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OGETUID.OBJ $CTMP5.$$$ E:GETW.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:GETW.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OGETW.OBJ $CTMP5.$$$ E:IDIV.AS 0:A:OPTIMH E:IDIV.AS $CTMP5.$$$ 1 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OIDIV.OBJ $CTMP5.$$$ E:IMUL.AS 0:A:OPTIMH E:IMUL.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OIMUL.OBJ $CTMP5.$$$ E:INDEX.AS 0:A:OPTIMH E:INDEX.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OINDEX.OBJ $CTMP5.$$$ E:INOUT.AS 0:A:OPTIMH E:INOUT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OINOUT.OBJ $CTMP5.$$$ E:IREGSET.AS 0:A:OPTIMH E:IREGSET.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OIREGSET.OBJ $CTMP5.$$$ E:ISALPHA.AS 0:A:OPTIMH E:ISALPHA.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OISALPHA.OBJ $CTMP5.$$$ E:ISATTY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:ISATTY.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 1 bytes size optimised away 3 bytes replaced 0:A:ZAS -J -N -OISATTY.OBJ $CTMP5.$$$ E:ISDIGIT.AS 0:A:OPTIMH E:ISDIGIT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OISDIGIT.OBJ $CTMP5.$$$ ERA $CTMP1.$$$ ERA $CTMP2.$$$ ERA $CTMP3.$$$ ERA $CTMP5.$$$ ERA $$EXEC.$$$ 10M>c280 A:C280 COM (User 0) 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 c> -v -o2 -c e:islower.as \ c> e:isspace.as \ c> e:isupper.as \ c> e:ladd.as \ c> e:land.as \ c> e:ldiv.as \ c> e:linc.as \ c> e:llrsh.as \ c> e:lmul.as \ c> e:longjmp.as \ c> e:lor.as \ c> e:lrelop.as \ c> e:lsub.as \ c> e:lxor.as \ c> e:malloc.c \ c> e:max.as \ c> e:memcmp.c \ c> e:memcpy.c \ c> e:memset.c \ c> e:mktime.c \ c> e:open.c \ c> e:perror.c \ c> e:pnum.c \ c> e:printf.c \ c> e:putchar.c E:ISLOWER.AS 0:A:OPTIMH E:ISLOWER.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OISLOWER.OBJ $CTMP5.$$$ E:ISSPACE.AS 0:A:OPTIMH E:ISSPACE.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OISSPACE.OBJ $CTMP5.$$$ E:ISUPPER.AS 0:A:OPTIMH E:ISUPPER.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OISUPPER.OBJ $CTMP5.$$$ E:LADD.AS 0:A:OPTIMH E:LADD.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OLADD.OBJ $CTMP5.$$$ E:LAND.AS 0:A:OPTIMH E:LAND.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OLAND.OBJ $CTMP5.$$$ E:LDIV.AS 0:A:OPTIMH E:LDIV.AS $CTMP5.$$$ 8 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -OLDIV.OBJ $CTMP5.$$$ E:LINC.AS 0:A:OPTIMH E:LINC.AS $CTMP5.$$$ 0 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -OLINC.OBJ $CTMP5.$$$ E:LLRSH.AS 0:A:OPTIMH E:LLRSH.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OLLRSH.OBJ $CTMP5.$$$ E:LMUL.AS 0:A:OPTIMH E:LMUL.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OLMUL.OBJ $CTMP5.$$$ E:LONGJMP.AS 0:A:OPTIMH E:LONGJMP.AS $CTMP5.$$$ 15 bytes size optimised away 36 bytes replaced 0:A:ZAS -J -OLONGJMP.OBJ $CTMP5.$$$ E:LOR.AS 0:A:OPTIMH E:LOR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OLOR.OBJ $CTMP5.$$$ E:LRELOP.AS 0:A:OPTIMH E:LRELOP.AS $CTMP5.$$$ 1 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OLRELOP.OBJ $CTMP5.$$$ E:LSUB.AS 0:A:OPTIMH E:LSUB.AS $CTMP5.$$$ 1 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OLSUB.OBJ $CTMP5.$$$ E:LXOR.AS 0:A:OPTIMH E:LXOR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OLXOR.OBJ $CTMP5.$$$ E:MALLOC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:MALLOC.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 99 bytes size optimised away 268 bytes replaced 0:A:ZAS -J -N -OMALLOC.OBJ $CTMP5.$$$ E:MAX.AS 0:A:OPTIMH E:MAX.AS $CTMP5.$$$ 1 bytes size optimised away 2 bytes replaced 0:A:ZAS -J -OMAX.OBJ $CTMP5.$$$ E:MEMCMP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:MEMCMP.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 13 bytes size optimised away 26 bytes replaced 0:A:ZAS -J -N -OMEMCMP.OBJ $CTMP5.$$$ E:MEMCPY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:MEMCPY.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OMEMCPY.OBJ $CTMP5.$$$ E:MEMSET.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:MEMSET.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 14 bytes size optimised away 28 bytes replaced 0:A:ZAS -J -N -OMEMSET.OBJ $CTMP5.$$$ E:MKTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:MKTIME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 75 bytes size optimised away 140 bytes replaced 0:A:ZAS -J -N -OMKTIME.OBJ $CTMP5.$$$ E:OPEN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:OPEN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 30 bytes size optimised away 81 bytes replaced 0:A:ZAS -J -N -OOPEN.OBJ $CTMP5.$$$ E:PERROR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:PERROR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 8 bytes size optimised away 18 bytes replaced 0:A:ZAS -J -N -OPERROR.OBJ $CTMP5.$$$ E:PNUM.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:PNUM.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 28 bytes size optimised away 50 bytes replaced 0:A:ZAS -J -N -OPNUM.OBJ $CTMP5.$$$ E:PRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:PRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 5 bytes size optimised away 6 bytes replaced 0:A:ZAS -J -N -OPRINTF.OBJ $CTMP5.$$$ E:PUTCHAR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:PUTCHAR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -N -OPUTCHAR.OBJ $CTMP5.$$$ ERA $CTMP1.$$$ ERA $CTMP2.$$$ ERA $CTMP3.$$$ ERA $CTMP5.$$$ ERA $$EXEC.$$$ 10M>c280 A:C280 COM (User 0) 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 c> -v -o2 -c e:puts.c \ c> e:putw.c \ c> e:qsort.c \ c> e:rand.c \ c> e:rcsv.as \ c> e:read.c \ c> e:remove.c \ c> e:rename.c \ c> e:rewind.c \ c> e:rindex.as \ c> e:sbrk.as \ c> e:scanf.c \ c> e:seek.c \ c> e:setbuf.c \ c> e:shar.as \ c> e:shll.as \ c> e:shlr.as \ c> e:signal.c \ c> e:sprintf.c \ c> e:srand1.c \ c> e:srand.as \ c> e:sscanf.c \ c> e:start1.as \ c> e:start2.as \ c> e:stat.c \ c> e:stdclean.c \ c> e:strcat.as \ c> e:strchr.as \ c> e:strcmp.as \ c> e:strcpy.as \ c> e:strdup.c \ c> e:strftime.c \ c> e:stricmp.as \ c> e:stristr.c \ c> e:strlen.as \ c> e:strncat.as \ c> e:strncmp.as \ c> e:strncpy.as \ c> e:strnicmp.as \ c> e:strnistr.c \ c> e:strnstr.c \ c> e:strrchr.as \ c> e:strstr.c \ c> e:strtok.c \ c> e:swap.as \ c> e:sys_err.c \ c> e:time.c \ c> e:timezone.c \ c> e:tolower.as \ c> e:toupper.as \ c> e:ungetc.c \ c> e:unlink.c \ c> e:wrelop.as \ c> e:write.c \ c> e:xtoi.as \ c> e:zc280cpm.as \ c> e:zd280cpm.as \ c> e:zn280cpm.as \ c> e:zr280cpm.as \ c> e:libcver.c E:PUTS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:PUTS.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 15 bytes size optimised away 30 bytes replaced 0:A:ZAS -J -N -OPUTS.OBJ $CTMP5.$$$ E:PUTW.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:PUTW.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 8 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -OPUTW.OBJ $CTMP5.$$$ E:QSORT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:QSORT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 142 bytes size optimised away 351 bytes replaced 0:A:ZAS -J -N -OQSORT.OBJ $CTMP5.$$$ E:RAND.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:RAND.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -N -ORAND.OBJ $CTMP5.$$$ E:RCSV.AS 0:A:OPTIMH E:RCSV.AS $CTMP5.$$$ 6 bytes size optimised away 12 bytes replaced 0:A:ZAS -J -ORCSV.OBJ $CTMP5.$$$ E:READ.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:READ.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 120 bytes size optimised away 221 bytes replaced 0:A:ZAS -J -N -OREAD.OBJ $CTMP5.$$$ E:REMOVE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:REMOVE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -N -OREMOVE.OBJ $CTMP5.$$$ E:RENAME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:RENAME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 15 bytes size optimised away 18 bytes replaced 0:A:ZAS -J -N -ORENAME.OBJ $CTMP5.$$$ E:REWIND.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:REWIND.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 2 bytes size optimised away 4 bytes replaced 0:A:ZAS -J -N -OREWIND.OBJ $CTMP5.$$$ E:RINDEX.AS 0:A:OPTIMH E:RINDEX.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -ORINDEX.OBJ $CTMP5.$$$ E:SBRK.AS 0:A:OPTIMH E:SBRK.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSBRK.OBJ $CTMP5.$$$ E:SCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 5 bytes size optimised away 6 bytes replaced 0:A:ZAS -J -N -OSCANF.OBJ $CTMP5.$$$ E:SEEK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SEEK.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 49 bytes size optimised away 99 bytes replaced 0:A:ZAS -J -N -OSEEK.OBJ $CTMP5.$$$ E:SETBUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SETBUF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 40 bytes size optimised away 80 bytes replaced 0:A:ZAS -J -N -OSETBUF.OBJ $CTMP5.$$$ E:SHAR.AS 0:A:OPTIMH E:SHAR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSHAR.OBJ $CTMP5.$$$ E:SHLL.AS 0:A:OPTIMH E:SHLL.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSHLL.OBJ $CTMP5.$$$ E:SHLR.AS 0:A:OPTIMH E:SHLR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSHLR.OBJ $CTMP5.$$$ E:SIGNAL.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SIGNAL.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OSIGNAL.OBJ $CTMP5.$$$ E:SPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SPRINTF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -OSPRINTF.OBJ $CTMP5.$$$ E:SRAND1.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SRAND1.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OSRAND1.OBJ $CTMP5.$$$ E:SRAND.AS 0:A:OPTIMH E:SRAND.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSRAND.OBJ $CTMP5.$$$ E:SSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SSCANF.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 18 bytes size optimised away 28 bytes replaced 0:A:ZAS -J -N -OSSCANF.OBJ $CTMP5.$$$ E:START1.AS 0:A:OPTIMH E:START1.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTART1.OBJ $CTMP5.$$$ E:START2.AS 0:A:OPTIMH E:START2.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTART2.OBJ $CTMP5.$$$ E:STAT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STAT.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 73 bytes size optimised away 154 bytes replaced 0:A:ZAS -J -N -OSTAT.OBJ $CTMP5.$$$ E:STDCLEAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STDCLEAN.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OSTDCLEAN.OBJ $CTMP5.$$$ E:STRCAT.AS 0:A:OPTIMH E:STRCAT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRCAT.OBJ $CTMP5.$$$ E:STRCHR.AS 0:A:OPTIMH E:STRCHR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRCHR.OBJ $CTMP5.$$$ E:STRCMP.AS 0:A:OPTIMH E:STRCMP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRCMP.OBJ $CTMP5.$$$ E:STRCPY.AS 0:A:OPTIMH E:STRCPY.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRCPY.OBJ $CTMP5.$$$ E:STRDUP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRDUP.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 10 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OSTRDUP.OBJ $CTMP5.$$$ E:STRFTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRFTIME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 185 bytes size optimised away 428 bytes replaced 0:A:ZAS -J -N -OSTRFTIME.OBJ $CTMP5.$$$ E:STRICMP.AS 0:A:OPTIMH E:STRICMP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRICMP.OBJ $CTMP5.$$$ E:STRISTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRISTR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 25 bytes size optimised away 50 bytes replaced 0:A:ZAS -J -N -OSTRISTR.OBJ $CTMP5.$$$ E:STRLEN.AS 0:A:OPTIMH E:STRLEN.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRLEN.OBJ $CTMP5.$$$ E:STRNCAT.AS 0:A:OPTIMH E:STRNCAT.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRNCAT.OBJ $CTMP5.$$$ E:STRNCMP.AS 0:A:OPTIMH E:STRNCMP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRNCMP.OBJ $CTMP5.$$$ E:STRNCPY.AS 0:A:OPTIMH E:STRNCPY.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRNCPY.OBJ $CTMP5.$$$ E:STRNICMP.AS 0:A:OPTIMH E:STRNICMP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRNICMP.OBJ $CTMP5.$$$ E:STRNISTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRNISTR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 45 bytes size optimised away 90 bytes replaced 0:A:ZAS -J -N -OSTRNISTR.OBJ $CTMP5.$$$ E:STRNSTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRNSTR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 44 bytes size optimised away 88 bytes replaced 0:A:ZAS -J -N -OSTRNSTR.OBJ $CTMP5.$$$ E:STRRCHR.AS 0:A:OPTIMH E:STRRCHR.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSTRRCHR.OBJ $CTMP5.$$$ E:STRSTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRSTR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 22 bytes size optimised away 44 bytes replaced 0:A:ZAS -J -N -OSTRSTR.OBJ $CTMP5.$$$ E:STRTOK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:STRTOK.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 38 bytes size optimised away 76 bytes replaced 0:A:ZAS -J -N -OSTRTOK.OBJ $CTMP5.$$$ E:SWAP.AS 0:A:OPTIMH E:SWAP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OSWAP.OBJ $CTMP5.$$$ E:SYS_ERR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:SYS_ERR.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OSYS_ERR.OBJ $CTMP5.$$$ E:TIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:TIME.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 18 bytes size optimised away 32 bytes replaced 0:A:ZAS -J -N -OTIME.OBJ $CTMP5.$$$ E:TIMEZONE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:TIMEZONE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTIMEZONE.OBJ $CTMP5.$$$ E:TOLOWER.AS 0:A:OPTIMH E:TOLOWER.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OTOLOWER.OBJ $CTMP5.$$$ E:TOUPPER.AS 0:A:OPTIMH E:TOUPPER.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OTOUPPER.OBJ $CTMP5.$$$ E:UNGETC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:UNGETC.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 27 bytes size optimised away 54 bytes replaced 0:A:ZAS -J -N -OUNGETC.OBJ $CTMP5.$$$ E:UNLINK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:UNLINK.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 14 bytes size optimised away 20 bytes replaced 0:A:ZAS -J -N -OUNLINK.OBJ $CTMP5.$$$ E:WRELOP.AS 0:A:OPTIMH E:WRELOP.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OWRELOP.OBJ $CTMP5.$$$ E:WRITE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:WRITE.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 94 bytes size optimised away 167 bytes replaced 0:A:ZAS -J -N -OWRITE.OBJ $CTMP5.$$$ E:XTOI.AS 0:A:OPTIMH E:XTOI.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OXTOI.OBJ $CTMP5.$$$ E:ZC280CPM.AS 0:A:OPTIMH E:ZC280CPM.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OZC280CPM.OBJ $CTMP5.$$$ E:ZD280CPM.AS 0:A:OPTIMH E:ZD280CPM.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OZD280CPM.OBJ $CTMP5.$$$ E:ZN280CPM.AS 0:A:OPTIMH E:ZN280CPM.AS $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -OZN280CPM.OBJ $CTMP5.$$$ E:ZR280CPM.AS 0:A:OPTIMH E:ZR280CPM.AS $CTMP5.$$$ 3 bytes size optimised away 10 bytes replaced 0:A:ZAS -J -OZR280CPM.OBJ $CTMP5.$$$ E:LIBCVER.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: E:LIBCVER.C $CTMP1.$$$ 0:A:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$ 0:A:CGEN $CTMP2.$$$ $CTMP1.$$$ 0:A:OPTIM $CTMP1.$$$ $CTMP2.$$$ 0:A:OPTIMH $CTMP2.$$$ $CTMP5.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OLIBCVER.OBJ $CTMP5.$$$ ERA $CTMP1.$$$ ERA $CTMP2.$$$ ERA $CTMP3.$$$ ERA $CTMP5.$$$ ERA $$EXEC.$$$ 10M>; All modules compiled. 10M>put console to console A:PUT COM (User 0) ================================================ FILE: stdio/C280LIBC.SUB ================================================ era c280libc.log put console output to file c280libc.log [system] date ; Compile all LIB280C.LIB modules from sources for Z280 ; ; Sources are on drive E: ; Z280 object files are created on drive M: ; m: pip m:=e:stdio.i c280 <-v -o2 -c e:abort.c \ char * cgets(s) char * s; { char * s1 = s; int c; while((c = getche()) != '\r' && c != '\n') *s++ = c; *s = 0; if(s == s1) return((char *)0); return(s1); } ================================================ FILE: stdio/COMPLIBC.LOG ================================================ 10E>date A:DATE COM (User 0) Fri 05/09/2025 09:37:50 10E>; Compile all LIBC19.LIB modules from sources 10E>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 c> -o -v -c abort.c \ c> abs.as \ c> allsh.as \ c> alrsh.as \ c> asallsh.as \ c> asalrsh.as \ c> asar.as \ c> asdiv.as \ c> asladd.as \ c> asland.as \ c> asll.as \ c> asllrsh.as \ c> aslmul.as \ c> aslor.as \ c> aslr.as \ c> aslsub.as \ c> aslxor.as \ c> asmod.as \ c> asmul.as \ c> assert.c \ c> atoi.as \ c> atol.c \ c> bdos.as \ c> bios.as \ c> bitfield.as \ c> blkclr.as \ c> blkcpy.c \ c> bmove.as \ c> brelop.as \ c> buf.c \ c> calloc.c \ c> cgets.c \ c> chmod.c \ c> cleanup.c \ c> close.c \ c> convtime.c \ c> cputs.c \ c> creat.c \ c> csv.as \ c> ctime.c \ c> ctype_.c \ c> ctype.c \ c> doprnt.c \ c> doscan.c \ c> dup.c \ c> exec.as \ c> execl.as \ c> _exit.as \ c> exit.c \ c> fakeclea.c \ c> fakecpcl.as \ c> fcbname.c \ c> fclose.c \ c> fflush.c \ c> fgetc.c \ c> filbuf.c \ c> flsbuf.c \ c> fopen.c \ c> fprintf.c \ c> fputc.c \ c> fread.c \ c> frelop.as \ c> freopen.c \ c> fscanf.c \ c> fseek.c \ c> fwrite.c \ c> getargs.c \ c> getch.c \ c> getenv.c \ c> getfcb.c \ c> gets.c \ c> getsp.as \ c> getuid.as \ c> getw.c \ c> idiv.as \ c> imul.as \ c> index.as \ c> inout.as \ c> iregset.as \ c> isalpha.as \ c> isatty.c \ c> isdigit.as ABORT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: ABORT.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 -OABORT.OBJ M:$CTMP2.$$$ ABS.AS 0:A:ZAS -J -OABS.OBJ ABS.AS ALLSH.AS 0:A:ZAS -J -OALLSH.OBJ ALLSH.AS ALRSH.AS 0:A:ZAS -J -OALRSH.OBJ ALRSH.AS ASALLSH.AS 0:A:ZAS -J -OASALLSH.OBJ ASALLSH.AS ASALRSH.AS 0:A:ZAS -J -OASALRSH.OBJ ASALRSH.AS ASAR.AS 0:A:ZAS -J -OASAR.OBJ ASAR.AS ASDIV.AS 0:A:ZAS -J -OASDIV.OBJ ASDIV.AS ASLADD.AS 0:A:ZAS -J -OASLADD.OBJ ASLADD.AS ASLAND.AS 0:A:ZAS -J -OASLAND.OBJ ASLAND.AS ASLL.AS 0:A:ZAS -J -OASLL.OBJ ASLL.AS ASLLRSH.AS 0:A:ZAS -J -OASLLRSH.OBJ ASLLRSH.AS ASLMUL.AS 0:A:ZAS -J -OASLMUL.OBJ ASLMUL.AS ASLOR.AS 0:A:ZAS -J -OASLOR.OBJ ASLOR.AS ASLR.AS 0:A:ZAS -J -OASLR.OBJ ASLR.AS ASLSUB.AS 0:A:ZAS -J -OASLSUB.OBJ ASLSUB.AS ASLXOR.AS 0:A:ZAS -J -OASLXOR.OBJ ASLXOR.AS ASMOD.AS 0:A:ZAS -J -OASMOD.OBJ ASMOD.AS ASMUL.AS 0:A:ZAS -J -OASMUL.OBJ ASMUL.AS ASSERT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: ASSERT.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 -OASSERT.OBJ M:$CTMP2.$$$ ATOI.AS 0:A:ZAS -J -OATOI.OBJ ATOI.AS ATOL.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: ATOL.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 -OATOL.OBJ M:$CTMP2.$$$ BDOS.AS 0:A:ZAS -J -OBDOS.OBJ BDOS.AS BIOS.AS 0:A:ZAS -J -OBIOS.OBJ BIOS.AS BITFIELD.AS 0:A:ZAS -J -OBITFIELD.OBJ BITFIELD.AS BLKCLR.AS 0:A:ZAS -J -OBLKCLR.OBJ BLKCLR.AS BLKCPY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: BLKCPY.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 -OBLKCPY.OBJ M:$CTMP2.$$$ BMOVE.AS 0:A:ZAS -J -OBMOVE.OBJ BMOVE.AS BRELOP.AS 0:A:ZAS -J -OBRELOP.OBJ BRELOP.AS BUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: BUF.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 -OBUF.OBJ M:$CTMP2.$$$ CALLOC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CALLOC.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 -OCALLOC.OBJ M:$CTMP2.$$$ CGETS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CGETS.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 -OCGETS.OBJ M:$CTMP2.$$$ CHMOD.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CHMOD.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 -OCHMOD.OBJ M:$CTMP2.$$$ CLEANUP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CLEANUP.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 -OCLEANUP.OBJ M:$CTMP2.$$$ CLOSE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CLOSE.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 -OCLOSE.OBJ M:$CTMP2.$$$ CONVTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CONVTIME.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 -OCONVTIME.OBJ M:$CTMP2.$$$ CPUTS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CPUTS.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 -OCPUTS.OBJ M:$CTMP2.$$$ CREAT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CREAT.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 -OCREAT.OBJ M:$CTMP2.$$$ CSV.AS 0:A:ZAS -J -OCSV.OBJ CSV.AS CTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CTIME.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 -OCTIME.OBJ M:$CTMP2.$$$ CTYPE_.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CTYPE_.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 -OCTYPE_.OBJ M:$CTMP2.$$$ CTYPE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: CTYPE.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 -OCTYPE.OBJ M:$CTMP2.$$$ DOPRNT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: DOPRNT.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 -ODOPRNT.OBJ M:$CTMP2.$$$ DOSCAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: DOSCAN.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 -ODOSCAN.OBJ M:$CTMP2.$$$ DUP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: DUP.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 -ODUP.OBJ M:$CTMP2.$$$ EXEC.AS 0:A:ZAS -J -OEXEC.OBJ EXEC.AS EXECL.AS 0:A:ZAS -J -OEXECL.OBJ EXECL.AS _EXIT.AS 0:A:ZAS -J -O_EXIT.OBJ _EXIT.AS EXIT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: EXIT.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 -OEXIT.OBJ M:$CTMP2.$$$ FAKECLEA.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FAKECLEA.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 -OFAKECLEA.OBJ M:$CTMP2.$$$ FAKECPCL.AS 0:A:ZAS -J -OFAKECPCL.OBJ FAKECPCL.AS FCBNAME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FCBNAME.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 -OFCBNAME.OBJ M:$CTMP2.$$$ FCLOSE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FCLOSE.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 -OFCLOSE.OBJ M:$CTMP2.$$$ FFLUSH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FFLUSH.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 -OFFLUSH.OBJ M:$CTMP2.$$$ FGETC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FGETC.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 -OFGETC.OBJ M:$CTMP2.$$$ FILBUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FILBUF.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 -OFILBUF.OBJ M:$CTMP2.$$$ FLSBUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FLSBUF.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 -OFLSBUF.OBJ M:$CTMP2.$$$ FOPEN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FOPEN.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 -OFOPEN.OBJ M:$CTMP2.$$$ FPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FPRINTF.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 -OFPRINTF.OBJ M:$CTMP2.$$$ FPUTC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FPUTC.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 -OFPUTC.OBJ M:$CTMP2.$$$ FREAD.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FREAD.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 -OFREAD.OBJ M:$CTMP2.$$$ FRELOP.AS 0:A:ZAS -J -OFRELOP.OBJ FRELOP.AS FREOPEN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FREOPEN.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 -OFREOPEN.OBJ M:$CTMP2.$$$ FSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FSCANF.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 -OFSCANF.OBJ M:$CTMP2.$$$ FSEEK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FSEEK.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 -OFSEEK.OBJ M:$CTMP2.$$$ FWRITE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: FWRITE.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 -OFWRITE.OBJ M:$CTMP2.$$$ GETARGS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: GETARGS.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 -OGETARGS.OBJ M:$CTMP2.$$$ GETCH.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: GETCH.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 -OGETCH.OBJ M:$CTMP2.$$$ GETENV.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: GETENV.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 -OGETENV.OBJ M:$CTMP2.$$$ GETFCB.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: GETFCB.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 -OGETFCB.OBJ M:$CTMP2.$$$ GETS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: GETS.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 -OGETS.OBJ M:$CTMP2.$$$ GETSP.AS 0:A:ZAS -J -OGETSP.OBJ GETSP.AS GETUID.AS 0:A:ZAS -J -OGETUID.OBJ GETUID.AS GETW.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: GETW.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 -OGETW.OBJ M:$CTMP2.$$$ IDIV.AS 0:A:ZAS -J -OIDIV.OBJ IDIV.AS IMUL.AS 0:A:ZAS -J -OIMUL.OBJ IMUL.AS INDEX.AS 0:A:ZAS -J -OINDEX.OBJ INDEX.AS INOUT.AS 0:A:ZAS -J -OINOUT.OBJ INOUT.AS IREGSET.AS 0:A:ZAS -J -OIREGSET.OBJ IREGSET.AS ISALPHA.AS 0:A:ZAS -J -OISALPHA.OBJ ISALPHA.AS ISATTY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: ISATTY.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 -OISATTY.OBJ M:$CTMP2.$$$ ISDIGIT.AS 0:A:ZAS -J -OISDIGIT.OBJ ISDIGIT.AS ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ ERA M:$$EXEC.$$$ 10E>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 c> -o -v -c islower.as \ c> isspace.as \ c> isupper.as \ c> ladd.as \ c> land.as \ c> ldiv.as \ c> linc.as \ c> llrsh.as \ c> lmul.as \ c> longjmp.as \ c> lor.as \ c> lrelop.as \ c> lsub.as \ c> lxor.as \ c> malloc.c \ c> max.as \ c> memcmp.c \ c> memcpy.c \ c> memset.c \ c> mktime.c \ c> open.c \ c> perror.c \ c> pnum.c \ c> printf.c \ c> putchar.c ISLOWER.AS 0:A:ZAS -J -OISLOWER.OBJ ISLOWER.AS ISSPACE.AS 0:A:ZAS -J -OISSPACE.OBJ ISSPACE.AS ISUPPER.AS 0:A:ZAS -J -OISUPPER.OBJ ISUPPER.AS LADD.AS 0:A:ZAS -J -OLADD.OBJ LADD.AS LAND.AS 0:A:ZAS -J -OLAND.OBJ LAND.AS LDIV.AS 0:A:ZAS -J -OLDIV.OBJ LDIV.AS LINC.AS 0:A:ZAS -J -OLINC.OBJ LINC.AS LLRSH.AS 0:A:ZAS -J -OLLRSH.OBJ LLRSH.AS LMUL.AS 0:A:ZAS -J -OLMUL.OBJ LMUL.AS LONGJMP.AS 0:A:ZAS -J -OLONGJMP.OBJ LONGJMP.AS LOR.AS 0:A:ZAS -J -OLOR.OBJ LOR.AS LRELOP.AS 0:A:ZAS -J -OLRELOP.OBJ LRELOP.AS LSUB.AS 0:A:ZAS -J -OLSUB.OBJ LSUB.AS LXOR.AS 0:A:ZAS -J -OLXOR.OBJ LXOR.AS MALLOC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: MALLOC.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 -OMALLOC.OBJ M:$CTMP2.$$$ MAX.AS 0:A:ZAS -J -OMAX.OBJ MAX.AS MEMCMP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: MEMCMP.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 -OMEMCMP.OBJ M:$CTMP2.$$$ MEMCPY.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: MEMCPY.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 -OMEMCPY.OBJ M:$CTMP2.$$$ MEMSET.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: MEMSET.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 -OMEMSET.OBJ M:$CTMP2.$$$ MKTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: MKTIME.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 -OMKTIME.OBJ M:$CTMP2.$$$ OPEN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: OPEN.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 -OOPEN.OBJ M:$CTMP2.$$$ PERROR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: PERROR.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 -OPERROR.OBJ M:$CTMP2.$$$ PNUM.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: PNUM.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 -OPNUM.OBJ M:$CTMP2.$$$ PRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: PRINTF.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 -OPRINTF.OBJ M:$CTMP2.$$$ PUTCHAR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: PUTCHAR.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 -OPUTCHAR.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ ERA M:$$EXEC.$$$ 10E>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 c> -o -v -c puts.c \ c> putw.c \ c> qsort.c \ c> rand.c \ c> rcsv.as \ c> read.c \ c> remove.c \ c> rename.c \ c> rewind.c \ c> rindex.as \ c> sbrk.as \ c> scanf.c \ c> seek.c \ c> setbuf.c \ c> shar.as \ c> shll.as \ c> shlr.as \ c> signal.c \ c> sprintf.c \ c> srand1.c \ c> srand.as \ c> sscanf.c \ c> start1.as \ c> start2.as \ c> stat.c \ c> stdclean.c \ c> strcat.as \ c> strchr.as \ c> strcmp.as \ c> strcpy.as \ c> strdup.c \ c> strftime.c \ c> stricmp.as \ c> stristr.c \ c> strlen.as \ c> strncat.as \ c> strncmp.as \ c> strncpy.as \ c> strnicmp.as \ c> strnistr.c \ c> strnstr.c \ c> strrchr.as \ c> strstr.c \ c> strtok.c \ c> swap.as \ c> sys_err.c \ c> time.c \ c> timezone.c \ c> tolower.as \ c> toupper.as \ c> ungetc.c \ c> unlink.c \ c> wrelop.as \ c> write.c \ c> xtoi.as \ c> zcrtcpm.as \ c> zdrtcpm.as \ c> znrtcpm.as \ c> zrrtcpm.as \ c> libcver.c PUTS.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: PUTS.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 -OPUTS.OBJ M:$CTMP2.$$$ PUTW.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: PUTW.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 -OPUTW.OBJ M:$CTMP2.$$$ QSORT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: QSORT.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 -OQSORT.OBJ M:$CTMP2.$$$ RAND.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: RAND.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 -ORAND.OBJ M:$CTMP2.$$$ RCSV.AS 0:A:ZAS -J -ORCSV.OBJ RCSV.AS READ.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: READ.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 -OREAD.OBJ M:$CTMP2.$$$ REMOVE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: REMOVE.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 -OREMOVE.OBJ M:$CTMP2.$$$ RENAME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: RENAME.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 -ORENAME.OBJ M:$CTMP2.$$$ REWIND.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: REWIND.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 -OREWIND.OBJ M:$CTMP2.$$$ RINDEX.AS 0:A:ZAS -J -ORINDEX.OBJ RINDEX.AS SBRK.AS 0:A:ZAS -J -OSBRK.OBJ SBRK.AS SCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SCANF.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 -OSCANF.OBJ M:$CTMP2.$$$ SEEK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SEEK.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 -OSEEK.OBJ M:$CTMP2.$$$ SETBUF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SETBUF.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 -OSETBUF.OBJ M:$CTMP2.$$$ SHAR.AS 0:A:ZAS -J -OSHAR.OBJ SHAR.AS SHLL.AS 0:A:ZAS -J -OSHLL.OBJ SHLL.AS SHLR.AS 0:A:ZAS -J -OSHLR.OBJ SHLR.AS SIGNAL.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SIGNAL.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 -OSIGNAL.OBJ M:$CTMP2.$$$ SPRINTF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SPRINTF.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 -OSPRINTF.OBJ M:$CTMP2.$$$ SRAND1.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SRAND1.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 -OSRAND1.OBJ M:$CTMP2.$$$ SRAND.AS 0:A:ZAS -J -OSRAND.OBJ SRAND.AS SSCANF.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SSCANF.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 -OSSCANF.OBJ M:$CTMP2.$$$ START1.AS 0:A:ZAS -J -OSTART1.OBJ START1.AS START2.AS 0:A:ZAS -J -OSTART2.OBJ START2.AS STAT.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STAT.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 -OSTAT.OBJ M:$CTMP2.$$$ STDCLEAN.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STDCLEAN.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 -OSTDCLEAN.OBJ M:$CTMP2.$$$ STRCAT.AS 0:A:ZAS -J -OSTRCAT.OBJ STRCAT.AS STRCHR.AS 0:A:ZAS -J -OSTRCHR.OBJ STRCHR.AS STRCMP.AS 0:A:ZAS -J -OSTRCMP.OBJ STRCMP.AS STRCPY.AS 0:A:ZAS -J -OSTRCPY.OBJ STRCPY.AS STRDUP.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRDUP.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 -OSTRDUP.OBJ M:$CTMP2.$$$ STRFTIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRFTIME.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 -OSTRFTIME.OBJ M:$CTMP2.$$$ STRICMP.AS 0:A:ZAS -J -OSTRICMP.OBJ STRICMP.AS STRISTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRISTR.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 -OSTRISTR.OBJ M:$CTMP2.$$$ STRLEN.AS 0:A:ZAS -J -OSTRLEN.OBJ STRLEN.AS STRNCAT.AS 0:A:ZAS -J -OSTRNCAT.OBJ STRNCAT.AS STRNCMP.AS 0:A:ZAS -J -OSTRNCMP.OBJ STRNCMP.AS STRNCPY.AS 0:A:ZAS -J -OSTRNCPY.OBJ STRNCPY.AS STRNICMP.AS 0:A:ZAS -J -OSTRNICMP.OBJ STRNICMP.AS STRNISTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRNISTR.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 -OSTRNISTR.OBJ M:$CTMP2.$$$ STRNSTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRNSTR.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 -OSTRNSTR.OBJ M:$CTMP2.$$$ STRRCHR.AS 0:A:ZAS -J -OSTRRCHR.OBJ STRRCHR.AS STRSTR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRSTR.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 -OSTRSTR.OBJ M:$CTMP2.$$$ STRTOK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: STRTOK.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 -OSTRTOK.OBJ M:$CTMP2.$$$ SWAP.AS 0:A:ZAS -J -OSWAP.OBJ SWAP.AS SYS_ERR.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: SYS_ERR.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 -OSYS_ERR.OBJ M:$CTMP2.$$$ TIME.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: TIME.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 -OTIME.OBJ M:$CTMP2.$$$ TIMEZONE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: TIMEZONE.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 -OTIMEZONE.OBJ M:$CTMP2.$$$ TOLOWER.AS 0:A:ZAS -J -OTOLOWER.OBJ TOLOWER.AS TOUPPER.AS 0:A:ZAS -J -OTOUPPER.OBJ TOUPPER.AS UNGETC.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: UNGETC.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 -OUNGETC.OBJ M:$CTMP2.$$$ UNLINK.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: UNLINK.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 -OUNLINK.OBJ M:$CTMP2.$$$ WRELOP.AS 0:A:ZAS -J -OWRELOP.OBJ WRELOP.AS WRITE.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: WRITE.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 -OWRITE.OBJ M:$CTMP2.$$$ XTOI.AS 0:A:ZAS -J -OXTOI.OBJ XTOI.AS ZCRTCPM.AS 0:A:ZAS -J -OZCRTCPM.OBJ ZCRTCPM.AS ZDRTCPM.AS 0:A:ZAS -J -OZDRTCPM.OBJ ZDRTCPM.AS ZNRTCPM.AS 0:A:ZAS -J -OZNRTCPM.OBJ ZNRTCPM.AS ZRRTCPM.AS 0:A:ZAS -J -OZRRTCPM.OBJ ZRRTCPM.AS LIBCVER.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: LIBCVER.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 -OLIBCVER.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ ERA M:$$EXEC.$$$ 10E>; All modules compiled. 10E>put console to console A:PUT COM (User 0) ================================================ FILE: stdio/COMPLIBC.SUB ================================================ era complibc.log put console output to file complibc.log [system] date ; Compile all LIBC19.LIB modules from sources c <-o -v -c abort.c \ void cputs(s) register char * s; { while(*s) putch(*s++); } ================================================ FILE: stdio/CTIME.C ================================================ /* * Ctime for HI-TECH C - no daylight saving */ #include unsigned char monlen[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static put2d(cp, i, cl, ct) char * cp, cl, ct; unsigned i; { *cp = ct; *--cp = i%10 + '0'; if(i /= 10) *--cp = i + '0'; else *--cp = cl; } static dylen(yr) unsigned yr; { if(yr%4) return(365); return(366); } struct tm * localtime(tp) time_t * tp; { time_t t; t = *tp - time_zone*60L; return gmtime(&t); } struct tm * gmtime(tp) time_t * tp; { unsigned day, mon, yr, cumday; time_t t; static struct tm tim; t = *tp; tim.tm_sec = t % 60L; t /= 60L; tim.tm_min = t % 60L; t /= 60L; tim.tm_hour = t % 24L; day = t / 24L; tim.tm_wday = (day + 4) % 7; yr = 70; cumday = 0; while((cumday += dylen(yr)) <= day) yr++; tim.tm_year = yr; cumday -= dylen(yr); day -= cumday; tim.tm_yday = day; cumday = 0; mon = 0; if((yr % 4) == 0) monlen[1] = 29; else monlen[1] = 28; while((cumday += monlen[mon]) <= day) mon++; cumday -= monlen[mon]; day -= cumday; tim.tm_mday = day + 1; tim.tm_mon = mon; return &tim; } char * asctime(tim) register struct tm * tim; { register char * s, * cp; short i; static char buf[27]; s = &"SunMonTueWedThuFriSat"[tim->tm_wday*3]; i = 3; cp = buf; do *cp++ = *s++; while(--i); *cp++ = ' '; s = &"JanFebMarAprMayJunJulAugSepOctNovDec"[tim->tm_mon*3]; i = 3; do *cp++ = *s++; while(--i); buf[7] = ' '; put2d(buf+10, tim->tm_mday, ' ', ' '); put2d(buf+13, tim->tm_hour, '0', ':'); put2d(buf+16, tim->tm_min, '0', ':'); put2d(buf+19, tim->tm_sec, '0', ' '); put2d(buf+22, tim->tm_year/100 + 19, ' ', 0); put2d(buf+24, tim->tm_year%100, '0', '\n'); return(buf); } char * ctime(tp) time_t * tp; { return asctime(localtime(tp)); } ================================================ FILE: stdio/DOPRNT.C ================================================ #include #include #include #include /* * doprnt for Z80 */ extern int _pnum(); static uchar ival; static char * x; static FILE * ffile; static pputc(c) char c; { putc(c, ffile); } static char * icvt(cp) register char * cp; { ival = atoi(cp); while(isdigit((unsigned)*cp)) cp++; return cp; } _doprnt(file, f, a) FILE * file; register char * f; int * a; { char c; uchar fill, left; unsigned int i; uchar base, width, prec, sign; unsigned int len; ffile = file; while(c = *f++) if(c != '%') pputc(c); else { base = 10; width = 0; sign = 0; left = 0; len = sizeof(int)/sizeof *a; if(*f == '-') { f++; left++; } fill = *f == '0'; if(isdigit((unsigned)*f)) { f = icvt(f); width = ival; } else if(*f == '*') { width = *a++; f++; } if(*f == '.') if(*++f == '*') { prec = *a++; f++; } else { f = icvt(f); prec = ival; } else prec = fill ? width : 0; if(*f == 'l') { f++; len = sizeof(long)/sizeof *a; } switch(c = *f++) { case 0: return; case 'o': case 'O': base = 8; break; case 'd': case 'D': sign = 1; break; case 'x': case 'X': base = 16; break; case 's': x = *(char **)a; a += sizeof(char *)/sizeof *a; if(!x) x = "(null)"; i = strlen(x); dostring: if(prec && prec < i) i = prec; if(width > i) width -= i; else width = 0; if(!left) while(width--) pputc(' '); while(i--) pputc(*x++); if(left) while(width--) pputc(' '); continue; case 'c': c = *a++; default: x = &c; i = 1; goto dostring; case 'u': break; } if(left) { left = width; width = 0; } if(isupper(c)) len = sizeof(long)/sizeof *a; width = _pnum((len == sizeof(int)/sizeof *a ? (sign ? (long)*a : (unsigned long)*a) : *(long *)a), prec, width, sign, base, pputc); a += len; while(left-- > width) pputc(' '); } } ================================================ FILE: stdio/DOSCAN.C ================================================ /* * _doscan - implement scanf, fscanf, sscanf */ #include #include #include static FILE * fp; static range(c, base) int c; uchar base; { if(isdigit(c)) c -= '0'; else { c = tolower(c) ; if (isalpha(c)) c = c - 'a' + 10 ; else return -1 ; } if (c >= base) return -1 ; return c ; } static wspace() { int c; while(isspace(c = getc(fp))) continue; if(c != EOF) ungetc(c, fp); } _doscan(file, fmt, args) FILE * file; register char * fmt; int ** args; { uchar c, sign, base, n, noass,len; char width ; char * sptr; int ch; long val; fp = file; n = 0; while(c = *fmt++) { len = 0 ; if(isspace(c)) { wspace(); continue; } if(c == '%') { noass = 0; width = 0; loop: switch(c = *fmt++) { case '\0': return n ? n : feof(fp) ? EOF : 0; case '*': noass++; goto loop; case 'l': len++; case 'h': goto loop; case 'D': len++; case 'd': base = 10; break; case 'O': len++; case 'o': base = 8; break; case 'X': len++; case 'x': base = 16; break ; case 's': wspace(); if ( !noass ) sptr = (char *)*args++; if ((ch = getc(fp)) == EOF ) return n ? n : EOF; while(ch && ch != EOF && !isspace(ch)) { if(ch == *fmt) { fmt++; break; } if ( !noass ) *sptr++ = ch; if(--width == 0) break; ch = getc(fp); } n++; if ( !noass ) *sptr = 0; continue; case 'c': if ( !noass ) sptr = (char *)*args++; do { if ((ch = getc(fp)) == EOF) return n ? n : EOF; if ( !noass ) *sptr++ = ch; } while(--width > 0); n++; continue; default: if(isdigit(c)) { width = atoi(fmt-1); while(isdigit(*fmt)) fmt++; goto loop; } if(c != (ch = getc(fp))) if(ch == EOF) return n ? n : EOF; else { ungetc(ch, fp); return n; } continue; } wspace(); val = 0; sign = 0; ch = getc(fp); if(ch == '-') { sign++; ch = getc(fp); } if(range(ch, base) == -1) return n ? n : feof(fp) ? EOF : 0; do { val = val * base + range(ch, base); } while (( --width != 0 ) && ( range(ch = getc(fp),base) != -1 )) ; n++; if (range(ch,base) == -1) ungetc(ch, fp); if(sign) val = -val; if ( !noass ) if(len) *(long *)*args++ = val; else **args++ = val; continue; } else if(c != (ch = getc(fp))) { if(ch != EOF) { ungetc(ch, fp); return n; } else return n ? n : EOF; } } return n; } ================================================ FILE: stdio/EXIT.C ================================================ extern void _cleanup(void); extern void _exit(int); exit(v) { _cleanup(); _exit(v); } ================================================ FILE: stdio/FAKECLEA.C ================================================ _cleanup() { } ================================================ FILE: stdio/FCLOSE.C ================================================ /* * fclose - for HI-TECH C Z80 CP/M stdio */ #include #include fclose(f) register FILE * f; { if(!(f->_flag & (_IOREAD|_IOWRT))) return(EOF); fflush(f); f->_flag &= ~(_IOREAD|_IOWRT|_IONBF|_IOLBF); if(f->_base && !(f->_flag & _IOMYBUF)) { _buffree(f->_base); f->_base = (char *)NULL; } if(close(fileno(f)) == -1 || f->_flag & _IOERR) return EOF; else return 0; } ================================================ FILE: stdio/FFLUSH.C ================================================ /* * fflush for HI-TECH C Z80 CP/M stdio */ #include #include int fflush(register FILE *f) { if (f->_flag & _IOREAD && !(f->_flag & _IODIRN)) { /* File in read mode and not modified */ f->_cnt = 0; f->_ptr = f->_base; if(f->_flag & _IOERR) return EOF; else return 0; } if(!(f->_flag & _IOWRT) || !(f->_flag & _IODIRN) || f->_base == NULL || f->_cnt == 0) return 0; if(write(fileno(f), f->_base, f->_cnt) != f->_cnt) f->_flag |= _IOERR|_IOEOF; f->_cnt = 0; f->_ptr = f->_base; if(f->_flag & _IOERR) return EOF; else return 0; } ================================================ FILE: stdio/FGETC.C ================================================ /* * fgetc */ #include extern int _filbuf(FILE *); fgetc(f) register FILE * f; { int c; if(f->_flag & _IOEOF || !(f->_flag & _IOREAD) || f->_flag & _IODIRN && f->_cnt) { reteof: f->_flag |= _IOEOF; return EOF; } f->_flag &= ~_IODIRN; for(;;) { if(f->_cnt > 0) { f->_cnt--; c = (unsigned)*f->_ptr++; } else if(f->_flag & _IOSTRG) goto reteof; else c = _filbuf(f); if(!(f->_flag & _IOBINARY)) { if(c == 032) { if(f->_base) { f->_cnt++; f->_ptr--; } goto reteof; } else if(c == '\r') continue; } return c; } } ================================================ FILE: stdio/FILBUF.C ================================================ /* * _filbuf for HI-TECH C stdio */ #include #include _filbuf(f) register FILE * f; { register FILE * op; f->_cnt = 0; if(!(f->_flag & _IOREAD)) return(EOF); for(op = _iob ; op != _iob + _NFILE ; op++) if((op->_flag & (_IOWRT|_IOLBF)) == (_IOWRT|_IOLBF)) fflush(op); if(f->_size == 0) { uchar c; f->_cnt = 0; if(read(fileno(f), &c, 1) == 1) return(c); f->_flag |= _IOEOF; return(EOF); } if((f->_cnt = read(fileno(f), f->_base, f->_size)) <= 0) { if(f->_cnt == 0) f->_flag |= _IOEOF; else f->_flag |= _IOERR|_IOEOF; f->_ptr = f->_base; f->_cnt = 0; return(EOF); } f->_ptr = f->_base; f->_cnt--; return((unsigned)*f->_ptr++); } ================================================ FILE: stdio/FLSBUF.C ================================================ /* * _flsbuf for HI-TECH C stdio */ #include #include _flsbuf(char c, register FILE * f) { if(!(f->_flag & _IOWRT)) { f->_flag |= _IOERR|_IOEOF; f->_cnt = 0; return EOF; } if(f->_size == 0) { if(f->_flag & (_IONBF|_IOMYBUF) || isatty(fileno(f)) || (f->_base = _bufallo()) == (char *)-1) { f->_base = (char *)0; f->_size = 0; f->_flag |= _IONBF; f->_cnt = 0; if(write(fileno(f), &c, 1) == 1) return c & 0xFF; f->_flag |= _IOERR|_IOEOF; return EOF; } else f->_size = BUFSIZ; } else if(write(fileno(f), f->_base, f->_cnt) != f->_cnt) f->_flag |= _IOERR|_IOEOF; f->_cnt = 1; *f->_base = c; f->_ptr = f->_base+1; if(f->_flag & _IOERR) return(EOF); return c & 0xFF; } ================================================ FILE: stdio/FOPEN.C ================================================ /* * fopen.c - stdio fopen */ #include FILE * fopen(name, mode) char * name, * mode; { register FILE * f; for(f = _iob ; f != &_iob[_NFILE] ; f++) if(!(f->_flag & (_IOREAD|_IOWRT))) break; if(f == &_iob[_NFILE]) return((FILE *)NULL); return freopen(name, mode, f); } ================================================ FILE: stdio/FPRINTF.C ================================================ #include extern int _doprnt(); fprintf(file, f, a) FILE * file; char * f; int a; { return(_doprnt(file, f, &a)); } ================================================ FILE: stdio/FPUTC.C ================================================ /* * fputc for HI-TECH C stdio */ #include extern int _flsbuf(char, FILE *); fputc(c, f) register FILE * f; int c; { if(!(f->_flag & _IOWRT) || !(f->_flag & _IODIRN) && f->_cnt) return EOF; f->_flag |= _IODIRN; c &= 0xFF; if(f->_cnt == 0) f->_ptr = f->_base; if(f->_flag & _IOSEEKED && f->_flag & _IOAPPEND) fseek(f, 0L, SEEK_END); /* force write at EOF */ f->_flag &= ~_IOSEEKED; if(c == '\n' && !(f->_flag & _IOBINARY)) fputc('\r', f); if(f->_cnt != f->_size) { f->_cnt++; *f->_ptr++ = c; } else return _flsbuf(c, f); if(c == '\n' && f->_flag & _IOLBF && fflush(f) == EOF) c = EOF; return c; } ================================================ FILE: stdio/FREAD.C ================================================ #include #include /* * fread for HI-TECH C stdio */ fread(buf, size, nitems, stream) void * buf; register FILE * stream; unsigned size, nitems; { register char * ptr; register unsigned count, n; short c; if(stream->_flag & _IOEOF || !(stream->_flag & _IOREAD) || stream->_flag & _IODIRN && stream->_cnt) { stream->_flag |= _IOEOF; return 0; } stream->_flag &= ~_IODIRN; count = size * nitems; ptr = buf; while(count && !feof(stream)) { if(stream->_cnt && stream->_size && stream->_flag & _IOBINARY) { n = stream->_cnt; if(n > count) n = count; if(n) { memcpy(ptr, stream->_ptr, n); ptr += n; count -= n; stream->_ptr += n; stream->_cnt -= n; continue; } } if((c = getc(stream)) == EOF) break; else { --count; *ptr++ = c; } } return(nitems - (count+size-1)/size); } ================================================ FILE: stdio/FREOPEN.C ================================================ /* * freopen.c - HI-TECH C stdio freopen */ #include #include FILE * freopen(name, mode, iob) char * name, * mode; register FILE * iob; { uchar c, rw; fclose(iob); c = rw = 0; iob->_flag &= _IOMYBUF; switch(*mode) { case 'w': c++; case 'a': c++; case 'r': break; default: return NULL; } rw = 0; while(*++mode) if(*mode == 'b') iob->_flag |= _IOBINARY; else if(*mode == '+') { iob->_flag |= _IORW; rw = 2; } else break; switch(c) { case 0: iob->_file = open(name, rw); break; case 1: if((iob->_file = open(name, rw ? 2 : 1)) >= 0) break; /* else fall through */ case 2: iob->_file = creat(name, 0666); if(iob->_file >= 0 && rw) { close(iob->_file); iob->_file = open(name, rw); } break; } if(iob->_file < 0) return (FILE *)NULL; if(!(iob->_flag & (_IONBF|_IOMYBUF))) { iob->_base = _bufallo(); iob->_size = BUFSIZ; } if(iob->_base == (char *)-1) { iob->_base = (char *)0; close(iob->_file); iob->_flag = 0; return (FILE *)NULL; } iob->_ptr = iob->_base; iob->_cnt = 0; if(c) iob->_flag |= _IOWRT; else iob->_flag |= _IOREAD; if(c == 1) fseek(iob, 0L, 2); return iob; } ================================================ FILE: stdio/FSCANF.C ================================================ /* * Stdio fscanf */ #include extern int _doscan(); fscanf(file, fmt, args) FILE * file; char * fmt; int args; { return _doscan(file, fmt, &args); } ================================================ FILE: stdio/FSEEK.C ================================================ #include #include extern long lseek(), _fsize(), ftell(); static long _ssize(f) register FILE * f; { uchar utmp, ftmp; long x; register struct fcb * fc; char buf[SECSIZE]; fc = &_fcb[fileno(f)]; if(f->_flag & _IOBINARY) #if 0 return _fsize(fileno(f)); #else return fc->fsize; /* Supports exact file sizes */ #endif if((ftmp = f->_flag) & _IOWRT) fflush(f); utmp = fc->use; fc->use = U_READ; f->_flag |= _IOREAD; f->_flag &= ~_IOWRT; lseek(fileno(f), -(long)SECSIZE, SEEK_END);/* seek 1 sector before end */ f->_cnt = 0; fread(buf, sizeof(buf[0]), SECSIZE, f); x = ftell(f); fc->use = utmp; f->_flag = ftmp; if(f->_flag & _IOWRT) { f->_cnt = BUFSIZ; f->_ptr = f->_base; } return x; } fseek(f, offs, ptr) register FILE * f; long offs; int ptr; { long roffs; clreof(f); if(!f->_base) if(lseek(fileno(f), offs, ptr) == -1L) return -1; else return 0; switch(ptr) { case 0: /* relative to beginning of file */ break; case 1: /* relative to current postion */ offs += ftell(f); break; case 2: /* relative toend of file- CP/M makes us work hard */ offs += _ssize(f); break; default: return -1; } roffs = offs - ftell(f); if(f->_flag & _IOREAD && !(f->_flag & _IOWRT) && roffs >= 0 && roffs <= f->_cnt) { f->_cnt -= roffs; f->_ptr += roffs; return 0; } if(f->_flag & _IODIRN && f->_cnt) fflush(f); f->_cnt = 0; f->_ptr = f->_base; if(lseek(f->_file, offs, 0) < 0) return -1; return 0; } long ftell(f) register FILE * f; { long pos; pos = lseek(f->_file, 0L, SEEK_CUR); if(f->_cnt < 0) f->_cnt = 0; if(f->_base && f->_flag & _IODIRN) return pos + f->_cnt; return pos - f->_cnt; } ================================================ FILE: stdio/FWRITE.C ================================================ #include #include /* * fwrite */ fwrite(buf, size, nitems, stream) void * buf; register FILE * stream; unsigned size, nitems; { register unsigned count, n; register char * ptr; if(!(stream->_flag & _IOWRT) || !(stream->_flag & _IODIRN) && stream->_cnt) return 0; stream->_flag |= _IODIRN; if(stream->_cnt == 0) stream->_ptr = stream->_base; if(stream->_flag & _IOSEEKED && stream->_flag & _IOAPPEND) fseek(stream, 0L, SEEK_END); /* force write at EOF */ stream->_flag &= ~_IOSEEKED; count = size * nitems; ptr = buf; while(count) { if(stream->_base && stream->_flag & _IOBINARY) { n = stream->_size - stream->_cnt; if(n > count) n = count; if(n) { memcpy(stream->_ptr, ptr, n); ptr += n; count -= n; stream->_ptr += n; stream->_cnt += n; if(stream->_cnt == stream->_size) fflush(stream); continue; } } if(putc(*ptr++, stream) == EOF) break; else --count; } return(nitems - (count+size-1)/size); } ================================================ FILE: stdio/GETARGS.C ================================================ /*--------------------------------------------------------------------------- * * GETARGS.C Modified version from Tesseract vol 91 * * _getargs(str, name) - process string into argument buffer. * * If str is null, read lines from standard input instead, using name as a * prompt. * * Continuation lines are recognized by a \ as the last character on the * line. * * The redirections recognized are: * * > >> < * * Redirections of the form >& and >>& are not yet supported. * Note that the >> redirections depend on fseek working correctly * on text files, when seeking relative to the end of the file. * * Wildcards (? and *) are expanded in the usual way. * * The quotes " and ' may be used to enclose arguments which contain * white space the wild characters and > or <. * * The argument buffer is sbrk-ed and a pointer to it is returned. * The count of arguments is left in the global _argc_. The count * may also be found by counting the arguments; the last one is a null * pointer. * * The zero'th argument is set to the name parameter. *---------------------------------------------------------------------------- * Jon Saxton, 2014-04-22 * * 1. The original implementation terminated the program if a wildcard * name did not match any file on disk. That no longer happens. The * program continues processing and expanding arguments. * 2. User numbers are now included in the expanded arguments if and when * appropriate. *---------------------------------------------------------------------------- * Usage: * #include / * for _getargs() declaration * / * extern int _argc_; * char **args; * / * Expand arguments and set program name.* / * args = _getargs((char *)0x81, "myprog"); * / * Now use _argc_ and args[] in lieu of argc and argv[] * / *--------------------------------------------------------------------------*/ #include #include #include #include #include #include #define MAXARGS 200 /* max number of arguments */ #define MAXLEN 100 /* max length of an argument */ #define QUOTE 0x80 /* quoted bit in args */ #define isterminator(c) ((c) == 0) #define look() (*str) extern int _argc_; extern int isatty(int); static char *name, *str, *bp; static char interactive; static char redone[3]; static void sputs(char *), error(char *, ...); static void redirect(char *, char *, char *, FILE *); static char *alloc(short); static char nxtch(); static char iswild(char *), isspecial(char), isseparator(char); char **_getargs(char *_str, char *_name) { char **argv; struct fcb fc, *fx; register char *ap; char *cp; short argc; char c, user, quote; unsigned short i, j; char *argbuf[MAXARGS]; char dmabuf[4][32]; char buf[MAXLEN]; bp = (char *)0; quote = redone[0] = redone[1] = redone[2] = 0; name = _name; str = _str; if (interactive = str == (char *)0) str = "\\"; argbuf[0] = name; argc = 1; /* first step - process arguments and do globbing */ while (look()) { if (argc == MAXARGS) error("too many arguments", 0); while (isseparator(c = nxtch())) continue; if (isterminator(c)) break; ap = buf; if (isspecial(c)) { *ap++ = c; if (c == '>' && look() == '>') *ap++ = nxtch(); } else { while (!isterminator(c) && (quote || !isspecial(c) && !isseparator(c))) { if (ap == &buf[MAXLEN]) error("argument too long", 0); if (c == quote) /* end of quoted string */ quote = 0; else if (!quote && (c == '\'' || c == '"')) quote = c; /* start of quoted string */ else { if (quote) c |= QUOTE; *ap++ = c; } if (!quote && isspecial(look())) break; c = nxtch(); } } *ap = 0; if (iswild(buf)) { ap = buf; setfcb(&fc, buf); bdos(CPMSDMA, dmabuf); user = (c = getuid()) != fc.uid; setuid(fc.uid); if ((j = bdos(CPMFFST, &fc) & 0xFF) != 255) do { ap = buf; if (c != fc.uid) { sprintf(ap, "%u", fc.uid); ap += strlen(ap); } if (fc.dr) *ap++ = fc.dr + 'A' - 1; if (fc.dr || user) *ap++ = ':'; fx = (struct fcb *)dmabuf[j]; cp = fx->name; while (*cp != ' ' && cp < &fx->name[8]) *ap++ = *cp++ & ~0x80; *ap++ = '.'; cp = fx->ft; while (*cp != ' ' && cp < &fx->ft[3]) *ap++ = *cp++ & ~0x80; *ap++ = 0; strcpy(argbuf[argc++] = alloc(ap-buf+1), buf); } while ((j = bdos(CPMFNXT) & 0xFF) != 255); setuid(c); } else { argbuf[argc++] = ap = alloc(ap-buf+1); cp = buf; do *ap++ = *cp & ~QUOTE; while(*cp++); } } /* now do redirection */ for (i = j = 0 ; j < argc ; j++) if (isspecial(c = argbuf[j][0])) { if (j == argc-1) error("no name after ", argbuf[j], 0); if (c == '<') redirect("input", argbuf[j+1], "r", stdin); else { ap = argbuf[j][1] == '>' ? "a" : "w"; redirect("output", argbuf[j+1], ap, stdout); } ++j; } else argbuf[i++] = argbuf[j]; _argc_ = i; argbuf[i++] = (char *)0; argv = (char **)alloc(i * sizeof *argv); bmove(argbuf, argv, i * sizeof *argv); return argv; } static char nxtch() { if (interactive && *str == '\\' && str[1] == 0) { if (!bp) bp = alloc(256); if (isatty(fileno(stdin))) { signal_t prev=signal(SIGINT,SIG_IGN); fprintf(stderr, "%s> ", name); signal(SIGINT,prev); } gets(bp); str = bp; } if (*str) return *str++; return 0; } static void error(char *s, ...) { register char **sp; sp = &s; while(*sp) sputs(*sp++); sputs("\n"); exit(-1); } static void sputs(char *s) { while (*s) { if (*s == '\n') bdos(CPMWCON, '\r'); bdos(CPMWCON, *s++); } } static char *alloc(short n) { char *bp; if ((bp = sbrk(n)) == (char *)-1) error("no room for arguments", 0); return bp; } static void redirect(char *str_name, char *file_name, char *mode, FILE *stream) { if (redone[stream-_iob]++) error("Ambiguous ", str_name, " redirection", 0); if (freopen(file_name, mode, stream) != stream) error("Can't open ", file_name, " for ", str_name, 0); } static char iswild(char *buf) { return strchr(buf, '*') || strchr(buf, '?'); } static char isspecial(char c) { return c == '<' || c == '>'; } static char isseparator(char c) { return c == ' ' || c == '\t' || c == '\n'; } ================================================ FILE: stdio/GETENV.C ================================================ #include #include #if CPM #include #endif #define ENVFILE "0:A:ENVIRON" /* Must be of the form 0:X: */ char ** environ; extern char * sbrk(); static char envname[]=ENVFILE; static char loadenv(char *name, char **avec, char *abuf, short *i, short avsize, short absize) { FILE *fp; register char *cp; if((fp = fopen(name, "r")) == NULL) return(0); while((*i) < avsize && fgets(abuf, absize, fp)) { cp = sbrk(strlen(abuf)+1); strcpy(cp, abuf); cp[strlen(cp)-1] = 0; avec[(*i)++] = cp; } fclose(fp); return(1); } char * getenv(char * s) { register char ** xp; short i; static char setup; if(!setup) { short av,ab; unsigned short scbpb; char drive; char * avec[40]; char abuf[128]; i = 0; #if CPM /* CP/M environment simulation? */ av=sizeof avec / sizeof avec[0]; ab=sizeof abuf; if((bdoshl(CPMVERS) & 0x0FF0)==0x0030) /* CP/M 3 */ { for (scbpb=0x4C; scbpb<0x50; scbpb++) { drive=bdos(CPMSCB,&scbpb); if (drive & 0x20) break; /* End of chain */ else { /* if default, get current drive 0..15 */ if (!drive) drive=bdos(CPMIDRV)+1; /**AGN fix*/ envname[2]=drive+'@'; if (loadenv(envname+2,avec,abuf,&i,av,ab)) break; if (loadenv(envname,avec,abuf,&i,av,ab)) break; } } if (i==0) loadenv(envname+4,avec,abuf,&i,av,ab); } else /* Not CP/M 3. Search current drive & user 0 */ { envname[2]='0'; if (!loadenv(envname+2,avec,abuf,&i,av,ab)) loadenv(envname+4,avec,abuf,&i,av,ab); } #else loadenv(envname+4,avec,abuf,&i,av,ab); #endif avec[i] = 0; xp = (char **)sbrk(i * sizeof avec[0]); memcpy(xp, avec, i * sizeof avec[0]); environ = xp; setup = 1; } i = strlen(s); for(xp = environ ; *xp ; xp++) if(strncmp(*xp, s, i) == 0 && (*xp)[i] == '=') return *xp + i+1; return (char *)0; } ================================================ FILE: stdio/GETS.C ================================================ /* * gets and fgets for HI-TECH C stdio */ #include #include char *fgets(char *s, int n, register FILE *f) { char *s1 = s; int c; while (--n && (c = fgetc(f)) != EOF && (*s++ = c) != '\n') /* VOID */; *s = 0; if (s == s1) return (char *)NULL; return s1; } char *gets(char *s) { if ((s = fgets(s, -1, stdin)) == (char *)NULL) return (char *)NULL; s[strlen(s)-1] = 0; return s; } ================================================ FILE: stdio/GETW.C ================================================ #include /* * Stdio getw() */ getw(stream) register FILE * stream; { short hi, lo; if((lo = getc(stream)) == EOF || (hi = getc(stream)) == EOF) return EOF; return (hi << 8) | (lo & 0xFF); } ================================================ FILE: stdio/LISTMODC.SUB ================================================ libr s libc12.lib > modules.prn ================================================ FILE: stdio/M280LIBC.LOG ================================================ 10E>; Use librarian to place all modules in m:lib280c.lib 10E>; NB: the ordering is important for resolving dependencies at link time 10E>m: 10M>era m:lib280c.lib No File 10M>libr A:LIBR COM (User 0) libr> r m:lib280c.lib \ libr> libcver.obj \ libr> start1.obj \ libr> getargs.obj \ libr> assert.obj \ libr> printf.obj \ libr> fprintf.obj \ libr> sprintf.obj \ libr> doprnt.obj \ libr> getenv.obj \ libr> gets.obj \ libr> puts.obj \ libr> fwrite.obj \ libr> getw.obj \ libr> putw.obj \ libr> close.obj \ libr> putchar.obj \ libr> perror.obj \ libr> fputc.obj \ libr> flsbuf.obj \ libr> fopen.obj \ libr> freopen.obj \ libr> fseek.obj \ libr> fread.obj \ libr> rewind.obj \ libr> remove.obj \ libr> setbuf.obj \ libr> fscanf.obj \ libr> ctime.obj \ libr> cgets.obj \ libr> cputs.obj \ libr> sscanf.obj \ libr> scanf.obj \ libr> doscan.obj \ libr> ungetc.obj \ libr> fgetc.obj \ libr> filbuf.obj \ libr> stdclean.obj \ libr> fclose.obj \ libr> fflush.obj \ libr> buf.obj \ libr> exit.obj \ libr> open.obj \ libr> read.obj \ libr> write.obj \ libr> seek.obj \ libr> stat.obj \ libr> chmod.obj \ libr> fcbname.obj \ libr> rename.obj \ libr> creat.obj \ libr> time.obj \ libr> convtime.obj \ libr> timezone.obj \ libr> mktime.obj \ libr> isatty.obj \ libr> cleanup.obj \ libr> close.obj \ libr> unlink.obj \ libr> dup.obj \ libr> execl.obj \ libr> getfcb.obj \ libr> srand1.obj \ libr> abort.obj \ libr> getch.obj \ libr> signal.obj \ libr> getuid.obj \ libr> bdos.obj \ libr> bios.obj \ libr> _exit.obj \ libr> fakeclean.obj \ libr> fakecpcln.obj \ libr> sys_err.obj \ libr> memcpy.obj \ libr> memcmp.obj \ libr> memset.obj \ libr> strftime.obj \ libr> asmod.obj \ libr> abs.obj \ libr> asallsh.obj \ libr> allsh.obj \ libr> asalrsh.obj \ libr> asar.obj \ libr> asdiv.obj \ libr> asladd.obj \ libr> asland.obj \ libr> asll.obj \ libr> asllrsh.obj \ libr> aslmul.obj \ libr> aslor.obj \ libr> aslsub.obj \ libr> aslxor.obj \ libr> atoi.obj \ libr> atol.obj \ libr> blkclr.obj \ libr> blkcpy.obj \ libr> calloc.obj \ libr> asmul.obj \ libr> bitfield.obj \ libr> ctype_.obj \ libr> getsp.obj \ libr> index.obj \ libr> strchr.obj \ libr> qsort.obj \ libr> malloc.obj \ libr> max.obj \ libr> idiv.obj \ libr> pnum.obj \ libr> ldiv.obj \ libr> swap.obj \ libr> aslr.obj \ libr> bmove.obj \ libr> imul.obj \ libr> rand.obj \ libr> alrsh.obj \ libr> lmul.obj \ libr> rindex.obj \ libr> strrchr.obj \ libr> sbrk.obj \ libr> shar.obj \ libr> shll.obj \ libr> shlr.obj \ libr> strcat.obj \ libr> strcmp.obj \ libr> strcpy.obj \ libr> strlen.obj \ libr> strncat.obj \ libr> strncmp.obj \ libr> strncpy.obj \ libr> strstr.obj \ libr> strnstr.obj \ libr> strdup.obj \ libr> stricmp.obj \ libr> stristr.obj \ libr> strnicmp.obj \ libr> strnistr.obj \ libr> strtok.obj \ libr> inout.obj \ libr> iregset.obj \ libr> isalpha.obj \ libr> isdigit.obj \ libr> islower.obj \ libr> isspace.obj \ libr> isupper.obj \ libr> ladd.obj \ libr> land.obj \ libr> linc.obj \ libr> llrsh.obj \ libr> longjmp.obj \ libr> lor.obj \ libr> brelop.obj \ libr> wrelop.obj \ libr> lrelop.obj \ libr> frelop.obj \ libr> lsub.obj \ libr> lxor.obj \ libr> csv.obj \ libr> rcsv.obj \ libr> tolower.obj \ libr> toupper.obj \ libr> xtoi.obj 10M>libr s m:lib280c.lib A:LIBR COM (User 0) libcver.obj D __libcver start1.obj D __argc_ U __getargs D startup getargs.obj U __argc_ D __getargs U __iob U _bdos U _bmove U _exit U _fprintf U _freopen U _gets U _getuid U _isatty U _sbrk U _setfcb U _setuid U _signal U _sprintf U _strchr U _strcpy U _strlen U adiv U cret U csv U indir U ncsv U shal U wrelop assert.obj D __fassert U __iob U _abort U _fprintf U cret U csv U indir U ncsv printf.obj U __doprnt U __iob D _printf U cret U csv U indir U ncsv fprintf.obj U __doprnt D _fprintf U cret U csv U indir U ncsv sprintf.obj U __doprnt D _sprintf U cret U csv U indir U ncsv doprnt.obj U __ctype_ D __doprnt U __pnum U _atoi U _fputc U _strlen U brelop U cret U csv U indir U ncsv U wrelop getenv.obj U _bdos D _environ U _fclose U _fgets U _fopen D _getenv U _memcpy U _sbrk U _strcpy U _strlen U _strncmp U cret U csv U indir U ncsv U wrelop gets.obj U __iob U _fgetc D _fgets D _gets U _strlen U cret U csv U indir U ncsv puts.obj U __iob U _fputc D _fputs D _puts U cret U csv U indir U ncsv fwrite.obj U _fflush U _fputc U _fseek D _fwrite U _memcpy U cret U indir U ldiv U lmul U ncsv U wrelop getw.obj U _fgetc D _getw U cret U csv U indir U ncsv U shal putw.obj U _fputc D _putw U cret U csv U indir U ncsv U shar close.obj U __exact U __fcb U _bdos D _close U _getuid U _setuid U amul U brelop U cret U csv U indir U ncsv putchar.obj U __iob U _fgetc U _fputc D _getchar D _putchar U cret U csv U indir U ncsv perror.obj U __iob U _errno U _fputc D _perror U _sys_err U _sys_ner U cret U csv U indir U ncsv U wrelop fputc.obj U __flsbuf U _fflush D _fputc U _fseek U cret U csv U indir U ncsv flsbuf.obj U __bufallo D __flsbuf U _isatty U _write U cret U csv U indir U ncsv fopen.obj U __iob D _fopen U _freopen U cret U csv U indir U ncsv freopen.obj U __bufallo U _close U _creat U _fclose D _freopen U _fseek U _open U cret U csv U indir U ncsv fseek.obj U __fcb U _fflush U _fread D _fseek D _ftell U _lseek U aladd U alsub U amul U arelop U asaladd U cret U csv U indir U ncsv fread.obj U _fgetc D _fread U _memcpy U cret U indir U ldiv U lmul U ncsv U wrelop rewind.obj U _fseek D _rewind U cret U csv U indir U ncsv remove.obj D _remove U _unlink U cret U csv U indir U ncsv setbuf.obj U __bufallo U __buffree D _setbuf D _setvbuf U cret U csv U indir U ncsv fscanf.obj U __doscan D _fscanf U cret U csv U indir U ncsv ctime.obj D _asctime D _ctime D _gmtime D _localtime D _monlen U _time_zone U adiv U aldiv U almod U almul U alsub U amod U amul U asaldiv U asldiv U cret U csv U indir U lmod U ncsv U wrelop cgets.obj D _cgets U _getche U cret U csv U indir U ncsv cputs.obj D _cputs U _putch U cret U csv U indir U ncsv sscanf.obj U __doscan D _sscanf U _strlen U cret U indir U ncsv scanf.obj U __doscan U __iob D _scanf U cret U csv U indir U ncsv doscan.obj U __ctype_ D __doscan U _atoi U _fgetc U _tolower U _ungetc U cret U csv U indir U lladd U llmul U ncsv U wrelop ungetc.obj D _ungetc U cret U csv U indir U ncsv fgetc.obj U __filbuf D _fgetc U cret U csv U indir U ncsv U wrelop filbuf.obj D __filbuf U __iob U _fflush U _read U cret U csv U indir U ncsv U wrelop stdclean.obj D __cleanup D __iob D __sibuf U _fclose U cret U csv U indir U ncsv fclose.obj U __buffree U _close D _fclose U _fflush U cret U csv U indir U ncsv fflush.obj D _fflush U _write U cret U csv U indir U ncsv buf.obj D __bufallo D __buffree U _sbrk U cret U csv U indir U ncsv exit.obj U __cleanup U __exit D _exit U cret U csv U indir U ncsv open.obj U __exact U __fcb D __fsize U _bdos U _errno U _getfcb U _getuid D _open U _putfcb U _setfcb U _setuid U adiv U aland U aldiv U amul U asalsub U brelop U cret U csv U indir U ncsv U shll U wrelop read.obj U __fcb U __piped U __putrno U __sigchk U _bdos U _bmove U _getuid D _read U _setuid U aldiv U alsub U amul U asaladd U brelop U cret U indir U lladd U lrelop U ncsv U wrelop write.obj U __fcb U __piped U __putrno U __sigchk U _bdos U _bmove U _getuid U _setuid D _write U aldiv U amul U arelop U asaladd U brelop U cret U indir U ncsv U wrelop seek.obj U __fcb D _lseek U aladd U amul U arelop U brelop U cret U csv U indir U ncsv stat.obj U __exact U _bdos U _convtime U _getuid U _setfcb U _setuid D _stat U asallsh U asalsub U cret U indir U lladd U lllsh U ncsv U shal U wrelop chmod.obj U _bdos D _chmod U _getuid U _setfcb U _setuid U cret U indir U ncsv fcbname.obj U __fcb U _bdos D _fcbname U _sprintf U _strlen U amul U cret U csv U indir U ncsv U wrelop rename.obj U _bdos D _rename U _setfcb U _unlink U cret U indir U ncsv creat.obj U __fcb U _bdos D _creat U _errno U _getfcb U _getuid U _setfcb U _setuid U _unlink U adiv U cret U csv U indir U ncsv U wrelop time.obj U _bdos U _convtime D _time U cret U indir U ncsv convtime.obj D _convtime D _frmbcd U asaladd U asalmul U cret U csv U indir U lmul U ncsv timezone.obj D _time_zone mktime.obj D _mktime U _time_zone U almul U amod U asaladd U cret U indir U ncsv U wrelop isatty.obj U __fcb D _isatty U amul U cret U csv U indir U ncsv cleanup.obj D __cpm_clean D __fcb D __initrsx D __putrno U _close U alrsh U brelop U cret U csv U indir U ncsv close.obj U __exact U __fcb U _bdos D _close U _getuid U _setuid U amul U brelop U cret U csv U indir U ncsv unlink.obj U _bdos U _errno U _getuid U _setfcb U _setuid D _unlink U cret U indir U ncsv dup.obj U __fcb D _dup U _getfcb U adiv U amul U cret U csv U indir U ncsv execl.obj U _bmove D _execl D _execv U _setfcb U _strcat U _strlen U _strncpy U indir getfcb.obj U __ctype_ U __fcb U _atoi D _getfcb U _getuid D _putfcb D _setfcb U _toupper U brelop U cret U csv U indir U ncsv U wrelop srand1.obj U _kbhit U _putchar U _srand D _srand1 U cret U csv U indir U ncsv abort.obj D _abort U _bdos U _exit U cret U indir U ncsv getch.obj U _bdos D _getch D _getche D _kbhit D _putch D _ungetch U cret U csv U indir U ncsv signal.obj D __sigchk U _bdos U _exit D _signal U cret U csv U indir U ncsv getuid.obj D _getuid D _setuid U cret U csv bdos.obj D _bdos U _errno U cret U csv bios.obj D _bios U cret U csv D exit22 _exit.obj U __cpm_clean D __exit fakeclean.obj D __cleanup U cret U indir U ncsv fakecpcln.obj D __cpm_clean sys_err.obj D _errno D _sys_err D _sys_ner memcpy.obj D _memcpy U cret U csv U indir U ncsv memcmp.obj D _memcmp U cret U csv U indir U ncsv memset.obj D _memset U cret U csv U indir U ncsv strftime.obj D _strftime U adiv U amod U asamod U cret U indir U ncsv U wrelop asmod.obj U amod D asamod D aslmod U lmod abs.obj D _abs asallsh.obj U allsh D asallsh D aslllsh U iregstore allsh.obj D allsh D lllsh asalrsh.obj U alrsh D asalrsh U iregstore asar.obj D asar U shar asdiv.obj U adiv D asadiv D asldiv U ldiv asladd.obj U aladd D asaladd D aslladd U iregset U iregstore asland.obj U aland D asaland D aslland U iregset U iregstore asll.obj D asal D asll U shal asllrsh.obj D asllrsh U iregstore U llrsh aslmul.obj U almul D asalmul D asllmul U iregset U iregstore aslor.obj U alor D asalor D asllor U iregset U iregstore aslsub.obj U alsub D asalsub D asllsub U iregset U iregstore aslxor.obj U alxor D asalxor D asllxor U iregset U iregstore atoi.obj D _atoi atol.obj U __ctype_ D _atol U aladd U almul U cret U indir U ncsv blkclr.obj D _blkclr blkcpy.obj D _blkcpy U cret U csv U indir U ncsv calloc.obj U _bmove D _calloc D _cfree U _free U _malloc U asamul U cret U csv U indir U ncsv asmul.obj U amul D asamul D aslmul bitfield.obj D bfext D bfins ctype_.obj D __ctype_ getsp.obj D __getsp index.obj D _index U cret U rcsv strchr.obj D _strchr U cret U rcsv qsort.obj U __swap U _bmove U _free U _malloc D _qsort U adiv U cret U indir U lmul U ncsv U wrelop malloc.obj U _bmove D _free D _malloc D _realloc U _sbrk U adiv U amul U cret U csv U indir U ldiv U lmul U ncsv U wrelop max.obj D _max idiv.obj D adiv D amod D ldiv D lmod pnum.obj D __pnum U aslldiv U brelop U cret U indir U llmod U ncsv U wrelop ldiv.obj D aldiv D almod D asaldiv D asalmod D aslldiv D asllmod D lldiv D llmod swap.obj D __swap U cret U rcsv aslr.obj D aslr U shlr bmove.obj D _bmove D _movmem imul.obj D amul D lmul rand.obj D _rand D _srand U almul U alrsh U cret U csv U indir U ncsv alrsh.obj D alrsh lmul.obj D almul D llmul rindex.obj D _rindex U cret U rcsv strrchr.obj D _strrchr U cret U rcsv sbrk.obj U __Hbss D _brk D _checksp D _sbrk shar.obj D shar shll.obj D shal D shll shlr.obj D shlr strcat.obj D _strcat strcmp.obj D _strcmp strcpy.obj D _strcpy strlen.obj D _strlen strncat.obj D _strncat U cret U rcsv strncmp.obj D _strncmp U cret U rcsv strncpy.obj D _strncpy U cret U rcsv strstr.obj D _strstr U cret U csv U indir U ncsv strnstr.obj D _strnstr U cret U indir U ncsv strdup.obj U _malloc U _strcpy D _strdup U _strlen U cret U csv U indir U ncsv stricmp.obj D _strcasecmp stristr.obj D _strcasestr U _toupper U cret U csv U indir U ncsv strnicmp.obj D _strncasecmp U cret U rcsv strnistr.obj D _strncasestr U _toupper U cret U indir U ncsv strtok.obj D _strtok U cret U csv U indir U ncsv U wrelop inout.obj D _in D _inp D _out D _outp iregset.obj D iregset D iregstore isalpha.obj D _isalpha isdigit.obj D _isdig D _isdigit islower.obj D _islower isspace.obj D _isspace isupper.obj D _isupper ladd.obj D aladd D lladd land.obj D aland D lland linc.obj D ladec D lainc D lldec D llinc llrsh.obj D llrsh longjmp.obj D _longjmp D _setjmp lor.obj D alor D llor brelop.obj D brelop wrelop.obj D wrelop lrelop.obj D arelop D lrelop frelop.obj D frelop lsub.obj D alsub D llsub lxor.obj D alxor D llxor csv.obj D cret D csv D indir D ncsv rcsv.obj D rcsv tolower.obj D _tolower toupper.obj D _toupper xtoi.obj D _ishex D _xtoi 10M>e: 10E>pip e:=m:lib280c.lib A:PIP COM (User 0) 10E>; Library m:lib280c.lib created 10E>; Remember to copy it to current directory and A0: 10E>; 10E>; Now save the Z280 object files in E:LIB280C.LBR 10E>dir m:*.obj[fu,length=65535] A:DIR COM (User 0) Scanning Directory... Sorting Directory... Directory For Drive M: User 10 Name Bytes Recs Attributes Prot Update Create ------------ ------ ------ ------------ ------ -------------- -------------- ABORT OBJ 4k 2 Dir RW None 05/09/25 12:33 05/09/25 12:33 ABS OBJ 4k 1 Dir RW None 05/09/25 12:33 05/09/25 12:33 ALLSH OBJ 4k 1 Dir RW None 05/09/25 12:33 05/09/25 12:33 ALRSH OBJ 4k 1 Dir RW None 05/09/25 12:33 05/09/25 12:33 ASALLSH OBJ 4k 2 Dir RW None 05/09/25 12:33 05/09/25 12:33 ASALRSH OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASAR OBJ 4k 1 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASDIV OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLADD OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLAND OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLL OBJ 4k 1 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLLRSH OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLMUL OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLOR OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLR OBJ 4k 1 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLSUB OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASLXOR OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASMOD OBJ 4k 2 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASMUL OBJ 4k 1 Dir RW None 05/09/25 12:34 05/09/25 12:34 ASSERT OBJ 4k 3 Dir RW None 05/09/25 12:34 05/09/25 12:34 ATOI OBJ 4k 2 Dir RW None 05/09/25 12:35 05/09/25 12:35 ATOL OBJ 4k 4 Dir RW None 05/09/25 12:35 05/09/25 12:35 BDOS OBJ 4k 4 Dir RW None 05/09/25 12:35 05/09/25 12:35 BIOS OBJ 4k 5 Dir RW None 05/09/25 12:35 05/09/25 12:35 BITFIELD OBJ 4k 2 Dir RW None 05/09/25 12:35 05/09/25 12:35 BLKCLR OBJ 4k 1 Dir RW None 05/09/25 12:35 05/09/25 12:35 BLKCPY OBJ 4k 2 Dir RW None 05/09/25 12:35 05/09/25 12:35 BMOVE OBJ 4k 1 Dir RW None 05/09/25 12:35 05/09/25 12:35 BRELOP OBJ 4k 1 Dir RW None 05/09/25 12:35 05/09/25 12:35 BUF OBJ 4k 3 Dir RW None 05/09/25 12:36 05/09/25 12:36 CALLOC OBJ 4k 4 Dir RW None 05/09/25 12:36 05/09/25 12:36 CGETS OBJ 4k 3 Dir RW None 05/09/25 12:36 05/09/25 12:36 CHMOD OBJ 4k 4 Dir RW None 05/09/25 12:36 05/09/25 12:36 CLEANUP OBJ 4k 7 Dir RW None 05/09/25 12:36 05/09/25 12:36 CLOSE OBJ 4k 5 Dir RW None 05/09/25 12:37 05/09/25 12:37 CONVTIME OBJ 4k 5 Dir RW None 05/09/25 12:37 05/09/25 12:37 CPUTS OBJ 4k 2 Dir RW None 05/09/25 12:37 05/09/25 12:37 CREAT OBJ 4k 6 Dir RW None 05/09/25 12:37 05/09/25 12:37 CSV OBJ 4k 2 Dir RW None 05/09/25 12:37 05/09/25 12:37 CTIME OBJ 4k 17 Dir RW None 05/09/25 12:38 05/09/25 12:38 CTYPE OBJ 4k 2 Dir RW None 05/09/25 12:38 05/09/25 12:38 CTYPE_ OBJ 4k 2 Dir RW None 05/09/25 12:38 05/09/25 12:38 DOPRNT OBJ 4k 17 Dir RW None 05/09/25 12:39 05/09/25 12:39 DOSCAN OBJ 4k 23 Dir RW None 05/09/25 12:39 05/09/25 12:39 DUP OBJ 4k 3 Dir RW None 05/09/25 12:39 05/09/25 12:39 EXEC OBJ 4k 22 Dir RW None 05/09/25 12:40 05/09/25 12:40 EXECL OBJ 4k 9 Dir RW None 05/09/25 12:40 05/09/25 12:40 EXIT OBJ 4k 2 Dir RW None 05/09/25 12:40 05/09/25 12:40 FAKECLEA OBJ 4k 1 Dir RW None 05/09/25 12:40 05/09/25 12:40 FAKECPCL OBJ 4k 1 Dir RW None 05/09/25 12:40 05/09/25 12:40 FCBNAME OBJ 4k 12 Dir RW None 05/09/25 12:40 05/09/25 12:40 FCLOSE OBJ 4k 3 Dir RW None 05/09/25 12:41 05/09/25 12:41 FFLUSH OBJ 4k 4 Dir RW None 05/09/25 12:41 05/09/25 12:41 FGETC OBJ 4k 4 Dir RW None 05/09/25 12:41 05/09/25 12:41 FILBUF OBJ 4k 6 Dir RW None 05/09/25 12:41 05/09/25 12:41 FLSBUF OBJ 4k 5 Dir RW None 05/09/25 12:42 05/09/25 12:42 FOPEN OBJ 4k 3 Dir RW None 05/09/25 12:42 05/09/25 12:42 FPRINTF OBJ 4k 2 Dir RW None 05/09/25 12:42 05/09/25 12:42 FPUTC OBJ 4k 5 Dir RW None 05/09/25 12:42 05/09/25 12:42 FREAD OBJ 4k 6 Dir RW None 05/09/25 12:42 05/09/25 12:42 FRELOP OBJ 4k 2 Dir RW None 05/09/25 12:43 05/09/25 12:43 FREOPEN OBJ 4k 9 Dir RW None 05/09/25 12:43 05/09/25 12:43 FSCANF OBJ 4k 2 Dir RW None 05/09/25 12:43 05/09/25 12:43 FSEEK OBJ 4k 11 Dir RW None 05/09/25 12:43 05/09/25 12:43 FWRITE OBJ 4k 7 Dir RW None 05/09/25 12:44 05/09/25 12:44 GETARGS OBJ 8k 37 Dir RW None 05/09/25 12:45 05/09/25 12:45 GETCH OBJ 4k 5 Dir RW None 05/09/25 12:45 05/09/25 12:45 GETENV OBJ 4k 14 Dir RW None 05/09/25 12:46 05/09/25 12:46 GETFCB OBJ 4k 16 Dir RW None 05/09/25 12:46 05/09/25 12:46 GETS OBJ 4k 4 Dir RW None 05/09/25 12:46 05/09/25 12:46 GETSP OBJ 4k 1 Dir RW None 05/09/25 12:46 05/09/25 12:46 GETUID OBJ 4k 2 Dir RW None 05/09/25 12:47 05/09/25 12:47 GETW OBJ 4k 3 Dir RW None 05/09/25 12:47 05/09/25 12:47 IDIV OBJ 4k 4 Dir RW None 05/09/25 12:47 05/09/25 12:47 IMUL OBJ 4k 2 Dir RW None 05/09/25 12:47 05/09/25 12:47 INDEX OBJ 4k 2 Dir RW None 05/09/25 12:47 05/09/25 12:47 INOUT OBJ 4k 2 Dir RW None 05/09/25 12:47 05/09/25 12:47 IREGSET OBJ 4k 1 Dir RW None 05/09/25 12:47 05/09/25 12:47 ISALPHA OBJ 4k 2 Dir RW None 05/09/25 12:47 05/09/25 12:47 ISATTY OBJ 4k 3 Dir RW None 05/09/25 12:47 05/09/25 12:47 ISDIGIT OBJ 4k 1 Dir RW None 05/09/25 12:47 05/09/25 12:47 ISLOWER OBJ 4k 1 Dir RW None 05/09/25 12:47 05/09/25 12:47 ISSPACE OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 ISUPPER OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 LADD OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 LAND OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 LDIV OBJ 4k 7 Dir RW None 05/09/25 12:48 05/09/25 12:48 LIBCVER OBJ 4k 1 Dir RW None 05/09/25 13:00 05/09/25 13:00 LINC OBJ 4k 2 Dir RW None 05/09/25 12:48 05/09/25 12:48 LLRSH OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 LMUL OBJ 4k 2 Dir RW None 05/09/25 12:48 05/09/25 12:48 LONGJMP OBJ 4k 2 Dir RW None 05/09/25 12:48 05/09/25 12:48 LOR OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 LRELOP OBJ 4k 2 Dir RW None 05/09/25 12:48 05/09/25 12:48 LSUB OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 LXOR OBJ 4k 1 Dir RW None 05/09/25 12:48 05/09/25 12:48 MALLOC OBJ 4k 14 Dir RW None 05/09/25 12:49 05/09/25 12:49 MAX OBJ 4k 1 Dir RW None 05/09/25 12:49 05/09/25 12:49 MEMCMP OBJ 4k 2 Dir RW None 05/09/25 12:49 05/09/25 12:49 MEMCPY OBJ 4k 2 Dir RW None 05/09/25 12:49 05/09/25 12:49 MEMSET OBJ 4k 2 Dir RW None 05/09/25 12:49 05/09/25 12:49 MKTIME OBJ 4k 10 Dir RW None 05/09/25 12:50 05/09/25 12:50 OPEN OBJ 4k 11 Dir RW None 05/09/25 12:50 05/09/25 12:50 PERROR OBJ 4k 5 Dir RW None 05/09/25 12:50 05/09/25 12:50 PNUM OBJ 4k 7 Dir RW None 05/09/25 12:50 05/09/25 12:50 PRINTF OBJ 4k 2 Dir RW None 05/09/25 12:51 05/09/25 12:51 PUTCHAR OBJ 4k 3 Dir RW None 05/09/25 12:51 05/09/25 12:51 PUTS OBJ 4k 3 Dir RW None 05/09/25 12:51 05/09/25 12:51 PUTW OBJ 4k 3 Dir RW None 05/09/25 12:51 05/09/25 12:51 QSORT OBJ 4k 10 Dir RW None 05/09/25 12:52 05/09/25 12:52 RAND OBJ 4k 3 Dir RW None 05/09/25 12:52 05/09/25 12:52 RCSV OBJ 4k 1 Dir RW None 05/09/25 12:52 05/09/25 12:52 READ OBJ 4k 15 Dir RW None 05/09/25 12:52 05/09/25 12:52 REMOVE OBJ 4k 2 Dir RW None 05/09/25 12:52 05/09/25 12:52 RENAME OBJ 4k 3 Dir RW None 05/09/25 12:53 05/09/25 12:53 REWIND OBJ 4k 2 Dir RW None 05/09/25 12:53 05/09/25 12:53 RINDEX OBJ 4k 2 Dir RW None 05/09/25 12:53 05/09/25 12:53 SBRK OBJ 4k 3 Dir RW None 05/09/25 12:53 05/09/25 12:53 SCANF OBJ 4k 2 Dir RW None 05/09/25 12:53 05/09/25 12:53 SEEK OBJ 4k 5 Dir RW None 05/09/25 12:53 05/09/25 12:53 SETBUF OBJ 4k 6 Dir RW None 05/09/25 12:54 05/09/25 12:54 SHAR OBJ 4k 1 Dir RW None 05/09/25 12:54 05/09/25 12:54 SHLL OBJ 4k 1 Dir RW None 05/09/25 12:54 05/09/25 12:54 SHLR OBJ 4k 1 Dir RW None 05/09/25 12:54 05/09/25 12:54 SIGNAL OBJ 4k 4 Dir RW None 05/09/25 12:54 05/09/25 12:54 SPRINTF OBJ 4k 3 Dir RW None 05/09/25 12:54 05/09/25 12:54 SRAND OBJ 4k 1 Dir RW None 05/09/25 12:54 05/09/25 12:54 SRAND1 OBJ 4k 3 Dir RW None 05/09/25 12:54 05/09/25 12:54 SSCANF OBJ 4k 2 Dir RW None 05/09/25 12:55 05/09/25 12:55 START1 OBJ 4k 2 Dir RW None 05/09/25 12:55 05/09/25 12:55 START2 OBJ 4k 2 Dir RW None 05/09/25 12:55 05/09/25 12:55 STAT OBJ 4k 10 Dir RW None 05/09/25 12:55 05/09/25 12:55 STDCLEAN OBJ 4k 4 Dir RW None 05/09/25 12:55 05/09/25 12:55 STRCAT OBJ 4k 1 Dir RW None 05/09/25 12:55 05/09/25 12:55 STRCHR OBJ 4k 1 Dir RW None 05/09/25 12:55 05/09/25 12:55 STRCMP OBJ 4k 1 Dir RW None 05/09/25 12:56 05/09/25 12:56 STRCPY OBJ 4k 1 Dir RW None 05/09/25 12:56 05/09/25 12:56 STRDUP OBJ 4k 3 Dir RW None 05/09/25 12:56 05/09/25 12:56 STRFTIME OBJ 4k 31 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRICMP OBJ 4k 1 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRISTR OBJ 4k 3 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRLEN OBJ 4k 1 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRNCAT OBJ 4k 2 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRNCMP OBJ 4k 2 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRNCPY OBJ 4k 2 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRNICMP OBJ 4k 3 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRNISTR OBJ 4k 4 Dir RW None 05/09/25 12:57 05/09/25 12:57 STRNSTR OBJ 4k 4 Dir RW None 05/09/25 12:58 05/09/25 12:58 STRRCHR OBJ 4k 1 Dir RW None 05/09/25 12:58 05/09/25 12:58 STRSTR OBJ 4k 3 Dir RW None 05/09/25 12:58 05/09/25 12:58 STRTOK OBJ 4k 4 Dir RW None 05/09/25 12:58 05/09/25 12:58 SWAP OBJ 4k 2 Dir RW None 05/09/25 12:58 05/09/25 12:58 SYS_ERR OBJ 4k 6 Dir RW None 05/09/25 12:58 05/09/25 12:58 TIME OBJ 4k 3 Dir RW None 05/09/25 12:59 05/09/25 12:59 TIMEZONE OBJ 4k 1 Dir RW None 05/09/25 12:59 05/09/25 12:59 TOLOWER OBJ 4k 1 Dir RW None 05/09/25 12:59 05/09/25 12:59 TOUPPER OBJ 4k 1 Dir RW None 05/09/25 12:59 05/09/25 12:59 UNGETC OBJ 4k 3 Dir RW None 05/09/25 12:59 05/09/25 12:59 UNLINK OBJ 4k 4 Dir RW None 05/09/25 12:59 05/09/25 12:59 WRELOP OBJ 4k 1 Dir RW None 05/09/25 12:59 05/09/25 12:59 WRITE OBJ 4k 14 Dir RW None 05/09/25 13:00 05/09/25 13:00 XTOI OBJ 4k 2 Dir RW None 05/09/25 13:00 05/09/25 13:00 ZC280CPM OBJ 4k 9 Dir RW None 05/09/25 13:00 05/09/25 13:00 ZD280CPM OBJ 4k 3 Dir RW None 05/09/25 13:00 05/09/25 13:00 ZN280CPM OBJ 4k 10 Dir RW None 05/09/25 13:00 05/09/25 13:00 ZR280CPM OBJ 4k 11 Dir RW None 05/09/25 13:00 05/09/25 13:00 _EXIT OBJ 4k 2 Dir RW None 05/09/25 12:40 05/09/25 12:40 Total Bytes = 672k Total Records = 695 Files Found = 167 Total 1k Blocks = 198 Used/Max Dir Entries For Drive M: 233/ 512 10E>era e:lib280c.lbr 10E>; Enter the number of files from above DIR command when prompted 10E>nulu e:lib280c.lbr -a m:*.obj -x A:NULU COM (User 0) ^Z NULU 1.52 (07/12/87) Copyright (C) 1984, 1985 & 1987 by Martin Murray Bug fixes in version 1.52 by Mick Waters TYPE -H FOR HELP COMPLIBC.LOG | ABORT .C | 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 ASSERT .C | ATOI .AS | ATOL .C | B280OVR .SUB | BUILDALL.SUB ABORT .OBJ | BITFIELD.AS | BLKCLR .AS | BLKCPY .C | BMOVE .AS BRELOP .AS | BUF .C | TESTBDOS.C | ABS .OBJ | BUILD-C2.SUB BUILDCPM.SUB | BUILDCRT.SUB | BUILDGEN.SUB | BUILDOVR.SUB | BUILDSTD.SUB C .C | C-JS .C | C-ORIG .C | TESTARGS.COM | OPTIMH .C TESTBDOS.COM | C280LIBC.SUB | C280OPTS. | _EXIT .AS | BDOS .AS OPTIMH .COM | CALLOC .C | CGETS .C | CHMOD .C | CLEANUP .C CLOSE .C | BIOS .AS | EXIT .AS | BUILD-C .LOG | ZCRTCPM .AS CONVTIME.C | CPUTS .C | CREAT .C | CSV .AS | CSV-CPM .AS CTIME .C | CTYPE .C | CTYPE_ .C | DECODE .C | DEHUFF .C DEHUFF .COM | DOPRNT .C | DOSCAN .C | DUP .C | ENCODE .C ENHUFF .C | ENHUFF .COM | ENVIRON . | EXEC .AS | EXECL .AS ALLSH .OBJ | EXIT .C | FAKECLEA.AS | FAKECLEA.C | FAKECPCL.AS FCBNAME .C | FCLOSE .C | C280Z80 .COM | ALRSH .OBJ | FILBUF .C FILESIZE.C | ASALLSH .OBJ | FLSBUF .C | FOPEN .C | FPRINTF .C FPUTC .AS | FREAD .C | FRELOP .AS | FREOPEN .C | FSCANF .C ASALRSH .OBJ | ZAS-SRC .LBR | GETARGS .C | GETCH .C | GETENV .C GETFCB .C | GETS .C | GETSP .AS | GETUID .AS | GETW .C HELLO .C | HELLOS .C | HUFF .H | IDIV .AS | IMUL .AS INDEX .AS | INOUT .AS | IREGSET .AS | ISALPHA .AS | ISATTY .C ISDIGIT .AS | ISLOWER .AS | ISSPACE .AS | ISUPPER .AS | LADD .AS LAND .AS | LDIV .AS | LIBCVER .C | LIBOVR .SUB | LIBSYM .PAS LINC .AS | LISTLIBS.SUB | LISTMODC.SUB | LLRSH .AS | LMUL .AS LONGJMP .AS | LOR .AS | LRELOP .AS | LSUB .AS | LXOR .AS M280LIBC.LOG | M280LIBV.SUB | MAKEFILE.COD | MAKEFILE.CPM | ASAR .OBJ MAKEFILE.GEN | MAKEFILE.STD | ZNRTCPM .AS | ASDIV .OBJ | MALLOC .C MAX .AS | MEMCMP .C | MEMCPY .C | MEMSET .C | MISC .C MKTIME .C | NOMAIN .C | OBJDUMP .COM | OPEN .C | ASLADD .OBJ ASLAND .OBJ | OPTIONS . | OVRBGN .AS | OVREADME.TXT | OVRLOAD .C PERROR .C | PNUM .C | PRINTF .C | PUTCHAR .C | PUTS .C PUTW .C | QSORT .C | RAND .C | RCSV .AS | READ .C RELIBCPM.SUB | RELIBGEN.SUB | RELIBSTD.SUB | REMOVE .C | RENAME .C REWIND .C | RINDEX .AS | SBRK .AS | SCANF .C | SEEK .C SETBUF .C | SHAR .AS | SHLL .AS | SHLR .AS | SIGNAL-O.C SPRINTF .C | SRAND .AS | SRAND1 .C | SSCANF .C | START1 .AS START2 .AS | STAT .C | ASLL .OBJ | STDCLEAN.C | STDIO .I 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 | SYMTOAS .C SYMTOAS .COM | SYS_ERR .C | TEST .LOG | TEST-OPT.AS | TESTAES .C TESTAES .COM | TESTARGS.C | ASLLRSH .OBJ | ASLMUL .OBJ | TESTBIOS.C ZRRTCPM .AS | TESTBUG .AS | TESTBUG .C | TESTENV .C | TESTFILE.C ASLOR .OBJ | TESTFTIM.C | ASLR .OBJ | TESTHELL.C | ASLSUB .OBJ TESTIO .C | ASLXOR .OBJ | TESTIO .ERR | TESTIO .STA | TESTL .C ZC280CPM.AS | TESTLTOF.AS | TESTLTOF.C | TESTOPTH.AS | TESTOVR .C ASMOD .OBJ | TESTOVR1.C | ZN280CPM.AS | TESTOVR2.C | ZR280CPM.AS ASMUL .OBJ | TESTPR .C | ASSERT .OBJ | TESTPWD .C | TESTQSRT.C TESTRC .C | ATOI .OBJ | TESTREL .C | TESTSTR .C | ATOL .OBJ TESTSUB .C | TESTTRIG.C | BDOS .OBJ | TESTUID .C | TESTVER .C TESTVER .SUB | TESTVIEW.C | TESTWILD.C | BIOS .OBJ | TIME .C TIMEZONE.C | TOLOWER .AS | TOUPPER .AS | FGETC .AS | BITFIELD.OBJ BLKCLR .OBJ | BLKCPY .OBJ | UNGETC .C | UNLINK .C | WRELOP .AS WRITE .C | XTOI .AS | BMOVE .OBJ | BRELOP .OBJ | ZD280CPM.AS ZDRTCPM .AS | BUF .OBJ | CALLOC .OBJ | CGETS .OBJ | CHMOD .OBJ ZXCCCPM .AS | CLEANUP .OBJ | CLOSE .OBJ | CONVTIME.OBJ | CPUTS .OBJ CREAT .OBJ | CSV .OBJ | CTIME .OBJ | CTYPE_ .OBJ | CTYPE .OBJ COMPLIBC.SUB | DOPRNT .OBJ | DOSCAN .OBJ | DUP .OBJ | EXEC .OBJ EXECL .OBJ | _EXIT .OBJ | EXIT .OBJ | FAKECLEA.OBJ | FAKECPCL.OBJ FCBNAME .OBJ | FCLOSE .OBJ | FFLUSH .OBJ | FGETC .OBJ | FILBUF .OBJ FLSBUF .OBJ | FOPEN .OBJ | FPRINTF .OBJ | FPUTC .OBJ | FREAD .OBJ FRELOP .OBJ | FREOPEN .OBJ | FSCANF .OBJ | FSEEK .OBJ | FWRITE .OBJ GETARGS .OBJ | GETCH .OBJ | GETENV .OBJ | GETFCB .OBJ | GETS .OBJ GETSP .OBJ | GETUID .OBJ | GETW .OBJ | IDIV .OBJ | IMUL .OBJ INDEX .OBJ | INOUT .OBJ | IREGSET .OBJ | ISALPHA .OBJ | ISATTY .OBJ ISDIGIT .OBJ | ISLOWER .OBJ | ISSPACE .OBJ | ISUPPER .OBJ | LADD .OBJ LAND .OBJ | LDIV .OBJ | LINC .OBJ | LLRSH .OBJ | FFLUSH .C LMUL .OBJ | LONGJMP .OBJ | LOR .OBJ | LRELOP .OBJ | LSUB .OBJ LXOR .OBJ | MALLOC .OBJ | MAX .OBJ | MEMCMP .OBJ | MEMCPY .OBJ MEMSET .OBJ | MKTIME .OBJ | OPEN .OBJ | PERROR .OBJ | PNUM .OBJ PRINTF .OBJ | PUTCHAR .OBJ | PUTS .OBJ | PUTW .OBJ | QSORT .OBJ RAND .OBJ | RCSV .OBJ | READ .OBJ | REMOVE .OBJ | RENAME .OBJ REWIND .OBJ | RINDEX .OBJ | SBRK .OBJ | SCANF .OBJ | SEEK .OBJ SETBUF .OBJ | SHAR .OBJ | SHLL .OBJ | SHLR .OBJ | SIGNAL .OBJ SPRINTF .OBJ | SRAND1 .OBJ | SRAND .OBJ | SSCANF .OBJ | START1 .OBJ START2 .OBJ | STAT .OBJ | STDCLEAN.OBJ | STRCAT .OBJ | STRCHR .OBJ STRCMP .OBJ | STRCPY .OBJ | STRDUP .OBJ | STRFTIME.OBJ | STRICMP .OBJ STRISTR .OBJ | STRLEN .OBJ | STRNCAT .OBJ | STRNCMP .OBJ | STRNCPY .OBJ STRNICMP.OBJ | STRNISTR.OBJ | STRNSTR .OBJ | STRRCHR .OBJ | STRSTR .OBJ STRTOK .OBJ | SWAP .OBJ | SYS_ERR .OBJ | TIME .OBJ | TIMEZONE.OBJ TOLOWER .OBJ | TOUPPER .OBJ | UNGETC .OBJ | UNLINK .OBJ | WRELOP .OBJ WRITE .OBJ | FILESIZE.COM | @LIBC309.-20 | XTOI .OBJ | ZCRTCPM .OBJ LIBOVR .LIB | C280LIBC.LOG | ZDRTCPM .OBJ | EXEC-BLD.SUB | FGETC .C FGETC-O .AS | TESTVER .COM | FPUTC .C | FPUTC-O .AS | FSHOW .C ZNRTCPM .OBJ | ZRRTCPM .OBJ | LIBCVER .OBJ | MAKELIBC.LOG | TEST .DAT TESTBIOS.COM | TESTFILE.COM | TESTFTIM.COM | TESTHELL.COM | TESTIO .COM TESTOVR .COM | TESTOVR1.OVR | TESTOVR2.OVR | TESTOVRX.SYM | TESTPR .COM TESTRC .COM | TESTSTR .COM | TESTTRIG.COM | TESTUID .COM | TESTVIEW.COM TESTWILD.COM | LIBC20 .LIB | LIB280C .LIB | BUILD-C .SUB | ZC280CPM.OBJ ZD280CPM.OBJ | ZN280CPM.OBJ | ZR280CPM.OBJ | SIGNAL .C | C309-20 .COM C280-20 .COM | M280LIBC.SUB | TEST280 .LOG | TEST-OPT.AS2 | TEST .SUB TEST280 .SUB | TEST-OPT.AS3 | OPTIMH80.COM | FSEEK .C | FWRITE .C MKLIBC .SUB | C309-20 .C | MAKELIBC.SUB | Drive E: Total 8000k, Used 7456k, Free 544k Library E10:LIB280C.LBR^G not found. To make it, enter the number of entries to allow. Press RETURN now to abort making the library. Allow how many entries: 167 Library E10:LIB280C.LBR open. (Buffer size: 216 sectors) Active entries: 1, Deleted: 0, Free: 167, Total: 168. Adding: M10:ISLOWER .OBJ Adding: M10:ISSPACE .OBJ Adding: M10:ISUPPER .OBJ Adding: M10:ABORT .OBJ Adding: M10:ABS .OBJ Adding: M10:ALLSH .OBJ Adding: M10:ALRSH .OBJ Adding: M10:ASALLSH .OBJ Adding: M10:ASALRSH .OBJ Adding: M10:ASAR .OBJ Adding: M10:ASDIV .OBJ Adding: M10:ASLADD .OBJ Adding: M10:ASLAND .OBJ Adding: M10:ASLL .OBJ Adding: M10:ASLLRSH .OBJ Adding: M10:ASLMUL .OBJ Adding: M10:ASLOR .OBJ Adding: M10:ASLR .OBJ Adding: M10:ASLSUB .OBJ Adding: M10:ASLXOR .OBJ Adding: M10:ASMOD .OBJ Adding: M10:ASMUL .OBJ Adding: M10:ASSERT .OBJ Adding: M10:ATOI .OBJ Adding: M10:ATOL .OBJ Adding: M10:BDOS .OBJ Adding: M10:BIOS .OBJ Adding: M10:BITFIELD.OBJ Adding: M10:BLKCLR .OBJ Adding: M10:BLKCPY .OBJ Adding: M10:BMOVE .OBJ Adding: M10:BRELOP .OBJ Adding: M10:BUF .OBJ Adding: M10:CALLOC .OBJ Adding: M10:CGETS .OBJ Adding: M10:CHMOD .OBJ Adding: M10:CLEANUP .OBJ Adding: M10:CLOSE .OBJ Adding: M10:CONVTIME.OBJ Adding: M10:CPUTS .OBJ Adding: M10:CREAT .OBJ Adding: M10:CSV .OBJ Adding: M10:CTIME .OBJ Adding: M10:CTYPE_ .OBJ Adding: M10:CTYPE .OBJ Adding: M10:DOPRNT .OBJ Adding: M10:DOSCAN .OBJ Adding: M10:DUP .OBJ Adding: M10:EXEC .OBJ Adding: M10:EXECL .OBJ Adding: M10:_EXIT .OBJ Adding: M10:EXIT .OBJ Adding: M10:FAKECLEA.OBJ Adding: M10:FAKECPCL.OBJ Adding: M10:FCBNAME .OBJ Adding: M10:FCLOSE .OBJ Adding: M10:FFLUSH .OBJ Adding: M10:FGETC .OBJ Adding: M10:FILBUF .OBJ Adding: M10:FLSBUF .OBJ Adding: M10:FOPEN .OBJ Adding: M10:FPRINTF .OBJ Adding: M10:FPUTC .OBJ Adding: M10:FREAD .OBJ Adding: M10:FRELOP .OBJ Adding: M10:FREOPEN .OBJ Adding: M10:FSCANF .OBJ Adding: M10:FSEEK .OBJ Adding: M10:FWRITE .OBJ Adding: M10:GETARGS .OBJ Adding: M10:GETCH .OBJ Adding: M10:GETENV .OBJ Adding: M10:GETFCB .OBJ Adding: M10:GETS .OBJ Adding: M10:GETSP .OBJ Adding: M10:GETUID .OBJ Adding: M10:GETW .OBJ Adding: M10:IDIV .OBJ Adding: M10:IMUL .OBJ Adding: M10:INDEX .OBJ Adding: M10:INOUT .OBJ Adding: M10:IREGSET .OBJ Adding: M10:ISALPHA .OBJ Adding: M10:ISATTY .OBJ Adding: M10:ISDIGIT .OBJ Adding: M10:LADD .OBJ Adding: M10:LAND .OBJ Adding: M10:LDIV .OBJ Adding: M10:LINC .OBJ Adding: M10:LLRSH .OBJ Adding: M10:LMUL .OBJ Adding: M10:LONGJMP .OBJ Adding: M10:LOR .OBJ Adding: M10:LRELOP .OBJ Adding: M10:LSUB .OBJ Adding: M10:LXOR .OBJ Adding: M10:MALLOC .OBJ Adding: M10:MAX .OBJ Adding: M10:MEMCMP .OBJ Adding: M10:MEMCPY .OBJ Adding: M10:MEMSET .OBJ Adding: M10:MKTIME .OBJ Adding: M10:OPEN .OBJ Adding: M10:PERROR .OBJ Adding: M10:PNUM .OBJ Adding: M10:PRINTF .OBJ Adding: M10:PUTCHAR .OBJ Adding: M10:PUTS .OBJ Adding: M10:PUTW .OBJ Adding: M10:QSORT .OBJ Adding: M10:RAND .OBJ Adding: M10:RCSV .OBJ Adding: M10:READ .OBJ Adding: M10:REMOVE .OBJ Adding: M10:RENAME .OBJ Adding: M10:REWIND .OBJ Adding: M10:RINDEX .OBJ Adding: M10:SBRK .OBJ Adding: M10:SCANF .OBJ Adding: M10:SEEK .OBJ Adding: M10:SETBUF .OBJ Adding: M10:SHAR .OBJ Adding: M10:SHLL .OBJ Adding: M10:SHLR .OBJ Adding: M10:SIGNAL .OBJ Adding: M10:SPRINTF .OBJ Adding: M10:SRAND1 .OBJ Adding: M10:SRAND .OBJ Adding: M10:SSCANF .OBJ Adding: M10:START1 .OBJ Adding: M10:START2 .OBJ Adding: M10:STAT .OBJ Adding: M10:STDCLEAN.OBJ Adding: M10:STRCAT .OBJ Adding: M10:STRCHR .OBJ Adding: M10:STRCMP .OBJ Adding: M10:STRCPY .OBJ Adding: M10:STRDUP .OBJ Adding: M10:STRFTIME.OBJ Adding: M10:STRICMP .OBJ Adding: M10:STRISTR .OBJ Adding: M10:STRLEN .OBJ Adding: M10:STRNCAT .OBJ Adding: M10:STRNCMP .OBJ Adding: M10:STRNCPY .OBJ Adding: M10:STRNICMP.OBJ Adding: M10:STRNISTR.OBJ Adding: M10:STRNSTR .OBJ Adding: M10:STRRCHR .OBJ Adding: M10:STRSTR .OBJ Adding: M10:STRTOK .OBJ Adding: M10:SWAP .OBJ Adding: M10:SYS_ERR .OBJ Adding: M10:TIME .OBJ Adding: M10:TIMEZONE.OBJ Adding: M10:TOLOWER .OBJ Adding: M10:TOUPPER .OBJ Adding: M10:UNGETC .OBJ Adding: M10:UNLINK .OBJ Adding: M10:WRELOP .OBJ Adding: M10:WRITE .OBJ Adding: M10:XTOI .OBJ Adding: M10:ZC280CPM.OBJ Adding: M10:ZD280CPM.OBJ Adding: M10:ZN280CPM.OBJ Adding: M10:ZR280CPM.OBJ Adding: M10:LIBCVER .OBJ Active entries: 168, Deleted: 0, Free: 0, Total: 168. Closing E10:LIB280C.LBR... 10E>; Finally copy over the start-up modules 10E>pip e:=m:z?280cpm.obj A:PIP COM (User 0) COPYING - ZC280CPM.OBJ ZD280CPM.OBJ ZN280CPM.OBJ ZR280CPM.OBJ 10E>; 10E>put console to console A:PUT COM (User 0)  ================================================ FILE: stdio/M280LIBC.SUB ================================================ era m280libc.log put console output to file m280libc.log [system] ; Use librarian to place all modules in m:lib280c.lib ; NB: the ordering is important for resolving dependencies at link time m: era m:lib280c.lib libr ; Use librarian to place all modules in LIBC20.LIB 10E>; NB: the ordering is important for resolving dependencies at link time 10E>era LIBC20.lib 10E>libr A:LIBR COM (User 0) libr> r LIBC20.lib \ libr> libcver.obj \ libr> start1.obj \ libr> getargs.obj \ libr> assert.obj \ libr> printf.obj \ libr> fprintf.obj \ libr> sprintf.obj \ libr> doprnt.obj \ libr> getenv.obj \ libr> gets.obj \ libr> puts.obj \ libr> fwrite.obj \ libr> getw.obj \ libr> putw.obj \ libr> putchar.obj \ libr> perror.obj \ libr> fputc.obj \ libr> flsbuf.obj \ libr> fopen.obj \ libr> freopen.obj \ libr> fseek.obj \ libr> fread.obj \ libr> rewind.obj \ libr> remove.obj \ libr> setbuf.obj \ libr> fscanf.obj \ libr> ctime.obj \ libr> cgets.obj \ libr> cputs.obj \ libr> sscanf.obj \ libr> scanf.obj \ libr> doscan.obj \ libr> ungetc.obj \ libr> fgetc.obj \ libr> filbuf.obj \ libr> stdclean.obj \ libr> fclose.obj \ libr> fflush.obj \ libr> buf.obj \ libr> exit.obj \ libr> open.obj \ libr> read.obj \ libr> write.obj \ libr> seek.obj \ libr> stat.obj \ libr> chmod.obj \ libr> fcbname.obj \ libr> rename.obj \ libr> creat.obj \ libr> time.obj \ libr> convtime.obj \ libr> timezone.obj \ libr> mktime.obj \ libr> isatty.obj \ libr> cleanup.obj \ libr> close.obj \ libr> unlink.obj \ libr> dup.obj \ libr> execl.obj \ libr> getfcb.obj \ libr> srand1.obj \ libr> abort.obj \ libr> getch.obj \ libr> signal.obj \ libr> getuid.obj \ libr> bdos.obj \ libr> bios.obj \ libr> _exit.obj \ libr> fakeclean.obj \ libr> fakecpcln.obj \ libr> sys_err.obj \ libr> memcpy.obj \ libr> memcmp.obj \ libr> memset.obj \ libr> strftime.obj \ libr> asmod.obj \ libr> abs.obj \ libr> asallsh.obj \ libr> allsh.obj \ libr> asalrsh.obj \ libr> asar.obj \ libr> asdiv.obj \ libr> asladd.obj \ libr> asland.obj \ libr> asll.obj \ libr> asllrsh.obj \ libr> aslmul.obj \ libr> aslor.obj \ libr> aslsub.obj \ libr> aslxor.obj \ libr> atoi.obj \ libr> atol.obj \ libr> blkclr.obj \ libr> blkcpy.obj \ libr> calloc.obj \ libr> asmul.obj \ libr> bitfield.obj \ libr> ctype_.obj \ libr> getsp.obj \ libr> index.obj \ libr> strchr.obj \ libr> qsort.obj \ libr> malloc.obj \ libr> max.obj \ libr> idiv.obj \ libr> pnum.obj \ libr> ldiv.obj \ libr> swap.obj \ libr> aslr.obj \ libr> bmove.obj \ libr> imul.obj \ libr> rand.obj \ libr> alrsh.obj \ libr> lmul.obj \ libr> rindex.obj \ libr> strrchr.obj \ libr> sbrk.obj \ libr> shar.obj \ libr> shll.obj \ libr> shlr.obj \ libr> strcat.obj \ libr> strcmp.obj \ libr> strcpy.obj \ libr> strlen.obj \ libr> strncat.obj \ libr> strncmp.obj \ libr> strncpy.obj \ libr> strstr.obj \ libr> strnstr.obj \ libr> strdup.obj \ libr> stricmp.obj \ libr> stristr.obj \ libr> strnicmp.obj \ libr> strnistr.obj \ libr> strtok.obj \ libr> inout.obj \ libr> iregset.obj \ libr> isalpha.obj \ libr> isdigit.obj \ libr> islower.obj \ libr> isspace.obj \ libr> isupper.obj \ libr> ladd.obj \ libr> land.obj \ libr> linc.obj \ libr> llrsh.obj \ libr> longjmp.obj \ libr> lor.obj \ libr> brelop.obj \ libr> wrelop.obj \ libr> lrelop.obj \ libr> frelop.obj \ libr> lsub.obj \ libr> lxor.obj \ libr> csv.obj \ libr> rcsv.obj \ libr> tolower.obj \ libr> toupper.obj \ libr> xtoi.obj 10E>; Library LIBC20.LIB created 10E>libr s LIBC20.lib A:LIBR COM (User 0) libcver.obj D __libcver start1.obj D __argc_ U __getargs D startup getargs.obj U __argc_ D __getargs U __iob U _bdos U _bmove U _exit U _fprintf U _freopen U _gets U _getuid U _isatty U _sbrk U _setfcb U _setuid U _signal U _sprintf U _strchr U _strcpy U _strlen U adiv U cret U csv U indir U ncsv U shal U wrelop assert.obj D __fassert U __iob U _abort U _fprintf U cret U csv U indir U ncsv printf.obj U __doprnt U __iob D _printf U cret U csv U indir U ncsv fprintf.obj U __doprnt D _fprintf U cret U csv U indir U ncsv sprintf.obj U __doprnt D _sprintf U cret U csv U indir U ncsv doprnt.obj U __ctype_ D __doprnt U __pnum U _atoi U _fputc U _strlen U brelop U cret U csv U indir U ncsv U wrelop getenv.obj U _bdos D _environ U _fclose U _fgets U _fopen D _getenv U _memcpy U _sbrk U _strcpy U _strlen U _strncmp U cret U csv U indir U ncsv U wrelop gets.obj U __iob U _fgetc D _fgets D _gets U _strlen U cret U csv U indir U ncsv puts.obj U __iob U _fputc D _fputs D _puts U cret U csv U indir U ncsv fwrite.obj U _fflush U _fputc U _fseek D _fwrite U _memcpy U cret U indir U ldiv U lmul U ncsv U wrelop getw.obj U _fgetc D _getw U cret U csv U indir U ncsv U shal putw.obj U _fputc D _putw U cret U csv U indir U ncsv U shar putchar.obj U __iob U _fgetc U _fputc D _getchar D _putchar U cret U csv U indir U ncsv perror.obj U __iob U _errno U _fputc D _perror U _sys_err U _sys_ner U cret U csv U indir U ncsv U wrelop fputc.obj U __flsbuf U _fflush D _fputc U _fseek U cret U csv U indir U ncsv flsbuf.obj U __bufallo D __flsbuf U _isatty U _write U cret U csv U indir U ncsv fopen.obj U __iob D _fopen U _freopen U cret U csv U indir U ncsv freopen.obj U __bufallo U _close U _creat U _fclose D _freopen U _fseek U _open U cret U csv U indir U ncsv fseek.obj U __fcb U _fflush U _fread D _fseek D _ftell U _lseek U aladd U alsub U amul U arelop U asaladd U cret U csv U indir U ncsv fread.obj U _fgetc D _fread U _memcpy U cret U indir U ldiv U lmul U ncsv U wrelop rewind.obj U _fseek D _rewind U cret U csv U indir U ncsv remove.obj D _remove U _unlink U cret U csv U indir U ncsv setbuf.obj U __bufallo U __buffree D _setbuf D _setvbuf U cret U csv U indir U ncsv fscanf.obj U __doscan D _fscanf U cret U csv U indir U ncsv ctime.obj D _asctime D _ctime D _gmtime D _localtime D _monlen U _time_zone U adiv U aldiv U almod U almul U alsub U amod U amul U asaldiv U asldiv U cret U csv U indir U lmod U ncsv U wrelop cgets.obj D _cgets U _getche U cret U csv U indir U ncsv cputs.obj D _cputs U _putch U cret U csv U indir U ncsv sscanf.obj U __doscan D _sscanf U _strlen U cret U indir U ncsv scanf.obj U __doscan U __iob D _scanf U cret U csv U indir U ncsv doscan.obj U __ctype_ D __doscan U _atoi U _fgetc U _tolower U _ungetc U cret U csv U indir U lladd U llmul U ncsv U wrelop ungetc.obj D _ungetc U cret U csv U indir U ncsv fgetc.obj U __filbuf D _fgetc U cret U csv U indir U ncsv U wrelop filbuf.obj D __filbuf U __iob U _fflush U _read U cret U csv U indir U ncsv U wrelop stdclean.obj D __cleanup D __iob D __sibuf U _fclose U cret U csv U indir U ncsv fclose.obj U __buffree U _close D _fclose U _fflush U cret U csv U indir U ncsv fflush.obj D _fflush U _write U cret U csv U indir U ncsv buf.obj D __bufallo D __buffree U _sbrk U cret U csv U indir U ncsv exit.obj U __cleanup U __exit D _exit U cret U csv U indir U ncsv open.obj U __exact U __fcb D __fsize U _bdos U _errno U _getfcb U _getuid D _open U _putfcb U _setfcb U _setuid U adiv U aland U aldiv U amul U asalsub U brelop U cret U csv U indir U ncsv U shll U wrelop read.obj U __fcb U __piped U __putrno U __sigchk U _bdos U _bmove U _getuid D _read U _setuid U aldiv U alsub U amul U asaladd U brelop U cret U indir U lladd U lrelop U ncsv U wrelop write.obj U __fcb U __piped U __putrno U __sigchk U _bdos U _bmove U _getuid U _setuid D _write U aldiv U amul U arelop U asaladd U brelop U cret U indir U ncsv U wrelop seek.obj U __fcb D _lseek U aladd U amul U arelop U brelop U cret U csv U indir U ncsv stat.obj U __exact U _bdos U _convtime U _getuid U _setfcb U _setuid D _stat U asallsh U asalsub U cret U indir U lladd U lllsh U ncsv U shal U wrelop chmod.obj U _bdos D _chmod U _getuid U _setfcb U _setuid U cret U indir U ncsv fcbname.obj U __fcb U _bdos D _fcbname U _sprintf U _strlen U amul U cret U csv U indir U ncsv U wrelop rename.obj U _bdos D _rename U _setfcb U _unlink U cret U indir U ncsv creat.obj U __fcb U _bdos D _creat U _errno U _getfcb U _getuid U _setfcb U _setuid U _unlink U adiv U cret U csv U indir U ncsv U wrelop time.obj U _bdos U _convtime D _time U cret U indir U ncsv convtime.obj D _convtime D _frmbcd U asaladd U asalmul U cret U csv U indir U lmul U ncsv timezone.obj D _time_zone mktime.obj D _mktime U _time_zone U almul U amod U asaladd U cret U indir U ncsv U wrelop isatty.obj U __fcb D _isatty U amul U cret U csv U indir U ncsv cleanup.obj D __cpm_clean D __fcb D __initrsx D __putrno U _close U alrsh U brelop U cret U csv U indir U ncsv close.obj U __exact U __fcb U _bdos D _close U _getuid U _setuid U amul U brelop U cret U csv U indir U ncsv unlink.obj U _bdos U _errno U _getuid U _setfcb U _setuid D _unlink U cret U indir U ncsv dup.obj U __fcb D _dup U _getfcb U adiv U amul U cret U csv U indir U ncsv execl.obj U _bmove D _execl D _execv U _setfcb U _strcat U _strlen U _strncpy U indir getfcb.obj U __ctype_ U __fcb U _atoi D _getfcb U _getuid D _putfcb D _setfcb U _toupper U brelop U cret U csv U indir U ncsv U wrelop srand1.obj U _kbhit U _putchar U _srand D _srand1 U cret U csv U indir U ncsv abort.obj D _abort U _bdos U _exit U cret U indir U ncsv getch.obj U _bdos D _getch D _getche D _kbhit D _putch D _ungetch U cret U csv U indir U ncsv signal.obj D __sigchk U _bdos U _exit D _signal U cret U csv U indir U ncsv getuid.obj D _getuid D _setuid U cret U csv bdos.obj D _bdos U _errno U cret U csv bios.obj D _bios U cret U csv D exit22 _exit.obj U __cpm_clean D __exit fakeclean.obj D __cleanup U cret U indir U ncsv fakecpcln.obj D __cpm_clean sys_err.obj D _errno D _sys_err D _sys_ner memcpy.obj D _memcpy U cret U csv U indir U ncsv memcmp.obj D _memcmp U cret U csv U indir U ncsv memset.obj D _memset U cret U csv U indir U ncsv strftime.obj D _strftime U adiv U amod U asamod U cret U indir U ncsv U wrelop asmod.obj U amod D asamod D aslmod U lmod abs.obj D _abs asallsh.obj U allsh D asallsh D aslllsh U iregstore allsh.obj D allsh D lllsh asalrsh.obj U alrsh D asalrsh U iregstore asar.obj D asar U shar asdiv.obj U adiv D asadiv D asldiv U ldiv asladd.obj U aladd D asaladd D aslladd U iregset U iregstore asland.obj U aland D asaland D aslland U iregset U iregstore asll.obj D asal D asll U shal asllrsh.obj D asllrsh U iregstore U llrsh aslmul.obj U almul D asalmul D asllmul U iregset U iregstore aslor.obj U alor D asalor D asllor U iregset U iregstore aslsub.obj U alsub D asalsub D asllsub U iregset U iregstore aslxor.obj U alxor D asalxor D asllxor U iregset U iregstore atoi.obj D _atoi atol.obj U __ctype_ D _atol U aladd U almul U cret U indir U ncsv blkclr.obj D _blkclr blkcpy.obj D _blkcpy U cret U csv U indir U ncsv calloc.obj U _bmove D _calloc D _cfree U _free U _malloc U asamul U cret U csv U indir U ncsv asmul.obj U amul D asamul D aslmul bitfield.obj D bfext D bfins ctype_.obj D __ctype_ getsp.obj D __getsp index.obj D _index U cret U rcsv strchr.obj D _strchr U cret U rcsv qsort.obj U __swap U _bmove U _free U _malloc D _qsort U adiv U cret U indir U lmul U ncsv U wrelop malloc.obj U _bmove D _free D _malloc D _realloc U _sbrk U adiv U amul U cret U csv U indir U ldiv U lmul U ncsv U wrelop max.obj D _max idiv.obj D adiv D amod D ldiv D lmod pnum.obj D __pnum U aslldiv U brelop U cret U indir U llmod U ncsv U wrelop ldiv.obj D aldiv D almod D asaldiv D asalmod D aslldiv D asllmod D lldiv D llmod swap.obj D __swap U cret U rcsv aslr.obj D aslr U shlr bmove.obj D _bmove D _movmem imul.obj D amul D lmul rand.obj D _rand D _srand U almul U alrsh U cret U csv U indir U ncsv alrsh.obj D alrsh lmul.obj D almul D llmul rindex.obj D _rindex U cret U rcsv strrchr.obj D _strrchr U cret U rcsv sbrk.obj U __Hbss D _brk D _checksp D _sbrk shar.obj D shar shll.obj D shal D shll shlr.obj D shlr strcat.obj D _strcat strcmp.obj D _strcmp strcpy.obj D _strcpy strlen.obj D _strlen strncat.obj D _strncat U cret U rcsv strncmp.obj D _strncmp U cret U rcsv strncpy.obj D _strncpy U cret U rcsv strstr.obj D _strstr U cret U csv U indir U ncsv strnstr.obj D _strnstr U cret U indir U ncsv strdup.obj U _malloc U _strcpy D _strdup U _strlen U cret U csv U indir U ncsv stricmp.obj D _strcasecmp stristr.obj D _strcasestr U _toupper U cret U csv U indir U ncsv strnicmp.obj D _strncasecmp U cret U rcsv strnistr.obj D _strncasestr U _toupper U cret U indir U ncsv strtok.obj D _strtok U cret U csv U indir U ncsv U wrelop inout.obj D _in D _inp D _out D _outp iregset.obj D iregset D iregstore isalpha.obj D _isalpha isdigit.obj D _isdig D _isdigit islower.obj D _islower isspace.obj D _isspace isupper.obj D _isupper ladd.obj D aladd D lladd land.obj D aland D lland linc.obj D ladec D lainc D lldec D llinc llrsh.obj D llrsh longjmp.obj D _longjmp D _setjmp lor.obj D alor D llor brelop.obj D brelop wrelop.obj D wrelop lrelop.obj D arelop D lrelop frelop.obj D frelop lsub.obj D alsub D llsub lxor.obj D alxor D llxor csv.obj D cret D csv D indir D ncsv rcsv.obj D rcsv tolower.obj D _tolower toupper.obj D _toupper xtoi.obj D _ishex D _xtoi 10E>put console to console A:PUT COM (User 0) ================================================ FILE: stdio/MAKELIBC.SUB ================================================ era makelibc.log put console output to file makelibc.log [system] ; Use librarian to place all modules in LIBC20.LIB ; NB: the ordering is important for resolving dependencies at link time era LIBC20.lib libr extern int errno; extern char * sys_err[]; extern int sys_ner; static void ps(char *s) { while(*s) putc(*s++, stderr); } void perror(char *s) { ps(s); putc(':', stderr); if (errno < sys_ner) ps(sys_err[errno]); else ps("Unknown error"); putc('\n', stderr); } ================================================ FILE: stdio/PRINTF.C ================================================ #include extern int _doprnt(); printf(f, a) char * f; int a; { return(_doprnt(stdout, f, &a)); } ================================================ FILE: stdio/PUTCHAR.C ================================================ /* * Fake routines for getchar and putchar */ #include #undef getchar #undef putchar getchar() { return(getc(stdin)); } putchar(c) { return(putc(c, stdout)); } ================================================ FILE: stdio/PUTS.C ================================================ /* * puts and fputs for HI-TECH C stdio */ #include fputs(s, f) char * s; register FILE * f; { while(*s) if(putc(*s++, f) == EOF) return EOF; return 0; } puts(s) char * s; { register int i; i = fputs(s, stdout); putchar('\n'); return i; } ================================================ FILE: stdio/PUTW.C ================================================ #include /* * putw for Zios */ putw(w, stream) register FILE * stream; { if(putc(w&0xFF, stream) == EOF || putc((w >> 8)&0xFF, stream) == EOF) return(EOF); return(w); } ================================================ FILE: stdio/RELIBCPM.SUB ================================================ libr remove(s) char * s; { return unlink(s); } ================================================ FILE: stdio/REWIND.C ================================================ #include rewind(stream) FILE * stream; { fseek(stream, 0L, SEEK_SET); } ================================================ FILE: stdio/SCANF.C ================================================ /* * Stdio scanf */ #include extern int _doscan(); scanf(fmt, args) char * fmt; int args; { return _doscan(stdin, fmt, &args); } ================================================ FILE: stdio/SETBUF.C ================================================ /* * Setbuf for HI-TECH C stdio */ #include void setbuf(f, c) register FILE * f; char * c; { if(c) setvbuf(f, c, _IOFBF, BUFSIZ); else setvbuf(f, c, _IONBF, 0); } setvbuf(register FILE * stream, register char * buf, int mode, size_t size) { switch(mode) { case _IONBF: /* Not buffered */ if(!(stream->_flag & _IOMYBUF) && stream->_base) _buffree(stream->_base); stream->_base = stream->_ptr = 0; stream->_flag &= ~(_IOMYBUF|_IOLBF); stream->_flag |= _IONBF; break; case _IOLBF: /* Line buffered or */ case _IOFBF: /* Fully buffered */ if(buf) stream->_flag |= _IOMYBUF; if(!buf && !(buf = stream->_base)) { if(!(buf = _bufallo())) return -1; size = BUFSIZ; } stream->_base = buf; stream->_size = size; stream->_flag &= ~(_IONBF|_IOLBF); stream->_flag |= mode; break; default: return -1; } stream->_cnt = 0; return 0; } ================================================ FILE: stdio/SPRINTF.C ================================================ #include static FILE spf; sprintf(wh, f, a) char * wh; char * f; int a; { spf._size = 32767; spf._cnt = 0; spf._base = spf._ptr = wh; spf._flag = _IOWRT|_IOBINARY|_IOSTRG; _doprnt(&spf, f, &a); *spf._ptr = 0; return spf._ptr - wh; } ================================================ FILE: stdio/SSCANF.C ================================================ /* * Stdio sscanf */ #include #include extern int _doscan(); sscanf(str, fmt, args) char * str; char * fmt; int args; { FILE file; file._base = file._ptr = str; file._size = file._cnt = strlen(str); file._flag = _IOSTRG|_IOBINARY|_IOREAD; return _doscan(&file, fmt, &args); } ================================================ FILE: stdio/STDCLEAN.C ================================================ #include _cleanup() { uchar i; register struct _iobuf * ip; i = _NFILE; ip = _iob; do { fclose(ip); ip++; } while(--i); } /* * Initial setup for stdio */ char _sibuf[BUFSIZ]; FILE _iob[_NFILE] = { { _sibuf, 0, _sibuf, _IOREAD|_IOMYBUF, 0, /* stdin */ BUFSIZ }, { (char *)0, 0, (char *)0, _IOWRT|_IONBF, 1, /* stdout */ 0 }, { (char *)0, 0, (char *)0, _IOWRT|_IONBF, 2, /* stderr */ 0 }, }; ================================================ FILE: stdio/STDIO.I ================================================ ; Offsets of things in the _iob structure ptr equ 0 ;pointer to next byte cnt equ 2 ;number of bytes left base equ 4 ;beginning of buffer flag equ 6 ;flag bits file equ 8 ;file number ; The bit numbers of the flags in flag _IOREAD_BIT equ 0 _IOWRT_BIT equ 1 _IONBF_BIT equ 2 _IOMYBUF_BIT equ 3 _IOEOF_BIT equ 4 _IOERR_BIT equ 5 _IOSTRG_BIT equ 6 _IOBINARY_BIT equ 7 ; Various characters CPMEOF equ 032q ; EOF byte NEWLINE equ 012q ; newline character RETURN equ 015q ; carriage return EOF equ -1 ; stdio EOF value ================================================ FILE: stdio/UNGETC.C ================================================ #include /* * ungetc for HI-TECH C */ ungetc(c, stream) int c; register FILE * stream; { if(c == EOF || !(stream->_flag & _IOREAD) || stream->_flag & _IODIRN || stream->_base == (char *)NULL || stream->_cnt == stream->_size) return(EOF); if(stream->_ptr == stream->_base) stream->_ptr++; else stream->_cnt++; *--stream->_ptr = c; return(c); } ================================================ FILE: test/TEST-OPT.AS ================================================ ; Test input for OPTIMH (Z280 code optimiser) ; global _instr n equ 25 nn equ 1abch psect text _instr: ; global csv,cret call csv jp cret ; global amul,lmul call amul call lmul ; label: ld (hl),c inc hl ld (hl),b inc hl ; ld (hl),c inc hl ld (hl),b ; ld (hl),e inc hl ld (hl),d ; ld c,(hl) inc hl ld b,(hl) ; ld e,(hl) inc hl ld d,(hl) ; ld c,(ix+n) ld b,(ix+n+1) ld c,(iy+n) ld b,(iy+n+1) ; ld e,(ix+n) ld d,(ix+n+1) ; ld l,(ix+n) ld h,(ix+n+1) ; ld (ix+n),c ld (ix+n+1),b ; ld (ix+n),e ld (ix+n+1),d ; ld (ix+n),l ld (ix+n+1),h ; or a sbc hl,bc ; or a sbc hl,de ; push ix pop de ld hl,nn add hl,de ; push ix pop de ; push ix pop hl ; ; Addressing with large offset ; push ix pop de ld hl,nn add hl,de ; push iy pop de ld hl,nn add hl,de ; ================================================ FILE: test/TEST-OPT.AS2 ================================================ ; Test input for OPTIMH (Z280 code optimiser) ; global _instr n equ 25 nn equ 1abch psect text _instr: ; global csv,cret ;->call csv push iy push ix ;-> lda ix,(sp+0) defb 0ddh,0edh,02h,0,0 ;->jp cret ld sp,ix pop ix pop iy ret ; global amul,lmul ;->multw hl,de defb 0edh,0d2h ;->multuw hl,de defb 0edh,0d3h ; label: ;->ldw (hl),bc defb 0edh,0eh inc hl inc hl ; ;->ldw (hl),bc defb 0edh,0eh inc hl ; ;->ldw (hl),de defb 0edh,1eh inc hl ; ;->ldw bc,(hl) defb 0edh,06h inc hl ; ;->ldw de,(hl) defb 0edh,16h inc hl ; ;->ldw bc,(ix+n) defb 0ddh,0edh,06h,+n ;->ldw bc,(iy+n) defb 0fdh,0edh,06h,+n ; ;->ldw de,(ix+n) defb 0ddh,0edh,16h,+n ; ;->ldw hl,(ix+n) defb 0ddh,0edh,26h,+n ; ;->ldw (ix+n),bc defb 0ddh,0edh,0eh,+n ; ;->ldw (ix+n),de defb 0ddh,0edh,1eh,+n ; ;->ldw (ix+n),hl defb 0ddh,0edh,2eh,+n ; ;->subw hl,bc defb 0edh,0ceh ; ;->subw hl,de defb 0edh,0deh ; ;->lda hl,(ix+nn) defb 0edh,2ah defw nn ; ;->ld d,ixh defb 0ddh,54h ;->ld e,ixl defb 0ddh,5dh ; ;->lda hl,(ix+0) defb 0edh,2ah,0,0 ; ; Addressing with large offset ; ;->lda hl,(ix+nn) defb 0edh,2ah defw nn ; ;->lda hl,(iy+nn) defb 0edh,32h defw nn ; ; optimiser statistics: ; 15 bytes speed optimised away ; 68 bytes replaced ================================================ FILE: test/TEST-OPT.AS3 ================================================ ; Test input for OPTIMH (Z280 code optimiser) ; global _instr n equ 25 nn equ 1abch psect text _instr: ; global csv,cret call csv jp cret ; global amul,lmul ;->multw hl,de defb 0edh,0d2h ;->multuw hl,de defb 0edh,0d3h ; label: ;->ldw (hl),bc defb 0edh,0eh inc hl inc hl ; ;->ldw (hl),bc defb 0edh,0eh inc hl ; ;->ldw (hl),de defb 0edh,1eh inc hl ; ;->ldw bc,(hl) defb 0edh,06h inc hl ; ;->ldw de,(hl) defb 0edh,16h inc hl ; ;->ldw bc,(ix+n) defb 0ddh,0edh,06h,+n ;->ldw bc,(iy+n) defb 0fdh,0edh,06h,+n ; ;->ldw de,(ix+n) defb 0ddh,0edh,16h,+n ; ;->ldw hl,(ix+n) defb 0ddh,0edh,26h,+n ; ;->ldw (ix+n),bc defb 0ddh,0edh,0eh,+n ; ;->ldw (ix+n),de defb 0ddh,0edh,1eh,+n ; ;->ldw (ix+n),hl defb 0ddh,0edh,2eh,+n ; ;->subw hl,bc defb 0edh,0ceh ; ;->subw hl,de defb 0edh,0deh ; ;->lda hl,(ix+nn) defb 0edh,2ah defw nn ; ;->ld d,ixh defb 0ddh,54h ;->ld e,ixl defb 0ddh,5dh ; ;->lda hl,(ix+0) defb 0edh,2ah,0,0 ; ; Addressing with large offset ; ;->lda hl,(ix+nn) defb 0edh,2ah defw nn ; ;->lda hl,(iy+nn) defb 0edh,32h defw nn ; ; optimiser statistics: ; 25 bytes size optimised away ; 62 bytes replaced ================================================ FILE: test/TEST.LOG ================================================ 10E>date A:DATE COM (User 0) Tue 02/09/2025 13:37:29 10E>; Compile all tests 10E>c -v -o filesize.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: FILESIZE.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 -OFILESIZE.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OFILESIZE.COM 0:A:CRTCPM.OBJ FILESIZE.OBJ 0:A:LIBC.LIB ERA FILESIZE.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testver.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: TESTVER.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 -OTESTVER.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTVER.COM 0:A:CRTCPM.OBJ TESTVER.OBJ 0:A:LIBC.LIB ERA TESTVER.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testio.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: TESTIO.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 -OTESTIO.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTIO.COM 0:A:CRTCPM.OBJ TESTIO.OBJ 0:A:LIBC.LIB ERA TESTIO.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testuid.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: TESTUID.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 -OTESTUID.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTUID.COM 0:A:CRTCPM.OBJ TESTUID.OBJ 0:A:LIBC.LIB ERA TESTUID.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o teststr.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: TESTSTR.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 -OTESTSTR.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTSTR.COM 0:A:CRTCPM.OBJ TESTSTR.OBJ 0:A:LIBC.LIB ERA TESTSTR.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testbios.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: TESTBIOS.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 -OTESTBIOS.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTBIOS.COM 0:A:CRTCPM.OBJ TESTBIOS.OBJ 0:A:LIBC.LIB ERA TESTBIOS.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testbdos.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: TESTBDOS.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 -OTESTBDOS.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTBDOS.COM 0:A:CRTCPM.OBJ TESTBDOS.OBJ 0:A:LIBC.LIB ERA TESTBDOS.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testtrig.c -lf 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: TESTTRIG.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 -OTESTTRIG.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTTRIG.COM 0:A:CRTCPM.OBJ TESTTRIG.OBJ 0:A:LIBF.LIB 0:A:LIBC.LIB ERA TESTTRIG.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testftim.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: TESTFTIM.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 -OTESTFTIM.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTFTIM.COM 0:A:CRTCPM.OBJ TESTFTIM.OBJ 0:A:LIBC.LIB ERA TESTFTIM.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testfile.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: TESTFILE.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 -OTESTFILE.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTFILE.COM 0:A:CRTCPM.OBJ TESTFILE.OBJ 0:A:LIBC.LIB ERA TESTFILE.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testaes.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: TESTAES.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 -OTESTAES.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTAES.COM 0:A:CRTCPM.OBJ TESTAES.OBJ 0:A:LIBC.LIB ERA TESTAES.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testrc.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: TESTRC.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 -OTESTRC.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTRC.COM 0:A:CRTCPM.OBJ TESTRC.OBJ 0:A:LIBC.LIB ERA TESTRC.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testview.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: TESTVIEW.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 -OTESTVIEW.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTVIEW.COM 0:A:CRTCPM.OBJ TESTVIEW.OBJ 0:A:LIBC.LIB ERA TESTVIEW.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testwild.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: TESTWILD.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 -OTESTWILD.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTWILD.COM 0:A:CRTCPM.OBJ TESTWILD.OBJ 0:A:LIBC.LIB ERA TESTWILD.OBJ ERA M:$$EXEC.$$$ 10E>c -ftestovrx.sym -v -o testovr.c -lovr 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: TESTOVR.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 -OTESTOVR.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -DTESTOVRX.SYM -Ptext=0,data,bss -C100H -OTESTOVR.COM 0:A:CRTCPM.OBJ TESTOVR.OBJ 0:A:LIBOVR.LIB 0:A:LIBC.LIB ERA TESTOVR.OBJ ERA M:$$EXEC.$$$ 10E>c -y -o -v testovr2.c testovrx.sym 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 TESTOVR2.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: TESTOVR2.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 -OTESTOVR2.OBJ M:$CTMP2.$$$ 0:A:SYMTOAS TESTOVRX.SYM M:$CTMP5.$$$ TESTOVRX.SYM 0:A:ZAS -OTESTOVRX.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=03689h,data -C3689H -OTESTOVR2.OVR TESTOVR2.OBJ TESTOVRX.OBJ ERA M:$$EXEC.$$$ 10E>c -y -o -v testovr1.c testovrx.sym 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 TESTOVR1.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -I0:A: TESTOVR1.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 -OTESTOVR1.OBJ M:$CTMP2.$$$ 0:A:SYMTOAS TESTOVRX.SYM M:$CTMP5.$$$ TESTOVRX.SYM 0:A:ZAS -OTESTOVRX.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=03689h,data -C3689H -OTESTOVR1.OVR TESTOVR1.OBJ TESTOVRX.OBJ ERA M:$$EXEC.$$$ 10E>c -a -v -o testhell.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: TESTHELL.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 -OTESTHELL.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -L -Pcpm=0,text,data,bss,stack -OM:$L.OBJ 0:A:RRTCPM.OBJ TESTHELL.OBJ 0:A:LIBC.LIB 0:A:OBJTOHEX -R -B100H M:$L.OBJ TESTHELL.COM ERA M:$L.OBJ ERA TESTHELL.OBJ ERA M:$$EXEC.$$$ 10E>c -v -o testpr.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: TESTPR.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 -OTESTPR.OBJ M:$CTMP2.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTPR.COM 0:A:CRTCPM.OBJ TESTPR.OBJ 0:A:LIBC.LIB ERA TESTPR.OBJ ERA M:$$EXEC.$$$ 10E>testver E:TESTVER COM CP/M BDOS Version (3.1) Machine (MCS80/Z80) BDOS Address (0xE500) BIOS Address (0xF800) TPA Size (57.0K) C library version LIBC 3.09-20 Using DOS Plus exact file size mode 10E>era testio.sta 10E>era testio.out No File 10E>era testio.err 10E>testovr E: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 10E>testio E:TESTIO COM hexa,22 CP/M BDOS 3.1 10E>testuid E:TESTUID COM getuid=10 setuid=0 getuid=3 getuid=3 10E>teststr E:TESTSTR COM strcmp test: - test<>Test=1 - test<>test=0 - test1<>test=1 - test<>test1=-1 - rest<>test=-1 stricmp test: - test<>Test=0 - test<>test=0 - test1<>test=1 - test<>test1=-1 - rest<>test=-1 strnicmp test: - test<>test1=0 - test1<>test=0 - Test1<>test=0 10E>testbios E:TESTBIOS COM Z3ENV is not established. (This is not an error.) Press a key: rc = 005A, character = Z The next message should say "Did this work?" Did this work? 10E>testbdos E:TESTBDOS COM First some perror() tests ... 0:Unknown error 1:Reading empty space 2:Disc is full 3:Can't close extent 4:Unwritten extent 5:Directory full 6:File pointer out of range 7:File not found 8:Unknown error 9:Invalid FCB 10:Disc has been changed 11:Unknown error 12:Unknown error 13:Unknown error 14:Unknown error 15:Unknown error 16:Unknown error 17:Disc I/O error 18:Disc is read-only 19:File is read-only 20:Invalid drive 21:File already open 22:Unknown error 23:Password error 24:File exists 25:Ambiguous filename 26:File is wheel protected 27:Unknown error 10E>testtrig E:TESTTRIG COM n LN EXP SIN COS ATAN 01 0.000000e+00 2.718282e+00 8.414710e-01 5.403027e-01 7.853984e-01 02 6.931472e-01 7.389057e+00 9.092979e-01 -4.161470e-01 1.107149e+00 03 1.098612e+00 2.008553e+01 1.411210e-01 -9.899925e-01 1.249046e+00 04 1.386294e+00 5.459816e+01 -7.568022e-01 -6.536458e-01 1.325818e+00 05 1.609438e+00 1.484131e+02 -9.589247e-01 2.836612e-01 1.373401e+00 06 1.791759e+00 4.034287e+02 -2.794167e-01 9.601700e-01 1.405648e+00 07 1.945910e+00 1.096633e+03 6.569862e-01 7.539034e-01 1.428900e+00 08 2.079441e+00 2.980960e+03 9.893584e-01 -1.454998e-01 1.446442e+00 09 2.197225e+00 8.103081e+03 4.121198e-01 -9.111303e-01 1.460140e+00 10 2.302585e+00 2.202647e+04 -5.440199e-01 -8.390721e-01 1.471128e+00 11 2.397895e+00 5.987416e+04 -9.999902e-01 4.425162e-03 1.480137e+00 12 2.484906e+00 1.627547e+05 -5.365752e-01 8.438536e-01 1.487656e+00 13 2.564949e+00 4.424134e+05 4.201660e-01 9.074473e-01 1.494025e+00 14 2.639057e+00 1.202605e+06 9.906074e-01 1.367387e-01 1.499489e+00 15 2.708050e+00 3.269020e+06 6.502893e-01 -7.596868e-01 1.504229e+00 16 2.772589e+00 8.886121e+06 -2.879014e-01 -9.576599e-01 1.508378e+00 17 2.833213e+00 2.415499e+07 -9.613971e-01 -2.751643e-01 1.512041e+00 18 2.890371e+00 6.565992e+07 -7.509893e-01 6.603170e-01 1.515298e+00 19 2.944439e+00 1.784822e+08 1.498742e-01 9.887048e-01 1.518214e+00 10E>testftim E:TESTFTIM COM 34: 01:50 PM Tue Sep 02 13:50:07 2025 10E>testfile E:TESTFILE COM create file... rename file (0) delete file (0) delete file (255) create file... 10E>testaes E:TESTAES COM txt: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF key: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F --- enc: 8E A2 B7 CA 51 67 45 BF EA FC 49 90 4B 49 60 89 tst: 8e a2 b7 ca 51 67 45 bf ea fc 49 90 4b 49 60 89 dec: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 10E>testrc E:TESTRC COM 10E>testview testh*.c testver.c E:TESTVIEW COM 1: TESTHELL.C #include int main() { printf("Hello\n"); } 2: TESTVER.C #include "stdio.h" #include "cpm.h" #include extern char _exact; /* exact file size mode */ extern char *_libcver; /* LIBC version string */ int main(int argc, char ** argv) { int i; int minor=0; int major=0; int machine; int system; int* bdosaddr=(int*)6; int* biosaddr=(int*)1; unsigned int tpa; i=bdos(CPMVERS,0); switch(i) { case 0x00: major=1; minor=0; break; default: major=((i>>4)&0x0F); minor=(i&0x0F); break; } machine=(i>>12)&0x0F; system=(i>>8)&0x0F; printf("CP/M BDOS Version (%d.%d)\n",major,minor); if(system!=0) { printf("Network (%s%s%s)\n",system&0x01?"[MP/M]":"",system&0x02?"[CP/Net]":"", system&0x04?"[Multi User]":""); } switch(machine) { case 0: printf("Machine (MCS80/Z80)\n",machine); break; case 1: printf("Machine (MCS86)\n"); break; case 2: printf("Machine (68000/Z8000)\n"); break; default: printf("Machine (?)\n"); break; } printf("BDOS Address (0x%04x)\n",*bdosaddr-6); printf("BIOS Address (0x%04x)\n",*biosaddr-3); tpa=((*bdosaddr-6)-0x100); fprintf(stdout,"TPA Size (%u.%uK)\n",tpa/1024,(tpa % 1024)/100); fprintf(stdout,"C library version %s\n",_libcver); switch(_exact) { case 'C': printf("Exact file size not used (CP/M 2 mode)\n"); break; case 'D': printf("Using DOS Plus exact file size mode\n"); break; case 'I': printf("Using ISIS exact file size mode\n"); default: printf("Unknown exact file size mode 0%xH\n",_exact); break; } return 0; } 10E>testwild test*.c test*.com E:TESTWILD COM Program name: TESTWILD 1: TESTBDOS.C 2: TESTAES.C 3: TESTARGS.C 4: TESTBIOS.C 5: TESTBUG.C 6: TESTENV.C 7: TESTFILE.C 8: TESTFTIM.C 9: TESTHELL.C 10: TESTIO.C 11: TESTL.C 12: TESTLTOF.C 13: TESTOVR.C 14: TESTOVR1.C 15: TESTOVR2.C 16: TESTPR.C 17: TESTPWD.C 18: TESTQSRT.C 19: TESTRC.C 20: TESTREL.C 21: TESTSTR.C 22: TESTSUB.C 23: TESTTRIG.C 24: TESTUID.C 25: TESTVER.C 26: TESTVIEW.C 27: TESTWILD.C 28: TESTARGS.COM 29: TESTBDOS.COM 30: TESTAES.COM 31: TESTVER.COM 32: TESTBIOS.COM 33: TESTFILE.COM 34: TESTFTIM.COM 35: TESTHELL.COM 36: TESTIO.COM 37: TESTOVR.COM 38: TESTPR.COM 39: TESTRC.COM 40: TESTSTR.COM 41: TESTTRIG.COM 42: TESTUID.COM 43: TESTVIEW.COM 44: TESTWILD.COM 10E>testhell E:TESTHELL COM Hello 10E>testpr E:TESTPR COM len: 320 string: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 10E>filesize test*.* E:FILESIZE COM argc = 65 Bytes File ftell() fopen() Sectors kB ----------------- --------- --------- ------- ----- TESTBDOS.C 1280 1280 10 2 TESTARGS.COM 12544 12544 98 13 TESTBDOS.COM 13568 13568 106 14 TEST.LOG 19072 19072 149 19 TEST-OPT.AS 896 896 7 1 TESTAES.C 13952 13952 109 14 TESTAES.COM 17152 17152 134 17 TESTARGS.C 256 256 2 1 TESTBIOS.C 1280 1280 10 2 TESTBUG.AS 4480 4480 35 5 TESTBUG.C 512 512 4 1 TESTENV.C 256 256 2 1 TESTFILE.C 896 896 7 1 TESTFTIM.C 512 512 4 1 TESTHELL.C 128 128 1 1 TESTIO.C 768 768 6 1 TESTIO.ERR 15 15 1 1 TESTIO.STA 8 8 1 1 TESTL.C 128 128 1 1 TESTLTOF.AS 8576 8576 67 9 TESTLTOF.C 1408 1408 11 2 TESTOPTH.AS 384 384 3 1 TESTOVR.C 512 512 4 1 TESTOVR1.C 128 128 1 1 TESTOVR2.C 128 128 1 1 TESTPR.C 640 640 5 1 TESTPWD.C 1152 1152 9 2 TESTQSRT.C 768 768 6 1 TESTRC.C 256 256 2 1 TESTOVR2.OBJ 256 256 2 1 TESTREL.C 128 128 1 1 TESTSTR.C 896 896 7 1 TESTSUB.C 1280 1280 10 2 TESTTRIG.C 4480 4480 35 5 TESTUID.C 384 384 3 1 TESTVER.C 1920 1920 15 2 TESTVER.SUB 128 128 1 1 TESTVIEW.C 1024 1024 8 1 TESTWILD.C 896 896 7 1 TESTVER.COM 13952 13952 109 14 TEST.DAT 7 7 1 1 TESTBIOS.COM 13824 13824 108 14 TESTFILE.COM 13696 13696 107 14 TESTFTIM.COM 16640 16640 130 17 TESTHELL.COM 9472 9472 74 10 TESTIO.COM 13568 13568 106 14 TESTOVR.COM 13824 13824 108 14 TESTOVR1.OVR 128 128 1 1 TESTOVR2.OVR 128 128 1 1 TESTOVRX.SYM 2688 2688 21 3 TESTPR.COM 13568 13568 106 14 TESTRC.COM 13056 13056 102 13 TESTSTR.COM 13824 13824 108 14 TESTTRIG.COM 18688 18688 146 19 TESTUID.COM 13184 13184 103 13 TESTVIEW.COM 13312 13312 104 13 TESTWILD.COM 13184 13184 103 13 TEST280.LOG 24064 24064 188 24 TEST-OPT.AS2 1311 1311 11 2 TEST.SUB 896 896 7 1 TEST280.SUB 1024 1024 8 1 TEST-OPT.AS3 1214 1214 10 2 TESTOVRX.OBJ 2944 2944 23 3 TESTOVR1.OBJ 256 256 2 1 10E>; All tests completed 10E>put console to console A:PUT COM (User 0) ================================================ FILE: test/TEST.SUB ================================================ era test.log put console output to file test.log [system] date ; Compile all tests c -v -o filesize.c c -v -o testver.c c -v -o testio.c c -v -o testuid.c c -v -o teststr.c c -v -o testbios.c c -v -o testbdos.c c -v -o testtrig.c -lf c -v -o testftim.c c -v -o testfile.c c -v -o testaes.c c -v -o testrc.c c -v -o testview.c c -v -o testwild.c c -ftestovrx.sym -v -o testovr.c -lovr c -y -o -v testovr2.c testovrx.sym c -y -o -v testovr1.c testovrx.sym c -a -v -o testhell.c c -v -o testpr.c testver era testio.sta era testio.out era testio.err testovr testio testuid teststr testbios testbdos testtrig testftim testfile testaes testrc testview testh*.c testver.c testwild test*.c test*.com testhell testpr filesize test*.* ; All tests completed put console to console ================================================ FILE: test/TEST280.LOG ================================================ 10E>date A:DATE COM (User 0) Tue 02/09/2025 13:51:35 10E>; Compile all test280 10E>c280 -v -o2 filesize.c A:C280 COM (User 0) 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: FILESIZE.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.$$$ 57 bytes size optimised away 123 bytes replaced 0:A:ZAS -J -N -OFILESIZE.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OFILESIZE.COM 0:A:C280CPM.OBJ FILESIZE.OBJ 0:A:LIB280C.LIB ERA FILESIZE.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testver.c A:C280 COM (User 0) 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: TESTVER.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.$$$ 34 bytes size optimised away 74 bytes replaced 0:A:ZAS -J -N -OTESTVER.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTVER.COM 0:A:C280CPM.OBJ TESTVER.OBJ 0:A:LIB280C.LIB ERA TESTVER.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testio.c A:C280 COM (User 0) 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: TESTIO.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.$$$ 32 bytes size optimised away 66 bytes replaced 0:A:ZAS -J -N -OTESTIO.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTIO.COM 0:A:C280CPM.OBJ TESTIO.OBJ 0:A:LIB280C.LIB ERA TESTIO.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testuid.c A:C280 COM (User 0) 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: TESTUID.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTUID.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTUID.COM 0:A:C280CPM.OBJ TESTUID.OBJ 0:A:LIB280C.LIB ERA TESTUID.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 teststr.c A:C280 COM (User 0) 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: TESTSTR.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.$$$ 28 bytes size optimised away 72 bytes replaced 0:A:ZAS -J -N -OTESTSTR.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTSTR.COM 0:A:C280CPM.OBJ TESTSTR.OBJ 0:A:LIB280C.LIB ERA TESTSTR.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testbios.c A:C280 COM (User 0) 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: TESTBIOS.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.$$$ 20 bytes size optimised away 42 bytes replaced 0:A:ZAS -J -N -OTESTBIOS.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTBIOS.COM 0:A:C280CPM.OBJ TESTBIOS.OBJ 0:A:LIB280C.LIB ERA TESTBIOS.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testbdos.c A:C280 COM (User 0) 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: TESTBDOS.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.$$$ 43 bytes size optimised away 66 bytes replaced 0:A:ZAS -J -N -OTESTBDOS.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTBDOS.COM 0:A:C280CPM.OBJ TESTBDOS.OBJ 0:A:LIB280C.LIB ERA TESTBDOS.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testtrig.c -lf A:C280 COM (User 0) 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: TESTTRIG.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTTRIG.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTTRIG.COM 0:A:C280CPM.OBJ TESTTRIG.OBJ 0:A:LIB280F.LIB 0:A:LIB280C.LIB ERA TESTTRIG.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testftim.c A:C280 COM (User 0) 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: TESTFTIM.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.$$$ 19 bytes size optimised away 30 bytes replaced 0:A:ZAS -J -N -OTESTFTIM.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTFTIM.COM 0:A:C280CPM.OBJ TESTFTIM.OBJ 0:A:LIB280C.LIB ERA TESTFTIM.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testfile.c A:C280 COM (User 0) 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: TESTFILE.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.$$$ 18 bytes size optimised away 36 bytes replaced 0:A:ZAS -J -N -OTESTFILE.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTFILE.COM 0:A:C280CPM.OBJ TESTFILE.OBJ 0:A:LIB280C.LIB ERA TESTFILE.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testaes.c A:C280 COM (User 0) 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: TESTAES.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.$$$ 264 bytes size optimised away 553 bytes replaced 0:A:ZAS -J -N -OTESTAES.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTAES.COM 0:A:C280CPM.OBJ TESTAES.OBJ 0:A:LIB280C.LIB ERA TESTAES.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testrc.c A:C280 COM (User 0) 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: TESTRC.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTRC.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTRC.COM 0:A:C280CPM.OBJ TESTRC.OBJ 0:A:LIB280C.LIB ERA TESTRC.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testview.c A:C280 COM (User 0) 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: TESTVIEW.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.$$$ 33 bytes size optimised away 66 bytes replaced 0:A:ZAS -J -N -OTESTVIEW.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTVIEW.COM 0:A:C280CPM.OBJ TESTVIEW.OBJ 0:A:LIB280C.LIB ERA TESTVIEW.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testwild.c A:C280 COM (User 0) 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: TESTWILD.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.$$$ 14 bytes size optimised away 32 bytes replaced 0:A:ZAS -J -N -OTESTWILD.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTWILD.COM 0:A:C280CPM.OBJ TESTWILD.OBJ 0:A:LIB280C.LIB ERA TESTWILD.OBJ ERA M:$$EXEC.$$$ 10E>c280 -ftestovrx.sym -v -o2 testovr.c -lovr A:C280 COM (User 0) 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: TESTOVR.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.$$$ 8 bytes size optimised away 16 bytes replaced 0:A:ZAS -J -N -OTESTOVR.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -DTESTOVRX.SYM -Ptext=0,data,bss -C100H -OTESTOVR.COM 0:A:C280CPM.OBJ TESTOVR.OBJ 0:A:LIB280OVR.LIB 0:A:LIB280C.LIB ERA TESTOVR.OBJ ERA M:$$EXEC.$$$ 10E>c280 -y -o2 -v testovr2.c testovrx.sym A:C280 COM (User 0) 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 TESTOVR2.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: TESTOVR2.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTOVR2.OBJ M:$CTMP5.$$$ 0:A:SYMTOAS TESTOVRX.SYM M:$CTMP5.$$$ TESTOVRX.SYM 0:A:ZAS -OTESTOVRX.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=031C2h,data -C31C2H -OTESTOVR2.OVR TESTOVR2.OBJ TESTOVRX.OBJ ERA M:$$EXEC.$$$ 10E>c280 -y -o2 -v testovr1.c testovrx.sym A:C280 COM (User 0) 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 TESTOVR1.C 0:A:CPP -DCPM -DHI_TECH_C -Dz80 -DZ280 -I0:A: TESTOVR1.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTOVR1.OBJ M:$CTMP5.$$$ 0:A:SYMTOAS TESTOVRX.SYM M:$CTMP5.$$$ TESTOVRX.SYM 0:A:ZAS -OTESTOVRX.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=031C2h,data -C31C2H -OTESTOVR1.OVR TESTOVR1.OBJ TESTOVRX.OBJ ERA M:$$EXEC.$$$ 10E>c280 -a -v -o2 testhell.c -lc A:C280 COM (User 0) 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: TESTHELL.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTHELL.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -L -Pcpm=0,text,data,bss,stack -OM:$L.OBJ 0:A:R280CPM.OBJ TESTHELL.OBJ 0:A:LIB280C.LIB 0:A:LIB280C.LIB 0:A:OBJTOHEX -R -B100H M:$L.OBJ TESTHELL.COM ERA M:$L.OBJ ERA TESTHELL.OBJ ERA M:$$EXEC.$$$ 10E>c280 -v -o2 testpr.c A:C280 COM (User 0) 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: TESTPR.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.$$$ 0 bytes size optimised away 0 bytes replaced 0:A:ZAS -J -N -OTESTPR.OBJ M:$CTMP5.$$$ ERA M:$CTMP1.$$$ ERA M:$CTMP2.$$$ ERA M:$CTMP3.$$$ ERA M:$CTMP5.$$$ 0:A:LINQ -Z -Ptext=0,data,bss -C100H -OTESTPR.COM 0:A:C280CPM.OBJ TESTPR.OBJ 0:A:LIB280C.LIB ERA TESTPR.OBJ ERA M:$$EXEC.$$$ 10E>testver E:TESTVER COM CP/M BDOS Version (3.1) Machine (MCS80/Z80) BDOS Address (0xE500) BIOS Address (0xF800) TPA Size (57.0K) C library version LIB280C 3.09-20 Using DOS Plus exact file size mode 10E>era testio.sta 10E>era testio.out No File 10E>era testio.err 10E>testovr E: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 10E>testio E:TESTIO COM hexa,22 CP/M BDOS 3.1 10E>testuid E:TESTUID COM getuid=10 setuid=0 getuid=3 getuid=3 10E>teststr E:TESTSTR COM strcmp test: - test<>Test=1 - test<>test=0 - test1<>test=1 - test<>test1=-1 - rest<>test=-1 stricmp test: - test<>Test=0 - test<>test=0 - test1<>test=1 - test<>test1=-1 - rest<>test=-1 strnicmp test: - test<>test1=0 - test1<>test=0 - Test1<>test=0 10E>testbios E:TESTBIOS COM Z3ENV is not established. (This is not an error.) Press a key: rc = 005A, character = Z The next message should say "Did this work?" Did this work? 10E>testbdos E:TESTBDOS COM First some perror() tests ... 0:Unknown error 1:Reading empty space 2:Disc is full 3:Can't close extent 4:Unwritten extent 5:Directory full 6:File pointer out of range 7:File not found 8:Unknown error 9:Invalid FCB 10:Disc has been changed 11:Unknown error 12:Unknown error 13:Unknown error 14:Unknown error 15:Unknown error 16:Unknown error 17:Disc I/O error 18:Disc is read-only 19:File is read-only 20:Invalid drive 21:File already open 22:Unknown error 23:Password error 24:File exists 25:Ambiguous filename 26:File is wheel protected 27:Unknown error 10E>testtrig E:TESTTRIG COM n LN EXP SIN COS ATAN 01 0.000000e+00 2.718281e+00 8.414713e-01 5.403028e-01 7.853984e-01 02 6.931472e-01 7.389053e+00 9.092976e-01 -4.161476e-01 1.107149e+00 03 1.098612e+00 2.008552e+01 1.411195e-01 -9.899930e-01 1.249045e+00 04 1.386294e+00 5.459809e+01 -7.568034e-01 -6.536440e-01 1.325817e+00 05 1.609438e+00 1.484130e+02 -9.589241e-01 2.836642e-01 1.373401e+00 06 1.791759e+00 4.034281e+02 -2.794138e-01 9.601711e-01 1.405647e+00 07 1.945910e+00 1.096632e+03 6.569884e-01 7.539010e-01 1.428899e+00 08 2.079441e+00 2.980951e+03 9.893582e-01 -1.455027e-01 1.446441e+00 09 2.197225e+00 8.103070e+03 4.121158e-01 -9.111318e-01 1.460139e+00 10 2.302585e+00 2.202641e+04 -5.440236e-01 -8.390698e-01 1.471127e+00 11 2.397895e+00 5.987400e+04 -9.999905e-01 4.429656e-03 1.480136e+00 12 2.484906e+00 1.627543e+05 -5.365700e-01 8.438562e-01 1.487655e+00 13 2.564949e+00 4.424122e+05 4.201716e-01 9.074452e-01 1.494024e+00 14 2.639058e+00 1.202601e+06 9.906083e-01 1.367328e-01 1.499489e+00 15 2.708050e+00 3.269011e+06 6.502848e-01 -7.596909e-01 1.504228e+00 16 2.772589e+00 8.886073e+06 -2.879071e-01 -9.576581e-01 1.508378e+00 17 2.833213e+00 2.415486e+07 -9.613985e-01 -2.751586e-01 1.512040e+00 18 2.890371e+00 6.565974e+07 -7.509834e-01 6.603216e-01 1.515297e+00 19 2.944439e+00 1.784818e+08 1.498831e-01 9.887040e-01 1.518213e+00 10E>testftim E:TESTFTIM COM 34: 02:05 PM Tue Sep 02 14:05:05 2025 10E>testfile E:TESTFILE COM create file... rename file (0) delete file (0) delete file (255) create file... 10E>testaes E:TESTAES COM txt: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF key: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F --- enc: 8E A2 B7 CA 51 67 45 BF EA FC 49 90 4B 49 60 89 tst: 8e a2 b7 ca 51 67 45 bf ea fc 49 90 4b 49 60 89 dec: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 10E>testrc E:TESTRC COM 10E>testview testh*.c testver.c E:TESTVIEW COM 1: TESTHELL.C #include int main() { printf("Hello\n"); } 2: TESTVER.C #include "stdio.h" #include "cpm.h" #include extern char _exact; /* exact file size mode */ extern char *_libcver; /* LIBC version string */ int main(int argc, char ** argv) { int i; int minor=0; int major=0; int machine; int system; int* bdosaddr=(int*)6; int* biosaddr=(int*)1; unsigned int tpa; i=bdos(CPMVERS,0); switch(i) { case 0x00: major=1; minor=0; break; default: major=((i>>4)&0x0F); minor=(i&0x0F); break; } machine=(i>>12)&0x0F; system=(i>>8)&0x0F; printf("CP/M BDOS Version (%d.%d)\n",major,minor); if(system!=0) { printf("Network (%s%s%s)\n",system&0x01?"[MP/M]":"",system&0x02?"[CP/Net]":"", system&0x04?"[Multi User]":""); } switch(machine) { case 0: printf("Machine (MCS80/Z80)\n",machine); break; case 1: printf("Machine (MCS86)\n"); break; case 2: printf("Machine (68000/Z8000)\n"); break; default: printf("Machine (?)\n"); break; } printf("BDOS Address (0x%04x)\n",*bdosaddr-6); printf("BIOS Address (0x%04x)\n",*biosaddr-3); tpa=((*bdosaddr-6)-0x100); fprintf(stdout,"TPA Size (%u.%uK)\n",tpa/1024,(tpa % 1024)/100); fprintf(stdout,"C library version %s\n",_libcver); switch(_exact) { case 'C': printf("Exact file size not used (CP/M 2 mode)\n"); break; case 'D': printf("Using DOS Plus exact file size mode\n"); break; case 'I': printf("Using ISIS exact file size mode\n"); default: printf("Unknown exact file size mode 0%xH\n",_exact); break; } return 0; } 10E>testwild test*.c test*.com E:TESTWILD COM Program name: TESTWILD 1: TESTBDOS.C 2: TESTAES.C 3: TESTARGS.C 4: TESTBIOS.C 5: TESTBUG.C 6: TESTENV.C 7: TESTFILE.C 8: TESTFTIM.C 9: TESTHELL.C 10: TESTIO.C 11: TESTL.C 12: TESTLTOF.C 13: TESTOVR.C 14: TESTOVR1.C 15: TESTOVR2.C 16: TESTPR.C 17: TESTPWD.C 18: TESTQSRT.C 19: TESTRC.C 20: TESTREL.C 21: TESTSTR.C 22: TESTSUB.C 23: TESTTRIG.C 24: TESTUID.C 25: TESTVER.C 26: TESTVIEW.C 27: TESTWILD.C 28: TESTARGS.COM 29: TESTBDOS.COM 30: TESTAES.COM 31: TESTVER.COM 32: TESTBIOS.COM 33: TESTFILE.COM 34: TESTFTIM.COM 35: TESTHELL.COM 36: TESTIO.COM 37: TESTOVR.COM 38: TESTPR.COM 39: TESTRC.COM 40: TESTSTR.COM 41: TESTTRIG.COM 42: TESTUID.COM 43: TESTVIEW.COM 44: TESTWILD.COM 10E>testhell E:TESTHELL COM Hello 10E>testpr E:TESTPR COM len: 320 string: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 10E>filesize test*.* E:FILESIZE COM argc = 65 Bytes File ftell() fopen() Sectors kB ----------------- --------- --------- ------- ----- TESTBDOS.C 1280 1280 10 2 TESTARGS.COM 12544 12544 98 13 TESTBDOS.COM 12288 12288 96 12 TEST.LOG 22912 22912 179 23 TEST-OPT.AS 896 896 7 1 TESTAES.C 13952 13952 109 14 TESTAES.COM 15616 15616 122 16 TESTARGS.C 256 256 2 1 TESTBIOS.C 1280 1280 10 2 TESTBUG.AS 4480 4480 35 5 TESTBUG.C 512 512 4 1 TESTENV.C 256 256 2 1 TESTFILE.C 896 896 7 1 TESTFTIM.C 512 512 4 1 TESTHELL.C 128 128 1 1 TESTIO.C 768 768 6 1 TESTIO.ERR 15 15 1 1 TESTIO.STA 8 8 1 1 TESTL.C 128 128 1 1 TESTLTOF.AS 8576 8576 67 9 TESTLTOF.C 1408 1408 11 2 TESTOPTH.AS 384 384 3 1 TESTOVR.C 512 512 4 1 TESTOVR1.C 128 128 1 1 TESTOVR2.C 128 128 1 1 TESTPR.C 640 640 5 1 TESTPWD.C 1152 1152 9 2 TESTQSRT.C 768 768 6 1 TESTRC.C 256 256 2 1 TESTOVR2.OBJ 256 256 2 1 TESTREL.C 128 128 1 1 TESTSTR.C 896 896 7 1 TESTSUB.C 1280 1280 10 2 TESTTRIG.C 4480 4480 35 5 TESTUID.C 384 384 3 1 TESTVER.C 1920 1920 15 2 TESTVER.SUB 128 128 1 1 TESTVIEW.C 1024 1024 8 1 TESTWILD.C 896 896 7 1 TESTVER.COM 12800 12800 100 13 TEST.DAT 7 7 1 1 TESTBIOS.COM 12544 12544 98 13 TESTFILE.COM 12416 12416 97 13 TESTFTIM.COM 15104 15104 118 15 TESTHELL.COM 8704 8704 68 9 TESTIO.COM 12288 12288 96 12 TESTOVR.COM 12544 12544 98 13 TESTOVR1.OVR 128 128 1 1 TESTOVR2.OVR 128 128 1 1 TESTOVRX.SYM 2688 2688 21 3 TESTPR.COM 12416 12416 97 13 TESTRC.COM 11904 11904 93 12 TESTSTR.COM 12672 12672 99 13 TESTTRIG.COM 17024 17024 133 17 TESTUID.COM 12032 12032 94 12 TESTVIEW.COM 12160 12160 95 12 TESTWILD.COM 12032 12032 94 12 TEST280.LOG 21120 21120 165 21 TEST-OPT.AS2 1311 1311 11 2 TEST.SUB 896 896 7 1 TEST280.SUB 1024 1024 8 1 TEST-OPT.AS3 1214 1214 10 2 TESTOVRX.OBJ 2944 2944 23 3 TESTOVR1.OBJ 256 256 2 1 10E>; Z280 optimiser 10E>optimh -f test-opt.as test-opt.as2 E:OPTIMH COM 15 bytes speed optimised away 68 bytes replaced 10E>optimh test-opt.as test-opt.as3 E:OPTIMH COM 25 bytes size optimised away 62 bytes replaced 10E>; All tests completed 10E>put console to console A:PUT COM (User 0) ================================================ FILE: test/TEST280.SUB ================================================ era test280.log put console output to file test280.log [system] date ; Compile all test280 c280 -v -o2 filesize.c c280 -v -o2 testver.c c280 -v -o2 testio.c c280 -v -o2 testuid.c c280 -v -o2 teststr.c c280 -v -o2 testbios.c c280 -v -o2 testbdos.c c280 -v -o2 testtrig.c -lf c280 -v -o2 testftim.c c280 -v -o2 testfile.c c280 -v -o2 testaes.c c280 -v -o2 testrc.c c280 -v -o2 testview.c c280 -v -o2 testwild.c c280 -ftestovrx.sym -v -o2 testovr.c -lovr c280 -y -o2 -v testovr2.c testovrx.sym c280 -y -o2 -v testovr1.c testovrx.sym c280 -a -v -o2 testhell.c -lc c280 -v -o2 testpr.c testver era testio.sta era testio.out era testio.err testovr testio testuid teststr testbios testbdos testtrig testftim testfile testaes testrc testview testh*.c testver.c testwild test*.c test*.com testhell testpr filesize test*.* ; Z280 optimiser optimh -f test-opt.as test-opt.as2 optimh test-opt.as test-opt.as3 ; All tests completed put console to console ================================================ FILE: test/TESTAES.C ================================================ /* * Byte-oriented AES-256 implementation. * All lookup tables replaced with 'on the fly' calculations. * * Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com * Other contributors: Hal Finney * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Some minor changes made for CP/M-80 C compiler compatibility * from Peter Dassow, see http://www.z80.eu/c-compiler.html */ typedef unsigned char uint8_t; typedef struct { uint8_t key[32]; uint8_t enckey[32]; uint8_t deckey[32]; } aes256_context; typedef uint8_t * u8ptr; typedef aes256_context * aes256_ptr; #define F(x) (((x)<<1) ^ ((((x)>>7) & 1) * 0x1b)) #define FD(x) (((x) >> 1) ^ (((x) & 1) ? 0x8d : 0)) /* #define BACK_TO_TABLES */ #ifdef BACK_TO_TABLES const uint8_t sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; const uint8_t sboxinv[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; #define rj_sbox(x) sbox[(x)] #define rj_sb_inv(x) sboxinv[(x)] #else /* tableless subroutines */ /* -------------------------------------------------------------------------- */ uint8_t gf_alog(x) /* calculate anti-logarithm gen 3 */ uint8_t x; { uint8_t atb = 1, z; while (x--) {z = atb; atb <<= 1; if (z & 0x80) atb^= 0x1b; atb ^= z;} return atb; } /* gf_alog */ /* -------------------------------------------------------------------------- */ uint8_t gf_log(x) /* calculate logarithm gen 3 */ uint8_t x; { uint8_t atb = 1, i = 0, z; do { if (atb == x) break; z = atb; atb <<= 1; if (z & 0x80) atb^= 0x1b; atb ^= z; } while (++i > 0); return i; } /* gf_log */ /* -------------------------------------------------------------------------- */ uint8_t gf_mulinv(x) /* calculate multiplicative inverse */ uint8_t x; { return (x) ? gf_alog(255 - gf_log(x)) : 0; } /* gf_mulinv */ /* -------------------------------------------------------------------------- */ uint8_t rj_sbox(x) uint8_t x; { uint8_t y, sb; sb = y = gf_mulinv(x); y = (y<<1)|(y>>7); sb ^= y; y = (y<<1)|(y>>7); sb ^= y; y = (y<<1)|(y>>7); sb ^= y; y = (y<<1)|(y>>7); sb ^= y; return (sb ^ 0x63); } /* rj_sbox */ /* -------------------------------------------------------------------------- */ uint8_t rj_sb_inv(x) uint8_t x; { uint8_t y, sb; y = x ^ 0x63; sb = y = (y<<1)|(y>>7); y = (y<<2)|(y>>6); sb ^= y; y = (y<<3)|(y>>5); sb ^= y; return gf_mulinv(sb); } /* rj_sb_inv */ #endif /* -------------------------------------------------------------------------- */ uint8_t rj_xtime(x) uint8_t x; { return (x & 0x80) ? ((x << 1) ^ 0x1b) : (x << 1); } /* rj_xtime */ /* -------------------------------------------------------------------------- */ void aes_subBytes(buf) uint8_t *buf; { register uint8_t i = 16; while (i--) buf[i] = rj_sbox(buf[i]); } /* aes_subBytes */ /* -------------------------------------------------------------------------- */ void aes_sb_inv(buf) u8ptr buf; { register uint8_t i = 16; while (i--) buf[i] = rj_sb_inv(buf[i]); } /* aes_sb_inv */ /* -------------------------------------------------------------------------- */ void aes_addRoundKey(buf,key) u8ptr buf,key; { register uint8_t i = 16; while (i--) buf[i] ^= key[i]; } /* aes_addRoundKey */ /* -------------------------------------------------------------------------- */ void aes_ar_cpy(buf,key,cpk) u8ptr buf,key,cpk; { register uint8_t i = 16; while (i--) buf[i] ^= (cpk[i] = key[i]), cpk[16+i] = key[16 + i]; } /* aes_ar_cpy */ /* -------------------------------------------------------------------------- */ void aes_shiftRows(buf) u8ptr buf; { register uint8_t i, j; /* to make it potentially parallelable :) */ i = buf[1]; buf[1] = buf[5]; buf[5] = buf[9]; buf[9] = buf[13]; buf[13] = i; i = buf[10]; buf[10] = buf[2]; buf[2] = i; j = buf[3]; buf[3] = buf[15]; buf[15] = buf[11]; buf[11] = buf[7]; buf[7] = j; j = buf[14]; buf[14] = buf[6]; buf[6] = j; } /* aes_shiftRows */ /* -------------------------------------------------------------------------- */ void aes_sr_inv(buf) u8ptr buf; { register uint8_t i, j; /* same as above :) */ i = buf[1]; buf[1] = buf[13]; buf[13] = buf[9]; buf[9] = buf[5]; buf[5] = i; i = buf[2]; buf[2] = buf[10]; buf[10] = i; j = buf[3]; buf[3] = buf[7]; buf[7] = buf[11]; buf[11] = buf[15]; buf[15] = j; j = buf[6]; buf[6] = buf[14]; buf[14] = j; } /* aes_sr_inv */ /* -------------------------------------------------------------------------- */ void aes_mixColumns(buf) u8ptr buf; { register uint8_t i, a, b, c, d, e; for (i = 0; i < 16; i += 4) { a = buf[i]; b = buf[i + 1]; c = buf[i + 2]; d = buf[i + 3]; e = a ^ b ^ c ^ d; buf[i] ^= e ^ rj_xtime(a^b); buf[i+1] ^= e ^ rj_xtime(b^c); buf[i+2] ^= e ^ rj_xtime(c^d); buf[i+3] ^= e ^ rj_xtime(d^a); } } /* aes_mixColumns */ /* -------------------------------------------------------------------------- */ void aes_mc_inv(buf) u8ptr buf; { register uint8_t i, a, b, c, d, e, x, y, z; for (i = 0; i < 16; i += 4) { a = buf[i]; b = buf[i + 1]; c = buf[i + 2]; d = buf[i + 3]; e = a ^ b ^ c ^ d; z = rj_xtime(e); x = e ^ rj_xtime(rj_xtime(z^a^c)); y = e ^ rj_xtime(rj_xtime(z^b^d)); buf[i] ^= x ^ rj_xtime(a^b); buf[i+1] ^= y ^ rj_xtime(b^c); buf[i+2] ^= x ^ rj_xtime(c^d); buf[i+3] ^= y ^ rj_xtime(d^a); } } /* aes_mc_inv */ /* -------------------------------------------------------------------------- */ void aes_expandEncKey(k,rc) u8ptr k, rc; { register uint8_t i; k[0] ^= rj_sbox(k[29]) ^ (*rc); k[1] ^= rj_sbox(k[30]); k[2] ^= rj_sbox(k[31]); k[3] ^= rj_sbox(k[28]); *rc = F( *rc); for(i = 4; i < 16; i += 4) { k[i] ^= k[i-4]; k[i+1] ^= k[i-3]; k[i+2] ^= k[i-2]; k[i+3] ^= k[i-1]; } k[16] ^= rj_sbox(k[12]); k[17] ^= rj_sbox(k[13]); k[18] ^= rj_sbox(k[14]); k[19] ^= rj_sbox(k[15]); for(i = 20; i < 32; i += 4) { k[i] ^= k[i-4]; k[i+1] ^= k[i-3]; k[i+2] ^= k[i-2]; k[i+3] ^= k[i-1]; } } /* aes_expandEncKey */ /* -------------------------------------------------------------------------- */ void aes_expDecKey(k, rc) u8ptr k, rc; { uint8_t i; for(i = 28; i > 16; i -= 4) { k[i+0] ^= k[i-4]; k[i+1] ^= k[i-3]; k[i+2] ^= k[i-2]; k[i+3] ^= k[i-1]; } k[16] ^= rj_sbox(k[12]); k[17] ^= rj_sbox(k[13]); k[18] ^= rj_sbox(k[14]); k[19] ^= rj_sbox(k[15]); for(i = 12; i > 0; i -= 4) { k[i+0] ^= k[i-4]; k[i+1] ^= k[i-3]; k[i+2] ^= k[i-2]; k[i+3] ^= k[i-1]; } *rc = FD(*rc); k[0] ^= rj_sbox(k[29]) ^ (*rc); k[1] ^= rj_sbox(k[30]); k[2] ^= rj_sbox(k[31]); k[3] ^= rj_sbox(k[28]); } /* aes_expDecKey */ /* -------------------------------------------------------------------------- */ void aes256_init(ctx, k) aes256_ptr ctx; u8ptr k; { uint8_t rcon = 1; register uint8_t i; for (i = 0; i < sizeof(ctx->key); i++) ctx->enckey[i] = ctx->deckey[i] = k[i]; for (i = 8;--i;) aes_expandEncKey(ctx->deckey, &rcon); } /* aes256_init */ /* -------------------------------------------------------------------------- */ void aes_done(ctx) aes256_ptr ctx; { register uint8_t i; for (i = 0; i < sizeof(ctx->key); i++) ctx->key[i] = ctx->enckey[i] = ctx->deckey[i] = 0; } /* aes_done */ /* -------------------------------------------------------------------------- */ void aes256_encrypt_ecb(ctx, buf) aes256_ptr ctx; u8ptr buf; { uint8_t i, rcon; aes_ar_cpy(buf, ctx->enckey, ctx->key); for(i = 1, rcon = 1; i < 14; ++i) { aes_subBytes(buf); aes_shiftRows(buf); aes_mixColumns(buf); if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]); else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key); } aes_subBytes(buf); aes_shiftRows(buf); aes_expandEncKey(ctx->key, &rcon); aes_addRoundKey(buf, ctx->key); } /* aes256_encrypt */ /* -------------------------------------------------------------------------- */ void aes256_decrypt_ecb(ctx, buf) aes256_ptr ctx; u8ptr buf; { uint8_t i, rcon; aes_ar_cpy(buf, ctx->deckey, ctx->key); aes_sr_inv(buf); aes_sb_inv(buf); for (i = 14, rcon = 0x80; --i;) { if( ( i & 1 ) ) { aes_expDecKey(ctx->key, &rcon); aes_addRoundKey(buf, &ctx->key[16]); } else aes_addRoundKey(buf, ctx->key); aes_mc_inv(buf); aes_sr_inv(buf); aes_sb_inv(buf); } aes_addRoundKey( buf, ctx->key); } /* aes256_decrypt */ #define DUMP(s, i, buf, sz) {printf(s); \ for (i = 0; i < (sz);i++) \ printf("%02x ", buf[i]); \ printf("\n");} aes256_context ctx; uint8_t key[32]; uint8_t buf[16]; int main (int argc, char *argv[]) { int i; /* put a test vector */ for (i = 0; i < sizeof(buf);i++) buf[i] = i * 16 + i; for (i = 0; i < sizeof(key);i++) key[i] = i; DUMP("txt: ", i, buf, sizeof(buf)); DUMP("key: ", i, key, sizeof(key)); printf("---\n"); aes256_init(&ctx, key); aes256_encrypt_ecb(&ctx, buf); DUMP("enc: ", i, buf, sizeof(buf)); printf("tst: 8e a2 b7 ca 51 67 45 bf ea fc 49 90 4b 49 60 89\n"); aes256_init(&ctx, key); aes256_decrypt_ecb(&ctx, buf); DUMP("dec: ", i, buf, sizeof(buf)); aes_done(&ctx); return 0; } /* main */ ================================================ FILE: test/TESTARGS.C ================================================ #include #include int main(int argc, char ** argv) { int i; for(i=0;i #include void test(short func, void *data) { int e; short rc = bdose(func, data); e = errno; printf("rc = %04x, errno = %d\n", rc, errno); errno = e; if (errno) perror("test"); } void vogon(char *fn) /* Just for the debugger */ { char fcb[50]; struct _pfcb { char *str; char *fcb; } pfcb; pfcb.fcb = fcb; pfcb.str = fn; test(152, &pfcb); test(15, fcb); } int main(int argc, char *argv[]) { int e; char s[6]; printf("First some perror() tests ...\n\n"); for (e=0; e<28; ++e) { sprintf(s,"%2d",e); errno = e; perror(s); } putchar('\n'); bdose(0x2D, 0xFF); /* test(14,(void *)3); test(14,(void *)6); */ /* vogon("b:zpm3ldr.rel;asdf"); if (argc > 1) vogon(argv[1]); */ return 0; } ================================================ FILE: test/TESTBIOS.C ================================================ /*----------------------------------------------------------------------*\ | TESTBIOS | | | | A small program to test BIOS calls with a variety of parameters. | | | | Written for CP/M 3. May not work on CP/M 2.2. | \*----------------------------------------------------------------------*/ #include #include char src[] = "Did this work?", dst[sizeof src]; int main(int argc, char *argv[], char *z3env) { short rc; if (z3env) printf("Z3ENV at %04x\n"); else puts("Z3ENV is not established. (This is not an error.)"); for (rc = 1; rc < argc; ++rc) printf("%2d: %s\n", argv[rc]); /* BIOS call with no parameters */ printf("Press a key: "); rc = bios(3,0xBCBC,0xDEDE); printf("rc = %04x, character = ", rc); /* BIOS call with one parameter (in BC) */ rc = bios(4, rc, 0xDEDE); /* BIOS call with one parameter (in A) */ rc = bios(27,1,0xBCBC,0xDEDE,0x1414); puts("\nThe next message should say \"Did this work?\""); /* BIOS call with three parameters (BC, DE & HL) */ bios(29,0x0101); bios(25,sizeof src, src, dst); puts(dst); } ================================================ FILE: test/TESTFILE.C ================================================ #include #include #include int main() { FILE * f; int i; fprintf(stderr,"create file...\n"); f=fopen("test.dat","w"); if(!f) { fprintf(stderr,"cannot create file (%d)\n",errno); return -1; } fprintf(f,"Hello\n"); fclose(f); i=rename("test.dat","testx.dat"); fprintf(stderr,"rename file (%d)\n",i); i=unlink("testx.dat"); fprintf(stderr,"delete file (%d)\n",i); i=unlink("testx.dat"); fprintf(stderr,"delete file (%d)\n",i); fprintf(stderr,"create file...\n"); f=fopen("test.dat","w"); if(!f) { fprintf(stderr,"cannot create file (%d)\n",errno); return -1; } fprintf(f,"Hello\n"); fclose(f); return 0; } ================================================ FILE: test/TESTFTIM.C ================================================ #include /* for printf */ #include /* for strftime */ char test[80]; int main(int argc, char *argv[]) { int len; char *fmt; time_t now; time(&now); fmt = (argc == 1) ? "%I:%M %p\n%c\n" : argv[1]; len = strftime(test,sizeof test, fmt, localtime(&now)); printf("%d: %s\n", len, test); return !len; } ================================================ FILE: test/TESTHELL.C ================================================ #include int main() { printf("Hello\n"); } ================================================ FILE: test/TESTIO.C ================================================ #include "stdio.h" #include "cpm.h" #include int main(int argc, char ** argv) { int i; int minor=0; int major=0; FILE *f; char c=34; fprintf(stderr,"%s,%02x\n","hexa",c); freopen("testio.err","w",stderr); fprintf(stderr,"argc=%d\n",argc); for(i=0;i>4)&0x0F); minor=(i&0x0F); break; } printf("CP/M BDOS %d.%d\n",major,minor); return 0; } ================================================ FILE: test/TESTOVR.C ================================================ #include #include #include 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; } ================================================ FILE: test/TESTOVR1.C ================================================ void * yop(void *a) { printf("hello from overlay 01\n"); return 0; } ================================================ FILE: test/TESTOVR2.C ================================================ void * yop(void *a) { printf("hello from overlay 02\n"); return 0; } ================================================ FILE: test/TESTPR.C ================================================ /* Test printf()'s ability to print long strings */ #include char test[500] = { "\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" }; int main() { printf("len: %d\n", strlen(test)); printf("string: %s\n", test); return 0; } ================================================ FILE: test/TESTPWD.C ================================================ #include #include #include #include struct fcb ffcb; char password[20]; char *getpass(struct fcb *pfcb) { char *cp, lyne[100]; printf("Enter password: "); fflush(stdout); gets(lyne); if (strlen(lyne)) { for (cp = lyne; *cp; ++cp) if (islower(*cp)) *cp = toupper(*cp); strncpy(password,lyne,8); strcat(password, " "); return password; } return NULL; } int main(int argc, char *argv[]) { FILE *f; int c; if (argc < 2) return 0; bdos(CPMERRM, 0xFF); setfcb(&ffcb, argv[2]); /* _passwd = getpass; */ f = fopen(argv[1],"r"); if (f) { printf("Processing %s:\n", argv[1]); while (!feof(f)) { c = fgetc(f); if (!feof(f)) putchar(c); } fclose(f); return 0; } else { printf("Failed to open %s", argv[1]); perror(" - "); } return 1; } ================================================ FILE: test/TESTRC.C ================================================ #include "stdio.h" #include "cpm.h" #include #include #include int main(int argc, char ** argv) { return 33; } ================================================ FILE: test/TESTREL.C ================================================ #include int main() { printf("Hello Reloc\n"); return 0; } ================================================ FILE: test/TESTSTR.C ================================================ #include #include #include char *v[]={ "test","Test", "test","test", "test1","test", "test","test1", "rest","test", 0 }; int main() { int i=0; printf("strcmp test:\n"); while(v[i]) { printf("- %s<>%s=%d\n",v[i],v[i+1],strcmp(v[i],v[i+1])); i=i+2; } i=0; printf("stricmp test:\n"); while(v[i]) { printf("- %s<>%s=%d\n",v[i],v[i+1],stricmp(v[i],v[i+1])); i=i+2; } printf("strnicmp test:\n"); printf("- %s<>%s=%d\n","test","test1",strnicmp("test","test1",strlen("test"))); printf("- %s<>%s=%d\n","test1","test",strnicmp("test1","test",strlen("test"))); printf("- %s<>%s=%d\n","Test1","test",strnicmp("Test1","test",strlen("test"))); return 0; } ================================================ FILE: test/TESTTRIG.C ================================================ /* * TESTTRIG.C * * Test to verify release v3.09-1 has fixed floating point * Trigonometry routines. * * Compile using * * c -o -lf testtrig.c * * From a USENET newsgroup post to comp.os.cpm on 2013-09-02 by "Ed" * * "LIBF.LIB supplied with the freeware Hitech-C 3.09 release * 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. * * Below is a comparison of results between the original and * rebuilt library. * * --- * * (using original LIBF.LIB) * * n LN EXP SIN COS ATAN * 01 0.000000e+00 2.703595e+00 8.502954e-01 5.339794e-01 7.800306e-01 * 02 6.931469e-01 7.309311e+00 9.107645e-01 -4.232263e-01 1.116727e+00 * 03 1.098605e+00 1.976185e+01 1.411983e-01 -9.956650e-01 1.257505e+00 * 04 1.386294e+00 5.342758e+01 -7.673132e-01 -6.481950e-01 1.333912e+00 * 05 1.609434e+00 1.444486e+02 -9.609912e-01 2.909977e-01 1.381350e+00 * 06 1.791752e+00 3.905289e+02 -2.795844e-01 9.680709e-01 1.413529e+00 * 07 1.945900e+00 1.055842e+03 6.572353e-01 7.495101e-01 1.436745e+00 * 08 2.079441e+00 2.854568e+03 9.921404e-01 -1.529755e-01 1.454266e+00 * 09 2.197222e+00 7.717445e+03 4.124018e-01 -9.213704e-01 1.467951e+00 * 10 2.302581e+00 2.086538e+04 -5.440205e-01 -8.359161e-01 1.478932e+00 * 11 2.397890e+00 5.641094e+04 -1.003614e+00 1.190640e-02 1.487935e+00 * 12 2.484899e+00 1.525148e+05 -5.370088e-01 8.565310e-01 1.495450e+00 * 13 2.564940e+00 4.123360e+05 4.199748e-01 9.057026e-01 1.501817e+00 * 14 2.639047e+00 1.114781e+06 9.952080e-01 1.294013e-01 1.507279e+00 * 15 2.708037e+00 3.013969e+06 6.509256e-01 -7.748882e-01 1.512017e+00 * 16 2.772588e+00 8.148225e+06 -2.875695e-01 -9.574937e-01 1.516165e+00 * 17 2.833212e+00 2.202966e+07 -9.671226e-01 -2.681288e-01 1.519827e+00 * 18 2.890369e+00 5.955735e+07 -7.518865e-01 6.661855e-01 1.523084e+00 * 19 2.944436e+00 1.610253e+08 1.494345e-01 9.902740e-01 1.525998e+00 * * * (using rebuilt LIBF.LIB) * * n LN EXP SIN COS ATAN * 01 0.000000e+00 2.718280e+00 8.414706e-01 5.403037e-01 7.853970e-01 * 02 6.931469e-01 7.389050e+00 9.092973e-01 -4.161461e-01 1.107148e+00 * 03 1.098612e+00 2.008552e+01 1.411217e-01 -9.899922e-01 1.249045e+00 * 04 1.386294e+00 5.459808e+01 -7.568023e-01 -6.536445e-01 1.325817e+00 * 05 1.609438e+00 1.484130e+02 -9.589242e-01 2.836605e-01 1.373400e+00 * 06 1.791759e+00 4.034281e+02 -2.794159e-01 9.601696e-01 1.405647e+00 * 07 1.945910e+00 1.096632e+03 6.569859e-01 7.539025e-01 1.428899e+00 * 08 2.079441e+00 2.980951e+03 9.893581e-01 -1.454975e-01 1.446441e+00 * 09 2.197224e+00 8.103068e+03 4.121197e-01 -9.111288e-01 1.460139e+00 * 10 2.302584e+00 2.202640e+04 -5.440195e-01 -8.390731e-01 1.471127e+00 * 11 2.397894e+00 5.987400e+04 -9.999901e-01 4.422163e-03 1.480136e+00 * 12 2.484906e+00 1.627543e+05 -5.365736e-01 8.438515e-01 1.487654e+00 * 13 2.564949e+00 4.424121e+05 4.201658e-01 9.074482e-01 1.494024e+00 * 14 2.639056e+00 1.202602e+06 9.906070e-01 1.367416e-01 1.499488e+00 * 15 2.708049e+00 3.269002e+06 6.502892e-01 -7.596840e-01 1.504228e+00 * 16 2.772588e+00 8.886073e+06 -2.879012e-01 -9.576598e-01 1.508377e+00 * 17 2.833213e+00 2.415486e+07 -9.613965e-01 -2.751657e-01 1.512040e+00 * 18 2.890371e+00 6.565973e+07 -7.509890e-01 6.603144e-01 1.515297e+00 * 19 2.944438e+00 1.784813e+08 1.498741e-01 9.887048e-01 1.518213e+00 * " */ #include float a,b,c,d,e,f,g; int i; int main() { a = 1.0; printf("\n n LN EXP SIN COS ATAN"); for(i=1;i<20;i++) { b = log(a); c = exp(a); d = sin(a); e = cos(a); f = atan(a); printf("\n%3.2d",i); printf("%14.6e ",b); printf("%14.6e ",c); printf("%14.6e ",d); printf("%14.6e ",e); printf("%14.6e ",f); a=a+1.0; } printf("\n"); return 0; } ================================================ FILE: test/TESTUID.C ================================================ #include "stdio.h" #include "cpm.h" #include #include #include int main(int argc, char ** argv) { printf("getuid=%d\n",getuid()); printf("setuid=%d\n",setuid(3)); printf("getuid=%d\n",getuid()); printf("getuid=%d\n",getuid()); return 0; } ================================================ FILE: test/TESTVER.C ================================================ #include "stdio.h" #include "cpm.h" #include extern char _exact; /* exact file size mode */ extern char *_libcver; /* LIBC version string */ int main(int argc, char ** argv) { int i; int minor=0; int major=0; int machine; int system; int* bdosaddr=(int*)6; int* biosaddr=(int*)1; unsigned int tpa; i=bdos(CPMVERS,0); switch(i) { case 0x00: major=1; minor=0; break; default: major=((i>>4)&0x0F); minor=(i&0x0F); break; } machine=(i>>12)&0x0F; system=(i>>8)&0x0F; printf("CP/M BDOS Version (%d.%d)\n",major,minor); if(system!=0) { printf("Network (%s%s%s)\n",system&0x01?"[MP/M]":"",system&0x02?"[CP/Net]":"", system&0x04?"[Multi User]":""); } switch(machine) { case 0: printf("Machine (MCS80/Z80)\n",machine); break; case 1: printf("Machine (MCS86)\n"); break; case 2: printf("Machine (68000/Z8000)\n"); break; default: printf("Machine (?)\n"); break; } printf("BDOS Address (0x%04x)\n",*bdosaddr-6); printf("BIOS Address (0x%04x)\n",*biosaddr-3); tpa=((*bdosaddr-6)-0x100); fprintf(stdout,"TPA Size (%u.%uK)\n",tpa/1024,(tpa % 1024)/100); fprintf(stdout,"C library version %s\n",_libcver); switch(_exact) { case 'C': printf("Exact file size not used (CP/M 2 mode)\n"); break; case 'D': printf("Using DOS Plus exact file size mode\n"); break; case 'I': printf("Using ISIS exact file size mode\n"); default: printf("Unknown exact file size mode 0%xH\n",_exact); break; } return 0; } ================================================ FILE: test/TESTVER.SUB ================================================ testver :dir testver.*[fu ================================================ FILE: test/TESTVIEW.C ================================================ /*----------------------------------------------------------------------*\ | testargs.c | | | | This program is designed to test wildcard expansion without calling | | routine _getargs(). | | | | Invoke with one or more file names (which may contain wildcards). | | The program will display the names of any files which match. | | | | Note that there is no easy way to set the program name (argv[0]). | \*----------------------------------------------------------------------*/ #include #include #include void view(char *); int main(int argc, char *argv[]) { int a; bdos(45,255); for (a = 1; a < argc; ++a) { printf("%2d: %s\n", a, argv[a]); view(argv[a]); } } void view(char *fn) { FILE *f; char *bp, buf[200]; f = fopen(fn, "r"); while (bp=fgets(buf, 200, f)) printf("%s", bp); fclose(f); } ================================================ FILE: test/TESTWILD.C ================================================ /*----------------------------------------------------------------------*\ | testwild.c | | | | This program is designed to test wildcard expansion using the stdio | | routine _getargs(). | | | | Invoke with one or more file names (which may contain wildcards). | | The program will display the names of any files which match. | \*----------------------------------------------------------------------*/ #include #include #include int main(int argc, char *argv[]) { int a; extern int _argc_; char **args; args = _getargs((char *)0x81, "TESTWILD"); printf("Program name: %s\n", args[0]); for (a = 1; a < _argc_; ++a) { printf("%2d: %s\n", a, args[a]); } } ================================================ FILE: z280dist/C280OPTS ================================================ HI-TECH Z280 CP/M C compiler options: -A Generate a self-relocating .COM program. -C Generate object code only; don't link. -CR Produce a cross-reference listing e.g. -CRfile.crf -D Define a symbol, e.g. -DDEBUG=1 -E Specify executable output filename, e.g. -Efile.com -Ffile Generate a symbol file for debug.com or overlay build (default L.SYM) -H Output help (the OPTIONS file) and exit. -I Specify an include directory, e.g. -I1:B: -L Scan a library, e.g. -LF scans the floating point library. -M Generate a map file, e.g. -Mfile.map -N Use the N280CPM.OBJ start-up with minimal _getargs(). -O Invoke the peephole optimizer (reduced code-size) -O2 Invoke the Z280 optimizer for reduced code size. -OF2 Invoke the Z280 optimizer for faster Speed (slightly larger code-size). -S Generate assembler code in a .AS file; don't assemble or link. -U Undefine a predefined symbol, e.g. -UDEBUG -V Be verbose during compilation. -W Set warning level, e.g. -w5 or -w-2 -X Suppress local symbols in symbol tables. ================================================ FILE: z280dist/OPTIMH.C ================================================ /*- * All OPTIMH.C source code is * (c) Copyright (1993-96) by Stefan Nitschke and Alexander Schmid * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, (2) it is not used for military purpose in * any form, and (3) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by Stefan Nitschke and his contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the author nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* Z280 optimiser for the HITECH 3.09 c-compiler St.Nitschke 11.05.93 Erweitert und Umgesetzt von Turbo-Pascal auf Hi-Tech-C (Converted and enhanced from Turbo-Pascal to Hi-Tech-C) Alexander Schmid 30.10.93 This version is included in the GitHub repository for Hi Tech Z80 C at https://github.com/agn453/HI-TECH-Z80-C Modification History 04-Jun-2025 Tony Nicholson Statement labels without a space after the colon were causing the character after the colon to be replaced by a space (overwriting the first character of the opcode/assembler directive). 31-Oct-2023 Tony Nicholson Translated German to English comments added in brackets; Correct additional byte and replaced counter updates; Summary output includes "speed" or "size"; Change default filetype for output from .ASO to .AS2; Some "call csv" and "jp cret" speed optimisations were not being detected (add space and tab tests); and Statement labels on optimised statements were being omitted from optimised output. 18-Mar-1996 Stefan Nitschke 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 (+4 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) 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) The following didn't work: ld hl,nn push hl -> push nn ld hl,(nn) push hl -> push (nn) ld de,(nn) ld hl,mm -> ld hl,(nn) add hl,de -> lda hl,(hl+mm) (1 byte) */ #include #include #include #define TRUE 1 #define FALSE 0 extern char *rindex(); FILE *infile,*outfile; char *inptr,inname[20],*outptr,outname[20]; int i,count,repl,lines,posit; char found; char speed; char text[101]; char line[6][101]; /* sucht dden String s im String t */ /* (search for the string s in the string t) */ int instr(char *t, char *s) { register int i,j,k; for (i=0; s[i] != '\0'; ++i) { for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; ++j, ++k); if (t[k] == '\0') return(i+1); } return 0; } /* kopiert ab Position p maximal i Zeichen von String a in String b */ /* (from position p, copy up to i characters from string a to string b) */ void copyn(char *a, char *b, int p, int i) { register int x; char ch; for(x=0; x<100; ++x) b[x]='\0'; for(x=p; xcall csv\n"); fprintf(outfile,"push\tiy\npush\tix\n;-> lda ix,(sp+0)\ndefb\t%s\n",bytes); lines = 0; count -= 6; /* 6 bytes mehr aber schneller */ repl += 3; /* more (but faster) */ found = TRUE; } } void cret(char *str1) { if(instr(str1,line[0])) { fprintf(outfile,";->jp cret\n"); fprintf(outfile,"ld\tsp,ix\npop\tix\npop\tiy\nret\n"); lines = 0; count -= 4; /* 4 bytes mehr aber schneller */ repl += 3; /* more (but faster) */ found = TRUE; } } void mult(char *str1, char *str2,char *bytes) { if(instr(str1,line[0])) { fprintf(outfile,";->%s hl,de\n",str2); fprintf(outfile,"defb\t%s\n",bytes); lines = 0; ++count; /* 1 byte less */ repl += 3; /* replaces call amul/lmul */ found = TRUE; } } void ldw1(char *str1, char *byte1) { /* ldw (hl),xx */ char *strr1="ld\t(hl),b"; strr1[8]=str1[1]; if(instr(strr1,line[0])) { if(lines<1) fgets(line[1],100,infile); lines = 1; if(instr("inc\thl",line[1])) { if(lines<2) fgets(line[2],100,infile); lines = 2; strr1[8]=str1[0]; if(instr(strr1,line[2])) { fprintf(outfile,";->ldw (hl),%s\n",str1); fprintf(outfile,"defb\t%s\n",byte1); fputs("inc\thl\n",outfile); lines = 0; found = TRUE; repl += 2; } } } } void ldw2(char *str1, char *byte1) { /* ldw xx,(hl) */ char *strr1="ld\tb,(hl)"; strr1[3]=str1[1]; if(instr(strr1,line[0])) { if(lines<1) fgets(line[1],100,infile); lines = 1; if(instr("inc\thl",line[1])) { if(lines<2) fgets(line[2],100,infile); lines = 2; strr1[3]=str1[0]; if(instr(strr1,line[2])) { fprintf(outfile,";->ldw %s,(hl)\n",str1); fprintf(outfile,"defb\t%s\n",byte1); fputs("inc\thl\n",outfile); lines = 0; found = TRUE; repl += 2; } } } } void ldw3(char *str1, char *str2, char *byte1) { /* ldw xx,(yy+ofs) */ char strr1[20]; strcpy(strr1,"ld\tc,("); strcat(strr1,str2); strr1[3]=str1[1]; if(instr(strr1,line[0])) { if(lines<1) fgets(line[1],100,infile); lines = 1; strr1[3]=str1[0]; if(instr(strr1,line[1])) { lines = 0; found = TRUE; count += 2; repl += 4; posit = instr(str2,line[0])+1; copyn(line[0],text,posit,instr(")",line[0])-posit-1); fprintf(outfile,";->ldw %s,(%s%s)\n",str1,str2,text); fprintf(outfile,"defb\t%s,%s\n",byte1,text); } } } void ldw4(char *str1, char *str2, char *byte1) { /* ldw (xx+ofs),yy */ char strr1[20],strr2[20]; strcpy(strr1,"ld\t("); strcat(strr1,str2); strcpy(strr2,"),c"); strr2[2]=str1[1]; if(instr(strr1,line[0]) && instr(strr2,line[0])) { if(lines<1) fgets(line[1],100,infile); lines = 1; strr2[2]=str1[0]; if(instr(strr1,line[1]) && instr(strr2,line[1])) { lines = 0; found = TRUE; count += 2; repl += 4; posit = instr(str2,line[0])+1; copyn(line[0],text,posit,instr(")",line[0])-posit-1); fprintf(outfile,";->ldw (%s%s),%s\n",str2,text,str1); fprintf(outfile,"defb\t%s,%s\n",byte1,text); } } } void pushix(void) { fprintf(outfile,";->ld d,ixh\n"); fprintf(outfile,"defb\t0ddh,54h\n"); fprintf(outfile,";->ld e,ixl\n"); fprintf(outfile,"defb\t0ddh,5dh\n"); found = TRUE; --count; /* eine Byte MEHR, aber schneller ! */ repl += 4; /* one more byte (but faster) */ } void pushiy(void) { fprintf(outfile,";->ld d,iyh\n"); fprintf(outfile,"defb\t0fdh,54h\n"); fprintf(outfile,";->ld e,iyl\n"); fprintf(outfile,"defb\t0fdh,5dh\n"); found = TRUE; --count; /* eine Byte MEHR, aber schneller ! */ repl += 4; /* one more byte (but faster) */ } void subwhl(char *str1, char *byte1) { if(instr("or\ta",line[0])) { char strr1[20]; strcpy(strr1,"sbc\thl,"); strcat(strr1,str1); if(lines<1) fgets(line[1],100,infile); /* subw hl,xx */ lines = 1; if(instr(strr1,line[1])) { lines = 0; found = TRUE; ++count; repl += 2; fprintf(outfile,";->subw hl,%s\n",str1); fprintf(outfile,"defb\t%s\n",byte1); } } } void label(void) { /* check for statement label in line[0]. if detected, output the label on a line by itself and strip the label from line[0] */ register int p, x; char lab[101], islabel, c; if(p = instr(":",line[0])) { copyn(line[0],lab,0,p); /* copy label */ islabel = TRUE; for (x=0; x<(p-1); x++) { c = lab[x]; /* valid chars are 0..9, a..z, $ and _ */ if( (!isalnum(c)) && (c!='$') && (c!='_') ) { islabel = FALSE; } } if (islabel && (line[0][p+1]!='\0')) { /* check if bare label too */ fprintf(outfile,"%s\n",lab); for (x=0; xlda hl,(ix+%s)\n",text); fputs("defb\t0edh,2ah\n",outfile); fprintf(outfile,"defw\t%s\n",text); lines = 0; found = TRUE; count += 3; repl += 2; } } else { pushix(); strcpy(line[0],line[1]); strcpy(line[1],line[2]); lines = 1; } } else if(instr("pop\thl",line[1])) { fprintf(outfile,";->lda hl,(ix+0)\n"); fprintf(outfile,"defb\t0edh,2ah,0,0\n"); found = TRUE; repl += 4; --count; lines = 0; } } /******************************************************************************/ if(!found) if(instr("push\tiy",line[0])) { if(lines<1) fgets(line[1],100,infile); /* lda hl,(iy+ofs) */ lines = 1; if(instr("pop\tde",line[1])) { if(lines<2) fgets(line[2],100,infile); lines = 2; if(instr("ld\thl,",line[2])) { if(lines<3) fgets(line[3],100,infile); lines = 3; if(instr("add\thl,de",line[3])) { copyn(line[2],text,instr("hl,",line[2])+2,6); if(instr(")",text)) copyn(text,text,instr(")",text)-1,strlen(text)); fprintf(outfile,";->lda hl,(iy+%s)\n",text); fputs("defb\t0edh,32h\n",outfile); fprintf(outfile,"defw\t%s\n",text); lines = 0; found = TRUE; count += 3; repl += 2; } } else { pushiy(); strcpy(line[0],line[1]); strcpy(line[1],line[2]); lines = 1; } } else if(instr("pop\thl",line[1])) { fprintf(outfile,";->lda hl,(iy+0)\n"); fprintf(outfile,"defb\t0edh,32h,0,0\n"); found = TRUE; repl += 4; --count; lines = 0; } } /******************************************************************************/ /* verursacht Fehler */ /* (causes errors) */ #ifdef xxx if(!found) if(instr("ld\thl,",line[0]) && instr("(",line[0])==0) { if(lines<1) fgets(line[1],100,infile); /* push arg */ lines = 1; if(instr("push\thl",line[1])) { lines = 0; found = TRUE; repl += 2; posit = instr("hl,",line[0])+2; copyn(line[0],text,posit,50); fprintf(outfile,";->push %s\n",text); fputs("defb\t0fdh,0f5h\n",outfile); fprintf(outfile,"defw\t%s\n",text); } } #endif /******************************************************************************/ /* verursacht Fehler */ /* (causes errors) */ #ifdef xxx if(!found) if(instr("ld\thl,(",line[0])) { if(lines<1) fgets(line[1],100,infile); /* push (arg) */ lines = 1; if(instr("push\thl",line[1])) { lines = 0; found = TRUE; repl += 2; posit = instr("hl,",line[0])+2; copyn(line[0],text,posit,50); fprintf(outfile,";->push %s\n",text); fputs("defb\t0ddh,0d5h\n",outfile); ++posit; copyn(line[0],text,posit,instr(")",line[0])-posit-1); fprintf(outfile,"defw\t%s\n",text); } } #endif /******************************************************************************/ /* verursacht Fehler */ /* (causes errors) */ #ifdef xxx if(!found) if(instr("ld\tde,(",line[0])) { if(lines<1) fgets(line[1],100,infile); /* lda hl,(hl+ofs) */ lines = 1; if(instr("ld\thl,",line[1]) && !instr("(",line[1])) { if(lines<2) fgets(line[2],100,infile); lines = 2; if(instr("add\thl,de",line[2])) { posit = instr("de",line[0]+1); line[0][posit] = 'h'; line[0][posit+1] = 'l'; copyn(line[1],text,instr("hl,",line[1])+2,50); fputs(line[0],outfile); fprintf(outfile,";->lda hl,(hl+%s)\n",text); fputs("defb\t0edh,3ah\n",outfile); fprintf(outfile,"defw\t%s\n",text); lines = 0; found = TRUE; ++count; repl += 5; } } } #endif /******************************************************************************/ } main(int argc,*argv[]) { if(argc==1) { puts("Z280 optimiser for the HITECH C-Compiler"); printf("Name of input file :"); scanf("%s",inname); printf("Name of output file :"); scanf("%s",outname); } else if(argc==2) { strcpy(inname,(char*)argv[1]); if(rindex(inname,'.')==NULL) strcat(inname,".AS"); inptr=inname; outptr=outname; while(*inptr != '.') *outptr++ = *inptr++; strcat(outname,".AS2"); } else if(argc==3) { strcpy(inname,(char*)argv[1]); strcpy(outname,(char*)argv[2]); } else if(argc==4) { if(stricmp((char *)argv[1],"-F")==0) speed = 1; else { printf("First arg can only be -F for speed (Fast) optimization\n"); exit(1); } strcpy(inname,(char*)argv[2]); strcpy(outname,(char*)argv[3]); } if((infile = fopen(inname,"r"))==NULL) { printf("Can't open %s\n",inname); exit(1); } if((outfile = fopen(outname,"w"))==NULL) { printf("Can't open %s\n",outname); exit(1); } count = 0; repl = 0; while(fgets(line[0],100,infile) != NULL) { label(); lines = 0; found = FALSE; check(); if(!found) fputs(line[0],outfile); while(lines>0) { found = FALSE; strcpy(line[0],line[1]); strcpy(line[1],line[2]); strcpy(line[2],line[3]); --lines; check(); if(!found) fputs(line[0],outfile); } } printf(" %d bytes %s optimised away\n",count,speed?"speed":"size"); printf(" %d bytes replaced\n",repl); fputs("\n; optimiser statistics:\n",outfile); fprintf(outfile,"; %d bytes %s optimised away\n",count,speed?"speed":"size"); fprintf(outfile,"; %d bytes replaced\n\n",repl); fputc(0x1a,outfile); /* explizites (explicit) EOF */ fclose(infile); fclose(outfile); exit(0); }