home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
pub
/
researchmachines
/
rmldis.c
< prev
next >
Wrap
Text File
|
2020-01-01
|
18KB
|
747 lines
/************************************************************************/
/* File KDISK.C - Disk & File Handling Support for Kermit.
Chris Kennington 5th July 1985. */
#include "stdio.h"
#ifdef MPUZ80 /* 480Z */
#ifndef TINY
#include "io.h"
#endif
#else /* Nimbus */
/* Layout of FCB (as in <io.h>): */
struct fcb {
char f_driv;
char f_name[8];
char f_type[3];
char f_ext;
char f_resv[2];
char f_rc;
char f_sydx[16];
char f_cr;
unsigned f_record; char f_overfl;
};
/* displacements in block returned by Find Match/Next File:- */
#define MCHATTRIB 21
#define MCHNAME 30
/* workspace for MCH* */
static char dmabuf[65];
#endif
#include "ctype.h"
#define DEFS2 1
#define DEFS5 1
#include "b:kext.h"
#define DMA 0x0080 /* use default DMA */
/* The routines in this file provide OS-independent support on Aztec-C
for the disk-maintenance functions:
CHAnge (reset all drives)
DIR dname/dfname
ERAse dfname (DEL is synonym)
HELP (print help-text; ? is synonym)
REName fname fname
TYPe dfname
UPAth (show environment)
USEr num (CP/M only)
[DRIve] dname
(only first 3 chars need be entered)
where the valid arguments are:-
dname - a valid disk-letter;
fname - a valid file-name (on default disk);
dfname - a valid file-name with optional disk-letter;
num - a valid user-number.
Standard Return-Code Byte:
bit 0 - file not found
bit 1 - filename invalid
bit 2 - disk-letter invalid
bit 3 - system file
bit 4 - file is read/only
bit 5 - disk is temporarily read-only (CP/M)
bit 6 - wildcards in name
bit 7 - directory-name (MSDOS)
*/
/* static variables for intercommunication */
static char *s1, *s2; /* => names 1 & 2 */
static char cmd; /* command-number */
static char *cmds[] = { /* valid commands */
"Nul", "DIR", "ERA", "REN", /* 0-3 (0 is unused) */
"TYP", "USE", "UPA", "DRI", /* 4-7 */
"DEL", "CHA", "HEL", /* 8-10 */
0}; /* zero to terminate */
static char allfiles[] = "*.*";
static char diskro[] = "(disk r/o) ";
static char exists[] = " <%s> already exists, ";
static char explicit[15]; /* new filename */
static char inval[] = "invalid";
static char invalid[] = " <%s> now invalid ";
static char notdel[] = " NOT deleted.";
static char notren[] = " NOT renamed.";
static char overw[] = "overwritten ";
static char reject[] = "rejecting <%s>.";
static char wildcds[] = "has wildcards";
/* working variables */
static char c, cold, rtn, rtnall, *e, *w;
/* Displayed text which needs to vary between CP/M & MSDOS */
#ifdef MPUZ80
char diskcmds[] = " CHAnge DIRectory DRIve ERAse REName TYPe USEr UPAth";
char diskfail[] = "Disk failure, CP/M code %d";
char os1[] = "\r The following commands are valid (only 3 letters needed):\r\
CHAnge floppy; DRIve change; DIRectory list; ERAse file(s);";
char os2[] = "\r\
REName file; TYPe file; USEr-number; UPAth (show defaults).\
\r Wildcards (? *) accepted in DIR & ERA.";
#else
char diskcmds[] = " DELete DIRectory DRIve REName TYPe UPAth";
char diskfail[] = "Disk failure, MSDOS code %d";
char os1[] = "\r The following commands are valid (only 3 letters needed):\r\
DELete file(s); DRIve change; DIRectory list;";
char os2[] = "\r\
REName file; TYPe file; UPAth (show path).\
\r Wildcards (? *) accepted in DIR & DEL.";
#endif
char *avoid(file) /* implement collison avoidance */
/* If the requested file already exists, queries setting of
nmavoid and acts accordingly;
Returns 0 if file not there or may be overwritten,
else address of explanatory string. */
char *file; /* file-name */
{
static char ret;
char c, *r2;
int len;
keyget(&c); /* trap ESC */
ret = filechek(0,file,work);
if ( (ret & (char)0x01) != 0 )
return(0); /* no such file */
if ( (ret & (char)0x06) != 0 )
return(invalid); /* bad name */
/* file exists - see what to do about it */
outc(CR);
printf(exists,file);
switch(nmavoid) { /* break if OK, return if not */
case 0: /* overwrite */
txtout(overw);
break;
case 1: /* avoid by renaming */
if ( (len = strlen(file) - 1) < 2 ) {
len = 2;
file[2] = '0';
}
if (file[len-1] == '.') {
len += 2;
file[len] = '0';
}
c = file[len];
if (file[len-1] == '$')
file[len] = ++c; /* increment last char */
else
file[len-1] = '$'; /* or set previous to $ */
file[len+1] = 0; /* ensure closed */
if ( (r2 = avoid(file)) == 0 )
break; /* then check that */
else
return(r2);
case 2: /* reject incoming file */
return(reject);
case 3: /* check with user */
printf("OK if %s",overw);
if (confirm())
break; /* Yes */
else
return(reject);
default: /* unkmown setting */
return(null);
} /* end switch */
vtline(LOCFILE,file);
/* Make sure BDOS will not prevent overwriting */
if ( (ret & (char)0x30) != 0 )
return("<%s> is read-only ");
else
return(0);
} /* End of avoid() */
char dirprt(name) /* list directory-matches */
/* Leaves expanded name in "explicit" and sets up "ownfcb";
Returns composite status-byte. */
char *name;
{
char ret;
cold = 0;
ret = rtn = fileok(name);
outfc(CR);
if ( (rtn & (char)0x07) != 0 )
return(rtn); /* not found or invalid */
else do {
ret |= rtn;
for (c=0; c<26; ++c)
work[c] = SP;
work[c] = 0;
w = work;
e = explicit;
while( (*w = *e++) != 0)
++w;
if ( (rtn & (char)0x08) != 0 ) {
e = " sys";
while( (*w = *e++) != 0)
++w;
}
if ( (rtn & (char)0x10) != 0 ) {
e = " r/o";
while( (*w = *e++) != 0)
++w;
}
*w = ',';
txtout(work);
if (++cold > 2) { /* in 3 columns of 25 ch */
if (outfc(CR) != 0) {
txtout("\rList aborted");
return(ret); /* abort list */
}
cold = 0;
}
} while ( ( (rtn = filechek(1,name,explicit)) & (char)0x01) == 0 ) ;
return(ret);
} /* End of dirprt() */
char filechek(mode,fname,nuname) /* verify disk-file */
/* Returns standard status-byte to give situation of file;
sets up ownfcb with expanded wildcard name & checks for it;
if file exists, copies explicit name into *nuname */
char mode, *fname, *nuname;
{
char c, disk, ret, *name;
int i, w, attrib;
struct fcb *fcb2;
bdos(SETDMA,DMA);
name = fname;
/* validate disk-letter if any */
if (fname[1] == ':') { /* if disk quoted */
disk = fname[0] & 0x5f;
fname += 2; /* up to filename */
if ( (disk < 'A') || (disk > 'P') )
return(0x04); /* bad disk-letter */
disk &= 0x3f; /* range 1-16 = A-P */
if (*fname == 0) { /* disk-letter only */
#ifdef MPUZ80 /* simple for CP/M */
fname = allfiles; /* point to *.* */
#else /* whole path needed for MSDOS */
e = fname;
w = allfiles;
while ( (*e++ = *w++) != 0 )
; /* copy *.* into name */
#endif
} }
else
disk = 0;
ownfcb->f_driv = disk; /* set up drive-code */
/* validate name */
if ( (w = filexpand(fname,ownfcb->f_name)) < 0 )
return(0x02); /* bad name */
ret = (w > 0) ? 0x40 : 0;
#ifdef MPUZ80 /* CP/M handling
mode += SCHFST; /* search first or next */
if ( (i = bdos(mode,ownfcb)) == 0xff)
return(0x01); /* not found */
fcb2 = DMA + (i * 32);
name = fcb2->f_name; /* explicit name + bits */
for (i=0; i<11; ++i) {
if (i == 8)
*nuname++ = '.';
if ( (c = (name[i] & (char)0x7f)) != SP )
*nuname++ = c;
}
if ( *(nuname-1) == '.' )
--nuname;
*nuname = 0; /* close string */
/* check for special conditions */
if ( (fcb2->f_type[0] & (char)0x80) != 0 )
ret |= 0x10; /* file r/o */
if ( (fcb2->f_type[1] & (char)0x80) != 0 )
ret |= (char)0x08; /* system file */
#else /* MSDOS handling */
fname = name; /* retreive original name */
bdos(SETDMA,dmabuf);
mode += MCHFST;
attrib = 0xffff; /* find all files/dirs */
if (dos(mode,0,attrib,fname,0,0) == -1)
return(0x01);
name = dmabuf + MCHNAME; /* name found */
attrib = *(dmabuf + MCHATTRIB); /* & its attributes */
while ( (*nuname = *name++) > SP )
++nuname;
*nuname = 0; /* overwrites first space/ctrl */
/* check for special conditions */
if ( (attrib & (char)0x01) != 0 )
ret |= (char)0x10; /* file r/o */
if ( (attrib & (char)0x06) != 0 )
ret |= (char)0x08; /* system file */
if ( (attrib & (char)0x10) != 0 )
ret |= (char)0x80; /* directory */
if ( (attrib & (char)0x08) != 0 ) {
w = " (Vol-Id)";
while ( (*nuname++ = *w++) != 0 )
;
}
#endif
if (disk == 0)
disk = bdos(CURDSK,0); /* default disk */
else
--disk;
/* disk now = 0-15 for A-P */
if (rochek(disk) != 0 )
ret |= (char)0x20; /* disk r/o */
return(ret); /* normal return */
} /* end of filechek() */
char fileok(nam) /* check & print if bad */
/* Leaves ownfcb set up for subsequent routines;
Returns standard status-byte. */
char *nam;
{
char ret;
ret = filechek(0,nam,explicit);
if ( (ret & (char)0x20) != 0 )
txtout(diskro);
if ( (ret & (char)0x06) != 0 )
printf("<%s> %s ",nam,inval);
#ifndef MPUZ80 /* only for MSDOS */
else if ( (ret & (char)0x80) != 0 )
printf("(dir) ");
#endif
else if ( (ret & (char)0x01) != 0 )
printf("<%s> not found ",nam);
return(ret);
} /* end of fileok() */
filexpand(fname,nuname) /* expand & check filename */
/* returns -1 for error, 0 for OK, +1 for OK with wildcards
fname must not have a disk-letter */
char *fname, *nuname; /* old & new names */
{
char c, wild;
int i, lim;
for (i=0; i<11; ++i) /* blanx to nuname */
nuname[i] = SP;
nuname[11] = 0;
wild = 0;
lim = 8; /* first part */
i = 0;
while (i < 11) switch (c = *fname++) {
case '?': /* wildcard */
wild = 1;
if (i < lim)
nuname[i++] = c; /* stored */
else
return(-1);
break;
case '*': /* multi-wildcard */
wild = 1;
while (i < lim)
nuname[i++] = '?'; /* stored */
break;
case '.': /* separator */
if ( (i == 0) || (lim == 11) ) /* leading dot or */
return(-1); /* second dot - invalid */
else {
i = 8;
lim = 11;
}
break;
case 0: /* end-of-string */
if (i == 0)
return(-1); /* null name */
--fname;
i = 11;
break;
default: /* all others */
if ( ( (isalnum(c) == 0) && (c != '$') ) /* bad char */
|| (i >= lim) ) /* too many chars */
return(-1);
else
nuname[i++] = c; /* stored */
break;
} /* end switch, while */
if (*fname != 0) /* surplus char(s) */
wild = -1;
return(wild);
} /* end of filexpand() */
findcmd(osl) /* structure user input */
/* Sets up cmd with cmd-no, s1 & s2 => names (zero-terminated);
Returns number of valid items, 0 - 3; -1 if string is null;
(If command invalid, returns 0 with s2 => invalid string). */
char *osl;
{
static char *ospm[4];
char c;
int i;
cmd = 4;
while (cmd-- > 0) /* clear ospm[] */
ospm[cmd] = 0; /* (leaves cmd = 0) */
decol8(osl,ospm,4);
if ( (s1=ospm[0]) == 0) /* null goes back to Kermit */
return(-1);
if (s1[1] == 0) switch (*s1) { /* 1-letter inputs */
case 'Q':
kermkill(0);
case 'K':
return(-1);
case '?':
cmd = 10;
return(1);
default:
return(0);
}
if ( (s1[1] == ':') && (s1[2] == 0) ) { /* disk-letter */
cmd = 7;
return(1);
}
/* identify command */
i = 0;
while ( (s2 = cmds[++i]) != 0 ) {
s1 = ospm[0];
while ( ( (c = *s2) == *s1) && (c != 0) ) { /* match chars */
++s1;
++s2;
}
if (c == 0) { /* whole command */
cmd = (char)i;
break;
} }
if (cmd == 0) {
s1 = 0;
s2 = ospm[0];
return(0); /* no match */
}
/* set up statics & return with count */
s1 = ospm[1];
if (*(s2 = ospm[2]) == '=')
s2 = ospm[3];
return(c);
} /* end of findcmd() */
char osaction() /* take action on disk/os command */
/* Get cmdline from user and take action on it; on null input
return 0, else 1. */
{
static FILE *tfp;
int ic, disk, user;
char d;
txtout(oprompt);
keyline(osline);
upper(osline);
scrline = 0; /* clear paging */
if (findcmd(osline) < 0) /* set up cmd, s1, s2 */
return(0); /* exit on null line */
if (s1 == 0)
s1 = allfiles;
if (s2 == 0)
s2 = allfiles;
switch (cmd) {
case 0: /* Null command */
printmsg(" <%s> - Not a valid command.",s2);
break;
case 1: /* DIR */
printf(" %s Directory for %s - ", userpath(),s1);
dirprt(s1);
break;
case 2: /* ERA */
case 8: /* DEL */
printmsg(" DELete command: ");
if ( (dirprt(s1) & (char)0x30) != 0 ) {
outc(CR);
printf(" R/O -%s",notdel);
break;
}
/* seek confirmation before deleting */
txtout("\r OK to delete");
if (confirm() == 0) {
printf(" Files%s",notdel);
break;
}
outc(CR);
printf(" Deleting %s: ",s1);
if (bdos(DELFIL,ownfcb) == (char)0x0ff )
printf("failed;%s",notdel);
else
txtout("Files deleted.");
break;
case 3: /* REN */
#ifndef MPUZ80
/* CP/M renames A <= B but MSDOS renames A => B, so switch names for MSDOS */
w = s1;
s1 = s2;
s2 = w;
#endif
printf(" RENaming %s to %s; ",s2,s1);
if ( (s1[1] == ':') || (s2[1] == ':') ) {
printf("Omit driveletter;%s",notren);
break;
}
/* check new (first) name */
if ( (rtn = filexpand(s1,work)) != 0 ) {
printf("%s %s; %s", s1, (rtn!=1) ? inval : wildcds, notren);
break;
}
rtn = filechek(0,s1,explicit);
if ( (rtn & (char)0x01) == 0 ) {
printf("%s exists -%s",s1,notren);
break;
}
/* check old (second) name */
if ( (rtn = filexpand(s2,explicit)) != 0 ) {
printf("%s %s; %s", s2, (rtn!=1) ? inval : wildcds, notren);
break;
}
if ( ( (rtn = fileok(s2)) & (char)0x37 ) != 0) {
if ( (rtn & (char)0x10) != 0 )
txtout("R/O");
txtout(notren);
break;
}
if ( (rtn & (char)0x08) != 0 )
txtout("(sys) ");
/* move second name into fcb + 16 */
e = &(ownfcb->f_sydx);
*e++ = 0; /* dummy disk */
w = work;
user = 12;
while (user-- != 0)
*e++ = *w++; /* new name */
if (bdos(RENFIL,ownfcb) == (char)0xff)
txtout(" Rename FAILED.");
else
txtout(" Renamed OK.");
break;
case 4: /* TYPE */
txtout(" ");
if ( (fileok(s1) & (char)0x07) != 0)
break;
printf("TYPing file <%s>:\r\r", explicit);
if ( (tfp = fopen(s1,"r")) == 0 )
txtout(" File inaccessible.");
else while ( (ic = getc(tfp)) != EOF ) {
c = ic;
if (c == CTLZ)
break; /* CP/M EOF */
if (outfc(ascch(c)) != 0)
break;
}
outfc(CR);
if (c == CTLZ)
printf("End of File <%s>.\r",s1);
fclose(tfp);
break;
#ifdef MPUZ80
case 5: /* USER (CP/M only) */
if ( (user = atoi(s1)) > 15 )
txtout(" User > 15 not valid");
else {
bdos(GETUSR,user);
printmsg(" Now: %s", userpath());
}
break;
#endif
case 6: /* UPATH */
printf(" Environment: %s ",userpath());
break;
case 7: /* DRIVE */
txtout(" DRIVE change: ");
disk = (*s1 & 0x5f) - 'A';
if ( (disk < 0) || (disk > 15) )
txtout("Only A-P are valid disks ");
else {
bdos(SELDSK,disk);
txtout(userpath());
if (rochek(disk) != 0)
txtout(diskro);
}
break;
#ifdef MPUZ80
case 9: /* CHAnge disks (CP/M only) */
bdos(SELDSK,0);
/* if not on drive A, r/o not permanently removed */
printmsg(" Back on %s; Change any disk & hit RETURN ",userpath());
while (kbdin() == 0)
;
bdos(RSTDRV,0xffff);
break;
#endif
case 10: /* HELP or ? */
txtout(os1);
txtout(os2);
break;
default:
txtout("???");
break;
} /* end switch */
return(1); /* normal return */
} /* end of osaction() */
rochek(d) /* check for disk r/o */
/* returns NZ if disk d is r/o */
int d; /* disknumber 0-15 */
{
if (d > 15)
return(-1);
else
#ifdef MPUZ80
return( bdoshl(GETROV,0) & (0x0001 << d) );
#else /* no-op under MSDOS */
return(0);
#endif
} /* end of rochek() */
char *userpath() /* return environment */
/* returns address of a string of about 20 chars containing
user-number & disk etc. */
{
int i;
char disk, user;
disk = bdos(CURDSK,0) + 'A';
#ifdef MPUZ80
/* CP/M - return disk & user-no */
user = bdos(GETUSR,0xff);
sprintf(work,"User %d, drive %c: ", user, disk);
#else
/* MSDOS - reutrn disk only (pathname doesnt work) */
sprintf(work,"Drive %c: ", disk);
#endif
return(work);
} /* end of userpath() */
CHAR wildex(wild,line) /* expand wildcard names */
/* Permits use of same workspace for two parameters, but
"line" must be at least 85 chars long.
Returns count of files expanded, with 80-bit set if still
more on disk. */
char *wild, *line;
{
char count = 0, dsk = 0, ic = 0;
char local[14], *last, *next;
if (wild[1] == ':') /* disk letter */
dsk = *wild;
next = local;
while ( (*next++ = *wild++) != 0 )
;
last = next = line;
if (dsk != 0) { /* disk-letter to first */
*(++next) = dsk;
*(++next) = ':';
}
if ( (filechek(0,local,++next) & (char)0x01) == 0 ) do {
if ( (++count > 8) || (ic > 70) )
return(count + (char)0x7f); /* count & 0x80 */
*last = SP; /* terminator => separator */
while ( *(++next) != 0 )
++ic;
last = next++;
if (dsk != 0) { /* copy disk-letter to next */
*next++ = dsk;
*next++ = ':';
}
} while ( (filechek(1,local,next) & (char)0x01) == 0 ) ;
/* this copies next explixcit name onto line */
else
*line = 0; /* null line */
return(count);
} /* end of wildex() */
/***************** End of file KDISK.C ************************/