Browse Source

ZXCC Cleanup

- I know I said I was done, but I found some more stuff to clean up.  I think I am really done now.
pull/283/head
Wayne Warthen 4 years ago
parent
commit
2c0b818aba
  1. 2
      Binary/Apps/Makefile
  2. 6
      Tools/unix/zxcc/Build-VC.cmd
  3. 5
      Tools/unix/zxcc/config.h.windows
  4. 6
      Tools/unix/zxcc/cpmdrv.c
  5. 158
      Tools/unix/zxcc/cpmglob.c
  6. 69
      Tools/unix/zxcc/cpmint.h
  7. 2
      Tools/unix/zxcc/cpmparse.c
  8. 485
      Tools/unix/zxcc/cpmredir.c
  9. 3
      Tools/unix/zxcc/cpmredir.h
  10. 59
      Tools/unix/zxcc/dirent.c
  11. 16
      Tools/unix/zxcc/dirent.h
  12. 8
      Tools/unix/zxcc/drdos.c
  13. 22
      Tools/unix/zxcc/track.c
  14. 196
      Tools/unix/zxcc/util.c
  15. 8
      Tools/unix/zxcc/xlt.c
  16. 2
      Tools/unix/zxcc/z80.c
  17. 14
      Tools/unix/zxcc/zxbdos.c
  18. 1
      Tools/unix/zxcc/zxbdos.h
  19. 11
      Tools/unix/zxcc/zxcbdos.c
  20. 4
      Tools/unix/zxcc/zxcbdos.h
  21. 116
      Tools/unix/zxcc/zxcc.c
  22. 27
      Tools/unix/zxcc/zxcc.h
  23. 6
      Tools/unix/zxcc/zxdbdos.c
  24. 4
      Tools/unix/zxcc/zxdbdos.h
  25. BIN
      Tools/zxcc/zxcc-src.zip
  26. BIN
      Tools/zxcc/zxcc.exe
  27. BIN
      Tools/zxcc/zxccdbg.exe

2
Binary/Apps/Makefile

@ -8,4 +8,4 @@ all::
mkdir -p Tunes mkdir -p Tunes
clobber:: clobber::
@rm -f *.bin *.com *.img *.rom *.pdf *.log *.eeprom *.ovr *.hlp *.doc *.COM *.BIN Tunes/*.mym Tunes/*.pt?
@rm -f *.bin *.com *.img *.rom *.pdf *.log *.eeprom *.ovr *.hlp *.doc *.COM *.BIN Tunes/*.mym Tunes/*.pt? Tunes/*.vgm

6
Tools/unix/zxcc/Build-VC.cmd

@ -5,7 +5,7 @@ setlocal
:: Visual Studio x86 Native Tools Command Prompt is assumed :: Visual Studio x86 Native Tools Command Prompt is assumed
:: ::
:: Below configures VS2012 to target Windows XP and beyond
:: Below configures VS2012 to target Windows XP.
:: Not sure if it will work in later versions of VS, but seems :: Not sure if it will work in later versions of VS, but seems
:: to do no harm. :: to do no harm.
set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE% set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE%
@ -16,10 +16,10 @@ set LINK=/SUBSYSTEM:CONSOLE,5.01 %LINK%
copy config.h.windows config.h copy config.h.windows config.h
cl zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c track.c
cl -I. zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c track.c
if errorlevel 1 exit /b 255 if errorlevel 1 exit /b 255
cl /DDEBUG /Fe"zxccdbg.exe" zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c track.c
cl -I. /DDEBUG /Fe"zxccdbg.exe" zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c track.c
if errorlevel 1 exit /b 255 if errorlevel 1 exit /b 255
copy cpm\bios.bin . copy cpm\bios.bin .

5
Tools/unix/zxcc/config.h.windows

@ -1,5 +1,10 @@
#define HAVE_WINDOWS_H #define HAVE_WINDOWS_H
#define HAVE_FCNTL_H #define HAVE_FCNTL_H
#ifdef _MSC_VER
#define HAVE_DIRENT_H
#endif
#define HAVE_DIRECT_H
#define HAVE_IO_H
#define WINVER _WIN32_WINNT_WINXP // target Windows XP #define WINVER _WIN32_WINNT_WINXP // target Windows XP
#define _WIN32_WINNT _WIN32_WINNT_WINXP // target Windows XP #define _WIN32_WINNT _WIN32_WINNT_WINXP // target Windows XP
//#define FILETRACKER 1 //#define FILETRACKER 1

6
Tools/unix/zxcc/cpmdrv.c

@ -81,7 +81,7 @@ cpm_byte fcb_user (cpm_byte usr)
{ {
if (usr != 0xFF) redir_cpmuser = usr % 16; if (usr != 0xFF) redir_cpmuser = usr % 16;
redir_Msg("User: parameter %d returns %d\r\n", usr, redir_cpmuser);
DBGMSGV("User: parameter %d returns %d\n", usr, redir_cpmuser);
return redir_cpmuser; return redir_cpmuser;
} }
@ -159,7 +159,6 @@ cpm_word fcb_getdpb(cpm_byte *dpb)
return 0x11; return 0x11;
} }
/* Create an entirely bogus ALV /* Create an entirely bogus ALV
* TODO: Make it a bit better */ * TODO: Make it a bit better */
@ -181,6 +180,3 @@ cpm_word fcb_dfree (cpm_byte drive, cpm_byte *dma)
redir_wr24(dma, 0x8000L); /* 8MB / 128 / 2 */ redir_wr24(dma, 0x8000L); /* 8MB / 128 / 2 */
return 0; return 0;
} }

158
Tools/unix/zxcc/cpmglob.c

@ -25,7 +25,6 @@
#define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0) #define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0)
#endif #endif
static cpm_byte* find_fcb; static cpm_byte* find_fcb;
static int find_n; static int find_n;
static int find_ext = 0; static int find_ext = 0;
@ -48,9 +47,11 @@ static char upper(char c)
* the naive code in the distributed zx will not work everywhere. * the naive code in the distributed zx will not work everywhere.
*/ */
/* Does the string "s" match the CP/M FCB? */
/* pattern[0-10] will become a CP/M name parsed from "s" if it matches. */
/* If 1st byte of FCB is '?' then anything matches. */
/*
* Does the string "s" match the CP/M FCB?
* pattern[0-10] will become a CP/M name parsed from "s" if it matches.
* If 1st byte of FCB is '?' then anything matches.
*/
static int cpm_match(char* s, cpm_byte* fcb, cpm_byte* pattern) static int cpm_match(char* s, cpm_byte* fcb, cpm_byte* pattern)
{ {
@ -65,6 +66,7 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern)
* the fcb. we reject any that can't be valid cp/m filenames, * the fcb. we reject any that can't be valid cp/m filenames,
* normalizing case as we go. all this goes into 'pattern' * normalizing case as we go. all this goes into 'pattern'
*/ */
for (n = 0; n < 11; n++) pattern[n] = ' '; for (n = 0; n < 11; n++) pattern[n] = ' ';
/* The name must have 1 or 0 dots */ /* The name must have 1 or 0 dots */
@ -74,7 +76,8 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern)
for (n = 0; n < m; n++) { for (n = 0; n < m; n++) {
pattern[n] = upper(s[n]) & 0x7F; pattern[n] = upper(s[n]) & 0x7F;
} }
} else { /* at least one dot */
}
else { /* at least one dot */
if (strchr(dotpos + 1, '.')) { /* More than 1 dot */ if (strchr(dotpos + 1, '.')) { /* More than 1 dot */
return 0; return 0;
} }
@ -100,6 +103,7 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern)
* handle special case where fcb[0] == '?' or fcb[0] & 0x80 * handle special case where fcb[0] == '?' or fcb[0] & 0x80
* this is used to return a full directory list on bdos's * this is used to return a full directory list on bdos's
*/ */
if (((fcb[0] & 0x7F) == '?') || (fcb[0] & 0x80)) { if (((fcb[0] & 0x7F) == '?') || (fcb[0] & 0x80)) {
return 1; return 1;
} }
@ -114,7 +118,6 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern)
return 1; /* Success! */ return 1; /* Success! */
} }
/* Get the next entry from the host's directory matching "fcb" */ /* Get the next entry from the host's directory matching "fcb" */
static struct dirent* next_entry(DIR* dir, cpm_byte* fcb, cpm_byte* pattern, static struct dirent* next_entry(DIR* dir, cpm_byte* fcb, cpm_byte* pattern,
@ -131,26 +134,25 @@ static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern,
for (unsatisfied = 1; unsatisfied; ) for (unsatisfied = 1; unsatisfied; )
{ {
/* 1. Get the next entry */ /* 1. Get the next entry */
en = readdir(dir); en = readdir(dir);
if (!en) return NULL; /* No next entry */ if (!en) return NULL; /* No next entry */
++entryno; /* 0 for 1st, 1 for 2nd, etc. */ ++entryno; /* 0 for 1st, 1 for 2nd, etc. */
/* 2. See if it matches. We do this first (in preference to /* 2. See if it matches. We do this first (in preference to
seeing if it's a subdirectory first) because it doesn't
require disc access */
* seeing if it's a subdirectory first) because it doesn't
* require disc access */
if (!cpm_match(en->d_name, fcb, pattern)) if (!cpm_match(en->d_name, fcb, pattern))
{ {
continue; continue;
} }
/* 3. Stat it, & reject it if it's a directory */
/* 3. Stat it, & reject it if it's a directory */
strcpy(target_name, redir_drive_prefix[drv]); strcpy(target_name, redir_drive_prefix[drv]);
strcat(target_name, en->d_name); strcat(target_name, en->d_name);
if (stat(target_name, st)) if (stat(target_name, st))
{ {
redir_Msg("Can't stat %s so omitting it.\n", target_name);
DBGMSGV("Can't stat %s so omitting it.\n", target_name);
continue; /* Can't stat */ continue; /* Can't stat */
} }
if (S_ISDIR(st->st_mode)) if (S_ISDIR(st->st_mode))
@ -166,8 +168,6 @@ static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern,
return en; return en;
} }
void volume_label(int drv, cpm_byte* dma) void volume_label(int drv, cpm_byte* dma)
{ {
struct stat st; struct stat st;
@ -176,6 +176,7 @@ void volume_label(int drv, cpm_byte *dma)
/* Get label name */ /* Get label name */
redir_get_label(drv, (char*)(dma + 1)); redir_get_label(drv, (char*)(dma + 1));
/* [0x0c] = label byte /* [0x0c] = label byte
* [0x0d] = password byte (=0) * [0x0d] = password byte (=0)
* [0x10-0x17] = password * [0x10-0x17] = password
@ -193,7 +194,7 @@ void volume_label(int drv, cpm_byte *dma)
if (stat(redir_drive_prefix[drv], &st)) if (stat(redir_drive_prefix[drv], &st))
{ {
redir_Msg("stat() fails on '%s'\n", redir_drive_prefix[drv]);
DBGMSGV("stat() fails on '%s'\n", redir_drive_prefix[drv]);
return; return;
} }
@ -201,8 +202,6 @@ void volume_label(int drv, cpm_byte *dma)
redir_wr32(dma + 0x1C, redir_cpmtime(st.st_mtime)); redir_wr32(dma + 0x1C, redir_cpmtime(st.st_mtime));
} }
cpm_word redir_find(int n, cpm_byte* fcb, cpm_byte* dma) cpm_word redir_find(int n, cpm_byte* fcb, cpm_byte* dma)
{ {
DIR* hostdir; DIR* hostdir;
@ -249,12 +248,10 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma)
return 0; return 0;
} }
memset(dma, 0, 128); /* Zap the buffer */ memset(dma, 0, 128); /* Zap the buffer */
/*
If returning all entries, return a volume label.
*/
/* If returning all entries, return a volume label. */
if ((fcb[0] & 0x7F) == '?') if ((fcb[0] & 0x7F) == '?')
{ {
if (!n) if (!n)
@ -266,18 +263,18 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma)
} }
/* Note: This implies that opendir() works on a filename with a /* Note: This implies that opendir() works on a filename with a
trailing slash. It does under Linux, but that's the only assurance
I can give.
*/
* trailing slash. It does under Linux, but that's the only assurance
* I can give. */
entryno = -1; entryno = -1;
hostdir = opendir(redir_drive_prefix[drv]); hostdir = opendir(redir_drive_prefix[drv]);
if (!hostdir) if (!hostdir)
{ {
redir_Msg("opendir() fails on '%s'\n", redir_drive_prefix[drv]);
DBGMSGV("opendir() fails on '%s'\n", redir_drive_prefix[drv]);
return 0xFF; return 0xFF;
} }
/* We have a handle to the directory. */ /* We have a handle to the directory. */
while (n >= 0) while (n >= 0)
{ {
@ -308,8 +305,6 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma)
if (attrib & 4) dma[10] |= 0x80; /* system */ if (attrib & 4) dma[10] |= 0x80; /* system */
if (!(attrib & 0x20)) dma[11] |= 0x80; /* archive */ if (!(attrib & 0x20)) dma[11] |= 0x80; /* archive */
/* TODO: Under Unix, work out correct RO setting */ /* TODO: Under Unix, work out correct RO setting */
recs = (st.st_size + 127) / 128; recs = (st.st_size + 127) / 128;
@ -322,8 +317,7 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma)
dma[0x12] = entryno & 0xFF; dma[0x12] = entryno & 0xFF;
redir_wr32(dma + 0x16, (dword)st.st_mtime); /* Modification time. */ redir_wr32(dma + 0x16, (dword)st.st_mtime); /* Modification time. */
/* TODO: It should be in DOS */
/* format */
/* TODO: It should be in DOS format */
/* TODO: At 0x1A, 1st cluster */ /* TODO: At 0x1A, 1st cluster */
redir_wr32(dma + 0x1C, st.st_size); /* True size */ redir_wr32(dma + 0x1C, st.st_size); /* True size */
@ -348,25 +342,13 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma)
return 0; return 0;
} }
#ifdef DEBUG
#define SHOWNAME(func) \
{ \
char fname[CPM_MAXPATH]; \
redir_fcb2unix(fcb, fname); \
redir_Msg(func "(\"%s\")\n", fname); \
}
#else
#define SHOWNAME(func)
#endif
cpm_word fcb_find1(cpm_byte* fcb, cpm_byte* dma) /* 0x11 */ cpm_word fcb_find1(cpm_byte* fcb, cpm_byte* dma) /* 0x11 */
{ {
#ifdef DEBUG #ifdef DEBUG
int rv; int rv;
#endif #endif
SHOWNAME("fcb_find1")
FCBENT(fcb);
redir_log_fcb(fcb); redir_log_fcb(fcb);
@ -374,17 +356,18 @@ cpm_word fcb_find1 (cpm_byte *fcb, cpm_byte *dma) /* 0x11 */
find_fcb = fcb; find_fcb = fcb;
find_ext = 0; find_ext = 0;
find_xfcb = 0; find_xfcb = 0;
#ifdef DEBUG #ifdef DEBUG
rv = redir_find(find_n, fcb, dma); rv = redir_find(find_n, fcb, dma);
if (rv < 4) if (rv < 4)
{ {
redir_Msg("Ret: %-11.11s\n", dma + 1);
DBGMSGV("Ret: %-11.11s\n", dma + 1);
} }
else redir_Msg("Ret: Fail\n");
return rv;
else DBGMSG("Ret: Fail\n");
FCBRET(rv);
#else #else
return redir_find(find_n, find_fcb, dma);
FCBRET(redir_find(find_n, find_fcb, dma));
#endif #endif
} }
@ -396,23 +379,29 @@ cpm_word fcb_find2 (cpm_byte *fcb, cpm_byte *dma) /* 0x12 */
{ {
#ifdef DEBUG #ifdef DEBUG
int rv; int rv;
char fname[CPM_MAXPATH]; char fname[CPM_MAXPATH];
#endif
FCBENT(find_fcb);
#ifdef DEBUG
redir_fcb2unix(find_fcb, fname); redir_fcb2unix(find_fcb, fname);
redir_Msg("fcb_find2(\"%s\") no. %d\n", fname, find_n);
DBGMSGV("file number %d, '%s'\n", find_n, fname);
#endif #endif
++find_n; ++find_n;
#ifdef DEBUG #ifdef DEBUG
rv = redir_find(find_n, find_fcb, dma); rv = redir_find(find_n, find_fcb, dma);
if (rv < 4) if (rv < 4)
{ {
redir_Msg("Ret: %-11.11s\n", dma + 1);
DBGMSGV("Ret: %-11.11s\n", dma + 1);
} }
else redir_Msg("Ret: Fail\n");
return rv;
else DBGMSG("Ret: Fail\n");
FCBRET(rv);
#else #else
return redir_find(find_n, find_fcb, dma);
FCBRET(redir_find(find_n, find_fcb, dma));
#endif #endif
} }
@ -427,8 +416,9 @@ cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma)
int handle = 0; int handle = 0;
int unpasswd = 0; int unpasswd = 0;
char fname[CPM_MAXPATH]; char fname[CPM_MAXPATH];
int del_cnt = 0;
SHOWNAME("fcb_unlink")
FCBENT(fcb);
if (fcb[5] & 0x80) unpasswd = 1; /* Remove password rather than file */ if (fcb[5] & 0x80) unpasswd = 1; /* Remove password rather than file */
@ -438,25 +428,30 @@ cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma)
if (!drv || drv == '?') drv = redir_cpmdrive; if (!drv || drv == '?') drv = redir_cpmdrive;
else drv--; else drv--;
if (redir_ro_drv(drv)) return 0x02FF; /* Error: R/O drive */
if (redir_ro_drv(drv))
{
/* Error: R/O drive */
DBGMSG("delete failed - R/O drive\n");
FCBRET(0x02FF);
}
#ifdef DEBUG #ifdef DEBUG
redir_fcb2unix(fcb, fname); redir_fcb2unix(fcb, fname);
redir_Msg("fcb_unlink(\"%s\")\n", fname);
DBGMSGV("fcb_unlink('%s')\n", fname);
#endif #endif
/* Note: This implies that opendir() works on a filename with a /* Note: This implies that opendir() works on a filename with a
trailing slash. It does under Linux, but that's the only assurance
I can give.
*/
* trailing slash. It does under Linux, but that's the only assurance
* I can give.*/
hostdir = opendir(redir_drive_prefix[drv]); hostdir = opendir(redir_drive_prefix[drv]);
if (!hostdir) if (!hostdir)
{ {
redir_Msg("opendir() fails on '%s'\n", redir_drive_prefix[drv]);
return 0xFF;
DBGMSGV("opendir failed on '%s'\n", redir_drive_prefix[drv]);
FCBRET(0xFF);
} }
/* We have a handle to the directory. */ /* We have a handle to the directory. */
do do
{ {
@ -465,7 +460,7 @@ cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma)
{ {
strcpy(target_name, redir_drive_prefix[drv]); strcpy(target_name, redir_drive_prefix[drv]);
strcat(target_name, de->d_name); strcat(target_name, de->d_name);
redir_Msg("Deleting %s\n", de->d_name);
DBGMSGV("deleting '%s'\n", de->d_name);
if (unpasswd) if (unpasswd)
{ {
#ifdef __MSDOS__ #ifdef __MSDOS__
@ -478,44 +473,59 @@ cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma)
} }
else if (fcb[0] & 0x80) else if (fcb[0] & 0x80)
{ {
DBGMSGV("rmdir '%s'\n", target_name);
handle = rmdir(target_name); handle = rmdir(target_name);
if (handle && redir_password_error()) if (handle && redir_password_error())
{ {
DBGMSGV("rmdir failed (errno=%lu): %s\n", errno, strerror(errno));
redir_password_append(target_name, dma); redir_password_append(target_name, dma);
DBGMSGV("rmdir '%s'\n", target_name);
handle = rmdir(target_name); handle = rmdir(target_name);
} }
if (handle)
DBGMSGV("rmdir failed (errno=%lu): %s\n", errno, strerror(errno));
} }
else else
{ {
releaseFile(target_name); releaseFile(target_name);
DBGMSGV("unlink '%s'\n", target_name);
handle = unlink(target_name); handle = unlink(target_name);
if (handle && redir_password_error()) if (handle && redir_password_error())
{ {
DBGMSGV("unlink failed (errno=%lu): %s\n", errno, strerror(errno));
redir_password_append(target_name, dma); redir_password_append(target_name, dma);
releaseFile(target_name); releaseFile(target_name);
DBGMSGV("unlink '%s'\n", target_name);
handle = unlink(target_name); handle = unlink(target_name);
} }
if (handle)
DBGMSGV("unlink failed (errno=%lu): %s\n", errno, strerror(errno));
} }
if (handle) de = NULL; /* Delete failed */
}
}
while (de != NULL);
if (handle) if (handle)
de = NULL; /* Delete failed */
else
del_cnt++;
}
} while (de != NULL);
if (!handle && !del_cnt)
DBGMSG("no matching directory entries\n");
else
DBGMSGV("deleted %i file(s)\n", del_cnt);
if (handle || !del_cnt)
{ {
redir_Msg("Ret: -1\n");
DBGMSG("delete processing failed\n");
closedir(hostdir); closedir(hostdir);
return 0xFF;
FCBRET(0xFF);
} }
redir_Msg("Ret: 0\n");
DBGMSG("delete processing succeeded\n");
closedir(hostdir); closedir(hostdir);
return 0;
FCBRET(0);
} }
#ifdef __MSDOS__ #ifdef __MSDOS__
cpm_word redir_get_label(cpm_byte drv, char* pattern) cpm_word redir_get_label(cpm_byte drv, char* pattern)
{ {
@ -585,6 +595,4 @@ cpm_word redir_get_label(cpm_byte drv, char *pattern)
return 0; return 0;
} }
#endif #endif

69
Tools/unix/zxcc/cpmint.h

@ -20,13 +20,7 @@
This file holds internal declarations for the library. This file holds internal declarations for the library.
*/ */
#ifndef _WIN32
#include "config.h" #include "config.h"
#define DIRSEP "/"
#else
#include "config.h"
#define DIRSEP "/\\:"
#endif
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_STDLIB_H #ifdef HAVE_STDLIB_H
#include <stdlib.h> #include <stdlib.h>
@ -47,16 +41,12 @@
#include <errno.h> #include <errno.h>
#ifdef HAVE_DIRENT_H #ifdef HAVE_DIRENT_H
#include <dirent.h> #include <dirent.h>
#endif
#ifdef HAVE_DIRECT_H #ifdef HAVE_DIRECT_H
#include <direct.h> #include <direct.h>
#endif #endif
#else
#ifdef __WATCOMC__
#ifdef HAVE_IO_H
#include <io.h> #include <io.h>
#include <direct.h>
#else
#include "dirent.h"
#endif
#endif #endif
#ifdef HAVE_NDIR_H #ifdef HAVE_NDIR_H
#include <ndir.h> #include <ndir.h>
@ -94,20 +84,32 @@
/* MSDOS includes removed */ /* MSDOS includes removed */
#ifdef _WIN32 #ifdef _WIN32
#define DIRSEP "/"
#define mkdir(dir, mode) _mkdir(dir) #define mkdir(dir, mode) _mkdir(dir)
#define strcasecmp _stricmp #define strcasecmp _stricmp
int truncate(const char* path, off_t length); /* see util.c */
#define ftruncate _chsize #define ftruncate _chsize
/* note Windows build assumes Windows is configured as a non case sensitive filesystem */ /* note Windows build assumes Windows is configured as a non case sensitive filesystem */
#ifndef STDIN_FILENO
#define STDIN_FILENO _fileno(stdin)
#define STDOUT_FILENO _fileno(stdout)
#define STDERR_FILENO _fileno(stderr)
#endif
#else #else
#define DIRSEP "/\\:"
#define CASE_SENSITIVE_FILESYSTEM 1 #define CASE_SENSITIVE_FILESYSTEM 1
#endif #endif
#include "cpmredir.h"
#ifdef _WIN32
int truncate(const char* path, off_t length); /* see util.c */
#endif
typedef unsigned char byte; /* Must be exactly 8 bits */
typedef unsigned short word; /* Must be exactly 16 bits */
typedef unsigned long dword; /* Must be at least 32 bits, and typedef unsigned long dword; /* Must be at least 32 bits, and
>= sizeof(int) */ >= sizeof(int) */
#include "cpmredir.h"
#ifdef CPMDEF #ifdef CPMDEF
#define EXT #define EXT
#define INIT(x) =x #define INIT(x) =x
@ -146,8 +148,6 @@ EXT cpm_word redir_ro_drives INIT(0);
#undef EXT #undef EXT
#undef INIT #undef INIT
/* Convert FCB to a Unix filename, returning 1 if it's ambiguous */ /* Convert FCB to a Unix filename, returning 1 if it's ambiguous */
int redir_fcb2unix(cpm_byte* fcb, char* fname); int redir_fcb2unix(cpm_byte* fcb, char* fname);
@ -163,21 +163,46 @@ int redir_verify_fcb(cpm_byte *fcb);
/* Facilities for debug tracing */ /* Facilities for debug tracing */
long zxlseek(int fd, long offset, int wh); long zxlseek(int fd, long offset, int wh);
#ifdef _WIN32
char* GetErrorStr(DWORD);
#endif
#ifdef DEBUG #ifdef DEBUG
// long zxlseek(int fd, long offset, int wh); // long zxlseek(int fd, long offset, int wh);
void redir_Msg(char *s, ...);
// void redir_Msg(char *s, ...);
void DbgMsg(const char* file, int line, const char* func, char* s, ...);
void redir_showfcb(cpm_byte* fcb); void redir_showfcb(cpm_byte* fcb);
#else #else
// #define zxlseek lseek // #define zxlseek lseek
/* Warning: This is a GCC extension */ /* Warning: This is a GCC extension */
#define redir_Msg(x, ...)
// #define redir_Msg(x, ...)
#define redir_showfcb(x) #define redir_showfcb(x)
#endif #endif
#ifdef DEBUG
#define FCBENT(fcb) \
{ \
char fname[CPM_MAXPATH] = ""; \
redir_fcb2unix(fcb, fname); \
DBGMSGV("entry w/ FCB @ 0x%04X, filename:'%s'\n", fcb-RAM, fname); \
}
#define FCBRET(rc) \
{ \
DBGMSGV("returning 0x%04X\n", rc); \
return rc; \
}
#define DBGMSGV(s, ...) DbgMsg(__FILE__, __LINE__, __func__, s, __VA_ARGS__)
#define DBGMSG(s) DbgMsg(__FILE__, __LINE__, __func__, s)
#else
#define FCBENT(fcb)
#define FCBRET(rc) return rc;
#define DBGMSGV(s, ...)
#define DBGMSG(s)
#endif
/* Get the "sequential access" file pointer out of an FCB */ /* Get the "sequential access" file pointer out of an FCB */
@ -192,7 +217,6 @@ dword redir_cpmtime(time_t t);
/* And back */ /* And back */
time_t redir_unixtime(cpm_byte* c); time_t redir_unixtime(cpm_byte* c);
/* Functions to access 24-bit & 32-bit words in memory. These are always /* Functions to access 24-bit & 32-bit words in memory. These are always
little-endian. */ little-endian. */
@ -223,7 +247,6 @@ cpm_word redir_xlt_err(void);
/* Get disc label */ /* Get disc label */
cpm_word redir_get_label(cpm_byte drv, char* pattern); cpm_word redir_get_label(cpm_byte drv, char* pattern);
/* DRDOS set/get access rights - no-ops under MSDOS and Unix: /* DRDOS set/get access rights - no-ops under MSDOS and Unix:
* *
* CP/M password mode -> DRDOS password mode */ * CP/M password mode -> DRDOS password mode */
@ -247,3 +270,5 @@ void redir_password_append(char *s, cpm_byte *dma);
void releaseFile(char* fname); void releaseFile(char* fname);
int trackFile(char* fname, void* fcb, int fd); int trackFile(char* fname, void* fcb, int fd);
#define releaseFCB(fcb) trackFile(NULL, fcb, -1) #define releaseFCB(fcb) trackFile(NULL, fcb, -1)
extern byte RAM[65536]; /* The Z80's address space */

2
Tools/unix/zxcc/cpmparse.c

@ -50,8 +50,6 @@ static int parse_drive_user(char *txt, cpm_byte *fcb)
return 0; return 0;
} }
cpm_word fcb_parse(char* txt, cpm_byte* fcb) cpm_word fcb_parse(char* txt, cpm_byte* fcb)
{ {
int nl = 0, tl = 0, pl = 0, phase = 0; int nl = 0, tl = 0, pl = 0, phase = 0;

485
Tools/unix/zxcc/cpmredir.c

File diff suppressed because it is too large

3
Tools/unix/zxcc/cpmredir.h

@ -86,7 +86,6 @@ int xlt_umap(int drive);
char* xlt_getcwd(int drive); char* xlt_getcwd(int drive);
/* BDOS functions. Eventually this should handle all disc-related BDOS /* BDOS functions. Eventually this should handle all disc-related BDOS
* functions. * functions.
* *
@ -143,9 +142,9 @@ cpm_word fcb_sdate (cpm_byte *fcb, cpm_byte *dma); /* 0x74 */
cpm_word fcb_parse(char* txt, cpm_byte* fcb); /* 0x98 */ cpm_word fcb_parse(char* txt, cpm_byte* fcb); /* 0x98 */
/* fcb_parse returns length of filename parsed, 0 if EOL, 0xFFFF if error */ /* fcb_parse returns length of filename parsed, 0 if EOL, 0xFFFF if error */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* def CPMREDIR_H_INCLUDED */ #endif /* def CPMREDIR_H_INCLUDED */

59
Tools/unix/zxcc/dirent.c

@ -7,10 +7,9 @@
Rights: See end of file. Rights: See end of file.
*/ */
#pragma warning(disable : 4996)
#include "dirent.h" #include "dirent.h"
#include <errno.h> #include <errno.h>
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -19,35 +18,20 @@ extern "C"
{ {
#endif #endif
//typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
typedef long handle_type; /* C99's intptr_t not sufficiently portable */
struct DIR
{
handle_type handle; /* -1 for failed rewind */
struct _finddata_t info;
struct dirent result; /* d_name null iff first time */
char *name; /* null-terminated char string */
};
DIR *opendir(const char *name)
{
DIR* opendir(const char* name) {
DIR* dir = 0; DIR* dir = 0;
if(name && name[0])
{
if (name && name[0]) {
size_t base_length = strlen(name); size_t base_length = strlen(name);
const char* all = /* search pattern must end with suitable wildcard */ const char* all = /* search pattern must end with suitable wildcard */
strchr("/\\", name[base_length - 1]) ? "*" : "/*"; strchr("/\\", name[base_length - 1]) ? "*" : "/*";
if ((dir = (DIR*)malloc(sizeof * dir)) != 0 && if ((dir = (DIR*)malloc(sizeof * dir)) != 0 &&
(dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
{
(dir->name = (char*)malloc(base_length + strlen(all) + 1)) != 0) {
strcat(strcpy(dir->name, name), all); strcat(strcpy(dir->name, name), all);
if ((dir->handle = if ((dir->handle =
(handle_type) _findfirst(dir->name, &dir->info)) != -1)
{
(handle_type)_findfirst(dir->name, &dir->info)) != -1) {
dir->result.d_name = 0; dir->result.d_name = 0;
} }
else /* rollback */ else /* rollback */
@ -64,22 +48,18 @@ DIR *opendir(const char *name)
errno = ENOMEM; errno = ENOMEM;
} }
} }
else
{
else {
errno = EINVAL; errno = EINVAL;
} }
return dir; return dir;
} }
int closedir(DIR *dir)
{
int closedir(DIR* dir) {
int result = -1; int result = -1;
if(dir)
{
if(dir->handle != -1)
{
if (dir) {
if (dir->handle != -1) {
result = _findclose(dir->handle); result = _findclose(dir->handle);
} }
@ -95,36 +75,29 @@ int closedir(DIR *dir)
return result; return result;
} }
struct dirent *readdir(DIR *dir)
{
struct dirent* readdir(DIR* dir) {
struct dirent* result = 0; struct dirent* result = 0;
if(dir && dir->handle != -1)
{
if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
{
if (dir && dir->handle != -1) {
if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
result = &dir->result; result = &dir->result;
result->d_name = dir->info.name; result->d_name = dir->info.name;
} }
} }
else
{
else {
errno = EBADF; errno = EBADF;
} }
return result; return result;
} }
void rewinddir(DIR *dir)
{
if(dir && dir->handle != -1)
{
void rewinddir(DIR* dir) {
if (dir && dir->handle != -1) {
_findclose(dir->handle); _findclose(dir->handle);
dir->handle = (handle_type)_findfirst(dir->name, &dir->info); dir->handle = (handle_type)_findfirst(dir->name, &dir->info);
dir->result.d_name = 0; dir->result.d_name = 0;
} }
else
{
else {
errno = EBADF; errno = EBADF;
} }
} }

16
Tools/unix/zxcc/dirent.h

@ -11,18 +11,26 @@
*/ */
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
#endif #endif
typedef struct DIR DIR;
struct dirent
{
struct dirent {
char *d_name; char *d_name;
}; };
typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
typedef struct {
handle_type handle; /* -1 for failed rewind */
struct _finddata_t info;
struct dirent result; /* d_name null iff first time */
char *name; /* null-terminated char string */
} DIR;
DIR *opendir(const char *); DIR *opendir(const char *);
int closedir(DIR *); int closedir(DIR *);
struct dirent *readdir(DIR *); struct dirent *readdir(DIR *);

8
Tools/unix/zxcc/drdos.c

@ -198,7 +198,7 @@ cpm_word redir_password_error(void)
intdos(&r, &r); intdos(&r, &r);
redir_Msg("Last error was: %04x\r\n", r.w.ax);
redir_Msg("Last error was: %04x\n", r.w.ax);
if (r.w.ax == 0x56) return 1; /* Bad password */ if (r.w.ax == 0x56) return 1; /* Bad password */
return 0; return 0;
@ -229,8 +229,8 @@ void redir_password_append(char *s, cpm_byte *dma)
void redir_password_append(char* s, cpm_byte* dma) {} void redir_password_append(char* s, cpm_byte* dma) {}
cpm_word redir_password_error(void) { return 0; } cpm_word redir_password_error(void) { return 0; }
cpm_word redir_drdos_put_rights(char* path, cpm_byte* dma, cpm_word rights) cpm_word redir_drdos_put_rights(char* path, cpm_byte* dma, cpm_word rights)
{ return 0; }
{
return 0;
}
cpm_word redir_drdos_get_rights(char* path) { return 0; } cpm_word redir_drdos_get_rights(char* path) { return 0; }
#endif /* __MSDOS__ */ #endif /* __MSDOS__ */

22
Tools/unix/zxcc/track.c

@ -22,8 +22,8 @@
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
//#include "cpmint.h"
#include "zxcc.h"
#include "cpmint.h"
/* CP/M does not require that files opened for reading need to be closed, /* CP/M does not require that files opened for reading need to be closed,
* this has two impacts * this has two impacts
@ -81,8 +81,22 @@
* a problem. I am not aware of any real programs that do this. * a problem. I am not aware of any real programs that do this.
* Please let me know if the situation arises. * Please let me know if the situation arises.
*/ */
/* windows needs to use file tracking, for unix/linux it is optional */
/*
* The FILETRACKER functionality was implemented primarily because
* MSDOS file interface does not allow opening files in shared mode.
* This port of zxcc deprecates MSDOS and uses WIN32 API calls to handle
* all file I/O. So, this means that FILETRACKER is now optional for
* for Windows as well as Unix. I have found some edge cases where
* FILETRACKER caused a CP/M program to misbehave. Specifically, ZSM4
* reuses FCBs if files are included and does it such a way that the
* FILETRACKER is unable to solve the problem. For maximum
* compatibility, FILETRACKER may now be left off with the implication
* that a lot of file handles will be left open.
*/
#ifdef FILETRACKER #ifdef FILETRACKER
typedef struct _track { typedef struct _track {
struct _track* next; struct _track* next;
int handle; int handle;
@ -111,7 +125,6 @@ void releaseFile(char* fname) {
s = s->next; s = s->next;
} }
int trackFile(char* fname, void* fcb, int fd) { int trackFile(char* fname, void* fcb, int fd) {
track_t* s = (track_t*)&openFiles; track_t* s = (track_t*)&openFiles;
Msg("trackFile: \"%s\", FCB=0x%X, Handle=%i\n", fname, (byte*)fcb - RAM, fd); Msg("trackFile: \"%s\", FCB=0x%X, Handle=%i\n", fname, (byte*)fcb - RAM, fd);
@ -147,4 +160,3 @@ void releaseFile(char* fname) {}
int trackFile(char* fname, void* fcb, int fd) { return fd; } int trackFile(char* fname, void* fcb, int fd) { return fd; }
#endif #endif

196
Tools/unix/zxcc/util.c

@ -22,52 +22,68 @@
#include "cpmint.h" #include "cpmint.h"
#ifdef _WIN32
char* GetErrorStr(dword dwErr)
{
LPVOID lpMsgBuf;
static char ErrStr[256] = "";
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
sizeof(ErrStr), NULL);
strncpy(ErrStr, lpMsgBuf, sizeof(ErrStr));
LocalFree(lpMsgBuf);
/* In debug mode, lseek()s can be traced. */
return ErrStr;
}
#ifdef DEBUG
#endif
char* whence(int wh)
{
switch (wh)
{
case SEEK_SET: return("SEEK_SET");
case SEEK_CUR: return("SEEK_CUR");
case SEEK_END: return("SEEK_END");
default: return("SEEK_???");
}
}
/* In debug mode, lseek()s can be traced. */
long zxlseek(int fd, long offset, int wh) long zxlseek(int fd, long offset, int wh)
{ {
#ifdef _WIN32 #ifdef _WIN32
long v; long v;
redir_Msg(">SetFilePointer() Handle=%lu, Offset=%lu, Method=%lu\n", fd, offset, wh);
DBGMSGV("seek on file #%i to 0x%lX using %s\n", fd, offset, whence(wh));
v = SetFilePointer((HANDLE)fd, offset, NULL, wh); v = SetFilePointer((HANDLE)fd, offset, NULL, wh);
redir_Msg("<SetFilePointer() FilePos=%lu, LastErr=%lu\n", v, GetLastError());
if (v == INVALID_SET_FILE_POINTER)
if (v != INVALID_SET_FILE_POINTER) return v;
DBGMSGV("seek failed (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
return -1; return -1;
return v;
#else #else
DBGMSGV("seek on #%i to 0x%lX using %s\n", fd, offset, whence(wh));
long v = lseek(fd, offset, wh); long v = lseek(fd, offset, wh);
if (v >= 0) return v; if (v >= 0) return v;
redir_Msg("lseek fails with errno = %d\n", errno);
if (errno == EBADF) redir_Msg(" (bad file descriptor %d)\n", fd);
if (errno == ESPIPE) redir_Msg(" (file %d is a pipe)\n", fd);
if (errno == EINVAL) redir_Msg(" (bad parameter %d)\n", wh);
DBGMSGV("seek failed (errno=%lu): %s\n", errno, strerror(errno));
return -1; return -1;
#endif
}
#else
long zxlseek(int fd, long offset, int wh)
{
#ifdef _WIN32
return SetFilePointer((HANDLE)fd, offset, NULL, wh);
#else
return lseek(fd, offset, wh);
#endif #endif
} }
#endif
#ifdef DEBUG #ifdef DEBUG
void redir_showfcb(cpm_byte* fd) void redir_showfcb(cpm_byte* fd)
@ -79,7 +95,7 @@ void redir_showfcb(cpm_byte *fd)
if (!n || n >= 12) printf("%02x ", fd[n]); if (!n || n >= 12) printf("%02x ", fd[n]);
else printf("%c", fd[n] & 0x7F); else printf("%c", fd[n] & 0x7F);
} }
printf("\r\n");
printf("\n");
} }
#endif #endif
@ -104,7 +120,6 @@ void redir_put_fcb_pos(cpm_byte *fcb, long npos)
fcb[0x0E] = (npos / 524288L) % 64; /* S2 */ fcb[0x0E] = (npos / 524288L) % 64; /* S2 */
} }
/* /*
* find a filename that works. * find a filename that works.
* note that this is where we handle the case sensitivity/non-case sensitivity * note that this is where we handle the case sensitivity/non-case sensitivity
@ -112,8 +127,7 @@ void redir_put_fcb_pos(cpm_byte *fcb, long npos)
* the name that is passed in should be in lower case. * the name that is passed in should be in lower case.
* we'll modify it to the first one that matches * we'll modify it to the first one that matches
*/ */
void
swizzle(char *fullpath)
void swizzle(char* fullpath)
{ {
struct stat ss; struct stat ss;
char* slash; char* slash;
@ -148,6 +162,7 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname)
{ {
int n, q, drv, ddrv; int n, q, drv, ddrv;
char s[2]; char s[2];
char buf[256];
s[1] = 0; s[1] = 0;
q = 0; q = 0;
@ -157,11 +172,6 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname)
ddrv = fcb[0] & 0x7F; ddrv = fcb[0] & 0x7F;
if (ddrv < 0x1F) ddrv += '@'; if (ddrv < 0x1F) ddrv += '@';
redir_Msg("%c:%-8.8s.%-3.3s\n",
ddrv,
fcb + 1,
fcb + 9);
if (!drv) strcpy(fname, redir_drive_prefix[redir_cpmdrive]); if (!drv) strcpy(fname, redir_drive_prefix[redir_cpmdrive]);
else strcpy(fname, redir_drive_prefix[drv - 1]); else strcpy(fname, redir_drive_prefix[drv - 1]);
@ -176,6 +186,16 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname)
strcat(fname, s); strcat(fname, s);
} }
} }
sprintf(buf, "'%c:%-8.8s.%-3.3s' --> '%s'", ddrv, fcb + 1, fcb + 9, fname);
for (n = 0; buf[n] != '\0'; n++)
{
buf[n] &= 0x7F;
if (buf[n] < ' ') buf[n] = 'x';
}
DBGMSGV("%s\n", buf);
return q; return q;
} }
@ -188,49 +208,83 @@ int redir_ofile(cpm_byte *fcb, char *s)
int h; int h;
/* Software write-protection */ /* Software write-protection */
#ifdef _WIN32 #ifdef _WIN32
redir_Msg(">CreateFile([OPEN_EXISTING]) Name='%s'\n", s);
releaseFCB(fcb);
if (!redir_ro_fcb(fcb))
{
// Attempt to open existing file with read/write access
DBGMSGV("open existing file '%s' with read/write access\n", s);
h = (int)CreateFile(s, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); h = (int)CreateFile(s, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
redir_Msg("<CreateFile([OPEN_EXISTING]) Handle=%lu, LastErr=%lu\n", h, GetLastError());
if (h != HFILE_ERROR)
{
DBGMSGV("file '%s' opened R/W as #%i\n", s, h);
return trackFile(s, fcb, h);
}
DBGMSGV("open R/W failed (errno=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
}
// Attempt to open existing file with read-only access
DBGMSGV("open existing file '%s' with read-only access\n", s);
h = (int)CreateFile(s, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == HFILE_ERROR) if (h == HFILE_ERROR)
{ {
redir_Msg("Returning -1\n");
DBGMSGV("open R/O failed (errno=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
return -1; return -1;
} }
DBGMSGV("file '%s' opened R/O as #%i\n", s, h);
fcb[9] |= 0x80; fcb[9] |= 0x80;
#else
#ifdef __MSDOS__
#elif defined(__MSDOS__)
int rv; int rv;
if (!redir_ro_fcb(fcb)) if (!redir_ro_fcb(fcb))
{ {
rv = _dos_open(s, O_RDWR, &h); rv = _dos_open(s, O_RDWR, &h);
if (!rv) return h; if (!rv) return h;
redir_Msg("Open of %s fails: error %x\r\n", s, rv);
DBGMSGV("Open of %s fails: error %x\n", s, rv);
} }
rv = _dos_open(s, O_RDONLY, &h); rv = _dos_open(s, O_RDONLY, &h);
if (rv) return -1; if (rv) return -1;
fcb[9] |= 0x80; fcb[9] |= 0x80;
#else #else
releaseFCB(fcb);
releaseFCB(fcb);
swizzle(s); swizzle(s);
if (!redir_ro_fcb(fcb)) if (!redir_ro_fcb(fcb))
{ {
// Attempt to open existing file with read/write access
DBGMSGV("open existing file '%s' with read/write access\n", s);
h = open(s, O_RDWR | O_BINARY); h = open(s, O_RDWR | O_BINARY);
if (h >= 0 || (errno != EACCES && errno != EROFS)) if (h >= 0 || (errno != EACCES && errno != EROFS))
{
DBGMSGV("file '%s' opened R/W as #%i\n", s, h);
return trackFile(s, fcb, h); return trackFile(s, fcb, h);
} }
DBGMSGV("failed to open R/W (errno=%lu): %s\n", errno, strerror(errno));
}
// Attempt to open existing file with read-only access
DBGMSGV("open existing file '%s' with read-only access\n", s);
h = open(s, O_RDONLY | O_BINARY); h = open(s, O_RDONLY | O_BINARY);
if (h < 0) return -1;
if (h < 0)
{
DBGMSGV("failed to open R/O (errno=%lu): %s\n", errno, strerror(errno));
return -1;
}
DBGMSGV("file '%s' opened R/O as #%i\n", s, h);
fcb[9] |= 0x80; fcb[9] |= 0x80;
#endif #endif
#endif
return trackFile(s, fcb, h); return trackFile(s, fcb, h);
} }
/* Extract a file handle from where it was stored in an FCB by fcb_open() /* Extract a file handle from where it was stored in an FCB by fcb_open()
or fcb_creat(). Aborts if the FCB has been tampered with. or fcb_creat(). Aborts if the FCB has been tampered with.
@ -245,19 +299,18 @@ int redir_verify_fcb(cpm_byte *fcb)
return -1; return -1;
} }
return (int)(redir_rd32(fcb + 18)); return (int)(redir_rd32(fcb + 18));
} }
/* Print a trace message */ /* Print a trace message */
#ifdef DEBUG #ifdef DEBUG
void redir_Msg(char *s, ...)
void DbgMsg(const char* file, int line, const char* func, char* s, ...)
{ {
va_list ap; va_list ap;
va_start(ap, s); va_start(ap, s);
fprintf(stderr, "cpmredir trace: ");
fprintf(stderr, "%s(%s@%i): ", func, file, line);
vfprintf(stderr, s, ap); vfprintf(stderr, s, ap);
va_end(ap); va_end(ap);
fflush(stderr); fflush(stderr);
@ -304,7 +357,6 @@ time_t redir_unixtime(cpm_byte *c)
#undef UNBCD #undef UNBCD
/* Functions to access 24-bit & 32-bit words in memory. These are always /* Functions to access 24-bit & 32-bit words in memory. These are always
little-endian. */ little-endian. */
@ -332,7 +384,6 @@ dword redir_rd24(cpm_byte *addr)
return rv; return rv;
} }
dword redir_rd32(cpm_byte* addr) dword redir_rd32(cpm_byte* addr)
{ {
register dword rv = addr[3]; register dword rv = addr[3];
@ -343,7 +394,6 @@ dword redir_rd32(cpm_byte *addr)
return rv; return rv;
} }
void redir_log_drv(cpm_byte drv) void redir_log_drv(cpm_byte drv)
{ {
if (!drv) redir_l_drives |= 1; if (!drv) redir_l_drives |= 1;
@ -358,7 +408,6 @@ void redir_log_fcb(cpm_byte *fcb)
else redir_log_drv(redir_cpmdrive); else redir_log_drv(redir_cpmdrive);
} }
int redir_ro_drv(cpm_byte drv) int redir_ro_drv(cpm_byte drv)
{ {
if (!drv) return redir_ro_drives & 1; if (!drv) return redir_ro_drives & 1;
@ -373,11 +422,10 @@ int redir_ro_fcb(cpm_byte *fcb)
else return redir_ro_drv(redir_cpmdrive); else return redir_ro_drv(redir_cpmdrive);
} }
cpm_word redir_xlt_err(void) cpm_word redir_xlt_err(void)
{ {
if (redir_password_error()) return 0x7FF; /* DRDOS pwd error */ if (redir_password_error()) return 0x7FF; /* DRDOS pwd error */
switch (errno) switch (errno)
{ {
case EISDIR: case EISDIR:
@ -389,20 +437,48 @@ cpm_word redir_xlt_err(void)
} }
} }
#ifdef _WIN32 #ifdef _WIN32
/* minimal implementation of truncate */
int truncate(const char* path, off_t length) int truncate(const char* path, off_t length)
{ {
int result;
int fd = open(path, O_BINARY | O_RDWR);
BOOL bResult;
HANDLE hFile;
DWORD dwOffset;
DBGMSGV("truncate file %s to %lu\n", path, length);
if (fd < 0)
hFile = CreateFile(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
DBGMSGV("truncate failed to open file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
return -1; return -1;
result = ftruncate(fd, length);
return close(fd) == 0 && result == 0 ? 0 : -1;
}
dwOffset = SetFilePointer(hFile, length, NULL, FILE_BEGIN);
if (dwOffset == INVALID_SET_FILE_POINTER)
{
DBGMSGV("truncate failed to open file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
CloseHandle(hFile);
return -1;
}
bResult = SetEndOfFile(hFile);
if (!bResult)
{
DBGMSGV("truncate failed to set end of file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
CloseHandle(hFile);
return -1;
} }
bResult = CloseHandle(hFile);
if (!bResult)
{
DBGMSGV("truncate failed to close file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
return -1;
}
DBGMSGV("truncate set file length to %lu\n", dwOffset);
return 0;
}
#endif #endif

8
Tools/unix/zxcc/xlt.c

@ -40,7 +40,7 @@ static void drdos_init(void)
__dpmi_int(0x21, &ir); __dpmi_int(0x21, &ir);
if (ir.x.flags & 1) return; /* Not DRDOS */ if (ir.x.flags & 1) return; /* Not DRDOS */
redir_Msg("DRDOS detected.\r\n");
redir_Msg("DRDOS detected.\n");
redir_drdos = 1; redir_drdos = 1;
@ -53,15 +53,13 @@ static void drdos_init(void)
intdos(&ir, &or ); intdos(&ir, &or );
if (or .w.cflag) return; /* Not DRDOS */ if (or .w.cflag) return; /* Not DRDOS */
redir_Msg("DRDOS detected.\r\n");
redir_Msg("DRDOS detected.\n");
redir_drdos = 1; redir_drdos = 1;
#endif /* __GO32__ */ #endif /* __GO32__ */
} }
#endif /* __MSDOS__ */ #endif /* __MSDOS__ */
int fcb_init(void) int fcb_init(void)
{ {
int n; int n;
@ -181,7 +179,6 @@ int xlt_map(int drive, char *localdir)
return 1; return 1;
} }
/* Unmap a drive /* Unmap a drive
*/ */
@ -192,7 +189,6 @@ int xlt_umap(int drive)
return 1; return 1;
} }
char* xlt_getcwd(int drive) char* xlt_getcwd(int drive)
{ {
if (drive < 0 || drive > 16) return ""; if (drive < 0 || drive > 16) return "";

2
Tools/unix/zxcc/z80.c

@ -123,7 +123,7 @@ void mainloop(word spc, word ssp){
// if (pc == 0x1177) tr = 1; // if (pc == 0x1177) tr = 1;
// if (pc == 0x1185) tr = 0; // if (pc == 0x1185) tr = 0;
if (tr >= 1) ++id; if (tr >= 1) ++id;
if (tr >= 1) printf("%d: PC=%04x %02x AF=%02x:%02x BC=%04x DE=%04x HL=%04x IX=%04x IY=%04x\r\n",
if (tr >= 1) printf("%d: PC=%04x %02x AF=%02x:%02x BC=%04x DE=%04x HL=%04x IX=%04x IY=%04x\n",
id, pc, fetch(pc), a,f, bc, de, hl, ix, iy); id, pc, fetch(pc), a,f, bc, de, hl, ix, iy);
} }
*/ */

14
Tools/unix/zxcc/zxbdos.c

@ -134,7 +134,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
word temp; word temp;
int retv; int retv;
Msg("BDOS service invoked: C=%02x DE=%04x\n", *c, de);
DBGMSGV("BDOS service invoked: C=0x%02X DE=0x%04X\n", *c, de);
switch (*c) switch (*c)
{ {
@ -263,7 +263,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
break; break;
case 0x1A: /* Set DMA */ case 0x1A: /* Set DMA */
Msg("Set DMA to %04x\n", de);
DBGMSGV("Set DMA to 0x%04X\n", de);
cpm_dma = de; cpm_dma = de;
break; break;
@ -287,7 +287,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
case 0x1F: /* Get DPB */ case 0x1F: /* Get DPB */
fcb_getdpb(RAM + 0xFFC0); fcb_getdpb(RAM + 0xFFC0);
setw(l, h, 0xFFC0); setw(l, h, 0xFFC0);
break; /* Whoops. Missed that 'break'. */
break;
case 0x20: /* Get/set uid */ case 0x20: /* Get/set uid */
setw(l, h, fcb_user(*e)); setw(l, h, fcb_user(*e));
@ -331,7 +331,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
case 0x2E: case 0x2E:
setw(l, h, fcb_dfree(*e, pdma)); setw(l, h, fcb_dfree(*e, pdma));
break; /* Whoops. Missed that 'break'. */
break;
/* 0x2F: Chain */ /* 0x2F: Chain */
@ -478,14 +478,12 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
*b = *h; *b = *h;
} }
void cpmbios(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f, void cpmbios(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f,
byte* h, byte* l, word* pc, word* ix, word* iy) byte* h, byte* l, word* pc, word* ix, word* iy)
{ {
int func = (((*ix) & 0xFF) / 3) - 1; int func = (((*ix) & 0xFF) / 3) - 1;
Msg("BIOS service invoked: func=%02x\n", func);
DBGMSGV("BIOS service invoked: func=0x%02X\n", func);
switch (func) /* BIOS function */ switch (func) /* BIOS function */
{ {
@ -533,7 +531,7 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
#ifdef USE_CPMIO #ifdef USE_CPMIO
cpm_bdos_110('$'); cpm_bdos_110('$');
cpm_bdos_9("This program has attempted to call USERF, " cpm_bdos_9("This program has attempted to call USERF, "
"which is not implemented\r\n$");
"which is not implemented\n$");
#else #else
printf("This program has attempted to call USERF, which " printf("This program has attempted to call USERF, which "
"is not implemented.\n"); "is not implemented.\n");

1
Tools/unix/zxcc/zxbdos.h

@ -47,4 +47,3 @@ void gsxwr(gsx_word addr, gsx_byte value);
void cpmbdos(); void cpmbdos();
void cpmbios(); void cpmbios();

11
Tools/unix/zxcc/zxcbdos.c

@ -2,18 +2,9 @@
#include "zxbdos.h" #include "zxbdos.h"
#include "zxcbdos.h" #include "zxcbdos.h"
#ifndef _WIN32
#include <sys/ioctl.h>
#endif
#ifdef _WIN32
#include <conio.h>
#endif
/* Line input */ /* Line input */
#ifdef USE_CPMIO #ifdef USE_CPMIO
void bdos_rdline(word line, word* PC) void bdos_rdline(word line, word* PC)
{ {
unsigned char* buf; unsigned char* buf;
@ -72,7 +63,7 @@ void bdos_rdline(word line, word *PC)
//RAM[line + 1] = strlen((char *)(RAM + line + 2)) - 1; //RAM[line + 1] = strlen((char *)(RAM + line + 2)) - 1;
RAM[line + 1] = (unsigned char)n; RAM[line + 1] = (unsigned char)n;
Msg("Input: [%d] %-*.*s\n", RAM[line + 1], RAM[line + 1], RAM[line +1], (char *)(RAM+line+2));
DBGMSGV("Input: [%d] %-*.*s\n", RAM[line + 1], RAM[line + 1], RAM[line + 1], (char*)(RAM + line + 2));
} }
#endif /* ndef USE_CPMIO */ #endif /* ndef USE_CPMIO */

4
Tools/unix/zxcc/zxcbdos.h

@ -1,4 +1,6 @@
void bdos_rdline(word line, word* PC); void bdos_rdline(word line, word* PC);
int cpm_bdos_6(byte e); int cpm_bdos_6(byte e);
byte cin(void);
void cout(byte);
int cstat(void);

116
Tools/unix/zxcc/zxcc.c

@ -14,6 +14,10 @@ char bindir80[CPM_MAXPATH] = "";
char libdir80[CPM_MAXPATH] = ""; char libdir80[CPM_MAXPATH] = "";
char incdir80[CPM_MAXPATH] = ""; char incdir80[CPM_MAXPATH] = "";
#ifndef _WIN32
struct termios tc_orig;
#endif
byte RAM[65536]; /* The Z80's address space */ byte RAM[65536]; /* The Z80's address space */
void load_comfile(void); /* Forward declaration */ void load_comfile(void); /* Forward declaration */
@ -21,13 +25,6 @@ void load_comfile(void); /* Forward declaration */
static int deinit_term, deinit_gsx; static int deinit_term, deinit_gsx;
static void mkpath(char* fullpath, char* path, char* subdir); static void mkpath(char* fullpath, char* path, char* subdir);
#ifndef _WIN32
struct termios tc_orig;
void raw_init(void);
void deinit_raw(void);
#endif
void dump_regs(FILE* fp, byte a, byte b, byte c, byte d, byte e, byte f, void dump_regs(FILE* fp, byte a, byte b, byte c, byte d, byte e, byte f,
byte h, byte l, word pc, word ix, word iy) byte h, byte l, word pc, word ix, word iy)
{ {
@ -36,8 +33,6 @@ void dump_regs(FILE *fp, byte a, byte b, byte c, byte d, byte e, byte f,
a, f, b, c, d, e, h, l, pc, ix, iy); a, f, b, c, d, e, h, l, pc, ix, iy);
} }
char* parse_to_fcb(char* s, int afcb) char* parse_to_fcb(char* s, int afcb)
{ {
byte* fcb = &RAM[afcb + 1]; byte* fcb = &RAM[afcb + 1];
@ -74,21 +69,6 @@ char *parse_to_fcb(char *s, int afcb)
return s; return s;
} }
void Msg(char *s, ...)
{
#ifdef DEBUG
va_list ap;
va_start(ap, s);
fprintf(stderr, "%s trace: ", progname);
vfprintf(stderr, s, ap);
fflush(stderr);
va_end(ap);
#endif
}
void ed_fe(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f, void ed_fe(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f,
byte* h, byte* l, word* pc, word* ix, word* iy) byte* h, byte* l, word* pc, word* ix, word* iy)
{ {
@ -120,7 +100,6 @@ void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
} }
} }
/* /*
* load_bios() loads the minimal CP/M BIOS and BDOS. * load_bios() loads the minimal CP/M BIOS and BDOS.
* *
@ -172,7 +151,7 @@ void load_bios(void)
} }
fclose(fp); fclose(fp);
Msg("Loaded %d bytes of BIOS\n", bios_len);
DBGMSGV("Loaded %d bytes of BIOS\n", bios_len);
} }
/* /*
* try_com() attempts to open file, file.com, file.COM, file.cpm and file.CPM * try_com() attempts to open file, file.com, file.COM, file.cpm and file.CPM
@ -218,7 +197,7 @@ void load_comfile(void)
} }
if (!fp) if (!fp)
{ {
fprintf(stderr,"%s: Cannot locate %s, %s.com, %s.COM, %s.cpm _or_ %s.CPM\r\n",
fprintf(stderr, "%s: Cannot locate %s, %s.com, %s.COM, %s.cpm _or_ %s.CPM\n",
progname, argv[1], argv[1], argv[1], argv[1], argv[1]); progname, argv[1], argv[1], argv[1], argv[1], argv[1]);
zxcc_term(); zxcc_term();
zxcc_exit(1); zxcc_exit(1);
@ -233,16 +212,16 @@ void load_comfile(void)
} }
fclose(fp); fclose(fp);
/* read() can corrupt buffer area following data read if length
* of data read is less than buffer. Clean it up. */
memset(RAM + 0x0100 + com_len, 0, 0xFD00 - com_len); memset(RAM + 0x0100 + com_len, 0, 0xFD00 - com_len);
Msg("Loaded %d bytes from %s\n", com_len, fname);
DBGMSGV("Loaded %d bytes from %s\n", com_len, fname);
} }
unsigned int in() { return 0; } unsigned int in() { return 0; }
unsigned int out() { return 0; } unsigned int out() { return 0; }
/* /*
* xltname: Convert a unix filepath into a CP/M compatible drive:name form. * xltname: Convert a unix filepath into a CP/M compatible drive:name form.
* The unix filename must be 8.3 or the CP/M code will reject it. * The unix filename must be 8.3 or the CP/M code will reject it.
@ -273,7 +252,6 @@ int main(int ac, char **av)
char* pCmd, * str; char* pCmd, * str;
char* tmpenv; char* tmpenv;
argc = ac; argc = ac;
argv = av; argv = av;
#ifdef __PACIFIC__ /* Pacific C doesn't support argv[0] */ #ifdef __PACIFIC__ /* Pacific C doesn't support argv[0] */
@ -289,16 +267,13 @@ int main(int ac, char **av)
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "\n\n"); fprintf(stderr, "\n\n");
Msg("Start of execution: ");
DBGMSG("Start of execution: ");
for (n = 0; n < argc; n++) for (n = 0; n < argc; n++)
fprintf(stderr, " %s", argv[n]); fprintf(stderr, " %s", argv[n]);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
if (_isatty(STDIN_FILENO))
Msg("Using interactive console mode\n");
else
Msg("Using standard input/ouput mode\n");
term_init();
if (sizeof(int) > 8 || sizeof(byte) != 1 || sizeof(word) != 2) if (sizeof(int) > 8 || sizeof(byte) != 1 || sizeof(word) != 2)
{ {
@ -313,14 +288,6 @@ int main(int ac, char **av)
zxcc_exit(1); zxcc_exit(1);
} }
#ifdef _WIN32
setmode(STDIN_FILENO, O_BINARY );
setmode(STDOUT_FILENO, O_BINARY );
#else
if (_isatty(STDIN_FILENO))
raw_init();
#endif
/* Parse arguments. An argument can be either: /* Parse arguments. An argument can be either:
* preceded by a '-', in which case it is copied in as-is, less the * preceded by a '-', in which case it is copied in as-is, less the
@ -360,9 +327,9 @@ int main(int ac, char **av)
if ((tmpenv = getenv("INCDIR80"))) if ((tmpenv = getenv("INCDIR80")))
mkpath(incdir80, tmpenv, ""); mkpath(incdir80, tmpenv, "");
Msg("BINDIR80=\"%s\"\n", bindir80);
Msg("LIBDIR80=\"%s\"\n", libdir80);
Msg("INCDIR80=\"%s\"\n", incdir80);
DBGMSGV("BINDIR80=\"%s\"\n", bindir80);
DBGMSGV("LIBDIR80=\"%s\"\n", libdir80);
DBGMSGV("INCDIR80=\"%s\"\n", incdir80);
xlt_map(0, bindir80); /* Establish the 3 fixed mappings */ xlt_map(0, bindir80); /* Establish the 3 fixed mappings */
xlt_map(1, libdir80); xlt_map(1, libdir80);
@ -401,7 +368,7 @@ int main(int ac, char **av)
parse_to_fcb(str, 0x6C); parse_to_fcb(str, 0x6C);
// This statement is very useful when creating a client like zxc or zxas // This statement is very useful when creating a client like zxc or zxas
Msg("Command tail is \"%s\"\n", pCmd);
DBGMSGV("Command tail is \"%s\"\n", pCmd);
load_bios(); load_bios();
@ -462,10 +429,6 @@ int zxcc_term(void)
{ {
word n; word n;
#ifndef _WIN32
deinit_raw();
#endif
//n = RAM[0x81]; /* Get the return code. This is Hi-Tech C */ //n = RAM[0x81]; /* Get the return code. This is Hi-Tech C */
//n = (n << 8) | RAM[0x80]; /* specific and fails with other COM files */ //n = (n << 8) | RAM[0x80]; /* specific and fails with other COM files */
n = 0; n = 0;
@ -476,13 +439,16 @@ int zxcc_term(void)
{ /* (my modified Hi-Tech C library uses this */ { /* (my modified Hi-Tech C library uses this */
n = cpm_error; /* call) */ n = cpm_error; /* call) */
} }
if (n < 256 || n == 0xFFFF) if (n < 256 || n == 0xFFFF)
{
Msg("Return code %d\n", n);
DBGMSGV("Return code %d\n", n);
else
n = 0;
term_reset();
return n; return n;
} }
else return 0;
}
/* helper function to build full path */ /* helper function to build full path */
/* make sure that a / or \ is present at the end of path /* make sure that a / or \ is present at the end of path
@ -503,11 +469,11 @@ void raw_init(void)
{ {
struct termios tc_raw; struct termios tc_raw;
Msg("Enabling RAW Terminal IO\n");
DBGMSG("Enabling RAW Terminal IO\n");
if (tcgetattr(STDIN_FILENO, &tc_orig) == -1) if (tcgetattr(STDIN_FILENO, &tc_orig) == -1)
{ {
Msg("Failed to enable RAW Terminal IO - tcgetattr() failed\n");
DBGMSG("Failed to enable RAW Terminal IO - tcgetattr() failed\n");
zxcc_exit(1);; zxcc_exit(1);;
} }
@ -527,11 +493,11 @@ void raw_init(void)
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_raw) == -1) if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_raw) == -1)
{ {
Msg("Failed to enable RAW Terminal IO - tcsetattr() failed\n");
DBGMSG("Failed to enable RAW Terminal IO - tcsetattr() failed\n");
zxcc_exit(1); zxcc_exit(1);
} }
Msg("Enabled RAW Terminal IO\n");
DBGMSG("Enabled RAW Terminal IO\n");
return; return;
} }
@ -540,13 +506,39 @@ void deinit_raw(void)
{ {
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_orig) == -1) if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_orig) == -1)
{ {
Msg("Failed to disable RAW Terminal IO - tcsetattr() failed\n");
DBGMSG("Failed to disable RAW Terminal IO - tcsetattr() failed\n");
return; return;
} }
Msg("Disabled RAW Terminal IO\n");
DBGMSG("Disabled RAW Terminal IO\n");
return; return;
} }
#endif #endif
void term_init(void)
{
#ifdef _WIN32
setmode(STDIN_FILENO, O_BINARY);
setmode(STDOUT_FILENO, O_BINARY);
#else
if (_isatty(STDIN_FILENO))
raw_init();
#endif
if (_isatty(STDIN_FILENO))
DBGMSG("Using interactive console mode\n");
else
DBGMSG("Using standard input/output mode\n");
return;
}
void term_reset(void)
{
#ifndef _WIN32
if (_isatty(STDIN_FILENO))
deinit_raw();
#endif
}

27
Tools/unix/zxcc/zxcc.h

@ -22,9 +22,15 @@
#endif #endif
/* the default sub directories trailing / is required */ /* the default sub directories trailing / is required */
#ifdef _WIN32
#define BIN80 "bin80\\"
#define LIB80 "lib80\\"
#define INC80 "include80\\"
#else
#define BIN80 "bin80/" #define BIN80 "bin80/"
#define LIB80 "lib80/" #define LIB80 "lib80/"
#define INC80 "include80/" #define INC80 "include80/"
#endif
#ifndef BINDIR80 #ifndef BINDIR80
#define BINDIR80 CPMDIR80 BIN80 #define BINDIR80 CPMDIR80 BIN80
@ -58,6 +64,7 @@ extern char incdir80[];
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <io.h> #include <io.h>
#include <conio.h>
#define strcasecmp _stricmp #define strcasecmp _stricmp
#ifndef STDIN_FILENO #ifndef STDIN_FILENO
#define STDIN_FILENO _fileno(stdin) #define STDIN_FILENO _fileno(stdin)
@ -90,11 +97,11 @@ extern char incdir80[];
#include "cpmgsx.h" #include "cpmgsx.h"
#endif #endif
#include "cpmredir.h" /* BDOS disc simulation */
typedef unsigned char byte; /* Must be exactly 8 bits */ typedef unsigned char byte; /* Must be exactly 8 bits */
typedef unsigned short word; /* Must be exactly 16 bits */ typedef unsigned short word; /* Must be exactly 16 bits */
#include "cpmredir.h" /* BDOS disc simulation */
/* Prototypes */ /* Prototypes */
void ed_fe (byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, void ed_fe (byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
@ -106,12 +113,21 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
void dump_regs(FILE *fp, byte a, byte b, byte c, byte d, byte e, byte f, void dump_regs(FILE *fp, byte a, byte b, byte c, byte d, byte e, byte f,
byte h, byte l, word pc, word ix, word iy); byte h, byte l, word pc, word ix, word iy);
void Msg(char *s, ...); void Msg(char *s, ...);
void DbgMsg(const char *file, int line, const char *func, char *s, ...);
int zxcc_term(void); int zxcc_term(void);
void zxcc_exit(int code); void zxcc_exit(int code);
byte cin(void);
void cout(byte);
int cstat(void);
void term_init(void);
void term_reset(void);
#ifdef DEBUG
#define DBGMSGV(s, ...) DbgMsg(__FILE__, __LINE__, __func__, s, __VA_ARGS__)
#define DBGMSG(s) DbgMsg(__FILE__, __LINE__, __func__, s)
#else
#define DBGMSGV(s, ...)
#define DBGMSG(s)
#endif
/* Global variables */ /* Global variables */
@ -123,4 +139,3 @@ extern byte RAM[65536]; /* The Z80's address space */
/* Z80 CPU emulation */ /* Z80 CPU emulation */
#include "z80.h" #include "z80.h"

6
Tools/unix/zxcc/zxdbdos.c

@ -10,7 +10,6 @@
properly. properly.
*/ */
/* If a file could not be found on the default drive, try again on a "search" /* If a file could not be found on the default drive, try again on a "search"
drive (A: for .COM files, B: for .LIB and .OBJ files) */ drive (A: for .COM files, B: for .LIB and .OBJ files) */
@ -75,8 +74,6 @@ word x_fcb_open(byte *fcb, byte *dma)
return rv; return rv;
} }
word x_fcb_stat(byte* fcb) word x_fcb_stat(byte* fcb)
{ {
word rv = fcb_stat(fcb); word rv = fcb_stat(fcb);
@ -92,6 +89,3 @@ word x_fcb_stat(byte *fcb)
} }
return rv; return rv;
} }

4
Tools/unix/zxcc/zxdbdos.h

@ -1,8 +1,4 @@
int fcbforce(byte* fcb, byte* odrv); int fcbforce(byte* fcb, byte* odrv);
word x_fcb_open(byte* fcb, byte* dma); word x_fcb_open(byte* fcb, byte* dma);
word x_fcb_stat(byte* fcb); word x_fcb_stat(byte* fcb);

BIN
Tools/zxcc/zxcc-src.zip

Binary file not shown.

BIN
Tools/zxcc/zxcc.exe

Binary file not shown.

BIN
Tools/zxcc/zxccdbg.exe

Binary file not shown.
Loading…
Cancel
Save