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.
patch
Wayne Warthen 4 years ago
parent
commit
2c0b818aba
  1. 2
      Binary/Apps/Makefile
  2. 6
      Tools/unix/zxcc/Build-VC.cmd
  3. 236
      Tools/unix/zxcc/cbops.h
  4. 5
      Tools/unix/zxcc/config.h.windows
  5. 20
      Tools/unix/zxcc/cpmdrv.c
  6. 210
      Tools/unix/zxcc/cpmglob.c
  7. 123
      Tools/unix/zxcc/cpmint.h
  8. 14
      Tools/unix/zxcc/cpmparse.c
  9. 547
      Tools/unix/zxcc/cpmredir.c
  10. 117
      Tools/unix/zxcc/cpmredir.h
  11. 81
      Tools/unix/zxcc/dirent.c
  12. 30
      Tools/unix/zxcc/dirent.h
  13. 26
      Tools/unix/zxcc/drdos.c
  14. 24
      Tools/unix/zxcc/track.c
  15. 242
      Tools/unix/zxcc/util.c
  16. 40
      Tools/unix/zxcc/xlt.c
  17. 2
      Tools/unix/zxcc/z80.c
  18. 12
      Tools/unix/zxcc/z80.h
  19. 66
      Tools/unix/zxcc/zxbdos.c
  20. 9
      Tools/unix/zxcc/zxbdos.h
  21. 25
      Tools/unix/zxcc/zxcbdos.c
  22. 6
      Tools/unix/zxcc/zxcbdos.h
  23. 186
      Tools/unix/zxcc/zxcc.c
  24. 33
      Tools/unix/zxcc/zxcc.h
  25. 20
      Tools/unix/zxcc/zxdbdos.c
  26. 10
      Tools/unix/zxcc/zxdbdos.h
  27. BIN
      Tools/zxcc/zxcc-src.zip
  28. BIN
      Tools/zxcc/zxcc.exe
  29. BIN
      Tools/zxcc/zxccdbg.exe

2
Binary/Apps/Makefile

@ -8,4 +8,4 @@ all::
mkdir -p Tunes
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
::
:: 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
:: to do no harm.
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
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
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
copy cpm\bios.bin .

236
Tools/unix/zxcc/cbops.h

@ -33,129 +33,129 @@
#define res(n,x) (x&=~(1<<n))
{
unsigned short addr;
unsigned char op,reg,val;
if(ixoriy){
addr=(ixoriy==1?ix:iy)+(signed char)fetch(pc);
unsigned short addr;
unsigned char op, reg, val;
if (ixoriy) {
addr = (ixoriy == 1 ? ix : iy) + (signed char)fetch(pc);
pc++;
tstates+=8;
op=fetch(pc);
reg=op&7;
op=(op&0xf8)|6;
}
else{
op=fetch(pc);
tstates+=4;
tstates += 8;
op = fetch(pc);
reg = op & 7;
op = (op & 0xf8) | 6;
}
else {
op = fetch(pc);
tstates += 4;
radjust++;
addr=hl;
}
pc++;
addr = hl;
}
pc++;
if(op<64)switch(op){
case 0: rlc(b); break;
case 1: rlc(c); break;
case 2: rlc(d); break;
case 3: rlc(e); break;
case 4: rlc(h); break;
case 5: rlc(l); break;
case 6: tstates+=7;val=fetch(addr);rlc(val);store(addr,val);break;
case 7: rlc(a); break;
case 8: rrc(b); break;
case 9: rrc(c); break;
case 10: rrc(d); break;
case 11: rrc(e); break;
case 12: rrc(h); break;
case 13: rrc(l); break;
case 14: tstates+=7;val=fetch(addr);rrc(val);store(addr,val);break;
case 15: rrc(a); break;
case 0x10: rl(b); break;
case 0x11: rl(c); break;
case 0x12: rl(d); break;
case 0x13: rl(e); break;
case 0x14: rl(h); break;
case 0x15: rl(l); break;
case 0x16: tstates+=7;val=fetch(addr);rl(val);store(addr,val);break;
case 0x17: rl(a); break;
case 0x18: rr(b); break;
case 0x19: rr(c); break;
case 0x1a: rr(d); break;
case 0x1b: rr(e); break;
case 0x1c: rr(h); break;
case 0x1d: rr(l); break;
case 0x1e: tstates+=7;val=fetch(addr);rr(val);store(addr,val);break;
case 0x1f: rr(a); break;
case 0x20: sla(b); break;
case 0x21: sla(c); break;
case 0x22: sla(d); break;
case 0x23: sla(e); break;
case 0x24: sla(h); break;
case 0x25: sla(l); break;
case 0x26: tstates+=7;val=fetch(addr);sla(val);store(addr,val);break;
case 0x27: sla(a); break;
case 0x28: sra(b); break;
case 0x29: sra(c); break;
case 0x2a: sra(d); break;
case 0x2b: sra(e); break;
case 0x2c: sra(h); break;
case 0x2d: sra(l); break;
case 0x2e: tstates+=7;val=fetch(addr);sra(val);store(addr,val);break;
case 0x2f: sra(a); break;
case 0x30: sll(b); break;
case 0x31: sll(c); break;
case 0x32: sll(d); break;
case 0x33: sll(e); break;
case 0x34: sll(h); break;
case 0x35: sll(l); break;
case 0x36: tstates+=7;val=fetch(addr);sll(val);store(addr,val);break;
case 0x37: sll(a); break;
case 0x38: srl(b); break;
case 0x39: srl(c); break;
case 0x3a: srl(d); break;
case 0x3b: srl(e); break;
case 0x3c: srl(h); break;
case 0x3d: srl(l); break;
case 0x3e: tstates+=7;val=fetch(addr);srl(val);store(addr,val);break;
case 0x3f: srl(a); break;
}
else{
unsigned char n=(op>>3)&7;
switch(op&0xc7){
case 0x40: bit(n,b); break;
case 0x41: bit(n,c); break;
case 0x42: bit(n,d); break;
case 0x43: bit(n,e); break;
case 0x44: bit(n,h); break;
case 0x45: bit(n,l); break;
case 0x46: tstates+=4;val=fetch(addr);bit(n,val);store(addr,val);break;
case 0x47: bit(n,a); break;
case 0x80: res(n,b); break;
case 0x81: res(n,c); break;
case 0x82: res(n,d); break;
case 0x83: res(n,e); break;
case 0x84: res(n,h); break;
case 0x85: res(n,l); break;
case 0x86: tstates+=4;val=fetch(addr);res(n,val);store(addr,val);break;
case 0x87: res(n,a); break;
case 0xc0: set(n,b); break;
case 0xc1: set(n,c); break;
case 0xc2: set(n,d); break;
case 0xc3: set(n,e); break;
case 0xc4: set(n,h); break;
case 0xc5: set(n,l); break;
case 0xc6: tstates+=4;val=fetch(addr);set(n,val);store(addr,val);break;
case 0xc7: set(n,a); break;
}
}
if(ixoriy)switch(reg){
case 0:b=val; break;
case 1:c=val; break;
case 2:d=val; break;
case 3:e=val; break;
case 4:h=val; break;
case 5:l=val; break;
case 7:a=val; break;
if (op < 64)switch (op) {
case 0: rlc(b); break;
case 1: rlc(c); break;
case 2: rlc(d); break;
case 3: rlc(e); break;
case 4: rlc(h); break;
case 5: rlc(l); break;
case 6: tstates += 7; val = fetch(addr); rlc(val); store(addr, val); break;
case 7: rlc(a); break;
case 8: rrc(b); break;
case 9: rrc(c); break;
case 10: rrc(d); break;
case 11: rrc(e); break;
case 12: rrc(h); break;
case 13: rrc(l); break;
case 14: tstates += 7; val = fetch(addr); rrc(val); store(addr, val); break;
case 15: rrc(a); break;
case 0x10: rl(b); break;
case 0x11: rl(c); break;
case 0x12: rl(d); break;
case 0x13: rl(e); break;
case 0x14: rl(h); break;
case 0x15: rl(l); break;
case 0x16: tstates += 7; val = fetch(addr); rl(val); store(addr, val); break;
case 0x17: rl(a); break;
case 0x18: rr(b); break;
case 0x19: rr(c); break;
case 0x1a: rr(d); break;
case 0x1b: rr(e); break;
case 0x1c: rr(h); break;
case 0x1d: rr(l); break;
case 0x1e: tstates += 7; val = fetch(addr); rr(val); store(addr, val); break;
case 0x1f: rr(a); break;
case 0x20: sla(b); break;
case 0x21: sla(c); break;
case 0x22: sla(d); break;
case 0x23: sla(e); break;
case 0x24: sla(h); break;
case 0x25: sla(l); break;
case 0x26: tstates += 7; val = fetch(addr); sla(val); store(addr, val); break;
case 0x27: sla(a); break;
case 0x28: sra(b); break;
case 0x29: sra(c); break;
case 0x2a: sra(d); break;
case 0x2b: sra(e); break;
case 0x2c: sra(h); break;
case 0x2d: sra(l); break;
case 0x2e: tstates += 7; val = fetch(addr); sra(val); store(addr, val); break;
case 0x2f: sra(a); break;
case 0x30: sll(b); break;
case 0x31: sll(c); break;
case 0x32: sll(d); break;
case 0x33: sll(e); break;
case 0x34: sll(h); break;
case 0x35: sll(l); break;
case 0x36: tstates += 7; val = fetch(addr); sll(val); store(addr, val); break;
case 0x37: sll(a); break;
case 0x38: srl(b); break;
case 0x39: srl(c); break;
case 0x3a: srl(d); break;
case 0x3b: srl(e); break;
case 0x3c: srl(h); break;
case 0x3d: srl(l); break;
case 0x3e: tstates += 7; val = fetch(addr); srl(val); store(addr, val); break;
case 0x3f: srl(a); break;
}
else {
unsigned char n = (op >> 3) & 7;
switch (op & 0xc7) {
case 0x40: bit(n, b); break;
case 0x41: bit(n, c); break;
case 0x42: bit(n, d); break;
case 0x43: bit(n, e); break;
case 0x44: bit(n, h); break;
case 0x45: bit(n, l); break;
case 0x46: tstates += 4; val = fetch(addr); bit(n, val); store(addr, val); break;
case 0x47: bit(n, a); break;
case 0x80: res(n, b); break;
case 0x81: res(n, c); break;
case 0x82: res(n, d); break;
case 0x83: res(n, e); break;
case 0x84: res(n, h); break;
case 0x85: res(n, l); break;
case 0x86: tstates += 4; val = fetch(addr); res(n, val); store(addr, val); break;
case 0x87: res(n, a); break;
case 0xc0: set(n, b); break;
case 0xc1: set(n, c); break;
case 0xc2: set(n, d); break;
case 0xc3: set(n, e); break;
case 0xc4: set(n, h); break;
case 0xc5: set(n, l); break;
case 0xc6: tstates += 4; val = fetch(addr); set(n, val); store(addr, val); break;
case 0xc7: set(n, a); break;
}
}
if (ixoriy)switch (reg) {
case 0:b = val; break;
case 1:c = val; break;
case 2:d = val; break;
case 3:e = val; break;
case 4:h = val; break;
case 5:l = val; break;
case 7:a = val; break;
}
}
#undef var_t
#undef rlc

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

@ -1,5 +1,10 @@
#define HAVE_WINDOWS_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 _WIN32_WINNT _WIN32_WINNT_WINXP // target Windows XP
//#define FILETRACKER 1

20
Tools/unix/zxcc/cpmdrv.c

@ -23,10 +23,10 @@
#include "cpmint.h"
#ifdef _WIN32
static char *drive_to_hostdrive(int cpm_drive)
static char* drive_to_hostdrive(int cpm_drive)
{
static char prefix[CPM_MAXPATH];
char *lpfp;
char* lpfp;
dword dw;
if (!redir_drive_prefix[cpm_drive]) return NULL;
@ -60,7 +60,7 @@ cpm_byte fcb_reset(void)
}
cpm_word fcb_drive (cpm_byte drv)
cpm_word fcb_drive(cpm_byte drv)
{
if (redir_drive_prefix[drv][0])
{
@ -77,11 +77,11 @@ cpm_byte fcb_getdrv(void)
}
cpm_byte fcb_user (cpm_byte usr)
cpm_byte fcb_user(cpm_byte usr)
{
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;
}
@ -152,18 +152,17 @@ static cpm_byte exdpb[0x11] = {
0x02, 0x03 /* 512-byte sectors */
};
cpm_word fcb_getdpb(cpm_byte *dpb)
cpm_word fcb_getdpb(cpm_byte* dpb)
{
/* Return the example dpb */
memcpy(dpb, &exdpb, 0x11);
return 0x11;
}
/* Create an entirely bogus ALV
* TODO: Make it a bit better */
cpm_word fcb_getalv(cpm_byte *alv, cpm_word max)
cpm_word fcb_getalv(cpm_byte* alv, cpm_word max)
{
if (max > 1024) max = 1024;
@ -175,12 +174,9 @@ cpm_word fcb_getalv(cpm_byte *alv, cpm_word max)
/* Get disk free space */
cpm_word fcb_dfree (cpm_byte drive, cpm_byte *dma)
cpm_word fcb_dfree(cpm_byte drive, cpm_byte* dma)
{
/* Return half of disk capacity */
redir_wr24(dma, 0x8000L); /* 8MB / 128 / 2 */
return 0;
}

210
Tools/unix/zxcc/cpmglob.c

@ -22,11 +22,10 @@
#include "cpmint.h"
#ifdef _MSC_VER
#define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0)
#define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0)
#endif
static cpm_byte *find_fcb;
static cpm_byte* find_fcb;
static int find_n;
static int find_ext = 0;
static int find_xfcb = 0;
@ -48,15 +47,17 @@ static char upper(char c)
* 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)
{
int n;
size_t m;
char *dotpos;
char* dotpos;
m = strlen(s);
@ -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,
* normalizing case as we go. all this goes into 'pattern'
*/
for (n = 0; n < 11; n++) pattern[n] = ' ';
/* 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++) {
pattern[n] = upper(s[n]) & 0x7F;
}
} else { /* at least one dot */
}
else { /* at least one dot */
if (strchr(dotpos + 1, '.')) { /* More than 1 dot */
return 0;
}
@ -100,13 +103,14 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern)
* handle special case where fcb[0] == '?' or fcb[0] & 0x80
* this is used to return a full directory list on bdos's
*/
if (((fcb[0] & 0x7F) == '?') || (fcb[0] & 0x80)) {
return 1;
}
for (n = 0; n < 11; n++)
{
if (fcb[n+1] == '?') continue;
if ((pattern[n] & 0x7F) != (fcb[n+1] & 0x7F))
if (fcb[n + 1] == '?') continue;
if ((pattern[n] & 0x7F) != (fcb[n + 1] & 0x7F))
{
return 0;
}
@ -114,13 +118,12 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern)
return 1; /* Success! */
}
/* Get the next entry from the host's directory matching "fcb" */
static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern,
struct stat *st)
static struct dirent* next_entry(DIR* dir, cpm_byte* fcb, cpm_byte* pattern,
struct stat* st)
{
struct dirent *en;
struct dirent* en;
int unsatisfied;
int drv = fcb[0] & 0x7F;
@ -131,26 +134,25 @@ static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern,
for (unsatisfied = 1; unsatisfied; )
{
/* 1. Get the next entry */
en = readdir(dir);
if (!en) return NULL; /* No next entry */
++entryno; /* 0 for 1st, 1 for 2nd, etc. */
/* 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))
{
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]);
strcat(target_name, en->d_name);
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 */
}
if (S_ISDIR(st->st_mode))
@ -166,16 +168,15 @@ static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern,
return en;
}
void volume_label(int drv, cpm_byte *dma)
void volume_label(int drv, cpm_byte* dma)
{
struct stat st;
memset(dma, 0x20, 12); /* Volume label */
/* Get label name */
redir_get_label(drv, (char *)(dma + 1));
redir_get_label(drv, (char*)(dma + 1));
/* [0x0c] = label byte
* [0x0d] = password byte (=0)
* [0x10-0x17] = password
@ -193,7 +194,7 @@ void volume_label(int drv, cpm_byte *dma)
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;
}
@ -201,15 +202,13 @@ void volume_label(int drv, cpm_byte *dma)
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;
int drv, attrib;
long recs;
struct stat st;
struct dirent *de;
struct dirent* de;
cpm_word rights;
drv = (fcb[0] & 0x7F);
@ -249,12 +248,10 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma)
return 0;
}
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 (!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
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;
hostdir = opendir(redir_drive_prefix[drv]);
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;
}
/* We have a handle to the directory. */
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 & 0x20)) dma[11] |= 0x80; /* archive */
/* TODO: Under Unix, work out correct RO setting */
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;
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 */
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;
}
#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
int rv;
#endif
SHOWNAME("fcb_find1")
FCBENT(fcb);
redir_log_fcb(fcb);
@ -374,17 +356,18 @@ cpm_word fcb_find1 (cpm_byte *fcb, cpm_byte *dma) /* 0x11 */
find_fcb = fcb;
find_ext = 0;
find_xfcb = 0;
#ifdef DEBUG
rv = redir_find(find_n, fcb, dma);
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
return redir_find(find_n, find_fcb, dma);
FCBRET(redir_find(find_n, find_fcb, dma));
#endif
}
@ -392,43 +375,50 @@ cpm_word fcb_find1 (cpm_byte *fcb, cpm_byte *dma) /* 0x11 */
* programs that do know about it will just pass in the same parameter
* that they did to function 0x11 */
cpm_word fcb_find2 (cpm_byte *fcb, cpm_byte *dma) /* 0x12 */
cpm_word fcb_find2(cpm_byte* fcb, cpm_byte* dma) /* 0x12 */
{
#ifdef DEBUG
int rv;
char fname[CPM_MAXPATH];
#endif
FCBENT(find_fcb);
#ifdef DEBUG
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
++find_n;
#ifdef DEBUG
rv = redir_find(find_n, find_fcb, dma);
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
return redir_find(find_n, find_fcb, dma);
FCBRET(redir_find(find_n, find_fcb, dma));
#endif
}
/* Under CP/M, unlinking works with wildcards */
cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma)
cpm_word fcb_unlink(cpm_byte* fcb, cpm_byte* dma)
{
DIR *hostdir;
DIR* hostdir;
int drv;
struct dirent *de;
struct dirent* de;
struct stat st;
int handle = 0;
int unpasswd = 0;
char fname[CPM_MAXPATH];
int del_cnt = 0;
SHOWNAME("fcb_unlink")
FCBENT(fcb);
if (fcb[5] & 0x80) unpasswd = 1; /* Remove password rather than file */
@ -438,91 +428,111 @@ cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma)
if (!drv || drv == '?') drv = redir_cpmdrive;
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
redir_fcb2unix(fcb, fname);
redir_Msg("fcb_unlink(\"%s\")\n", fname);
DBGMSGV("fcb_unlink('%s')\n", fname);
#endif
/* 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]);
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. */
do
{
de = next_entry(hostdir, fcb, (cpm_byte *)fname, &st);
de = next_entry(hostdir, fcb, (cpm_byte*)fname, &st);
if (de)
{
strcpy(target_name, redir_drive_prefix[drv]);
strcat(target_name, de->d_name);
redir_Msg("Deleting %s\n", de->d_name);
DBGMSGV("deleting '%s'\n", de->d_name);
if (unpasswd)
{
#ifdef __MSDOS__
if (redir_drdos)
{
handle = redir_drdos_put_rights (target_name, dma, 0);
handle = redir_drdos_put_rights(target_name, dma, 0);
}
else handle = 0;
#endif
}
else if (fcb[0] & 0x80)
{
DBGMSGV("rmdir '%s'\n", target_name);
handle = rmdir(target_name);
if (handle && redir_password_error())
{
DBGMSGV("rmdir failed (errno=%lu): %s\n", errno, strerror(errno));
redir_password_append(target_name, dma);
DBGMSGV("rmdir '%s'\n", target_name);
handle = rmdir(target_name);
}
if (handle)
DBGMSGV("rmdir failed (errno=%lu): %s\n", errno, strerror(errno));
}
else
{
releaseFile(target_name);
DBGMSGV("unlink '%s'\n", target_name);
handle = unlink(target_name);
if (handle && redir_password_error())
{
DBGMSGV("unlink failed (errno=%lu): %s\n", errno, strerror(errno));
redir_password_append(target_name, dma);
releaseFile(target_name);
DBGMSGV("unlink '%s'\n", 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)
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);
return 0xFF;
FCBRET(0xFF);
}
redir_Msg("Ret: 0\n");
DBGMSG("delete processing succeeded\n");
closedir(hostdir);
return 0;
FCBRET(0);
}
#ifdef __MSDOS__
cpm_word redir_get_label(cpm_byte drv, char *pattern)
cpm_word redir_get_label(cpm_byte drv, char* pattern)
{
char strs[10];
struct ffblk fblk;
int done;
char *s;
char* s;
int n;
/* We need the drive prefix to be of the form "C:\etc..." */
@ -531,7 +541,7 @@ cpm_word redir_get_label(cpm_byte drv, char *pattern)
if (!redir_drive_prefix[drv][0] || redir_drive_prefix[drv][1] != ':')
return 0;
sprintf(strs,"%c:/*.*", redir_drive_prefix[drv][0]);
sprintf(strs, "%c:/*.*", redir_drive_prefix[drv][0]);
done = findfirst(strs, &fblk, FA_LABEL);
while (!done)
@ -562,9 +572,9 @@ cpm_word redir_get_label(cpm_byte drv, char *pattern)
return 0;
}
#else
cpm_word redir_get_label(cpm_byte drv, char *pattern)
cpm_word redir_get_label(cpm_byte drv, char* pattern)
{
char *dname;
char* dname;
size_t l;
int n;
@ -585,6 +595,4 @@ cpm_word redir_get_label(cpm_byte drv, char *pattern)
return 0;
}
#endif

123
Tools/unix/zxcc/cpmint.h

@ -20,13 +20,7 @@
This file holds internal declarations for the library.
*/
#ifndef _WIN32
#include "config.h"
#define DIRSEP "/"
#else
#include "config.h"
#define DIRSEP "/\\:"
#endif
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@ -47,16 +41,12 @@
#include <errno.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#ifdef HAVE_DIRECT_H
#endif
#ifdef HAVE_DIRECT_H
#include <direct.h>
#endif
#else
#ifdef __WATCOMC__
#endif
#ifdef HAVE_IO_H
#include <io.h>
#include <direct.h>
#else
#include "dirent.h"
#endif
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
@ -94,20 +84,32 @@
/* MSDOS includes removed */
#ifdef _WIN32
#define DIRSEP "/"
#define mkdir(dir, mode) _mkdir(dir)
#define strcasecmp _stricmp
int truncate(const char* path, off_t length); /* see util.c */
#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
#define DIRSEP "/\\:"
#define CASE_SENSITIVE_FILESYSTEM 1
#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
>= sizeof(int) */
#include "cpmredir.h"
#ifdef CPMDEF
#define EXT
#define INIT(x) =x
@ -146,16 +148,14 @@ EXT cpm_word redir_ro_drives INIT(0);
#undef EXT
#undef INIT
/* 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);
/* Open FCB, set file attributes */
int redir_ofile(cpm_byte * fcb, char *s);
int redir_ofile(cpm_byte* fcb, char* s);
/* Check that the FCB we have is valid */
int redir_verify_fcb(cpm_byte *fcb);
int redir_verify_fcb(cpm_byte* fcb);
#ifndef O_BINARY /* Necessary in DOS, not present in Linux */
#define O_BINARY 0
@ -163,43 +163,67 @@ int redir_verify_fcb(cpm_byte *fcb);
/* Facilities for debug tracing */
long zxlseek(int fd, long offset, int wh);
#ifdef _WIN32
char* GetErrorStr(DWORD);
#endif
#ifdef DEBUG
// long zxlseek(int fd, long offset, int wh);
void redir_Msg(char *s, ...);
void redir_showfcb(cpm_byte *fcb);
// long zxlseek(int fd, long offset, int wh);
// void redir_Msg(char *s, ...);
void DbgMsg(const char* file, int line, const char* func, char* s, ...);
void redir_showfcb(cpm_byte* fcb);
#else
// #define zxlseek lseek
/* Warning: This is a GCC extension */
#define redir_Msg(x, ...)
#define redir_showfcb(x)
// #define zxlseek lseek
/* Warning: This is a GCC extension */
// #define redir_Msg(x, ...)
#define redir_showfcb(x)
#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 */
long redir_get_fcb_pos(cpm_byte *fcb);
long redir_get_fcb_pos(cpm_byte* fcb);
/* Write "sequential access" pointer to FCB */
void redir_put_fcb_pos(cpm_byte *fcb, long npos);
void redir_put_fcb_pos(cpm_byte* fcb, long npos);
/* Convert time_t to CP/M day count/hours/minutes */
dword redir_cpmtime(time_t t);
/* 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
little-endian. */
void redir_wr24(cpm_byte *addr, dword v);
void redir_wr32(cpm_byte *addr, dword v);
dword redir_rd24(cpm_byte *addr);
dword redir_rd32(cpm_byte *addr);
void redir_wr24(cpm_byte* addr, dword v);
void redir_wr32(cpm_byte* addr, dword v);
dword redir_rd24(cpm_byte* addr);
dword redir_rd32(cpm_byte* addr);
/* If you have 64-bit file handles, you'll need to write separate wrhandle()
and rdhandle() routines */
@ -209,20 +233,19 @@ dword redir_rd32(cpm_byte *addr);
/* Mark a drive as logged in */
void redir_log_drv(cpm_byte drv);
void redir_log_fcb(cpm_byte *fcb);
void redir_log_fcb(cpm_byte* fcb);
/* Check if a drive is software read-only */
int redir_ro_drv(cpm_byte drv);
int redir_ro_fcb(cpm_byte *fcb);
int redir_ro_fcb(cpm_byte* fcb);
/* Translate errno to a CP/M error */
cpm_word redir_xlt_err(void);
/* 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:
*
@ -233,17 +256,19 @@ cpm_word redir_drdos_pwmode(cpm_byte b);
cpm_byte redir_cpm_pwmode(cpm_word w);
/* Get DRDOS access rights for a file */
cpm_word redir_drdos_get_rights(char *path);
cpm_word redir_drdos_get_rights(char* path);
/* Set DRDOS access rights and/or password */
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);
/* Was the last error caused by invalid password? */
cpm_word redir_password_error(void);
/* Append password to filename (FILE.TYP -> FILE.TYP;PASSWORD) */
void redir_password_append(char *s, cpm_byte *dma);
void redir_password_append(char* s, cpm_byte* dma);
void releaseFile(char *fname);
int trackFile(char *fname, void *fcb, int fd);
void releaseFile(char* fname);
int trackFile(char* fname, void* fcb, int fd);
#define releaseFCB(fcb) trackFile(NULL, fcb, -1)
extern byte RAM[65536]; /* The Z80's address space */

14
Tools/unix/zxcc/cpmparse.c

@ -24,14 +24,14 @@
#define is_num(c) ((c >= '0') && (c <= '9'))
static int parse_drive_user(char *txt, cpm_byte *fcb)
static int parse_drive_user(char* txt, cpm_byte* fcb)
{
char uid[4], drvid[4];
int up, dp;
for (up = dp = 0; *txt != ':'; ++txt)
{
if (is_num (*txt)) uid [up++] = *txt;
if (is_num(*txt)) uid[up++] = *txt;
if (isalpha(*txt)) drvid[dp++] = *txt;
if (!is_num(*txt) && !isalpha(*txt)) return -1;
}
@ -50,12 +50,10 @@ static int parse_drive_user(char *txt, cpm_byte *fcb)
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;
char *ntxt, ch;
char* ntxt, ch;
memset(fcb, 0, 0x24);
@ -71,7 +69,7 @@ cpm_word fcb_parse(char *txt, cpm_byte *fcb)
ch = *ntxt;
if (islower(ch)) ch = toupper(ch);
switch(ch)
switch (ch)
{
case 0:
case '\r': /* EOL */
@ -94,7 +92,7 @@ cpm_word fcb_parse(char *txt, cpm_byte *fcb)
phase = 3;
default:
switch(phase)
switch (phase)
{
case 0:
if (nl >= 8) return 0xFFFF;

547
Tools/unix/zxcc/cpmredir.c

File diff suppressed because it is too large

117
Tools/unix/zxcc/cpmredir.h

@ -44,17 +44,17 @@ typedef unsigned short cpm_word;
extern "C" {
#endif
/* Initialise this library. Call this function first.
/* Initialise this library. Call this function first.
*
* Returns 0 if failed to initialise.
*/
int fcb_init(void);
int fcb_init(void);
/* Deinitialise the library. */
/* Deinitialise the library. */
void fcb_deinit(void);
void fcb_deinit(void);
/* Translate a name from the host FS to a CP/M name. This will (if necessary)
/* Translate a name from the host FS to a CP/M name. This will (if necessary)
* create a mapping between a CP/M drive and a host directory path.
*
* CP/M drives A: to O: can be mapped in this way. P: is always the current
@ -62,9 +62,9 @@ void fcb_deinit(void);
*
*/
void xlt_name(char *localname, char *cpmname);
void xlt_name(char* localname, char* cpmname);
/* It is sometimes convenient to set some fixed mappings. This will create
/* It is sometimes convenient to set some fixed mappings. This will create
* a mapping for a given directory.
* Pass drive = -1 for "first available", or 0-15 for A: to P:
* Returns 1 if OK, 0 if requested drive not available.
@ -73,21 +73,20 @@ void xlt_name(char *localname, char *cpmname);
* directory separator!
*/
int xlt_map(int drive, char *localdir);
int xlt_map(int drive, char* localdir);
/*
/*
* This revokes a mapping. No check is made whether CP/M has files open
* on the drive or not.
*/
int xlt_umap(int drive);
/* Find out if a drive is mapped, and if so to what directory */
int xlt_umap(int drive);
char *xlt_getcwd(int drive);
/* Find out if a drive is mapped, and if so to what directory */
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.
*
* I am assuming that your emulator has the CP/M RAM in its normal address
@ -99,53 +98,53 @@ char *xlt_getcwd(int drive);
*
*/
cpm_byte fcb_reset (void); /* 0x0D */
cpm_word fcb_drive (cpm_byte drv); /* 0x0E */
cpm_word fcb_open (cpm_byte *fcb, cpm_byte *dma); /* 0x0F */
cpm_word fcb_close (cpm_byte *fcb); /* 0x10 */
cpm_word fcb_find1 (cpm_byte *fcb, cpm_byte *dma); /* 0x11 */
cpm_word fcb_find2 (cpm_byte *fcb, cpm_byte *dma); /* 0x12 */
cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma); /* 0x13 */
cpm_word fcb_read (cpm_byte *fcb, cpm_byte *dma); /* 0x14 */
cpm_word fcb_write (cpm_byte *fcb, cpm_byte *dma); /* 0x15 */
cpm_word fcb_creat (cpm_byte *fcb, cpm_byte *dma); /* 0x16 */
cpm_word fcb_rename(cpm_byte *fcb, cpm_byte *dma); /* 0x17 */
cpm_word fcb_logvec(void); /* 0x18 */
cpm_byte fcb_getdrv(void); /* 0x19 */
/* DMA is a parameter to routines, not a separate call */
cpm_word fcb_getalv(cpm_byte *alv, cpm_word max); /* 0x1B */
/* Get alloc vector: caller must provide space and say how big it is. */
cpm_word fcb_rodisk(void); /* 0x1C */
cpm_word fcb_rovec (void); /* 0x1D */
cpm_word fcb_chmod (cpm_byte *fcb, cpm_byte *dma); /* 0x1E */
cpm_word fcb_getdpb(cpm_byte *dpb); /* 0x1F */
cpm_byte fcb_user (cpm_byte usr); /* 0x20 */
cpm_word fcb_randrd(cpm_byte *fcb, cpm_byte *dma); /* 0x21 */
cpm_word fcb_randwr(cpm_byte *fcb, cpm_byte *dma); /* 0x22 */
cpm_word fcb_stat (cpm_byte *fcb); /* 0x23 */
cpm_word fcb_tell (cpm_byte *fcb); /* 0x24 */
cpm_word fcb_resro (cpm_word bitmap); /* 0x25 */
/* Access Drives and Free Drives are not supported. */
cpm_word fcb_randwz(cpm_byte *fcb, cpm_byte *dma); /* 0x28 */
/* Record locking calls not supported (though they could be) */
cpm_word fcb_multirec(cpm_byte rc); /* 0x2C */
/* Set hardware error action must be done by caller */
cpm_word fcb_dfree (cpm_byte drive, cpm_byte *dma);/* 0x2E */
cpm_word fcb_sync (cpm_byte flag); /* 0x30 */
cpm_word fcb_purge (void); /* 0x62 */
cpm_word fcb_trunc (cpm_byte *fcb, cpm_byte *dma); /* 0x63 */
cpm_word fcb_setlbl(cpm_byte *fcb, cpm_byte *dma); /* 0x64 */
cpm_word fcb_getlbl(cpm_byte drive); /* 0x65 */
cpm_word fcb_date (cpm_byte *fcb); /* 0x66 */
cpm_word fcb_setpwd(cpm_byte *fcb, cpm_byte *dma); /* 0x67 */
cpm_word fcb_defpwd(cpm_byte *pwd); /* 0x6A */
cpm_word fcb_sdate (cpm_byte *fcb, cpm_byte *dma); /* 0x74 */
cpm_word fcb_parse (char *txt, cpm_byte *fcb); /* 0x98 */
/* fcb_parse returns length of filename parsed, 0 if EOL, 0xFFFF if error */
cpm_byte fcb_reset(void); /* 0x0D */
cpm_word fcb_drive(cpm_byte drv); /* 0x0E */
cpm_word fcb_open(cpm_byte* fcb, cpm_byte* dma); /* 0x0F */
cpm_word fcb_close(cpm_byte* fcb); /* 0x10 */
cpm_word fcb_find1(cpm_byte* fcb, cpm_byte* dma); /* 0x11 */
cpm_word fcb_find2(cpm_byte* fcb, cpm_byte* dma); /* 0x12 */
cpm_word fcb_unlink(cpm_byte* fcb, cpm_byte* dma); /* 0x13 */
cpm_word fcb_read(cpm_byte* fcb, cpm_byte* dma); /* 0x14 */
cpm_word fcb_write(cpm_byte* fcb, cpm_byte* dma); /* 0x15 */
cpm_word fcb_creat(cpm_byte* fcb, cpm_byte* dma); /* 0x16 */
cpm_word fcb_rename(cpm_byte* fcb, cpm_byte* dma); /* 0x17 */
cpm_word fcb_logvec(void); /* 0x18 */
cpm_byte fcb_getdrv(void); /* 0x19 */
/* DMA is a parameter to routines, not a separate call */
cpm_word fcb_getalv(cpm_byte* alv, cpm_word max); /* 0x1B */
/* Get alloc vector: caller must provide space and say how big it is. */
cpm_word fcb_rodisk(void); /* 0x1C */
cpm_word fcb_rovec(void); /* 0x1D */
cpm_word fcb_chmod(cpm_byte* fcb, cpm_byte* dma); /* 0x1E */
cpm_word fcb_getdpb(cpm_byte* dpb); /* 0x1F */
cpm_byte fcb_user(cpm_byte usr); /* 0x20 */
cpm_word fcb_randrd(cpm_byte* fcb, cpm_byte* dma); /* 0x21 */
cpm_word fcb_randwr(cpm_byte* fcb, cpm_byte* dma); /* 0x22 */
cpm_word fcb_stat(cpm_byte* fcb); /* 0x23 */
cpm_word fcb_tell(cpm_byte* fcb); /* 0x24 */
cpm_word fcb_resro(cpm_word bitmap); /* 0x25 */
/* Access Drives and Free Drives are not supported. */
cpm_word fcb_randwz(cpm_byte* fcb, cpm_byte* dma); /* 0x28 */
/* Record locking calls not supported (though they could be) */
cpm_word fcb_multirec(cpm_byte rc); /* 0x2C */
/* Set hardware error action must be done by caller */
cpm_word fcb_dfree(cpm_byte drive, cpm_byte* dma); /* 0x2E */
cpm_word fcb_sync(cpm_byte flag); /* 0x30 */
cpm_word fcb_purge(void); /* 0x62 */
cpm_word fcb_trunc(cpm_byte* fcb, cpm_byte* dma); /* 0x63 */
cpm_word fcb_setlbl(cpm_byte* fcb, cpm_byte* dma); /* 0x64 */
cpm_word fcb_getlbl(cpm_byte drive); /* 0x65 */
cpm_word fcb_date(cpm_byte* fcb); /* 0x66 */
cpm_word fcb_setpwd(cpm_byte* fcb, cpm_byte* dma); /* 0x67 */
cpm_word fcb_defpwd(cpm_byte* pwd); /* 0x6A */
cpm_word fcb_sdate(cpm_byte* fcb, cpm_byte* dma); /* 0x74 */
cpm_word fcb_parse(char* txt, cpm_byte* fcb); /* 0x98 */
/* fcb_parse returns length of filename parsed, 0 if EOL, 0xFFFF if error */
#ifdef __cplusplus
}
#endif
#endif /* def CPMREDIR_H_INCLUDED */

81
Tools/unix/zxcc/dirent.c

@ -7,10 +7,9 @@
Rights: See end of file.
*/
#pragma warning(disable : 4996)
#include "dirent.h"
#include <errno.h>
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
#include <stdlib.h>
#include <string.h>
@ -19,35 +18,20 @@ extern "C"
{
#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* dir = 0;
DIR *opendir(const char *name)
{
DIR *dir = 0;
if(name && name[0])
{
if (name && name[0]) {
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]) ? "*" : "/*";
if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
(dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
{
if ((dir = (DIR*)malloc(sizeof * dir)) != 0 &&
(dir->name = (char*)malloc(base_length + strlen(all) + 1)) != 0) {
strcat(strcpy(dir->name, name), all);
if((dir->handle =
(handle_type) _findfirst(dir->name, &dir->info)) != -1)
{
if ((dir->handle =
(handle_type)_findfirst(dir->name, &dir->info)) != -1) {
dir->result.d_name = 0;
}
else /* rollback */
@ -64,22 +48,18 @@ DIR *opendir(const char *name)
errno = ENOMEM;
}
}
else
{
else {
errno = EINVAL;
}
return dir;
}
}
int closedir(DIR *dir)
{
int closedir(DIR* dir) {
int result = -1;
if(dir)
{
if(dir->handle != -1)
{
if (dir) {
if (dir->handle != -1) {
result = _findclose(dir->handle);
}
@ -87,47 +67,40 @@ int closedir(DIR *dir)
free(dir);
}
if(result == -1) /* map all errors to EBADF */
if (result == -1) /* map all errors to EBADF */
{
errno = EBADF;
}
return result;
}
}
struct dirent *readdir(DIR *dir)
{
struct dirent *result = 0;
struct dirent* readdir(DIR* dir) {
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->d_name = dir->info.name;
}
}
else
{
else {
errno = EBADF;
}
return result;
}
}
void rewinddir(DIR *dir)
{
if(dir && dir->handle != -1)
{
void rewinddir(DIR* dir) {
if (dir && dir->handle != -1) {
_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;
}
else
{
else {
errno = EBADF;
}
}
}
#ifdef __cplusplus
}

30
Tools/unix/zxcc/dirent.h

@ -11,24 +11,32 @@
*/
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct DIR DIR;
struct dirent
{
struct dirent {
char *d_name;
};
};
DIR *opendir(const char *);
int closedir(DIR *);
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
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 *);
int closedir(DIR *);
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
/*
Copyright Kevlin Henney, 1997, 2003. All rights reserved.
@ -41,7 +49,7 @@ void rewinddir(DIR *);
But that said, if there are any problems please get in touch.
*/
*/
#ifdef __cplusplus
}

26
Tools/unix/zxcc/drdos.c

@ -49,7 +49,7 @@ cpm_byte redir_cpm_pwmode(cpm_word w)
* functions, so these are done with __dpmi_int() rather
* than intdos() */
cpm_word redir_drdos_get_rights(char *path)
cpm_word redir_drdos_get_rights(char* path)
{
__dpmi_regs r;
@ -71,7 +71,7 @@ cpm_word redir_drdos_get_rights(char *path)
}
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)
{
__dpmi_regs r;
@ -79,7 +79,7 @@ cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights)
redir_Msg("Put rights for file %s: %04x %-8.8s %-8.8s\n\r", path, rights, dma, dma + 8);
dosmemput(dma+8, 8, __tb); /* Point DTA at password */
dosmemput(dma + 8, 8, __tb); /* Point DTA at password */
r.x.ax = 0x1A00;
r.x.dx = (__tb & 0x0F);
r.x.ds = (__tb) >> 4;
@ -117,7 +117,7 @@ cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights)
#else /* __GO32__ */
cpm_word redir_drdos_get_rights(char *path)
cpm_word redir_drdos_get_rights(char* path)
{
union REGS r;
struct SREGS s;
@ -140,7 +140,7 @@ cpm_word redir_drdos_get_rights(char *path)
}
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)
{
union REGS r;
struct SREGS s;
@ -198,14 +198,14 @@ cpm_word redir_password_error(void)
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 */
return 0;
}
void redir_password_append(char *s, cpm_byte *dma)
void redir_password_append(char* s, cpm_byte* dma)
{
int n, m;
@ -226,11 +226,11 @@ void redir_password_append(char *s, cpm_byte *dma)
}
#else /* __MSDOS__ */
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_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights)
{ return 0; }
cpm_word redir_drdos_get_rights(char *path) { return 0; }
cpm_word redir_drdos_put_rights(char* path, cpm_byte* dma, cpm_word rights)
{
return 0;
}
cpm_word redir_drdos_get_rights(char* path) { return 0; }
#endif /* __MSDOS__ */

24
Tools/unix/zxcc/track.c

@ -22,8 +22,8 @@
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,
* this has two impacts
@ -81,8 +81,22 @@
* a problem. I am not aware of any real programs that do this.
* 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
typedef struct _track {
struct _track* next;
int handle;
@ -111,10 +125,9 @@ void releaseFile(char* fname) {
s = s->next;
}
int trackFile(char* fname, void* fcb, int fd) {
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);
while (s->next) { /* find any existing fcb or fd */
if (s->next->fcb == fcb || s->next->handle == fd) {
if (s->next->handle != fd) {
@ -147,4 +160,3 @@ void releaseFile(char* fname) {}
int trackFile(char* fname, void* fcb, int fd) { return fd; }
#endif

242
Tools/unix/zxcc/util.c

@ -22,71 +22,87 @@
#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)
{
#ifdef _WIN32
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);
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 v;
#else
DBGMSGV("seek on #%i to 0x%lX using %s\n", fd, offset, whence(wh));
long v = lseek(fd, offset, wh);
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;
#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
}
#ifdef DEBUG
void redir_showfcb(cpm_byte *fd)
void redir_showfcb(cpm_byte* fd)
{
int n;
for (n = 0; n < 32; n++)
{
if (!n || n>= 12) printf("%02x ", fd[n]);
if (!n || n >= 12) printf("%02x ", fd[n]);
else printf("%c", fd[n] & 0x7F);
}
printf("\r\n");
printf("\n");
}
#endif
/* Get the "sequential access" file pointer out of an FCB */
long redir_get_fcb_pos(cpm_byte *fcb)
long redir_get_fcb_pos(cpm_byte* fcb)
{
long npos;
@ -97,14 +113,13 @@ long redir_get_fcb_pos(cpm_byte *fcb)
return npos;
}
void redir_put_fcb_pos(cpm_byte *fcb, long npos)
void redir_put_fcb_pos(cpm_byte* fcb, long npos)
{
fcb[0x20] = (npos / 128) % 128; /* Record */
fcb[0x0C] = (npos / 16384) % 32; /* Extent */
fcb[0x0E] = (npos / 524288L) % 64; /* S2 */
}
/*
* find a filename that works.
* note that this is where we handle the case sensitivity/non-case sensitivity
@ -112,13 +127,12 @@ void redir_put_fcb_pos(cpm_byte *fcb, long npos)
* the name that is passed in should be in lower case.
* we'll modify it to the first one that matches
*/
void
swizzle(char *fullpath)
void swizzle(char* fullpath)
{
struct stat ss;
char *slash;
DIR *dirp;
struct dirent *dentry;
char* slash;
DIR* dirp;
struct dirent* dentry;
/* short circuit if ok */
if (stat(fullpath, &ss) == 0) {
@ -144,10 +158,11 @@ swizzle(char *fullpath)
/* Passed a CP/M FCB, convert it to a unix filename. Turn its drive back into
* a path. */
int redir_fcb2unix(cpm_byte *fcb, char *fname)
int redir_fcb2unix(cpm_byte* fcb, char* fname)
{
int n, q, drv, ddrv;
char s[2];
char buf[256];
s[1] = 0;
q = 0;
@ -157,11 +172,6 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname)
ddrv = fcb[0] & 0x7F;
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]);
else strcpy(fname, redir_drive_prefix[drv - 1]);
@ -176,6 +186,16 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname)
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;
}
@ -183,81 +203,114 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname)
#define EROFS EACCES
#endif
int redir_ofile(cpm_byte *fcb, char *s)
int redir_ofile(cpm_byte* fcb, char* s)
{
int h;
/* Software write-protection */
#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);
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)
{
redir_Msg("Returning -1\n");
DBGMSGV("open R/O failed (errno=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError()));
return -1;
}
DBGMSGV("file '%s' opened R/O as #%i\n", s, h);
fcb[9] |= 0x80;
#else
#ifdef __MSDOS__
#elif defined(__MSDOS__)
int rv;
if (!redir_ro_fcb(fcb))
{
rv = _dos_open(s, O_RDWR, &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);
if (rv) return -1;
fcb[9] |= 0x80;
#else
releaseFCB(fcb);
#else
releaseFCB(fcb);
swizzle(s);
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);
if (h >= 0 || (errno != EACCES && errno != EROFS))
{
DBGMSGV("file '%s' opened R/W as #%i\n", s, 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);
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;
#endif
#endif
return trackFile(s, fcb, h);
}
/* 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.
Note: Some programs (like GENCOM) close FCBs they never opened. This causes
the Corrupt FCB message, but no harm seems to ensue. */
int redir_verify_fcb(cpm_byte *fcb)
int redir_verify_fcb(cpm_byte* fcb)
{
if (fcb[16] != 0xFD || fcb[17] != 0x00)
{
fprintf(stderr,"cpmredir: Corrupt FCB\n");
fprintf(stderr, "cpmredir: Corrupt FCB\n");
return -1;
}
return (int)(redir_rd32(fcb + 18));
}
/* Print a trace message */
#ifdef DEBUG
void redir_Msg(char *s, ...)
void DbgMsg(const char* file, int line, const char* func, char* s, ...)
{
va_list ap;
va_start(ap, s);
fprintf(stderr, "cpmredir trace: ");
fprintf(stderr, "%s(%s@%i): ", func, file, line);
vfprintf(stderr, s, ap);
va_end(ap);
fflush(stderr);
@ -270,7 +323,7 @@ void redir_Msg(char *s, ...)
/* Convert time_t to CP/M day count/hours/minutes */
dword redir_cpmtime(time_t t)
{
/* Microsoft compiler warned around the conversion from time_t to long
/* Microsoft compiler warned around the conversion from time_t to long
* as to support dates beyond 2038 time_t is set as a long long
* and for the Microsoft compiler sizeof(long) == 4 and sizeof(long long) == 8
* for other compilers both have size 8
@ -288,7 +341,7 @@ dword redir_cpmtime(time_t t)
#define UNBCD(x) (((x % 16) + 10 * (x / 16)) & 0xFF)
time_t redir_unixtime(cpm_byte *c)
time_t redir_unixtime(cpm_byte* c)
{
time_t t;
cpm_word days;
@ -304,18 +357,17 @@ time_t redir_unixtime(cpm_byte *c)
#undef UNBCD
/* Functions to access 24-bit & 32-bit words in memory. These are always
little-endian. */
void redir_wr24(cpm_byte *addr, dword v)
void redir_wr24(cpm_byte* addr, dword v)
{
addr[0] = v & 0xFF;
addr[1] = (v >> 8) & 0xFF;
addr[2] = (v >> 16) & 0xFF;
}
void redir_wr32(cpm_byte *addr, dword v)
void redir_wr32(cpm_byte* addr, dword v)
{
addr[0] = v & 0xFF;
addr[1] = (v >> 8) & 0xFF;
@ -323,7 +375,7 @@ void redir_wr32(cpm_byte *addr, dword v)
addr[3] = (v >> 24) & 0xFF;
}
dword redir_rd24(cpm_byte *addr)
dword redir_rd24(cpm_byte* addr)
{
register dword rv = addr[2];
@ -332,8 +384,7 @@ dword redir_rd24(cpm_byte *addr)
return rv;
}
dword redir_rd32(cpm_byte *addr)
dword redir_rd32(cpm_byte* addr)
{
register dword rv = addr[3];
@ -343,14 +394,13 @@ dword redir_rd32(cpm_byte *addr)
return rv;
}
void redir_log_drv(cpm_byte drv)
{
if (!drv) redir_l_drives |= 1;
else redir_l_drives |= (1L << drv);
}
void redir_log_fcb(cpm_byte *fcb)
void redir_log_fcb(cpm_byte* fcb)
{
int drv = fcb[0] & 0x7F;
@ -358,14 +408,13 @@ void redir_log_fcb(cpm_byte *fcb)
else redir_log_drv(redir_cpmdrive);
}
int redir_ro_drv(cpm_byte drv)
{
if (!drv) return redir_ro_drives & 1;
else return redir_ro_drives & (1L << drv);
}
int redir_ro_fcb(cpm_byte *fcb)
int redir_ro_fcb(cpm_byte* fcb)
{
int drv = fcb[0] & 0x7F;
@ -373,12 +422,11 @@ int redir_ro_fcb(cpm_byte *fcb)
else return redir_ro_drv(redir_cpmdrive);
}
cpm_word redir_xlt_err(void)
{
if (redir_password_error()) return 0x7FF; /* DRDOS pwd error */
switch(errno)
switch (errno)
{
case EISDIR:
case EBADF: return 9; /* Bad FCB */
@ -389,20 +437,48 @@ cpm_word redir_xlt_err(void)
}
}
#ifdef _WIN32
/* minimal implementation of truncate */
int truncate(const char* path, off_t length)
{
int result;
int fd = open(path, O_BINARY | O_RDWR);
BOOL bResult;
HANDLE hFile;
DWORD dwOffset;
if (fd < 0)
DBGMSGV("truncate file %s to %lu\n", path, length);
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;
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

40
Tools/unix/zxcc/xlt.c

@ -29,10 +29,10 @@ static char* skipUser(char* localname);
static void drdos_init(void)
{
/* The DJGPP DOS extender won't detect DRDOS using intdos(), so we have
/* The DJGPP DOS extender won't detect DRDOS using intdos(), so we have
to use __dpmi_int() instead. */
#ifdef __GO32__
#ifdef __GO32__
__dpmi_regs ir;
ir.x.ax = 0x4452; /* "DR" */
@ -40,28 +40,26 @@ static void drdos_init(void)
__dpmi_int(0x21, &ir);
if (ir.x.flags & 1) return; /* Not DRDOS */
redir_Msg("DRDOS detected.\r\n");
redir_Msg("DRDOS detected.\n");
redir_drdos = 1;
#else /* __GO32__ */
#else /* __GO32__ */
union REGS ir, or;
union REGS ir, or ;
ir.w.ax = 0x4452; /* "DR" */
intdos(&ir, &or);
if (or.w.cflag) return; /* Not DRDOS */
intdos(&ir, &or );
if (or .w.cflag) return; /* Not DRDOS */
redir_Msg("DRDOS detected.\r\n");
redir_Msg("DRDOS detected.\n");
redir_drdos = 1;
#endif /* __GO32__ */
#endif /* __GO32__ */
}
#endif /* __MSDOS__ */
int fcb_init(void)
{
int n;
@ -96,12 +94,12 @@ void fcb_deinit(void)
*
*/
void xlt_name(char *localname, char *cpmname)
void xlt_name(char* localname, char* cpmname)
{
char ibuf[CPM_MAXPATH + 1];
char nbuf[CPM_MAXPATH + 1];
char *pname = ibuf;
char *s;
char* pname = ibuf;
char* s;
int n;
sprintf(ibuf, "%-.*s", CPM_MAXPATH, skipUser(localname));
@ -137,7 +135,7 @@ void xlt_name(char *localname, char *cpmname)
{
if (redir_drive_prefix[n][0] && !strcmp(ibuf, redir_drive_prefix[n]))
{
sprintf(cpmname,"%c:%s", n + 'a', nbuf);
sprintf(cpmname, "%c:%s", n + 'a', nbuf);
return;
}
}
@ -147,13 +145,13 @@ void xlt_name(char *localname, char *cpmname)
for (n = 0; n < 15; n++) if (!redir_drive_prefix[n][0])
{
strcpy(redir_drive_prefix[n], ibuf);
sprintf(cpmname,"%c:%s", n + 'a', nbuf);
sprintf(cpmname, "%c:%s", n + 'a', nbuf);
return;
}
/* No other drive can be allocated */
strcpy(cpmname,"p:");
strcpy(cpmname, "p:");
strcat(cpmname, nbuf);
}
@ -162,7 +160,7 @@ void xlt_name(char *localname, char *cpmname)
* Pass drive = -1 for "first available", or 0-15 for A: to P:
*/
int xlt_map(int drive, char *localdir)
int xlt_map(int drive, char* localdir)
{
int n;
@ -181,7 +179,6 @@ int xlt_map(int drive, char *localdir)
return 1;
}
/* Unmap a drive
*/
@ -192,8 +189,7 @@ int xlt_umap(int drive)
return 1;
}
char *xlt_getcwd(int drive)
char* xlt_getcwd(int drive)
{
if (drive < 0 || drive > 16) return "";
@ -201,7 +197,7 @@ char *xlt_getcwd(int drive)
}
/* as zxcc doesn't really support user spaces, remove any user specification
*hitech c supports
* hitech c supports
* [[0-9]+[:]][[a-pA-P]:]name[.ext] | [[a-pA-p][[0-9]+]:]name[.ext]
* this function also checks that user is no more than 2 digits and user # <= 31
* the hitech fcb checks for : as char 2, 3, or 4 which aligns to this

2
Tools/unix/zxcc/z80.c

@ -123,7 +123,7 @@ void mainloop(word spc, word ssp){
// if (pc == 0x1177) tr = 1;
// if (pc == 0x1185) tr = 0;
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);
}
*/

12
Tools/unix/zxcc/z80.h

@ -15,7 +15,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* [John Elliott, 15 July 2001]
/* [John Elliott, 15 July 2001]
* Copied this file into ZXCC, a CP/M emulator.
* Since ZXCC's memory is a flat 64k space and will never be bank-switched,
* the bank-switching code is removed.
@ -61,21 +61,21 @@ void drawborder();
#define store(x,y) do { RAM[(x)] = (y); } while(0)
#define store2b(x,hi,lo) do {\
#define store2b(x,hi,lo) do { \
RAM[(x)]=(lo); \
RAM[((x+1) & 0xFFFF)]=(hi); } while(0)
#define store2(x,y) store2b(x,(y)>>8,y)
#ifdef __GNUC__
static void inline storefunc(unsigned short ad,unsigned char b){
store(ad,b);
static void inline storefunc(unsigned short ad, unsigned char b) {
store(ad, b);
}
#undef store
#define store(x,y) storefunc(x,y)
static void inline store2func(unsigned short ad,unsigned char b1,unsigned char b2){
store2b(ad,b1,b2);
static void inline store2func(unsigned short ad, unsigned char b1, unsigned char b2) {
store2b(ad, b1, b2);
}
#undef store2b
#define store2b(x,hi,lo) store2func(x,hi,lo)

66
Tools/unix/zxcc/zxbdos.c

@ -41,14 +41,14 @@ byte get_time(cpm_word b)
void wr24(word addr, dword v)
{
RAM[addr ] = v & 0xFF;
RAM[addr] = v & 0xFF;
RAM[addr + 1] = (v >> 8) & 0xFF;
RAM[addr + 2] = (v >> 16) & 0xFF;
}
void wr32(word addr, dword v)
{
RAM[addr ] = v & 0xFF;
RAM[addr] = v & 0xFF;
RAM[addr + 1] = (v >> 8) & 0xFF;
RAM[addr + 2] = (v >> 16) & 0xFF;
RAM[addr + 3] = (v >> 24) & 0xFF;
@ -118,25 +118,25 @@ void gsxwr(gsx_word addr, gsx_byte value)
#undef de
#undef hl
void setw(byte *l, byte *h, word w)
void setw(byte* l, byte* h, word w)
{
*l = (w & 0xFF);
*h = (w >> 8) & 0xFF;
}
void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
byte *h, byte *l, word *pc, word *ix, word *iy)
void cpmbdos(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f,
byte* h, byte* l, word* pc, word* ix, word* iy)
{
word de = ((*d) << 8) | *e;
word hl = ((*h) << 8) | *l;
byte *pde = &RAM[de];
byte *pdma = &RAM[cpm_dma];
byte* pde = &RAM[de];
byte* pdma = &RAM[cpm_dma];
word temp;
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)
{
case 0:
*pc = 0;
@ -182,7 +182,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
case 9: /* Print a $-terminated string */
#ifdef USE_CPMIO
if (cpm_bdos_9((char *)pde)) *pc = 0;
if (cpm_bdos_9((char*)pde)) *pc = 0;
# else
for (temp = 0; RAM[de + temp] != '$'; ++temp)
{
@ -196,14 +196,14 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
break;
case 0x0B: /* Console status */
//*l = *h = 0; /* No keys pressed */
// *l = *h = 0; /* No keys pressed */
*l = cstat();
*h = 0;
break;
case 0x0C: /* Get CP/M version */
/* For GENCOM's benefit, claim to be v3.1 */
/* For GENCOM's benefit, claim to be v3.1 */
*l = 0x31; /* v3.1 */
/* *l = 0x22; * v2.2 */
@ -263,7 +263,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
break;
case 0x1A: /* Set DMA */
Msg("Set DMA to %04x\n", de);
DBGMSGV("Set DMA to 0x%04X\n", de);
cpm_dma = de;
break;
@ -287,7 +287,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
case 0x1F: /* Get DPB */
fcb_getdpb(RAM + 0xFFC0);
setw(l, h, 0xFFC0);
break; /* Whoops. Missed that 'break'. */
break;
case 0x20: /* Get/set uid */
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:
setw(l, h, fcb_dfree(*e, pdma));
break; /* Whoops. Missed that 'break'. */
break;
/* 0x2F: Chain */
@ -366,7 +366,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
*d = pde[5];
*l = pde[6];
*h = pde[7];
cpmbios(a,b,c,d,e,f,h,l,pc,ix,iy);
cpmbios(a, b, c, d, e, f, h, l, pc, ix, iy);
*ix = temp;
break;
@ -428,7 +428,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
break;
case 0x6F: /* Send fixed length string to screen */
if (cpm_bdos_111((char *)RAM + peekw(de),
if (cpm_bdos_111((char*)RAM + peekw(de),
peekw(de + 2)))
*pc = 0;
break;
@ -455,8 +455,8 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
break;
case 0x98: /* Parse filename */
setw(l, h, fcb_parse((char *)RAM + peekw(de),
(byte *)RAM + peekw(de + 2)));
setw(l, h, fcb_parse((char*)RAM + peekw(de),
(byte*)RAM + peekw(de + 2)));
break;
default:
@ -467,9 +467,9 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
gsx_deinit();
#endif
fprintf(stderr,"%s: Unsupported BDOS call %d\n", progname,
fprintf(stderr, "%s: Unsupported BDOS call %d\n", progname,
(int)(*c));
dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy);
dump_regs(stderr, *a, *b, *c, *d, *e, *f, *h, *l, *pc, *ix, *iy);
zxcc_exit(1);
break;
}
@ -478,16 +478,14 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
*b = *h;
}
void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
byte *h, byte *l, word *pc, word *ix, word *iy)
void cpmbios(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f,
byte* h, byte* l, word* pc, word* ix, word* iy)
{
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 */
{
case 1:
zxcc_exit(zxcc_term()); /* Program termination */
@ -495,17 +493,17 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
case 2: /* CONST */
#ifdef USE_CPMIO
*a = cpm_const();
* a = cpm_const();
#else
*a = cpm_bdos_6(0xFE);
* a = cpm_bdos_6(0xFE);
#endif
break;
case 3: /* CONIN */
#ifdef USE_CPMIO
*a = cpm_conin();
* a = cpm_conin();
#else
*a = cpm_bdos_6(0xFD);
* a = cpm_bdos_6(0xFD);
#endif
break;
@ -533,7 +531,7 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
#ifdef USE_CPMIO
cpm_bdos_110('$');
cpm_bdos_9("This program has attempted to call USERF, "
"which is not implemented\r\n$");
"which is not implemented\n$");
#else
printf("This program has attempted to call USERF, which "
"is not implemented.\n");
@ -550,8 +548,8 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
gsx_deinit();
#endif
fprintf(stderr,"%s: Unsupported BIOS call %d\n", progname, func);
dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy);
fprintf(stderr, "%s: Unsupported BIOS call %d\n", progname, func);
dump_regs(stderr, *a, *b, *c, *d, *e, *f, *h, *l, *pc, *ix, *iy);
zxcc_exit(1);
}
}

9
Tools/unix/zxcc/zxbdos.h

@ -1,5 +1,5 @@
extern char *progname;
extern char **argv;
extern char* progname;
extern char** argv;
extern int argc;
extern byte cpm_drive;
@ -7,7 +7,7 @@ extern byte cpm_user;
extern byte RAM[65536]; /* The Z80's address space */
extern void Msg(char *s, ...);
extern void Msg(char* s, ...);
#ifdef BDOS_DEF
@ -26,7 +26,7 @@ extern byte err_mode, rec_multi, cpm_error;
#endif /* BDOS_DEF */
#ifndef O_BINARY /* Necessary in DOS, not present in Linux */
#define O_BINARY 0
#define O_BINARY 0
#endif
typedef unsigned long dword;
@ -47,4 +47,3 @@ void gsxwr(gsx_word addr, gsx_byte value);
void cpmbdos();
void cpmbios();

25
Tools/unix/zxcc/zxcbdos.c

@ -2,36 +2,27 @@
#include "zxbdos.h"
#include "zxcbdos.h"
#ifndef _WIN32
#include <sys/ioctl.h>
#endif
#ifdef _WIN32
#include <conio.h>
#endif
/* Line input */
#ifdef USE_CPMIO
void bdos_rdline(word line, word *PC)
void bdos_rdline(word line, word* PC)
{
unsigned char *buf;
unsigned char* buf;
if (!line) line = cpm_dma;
else RAM[line + 1] = 0;
buf = (unsigned char *)&RAM[line];
buf = (unsigned char*)&RAM[line];
if (cpm_bdos_10(buf)) *PC = 0;
}
#else /* def USE_CPMIO */
void bdos_rdline(word line, word *PC)
void bdos_rdline(word line, word* PC)
{
unsigned char c;
unsigned char *p;
unsigned char* p;
int n;
int maxlen;
@ -39,7 +30,7 @@ void bdos_rdline(word line, word *PC)
maxlen = RAM[line];
// fgets causes extra linefeeds, so we invent our own
//fgets((char *)(RAM + line + 2), maxlen, stdin);
// fgets((char *)(RAM + line + 2), maxlen, stdin);
p = (RAM + line + 2);
n = 0;
@ -72,7 +63,7 @@ void bdos_rdline(word line, word *PC)
//RAM[line + 1] = strlen((char *)(RAM + line + 2)) - 1;
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 */
@ -82,7 +73,7 @@ int cpm_bdos_6(byte e)
{
int c;
switch(e) {
switch (e) {
case 0xFF:
if (cstat()) return cin();
return 0;

6
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);
byte cin(void);
void cout(byte);
int cstat(void);

186
Tools/unix/zxcc/zxcc.c

@ -2,8 +2,8 @@
/* Global variables */
char *progname;
char **argv;
char* progname;
char** argv;
int argc;
byte cpm_drive;
@ -14,6 +14,10 @@ char bindir80[CPM_MAXPATH] = "";
char libdir80[CPM_MAXPATH] = "";
char incdir80[CPM_MAXPATH] = "";
#ifndef _WIN32
struct termios tc_orig;
#endif
byte RAM[65536]; /* The Z80's address space */
void load_comfile(void); /* Forward declaration */
@ -21,31 +25,22 @@ void load_comfile(void); /* Forward declaration */
static int deinit_term, deinit_gsx;
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)
{
fprintf(fp, "\tAF=%02x%02x BC=%02x%02x DE=%02x%02x HL=%02x%02x\n"
"\tIX=%04x IY=%04x PC=%04x\n",
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];
RAM[afcb] = 0;
memset(fcb, ' ', 11);
while (s[0]==' ') /* skip leading spaces */
while (s[0] == ' ') /* skip leading spaces */
{
s++;
}
@ -57,45 +52,30 @@ char *parse_to_fcb(char *s, int afcb)
{
RAM[afcb] = s[0] - '@';
if (RAM[afcb] > 16) RAM[afcb] -= 0x20;
s+=2;
s += 2;
continue;
}
if (s[0] == '.')
{
++s;
fcb = &RAM[afcb+9];
fcb = &RAM[afcb + 9];
continue;
}
*fcb = *s; if (islower(*fcb)) *fcb = toupper(*fcb);
++s;
++fcb;
if (fcb >= &RAM[afcb+12]) break;
if (fcb >= &RAM[afcb + 12]) break;
}
return s;
}
void Msg(char *s, ...)
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)
{
#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,
byte *h, byte *l, word *pc, word *ix, word *iy)
{
switch(*a)
switch (*a)
{
case 0xC0:
cpmbdos(a,b,c,d,e,f,h,l,pc,ix,iy);
cpmbdos(a, b, c, d, e, f, h, l, pc, ix, iy);
break;
case 0xC1:
@ -103,24 +83,23 @@ void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f,
break;
case 0xC2:
fprintf(stderr,"%s: Incompatible BIOS.BIN\n", progname);
fprintf(stderr, "%s: Incompatible BIOS.BIN\n", progname);
zxcc_term();
zxcc_exit(1);
case 0xC3:
cpmbios(a,b,c,d,e,f,h,l,pc,ix,iy);
cpmbios(a, b, c, d, e, f, h, l, pc, ix, iy);
break;
default:
fprintf(stderr, "%s: Z80 encountered invalid trap\n", progname);
dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy);
dump_regs(stderr, *a, *b, *c, *d, *e, *f, *h, *l, *pc, *ix, *iy);
zxcc_term();
zxcc_exit(1);
}
}
/*
* load_bios() loads the minimal CP/M BIOS and BDOS.
*
@ -158,7 +137,7 @@ void load_bios(void)
}
if (!fp)
{
fprintf(stderr,"%s: Cannot locate bios.bin\n", progname);
fprintf(stderr, "%s: Cannot locate bios.bin\n", progname);
zxcc_term();
zxcc_exit(1);
}
@ -166,30 +145,30 @@ void load_bios(void)
if (bios_len < 1 || ferror(fp))
{
fclose(fp);
fprintf(stderr,"%s: Cannot load bios.bin\n", progname);
fprintf(stderr, "%s: Cannot load bios.bin\n", progname);
zxcc_term();
zxcc_exit(1);
}
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
*
*/
FILE *try_com(char *s)
FILE* try_com(char* s)
{
char fname[CPM_MAXPATH + 1];
FILE *fp;
FILE* fp;
strcpy(fname, s);
fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s,"%s.com", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s,"%s.COM", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s,"%s.cpm", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s,"%s.CPM", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s, "%s.com", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s, "%s.COM", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s, "%s.cpm", fname); fp = fopen(s, "rb"); if (fp) return fp;
sprintf(s, "%s.CPM", fname); fp = fopen(s, "rb"); if (fp) return fp;
strcpy(s, fname);
return NULL;
@ -205,7 +184,7 @@ void load_comfile(void)
{
size_t com_len;
char fname[CPM_MAXPATH + 1];
FILE *fp;
FILE* fp;
/* Look in current directory first */
strcpy(fname, argv[1]);
@ -218,7 +197,7 @@ void load_comfile(void)
}
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]);
zxcc_term();
zxcc_exit(1);
@ -227,22 +206,22 @@ void load_comfile(void)
if (com_len < 1 || ferror(fp))
{
fclose(fp);
fprintf(stderr,"%s: Cannot load %s\n", progname, fname);
fprintf(stderr, "%s: Cannot load %s\n", progname, fname);
zxcc_term();
zxcc_exit(1);
}
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);
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 out() { return 0; }
/*
* 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.
@ -251,7 +230,7 @@ unsigned int out() { return 0; }
* the result to the command line.
*/
void zxcc_xltname(char *name, char *pcmd)
void zxcc_xltname(char* name, char* pcmd)
{
char nbuf[CPM_MAXPATH + 1];
@ -267,17 +246,16 @@ void zxcc_xltname(char *name, char *pcmd)
on the endianness of the host CPU and the sizes of data types.
*/
int main(int ac, char **av)
int main(int ac, char** av)
{
int n;
char *pCmd, *str;
char* pCmd, * str;
char* tmpenv;
argc = ac;
argv = av;
#ifdef __PACIFIC__ /* Pacific C doesn't support argv[0] */
progname="ZXCC";
progname = "ZXCC";
#endif
progname = argv[0];
@ -289,38 +267,27 @@ int main(int ac, char **av)
#ifdef DEBUG
fprintf(stderr, "\n\n");
Msg("Start of execution: ");
DBGMSG("Start of execution: ");
for (n = 0; n < argc; n++)
fprintf(stderr, " %s", argv[n]);
fprintf(stderr, "\n");
#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)
{
fprintf(stderr,"%s: type lengths incorrect; edit typedefs "
fprintf(stderr, "%s: type lengths incorrect; edit typedefs "
"and recompile.\n", progname);
zxcc_exit(1);
}
if (argc < 2)
{
fprintf(stderr,"%s: No CP/M program name provided.\n",progname);
fprintf(stderr, "%s: No CP/M program name provided.\n", progname);
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:
* preceded by a '-', in which case it is copied in as-is, less the
@ -360,15 +327,15 @@ int main(int ac, char **av)
if ((tmpenv = getenv("INCDIR80")))
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(1, libdir80);
xlt_map(2, incdir80);
pCmd = (char *)RAM + 0x81;
pCmd = (char*)RAM + 0x81;
for (n = 2; n < argc; n++)
{
@ -385,7 +352,7 @@ int main(int ac, char **av)
}
else if (argv[n][0] == '+')
{
zxcc_xltname(pCmd, argv[n]+1);
zxcc_xltname(pCmd, argv[n] + 1);
}
else /* Translate a filename */
{
@ -401,7 +368,7 @@ int main(int ac, char **av)
parse_to_fcb(str, 0x6C);
// 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();
@ -462,10 +429,6 @@ int zxcc_term(void)
{
word n;
#ifndef _WIN32
deinit_raw();
#endif
//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 = 0;
@ -476,12 +439,15 @@ int zxcc_term(void)
{ /* (my modified Hi-Tech C library uses this */
n = cpm_error; /* call) */
}
if (n < 256 || n == 0xFFFF)
{
Msg("Return code %d\n", n);
DBGMSGV("Return code %d\n", n);
else
n = 0;
term_reset();
return n;
}
else return 0;
}
/* helper function to build full path */
@ -503,11 +469,11 @@ void raw_init(void)
{
struct termios tc_raw;
Msg("Enabling RAW Terminal IO\n");
DBGMSG("Enabling RAW Terminal IO\n");
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);;
}
@ -527,11 +493,11 @@ void raw_init(void)
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);
}
Msg("Enabled RAW Terminal IO\n");
DBGMSG("Enabled RAW Terminal IO\n");
return;
}
@ -540,13 +506,39 @@ void deinit_raw(void)
{
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;
}
Msg("Disabled RAW Terminal IO\n");
DBGMSG("Disabled RAW Terminal IO\n");
return;
}
#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
}

33
Tools/unix/zxcc/zxcc.h

@ -22,9 +22,15 @@
#endif
/* the default sub directories trailing / is required */
#define BIN80 "bin80/"
#define LIB80 "lib80/"
#define INC80 "include80/"
#ifdef _WIN32
#define BIN80 "bin80\\"
#define LIB80 "lib80\\"
#define INC80 "include80\\"
#else
#define BIN80 "bin80/"
#define LIB80 "lib80/"
#define INC80 "include80/"
#endif
#ifndef BINDIR80
#define BINDIR80 CPMDIR80 BIN80
@ -58,6 +64,7 @@ extern char incdir80[];
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <conio.h>
#define strcasecmp _stricmp
#ifndef STDIN_FILENO
#define STDIN_FILENO _fileno(stdin)
@ -90,11 +97,11 @@ extern char incdir80[];
#include "cpmgsx.h"
#endif
#include "cpmredir.h" /* BDOS disc simulation */
typedef unsigned char byte; /* Must be exactly 8 bits */
typedef unsigned short word; /* Must be exactly 16 bits */
#include "cpmredir.h" /* BDOS disc simulation */
/* Prototypes */
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,
byte h, byte l, word pc, word ix, word iy);
void Msg(char *s, ...);
void DbgMsg(const char *file, int line, const char *func, char *s, ...);
int zxcc_term(void);
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 */
@ -123,4 +139,3 @@ extern byte RAM[65536]; /* The Z80's address space */
/* Z80 CPU emulation */
#include "z80.h"

20
Tools/unix/zxcc/zxdbdos.c

@ -10,30 +10,29 @@
properly.
*/
/* 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) */
int fcbforce(byte *fcb, byte *odrv)
int fcbforce(byte* fcb, byte* odrv)
{
byte drive;
char nam[9];
char typ[4];
int n;
for (n = 0; n < 8; n++) nam[n] = fcb[n+1] & 0x7F;
for (n = 0; n < 8; n++) nam[n] = fcb[n + 1] & 0x7F;
nam[8] = 0;
for (n = 0; n < 3; n++) typ[n] = fcb[n+9] & 0x7F;
for (n = 0; n < 3; n++) typ[n] = fcb[n + 9] & 0x7F;
typ[3] = 0;
drive = 0;
if (*fcb) return 0; /* not using default drive */
/* Microsoft BASIC compiler run-time */
if (!strcmp(nam,"BCLOAD ") && !strcmp(typ, " ")) drive = 2;
if (!strcmp(nam, "BCLOAD ") && !strcmp(typ, " ")) drive = 2;
/* HI-TECH C options help file */
if (!strcmp(nam,"OPTIONS ") && !strcmp(typ, " ")) drive = 1;
if (!strcmp(nam, "OPTIONS ") && !strcmp(typ, " ")) drive = 1;
/* binaries, libraries and object files */
if (!strcmp(typ, "COM")) drive = 1;
@ -59,7 +58,7 @@ int fcbforce(byte *fcb, byte *odrv)
LIBDIR80 or INCDIR80 (depending on the type of the file).
*/
word x_fcb_open(byte *fcb, byte *dma)
word x_fcb_open(byte* fcb, byte* dma)
{
word rv = fcb_open(fcb, dma);
byte odrv;
@ -75,9 +74,7 @@ word x_fcb_open(byte *fcb, byte *dma)
return rv;
}
word x_fcb_stat(byte *fcb)
word x_fcb_stat(byte* fcb)
{
word rv = fcb_stat(fcb);
byte odrv;
@ -92,6 +89,3 @@ word x_fcb_stat(byte *fcb)
}
return rv;
}

10
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_stat(byte *fcb);
word x_fcb_open(byte* fcb, byte* dma);
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