You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

237 lines
6.0 KiB

/*
CPMREDIR: CP/M filesystem redirector
Copyright (C) 1998, John Elliott <jce@seasip.demon.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file holds functions dealing with name translation; also the
initialisation code.
*/
#include "cpmint.h"
static char* skipUser(char* localname);
/* Detect DRDOS */
#ifdef __MSDOS__
static void drdos_init(void)
{
/* The DJGPP DOS extender won't detect DRDOS using intdos(), so we have
to use __dpmi_int() instead. */
#ifdef __GO32__
__dpmi_regs ir;
ir.x.ax = 0x4452; /* "DR" */
__dpmi_int(0x21, &ir);
if (ir.x.flags & 1) return; /* Not DRDOS */
redir_Msg("DRDOS detected.\n");
redir_drdos = 1;
#else /* __GO32__ */
union REGS ir, or ;
ir.w.ax = 0x4452; /* "DR" */
intdos(&ir, &or );
if (or .w.cflag) return; /* Not DRDOS */
redir_Msg("DRDOS detected.\n");
redir_drdos = 1;
#endif /* __GO32__ */
}
#endif /* __MSDOS__ */
int fcb_init(void)
{
int n;
/* A: to O: free */
for (n = 0; n < 15; n++) redir_drive_prefix[n][0] = 0;
strcpy(redir_drive_prefix[15], "./"); /* P: is current directory */
/* Log on to P:. It is the only drive at this point which we
* know works. */
redir_cpmdrive = 15;
#ifdef __MSDOS__
drdos_init();
#endif
return 1;
}
/* Deinitialise the library. */
void fcb_deinit(void)
{
/* Nothing */
}
/* 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
* drive.
*
*/
void xlt_name(char* localname, char* cpmname)
{
char ibuf[CPM_MAXPATH + 1];
char nbuf[CPM_MAXPATH + 1];
char* pname = ibuf;
char* s;
int n;
sprintf(ibuf, "%-.*s", CPM_MAXPATH, skipUser(localname));
while ((s = strpbrk(pname, DIRSEP))) { /* find the last directory separator allows mixed \ and / in windows */
#ifdef _WIN32
if (*s == '\\') /* convert separators to common format so directory tracking works more efficiently */
*s = '/';
#endif
pname = s + 1;
}
if (pname == ibuf) { /* No path separators in the name. It is therefore a
local filename, so map it to drive P: */
strcpy(cpmname, "p:");
strcat(cpmname, ibuf);
return;
}
/* catch user specified current drive a,b,c,p or A,B,C,P only, which map to predefined directories */
if (pname == ibuf + 2 && ibuf[1] == ':' && (s = strchr("aAbBcCpP", ibuf[0]))) {
cpmname[0] = tolower(*s); /* make sure it's lower case */
strcpy(cpmname + 1, ibuf + 1);
return;
}
strcpy(nbuf, pname); /* nbuf holds filename component */
*pname = 0; /* ibuf holds path component */
/* See if the path is one of those already mapped to drives */
for (n = 0; n < 15; n++)
{
if (redir_drive_prefix[n][0] && !strcmp(ibuf, redir_drive_prefix[n]))
{
sprintf(cpmname, "%c:%s", n + 'a', nbuf);
return;
}
}
/* It is not, see if another drive can be allocated */
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);
return;
}
/* No other drive can be allocated */
strcpy(cpmname, "p:");
strcat(cpmname, nbuf);
}
/* 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:
*/
int xlt_map(int drive, char* localdir)
{
int n;
if (drive == -1)
{
for (n = 0; n < 15; n++) if (!redir_drive_prefix[n][0])
{
drive = n;
break;
}
if (drive == -1) return 0; /* No space for mappings */
}
if (redir_drive_prefix[drive][0]) return 0; /* Drive taken */
sprintf(redir_drive_prefix[drive], "%-.*s", CPM_MAXPATH, localdir);
return 1;
}
/* Unmap a drive
*/
int xlt_umap(int drive)
{
if (!redir_drive_prefix[drive][0]) return 0; /* Drive not taken */
redir_drive_prefix[drive][0] = 0;
return 1;
}
char* xlt_getcwd(int drive)
{
if (drive < 0 || drive > 16) return "";
return redir_drive_prefix[drive];
}
/* as zxcc doesn't really support user spaces, remove any user specification
* 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
*/
static char* skipUser(char* localname) {
char* s;
int user;
int drive;
if (!localname || !(s = strchr(localname, ':')) || s > localname + 3)
return localname;
s = localname;
if (isdigit(*s)) {
user = *s++ - '0';
if (isdigit(*s)) {
user = user * 10 + *s++ - '0';
if (user > 31) /* check sensible user id */
return localname;
}
if (*s == ':') /* just strip the user id assume rest is a filename */
return s + 1;
if ('a' <= (drive = tolower(*s)) && drive <= 'p' && s[1] == ':')
return s; /* was form [0-9]+[a-pA-P] so strip user id */
else
return localname; /* not vaild so don't change */
}
if ((drive = tolower(*s++)) < 'a' || 'p' < drive || !isdigit(*s))
return localname; /* not a valid drive prefix or simple drive spec */
user = *s++ - '0';
if (isdigit(*s))
user = user * 10 + *s++ - '0';
if (*s != ':' || user > 31)
return localname;
*--s = drive; /* reinsert the drive just before the : */
return s;
}