1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-15 15:57:13 +00:00
Nick Briggs 533c935e72
Fix various bugprone warnings (#397)
* Fix some warnings in main.c

main.c:678: narrowing conversion from 'unsigned long' to signed type 'int' is implementation-defined
main.c:493: The return value from the call to 'seteuid' is not checked.

* Fix some warnings in array operations

Instead of extracting typenumbers to an 'int', use the unsigned typenumber directly

array3.c:49: narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined
array4.c:61: narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined
array5.c:63: narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined
array6.c:50: narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined

* Resolve type mismatches for version numbers and propp flag

dir.c:1849: narrowing conversion from 'unsigned int' to signed type 'int'
dir.c:1850: narrowing conversion from 'unsigned int' to signed type 'int'
dir.c:2114: narrowing conversion from 'unsigned long' to signed type 'int'
dir.c:2207: narrowing conversion from 'unsigned int' to signed type 'int'

* Resolve type mismatches for version numbers and strlen result type

dsk.c:1072: narrowing conversion from 'unsigned long' to signed type 'int'
dsk.c:1108: narrowing conversion from 'unsigned long' to signed type 'int'
dsk.c:1549: narrowing conversion from 'unsigned long' to signed type 'int'
dsk.c:1712: narrowing conversion from 'unsigned long' to signed type 'int'
dsk.c:1751: narrowing conversion from 'unsigned long' to signed type 'int'
dsk.c:3426: narrowing conversion from 'unsigned int' to signed type 'int'

* Resolve type mismatches for strlen result type

ufs.c:213: narrowing conversion from 'unsigned long' to signed type 'int'
ufs.c:404: narrowing conversion from 'unsigned long' to signed type 'int'

* Resolve type error

uutils.c:117: 'signed char' to 'int' conversion [bugprone-signed-char-misuse,cert-str34-c]
2021-09-16 17:24:25 -07:00

1311 lines
34 KiB
C

/* $Id: ufs.c,v 1.2 1999/01/03 02:07:41 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved */
/************************************************************************/
/* */
/* (C) Copyright 1989-95 Venue. All Rights Reserved. */
/* Manufactured in the United States of America. */
/* */
/************************************************************************/
#include "version.h"
#include <errno.h>
#include <fcntl.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef DOS
#include <dirent.h>
#include <pwd.h>
#include <sys/param.h>
#include <sys/time.h>
#else /* DOS */
#include <dos.h>
#include <i32.h> /* "#pragma interrupt" & '_chain_intr'*/
#include <io.h>
#include <stk.h> /* _XSTACK struct definition */
#define MAXPATHLEN _MAX_PATH
#define MAXNAMLEN _MAX_PATH
#define alarm(x) 1
#endif /* DOS */
#include "lispemul.h"
#include "lispmap.h"
#include "adr68k.h"
#include "lsptypes.h"
#include "lspglob.h"
#include "arith.h"
#include "stream.h"
#include "timeout.h"
#include "locfile.h"
#include "dbprint.h"
#include "ufsdefs.h"
#include "commondefs.h"
#include "dskdefs.h"
int *Lisp_errno;
int Dummy_errno; /* If errno cell is not provided by Lisp, dummy_errno is used. */
/***********************************************/
/* file-system-specific defns */
/***********************************************/
/* Used to limit DOS filenames to 8.3 format */
#ifdef DOS
#define NameValid extensionp ? (extlen < 3) : (namelen < 8)
#define CountNameChars \
{ extensionp ? extlen++ : namelen++; }
#else
/* Other file systems don't care */
#define NameValid 1
#define CountNameChars
#endif /* DOS */
#ifdef DOS
void (*prev_int_24)(); /* keeps address of previous 24 handlr*/
#pragma interrupt(Int24)
/*
* Name: Int24
*
* Description: Bypass the "Abort, Retry, Fail?" message that
* DOS issues.
*
*/
void Int24(void) {
unsigned deverr, errcode;
union REGS regs;
_XSTACK *stk;
stk = (_XSTACK *)_get_stk_frame(); /* get ptr to the V86 _XSTACK frame */
deverr = stk->eax;
if ((deverr & 0x00008000) == 0) /* is a disk error */
{
stk->eax = _HARDERR_FAIL;
stk->opts |= _STK_NOINT; /* set _STK_NOINT to prevent V86 call */
_chain_intr(prev_int_24); /* call previous int 24 handlr, if any*/
/* (pts to 'ret' if no prev installed)*/
}
}
/*
* Name: init_host_filesystem
*
* Description: Initialize the hosts filesystem by installing
* the "critical error handler".
*/
init_host_filesystem() {
prev_int_24 = _dos_getvect(0x24); /* get addr of current handler, if any */
_dos_setvect(0x24, Int24); /* hook our int handler to interrupt */
_dpmi_lockregion((void *)prev_int_24, sizeof(prev_int_24));
_dpmi_lockregion((void *)&Int24, 4096);
}
/*
* Name: exit_host_filesystem
*
* Description: Cleanup the filesystem specific patches.
*
*/
exit_host_filesystem() {
_dos_setvect(0x24, prev_int_24); /* unhook our handlr, install previous*/
_dpmi_unlockregion((void *)prev_int_24, sizeof(prev_int_24));
_dpmi_unlockregion((void *)&Int24, 4096);
}
#endif /* DOS */
/*
* Name: UFS_getfilename
*
* Argument: LispPTR *args args[0]
* Full file name in Lisp format.
* args[1]
* Recognition mode. See IRM.
* args[2]
* Name area where the recognized full file name
* will be stored.
* args[3]
* The place where the error number should be
* stored.
*
* Value: If succeed, returns the Lisp smallp which represents the length
* of the recognized full file name, otherwise Lisp NIL.
*
* Side Effect: If succeed, name area (args[2]) will be replaced with the
* recognized full file name.
*
* Description:
*
* The implementation of GETFILENAME FDEV method for UNIX device. Performs the
* recognition on the specified name. Does not check if OPENFILE actually
* can open the file with the specified mode or not.
*/
LispPTR UFS_getfilename(LispPTR *args)
{
register char *base;
size_t len;
register int rval;
char lfname[MAXPATHLEN], file[MAXPATHLEN];
ERRSETJMP(NIL);
Lisp_errno = (int *)(Addr68k_from_LADDR(args[3]));
LispStringLength(args[0], len, rval);
len += 1; /* Add 1 for terminating NULL char. */
if (len > MAXPATHLEN) FileNameTooLong(NIL);
LispStringToCString(args[0], lfname, MAXPATHLEN);
/*
* Convert a Lisp file name to UNIX one. This is a UNIX device method.
* Thus we don't need to convert a version field. Third argument for
* unixpathname specifies it.
*/
#ifdef DOS
if (unixpathname(lfname, file, 0, 0, 0, 0, 0) == 0) return (NIL);
#else
if (unixpathname(lfname, file, 0, 0) == 0) return (NIL);
#endif /* DOS */
switch (args[1]) {
case RECOG_OLD:
case RECOG_OLDEST:
/*
* "Old" and "Oldest" means the "existing" file. All we have to do
* is to make sure it is an existing file or not.
*/
TIMEOUT(rval = access(file, F_OK));
if (rval == -1) {
*Lisp_errno = errno;
return (NIL);
}
break;
case RECOG_NEW:
case RECOG_OLD_NEW:
case RECOG_NON:
/*
* "New" file means the "not existing" file. UNIX device always
* recognizes a not existing file as if, the subsequent OPENFILE will
* find the truth.
* "Non" recognition is used to recognize a sysout file.
*/
break;
}
/*
* Now, we convert a file name back to Lisp format. The version field have not
* to be converted. The fourth argument for lisppathname specifies it.
*/
if (lisppathname(file, lfname, 0, 0) == 0) return (NIL);
STRING_BASE(args[2], base);
len = strlen(lfname);
#ifndef BYTESWAP
strncpy(base, lfname, len + 1);
#else
StrNCpyFromCToLisp(base, lfname, len + 1);
#endif /* BYTESWAP */
return (GetSmallp(len));
}
/*
* Name: UFS_deletefile
*
* Argument: LispPTR *args args[0]
* Full file name in Lisp format.
* args[1]
* The place where the error number should be
* stored.
*
* Value: If succeed, returns the Lisp symbol T, otherwise Lisp NIL.
*
* Side Effect: If succeed, the specified file is unlinked.
*
* Description:
*
* The implementation of DELETEFILE FDEV method for UNIX device. Try to delete
* a specified file.
*/
LispPTR UFS_deletefile(LispPTR *args)
{
char file[MAXPATHLEN], fbuf[MAXPATHLEN];
register int len, rval;
ERRSETJMP(NIL);
Lisp_errno = (int *)(Addr68k_from_LADDR(args[1]));
LispStringLength(args[0], len, rval);
len += 1;
if (len > MAXPATHLEN) FileNameTooLong(NIL);
LispStringToCString(args[0], fbuf, MAXPATHLEN);
#ifdef DOS
if (unixpathname(fbuf, file, 0, 0, 0, 0, 0) == 0) return (NIL);
#else
if (unixpathname(fbuf, file, 0, 0) == 0) return (NIL);
#endif /* DOS */
/*
* On UNIX device, all we have to do is just to unlink the file.
*/
TIMEOUT(rval = unlink(file));
if (rval == -1) {
*Lisp_errno = errno;
return (NIL);
}
return (ATOM_T);
}
/*
* Name: UFS_renamefile
*
* Argument: LispPTR *args args[0]
* Full file name in Lisp format. The file which
* is being renamed.
* args[1]
* Full file name in Lisp format. The file to which
* args[0] is being renamed.
* args[2]
* The place where the error number should be
* stored.
*
* Value: If succeed, returns the Lisp symbol T, otherwise Lisp NIL.
*
* Side Effect: If succeed, the specified file is unlinked.
*
* Description:
*
* The implementation of RENAMEFILE FDEV method for UNIX device. Try to rename
* a specified file.
*/
LispPTR UFS_renamefile(LispPTR *args)
{
char fbuf[MAXPATHLEN], src[MAXPATHLEN], dst[MAXPATHLEN];
int rval, len;
ERRSETJMP(NIL);
Lisp_errno = (int *)(Addr68k_from_LADDR(args[2]));
LispStringLength(args[0], len, rval);
len += 1;
if (len > MAXPATHLEN) FileNameTooLong(NIL);
LispStringLength(args[1], len, rval);
len += 1;
if (len > MAXPATHLEN) FileNameTooLong(NIL);
LispStringToCString(args[0], fbuf, MAXPATHLEN);
#ifdef DOS
if (unixpathname(fbuf, src, 0, 0, 0, 0, 0) == 0) return (NIL);
#else
if (unixpathname(fbuf, src, 0, 0) == 0) return (NIL);
#endif /* DOS */
LispStringToCString(args[1], fbuf, MAXPATHLEN);
#ifdef DOS
if (unixpathname(fbuf, dst, 0, 0, 0, 0, 0) == 0) return (NIL);
#else
if (unixpathname(fbuf, dst, 0, 0) == 0) return (NIL);
#endif /* DOS */
TIMEOUT(rval = rename(src, dst));
if (rval == -1) {
*Lisp_errno = errno;
return (NIL);
}
return (ATOM_T);
}
/*
* Name: UFS_directorynamep
*
* Argument: LispPTR *args args[0]
* Directory name in Lisp format. Both of the initial
* and trail directory delimiter are stripped by Lisp
* code. Only one exception is a "root directory".
* "Root directory is represented as ">".
* args[1]
* The place where the "true" name of the directory
* in Lisp format will be stored.
* args[2]
* The place where the error number should be stored.
* Not use in the current Lisp code implementation.
*
* Value: If succeed, returns the Lisp smallp which represents the length
* of the "true" name of the directory, otherwise Lisp NIL.
*
* Side Effect: If the directory is recognized as a valid directory representation,
* args[1] is replaced with the "true" directory name.
*
* Description:
*
* The implementation of the DIRECTORYNAMEP FDEV method for UNIX device.
* Performs the recognition as well. Accepts the directory representation which
* obeys the Xerox Lisp file naming convention. The "true" name which is stored
* on the area specified with the second argument also follows the Xerox Lisp
* file naming convention, and it includes the initial and trail directory
* delimiter. Thus the Lisp code does not have to worry about the conversion of
* the directory name representation.
*/
LispPTR UFS_directorynamep(LispPTR *args)
{
char dirname[MAXPATHLEN];
char fullname[MAXPATHLEN];
size_t len;
register int rval;
register char *base;
struct stat sbuf;
ERRSETJMP(NIL);
Lisp_errno = (int *)(Addr68k_from_LADDR(args[2]));
LispStringLength(args[0], len, rval);
len += 1;
/* -2 for the initial and trail directory delimiter. */
if (len > MAXPATHLEN - 2) FileNameTooLong(NIL);
LispStringToCString(args[0], dirname, MAXPATHLEN);
/* Convert Xerox Lisp file naming convention to Unix one. */
#ifdef DOS
if (unixpathname(dirname, fullname, 0, 0, 0, 0, 0) == 0) return (NIL);
#else
if (unixpathname(dirname, fullname, 0, 0) == 0) return (NIL);
#endif /* DOS */
TIMEOUT(rval = stat(fullname, &sbuf));
if (rval == -1) {
*Lisp_errno = errno;
return (NIL);
}
if ((sbuf.st_mode & S_IFMT) != S_IFDIR) return (NIL);
/* Convert Unix file naming convention to Xerox Lisp one. */
if (lisppathname(fullname, dirname, 1, 0) == 0) return (NIL);
len = strlen(dirname);
STRING_BASE(args[1], base);
#ifndef BYTESWAP
strncpy(base, dirname, len + 1);
#else
StrNCpyFromCToLisp(base, dirname, len + 1);
#endif /* BYTESWAP */
return (GetSmallp(len));
}
/*
* Name: unixpathname
*
* Argument: char *src Xerox Lisp syntax pathname.
* The HOST name field is not included.
* The initial directory delimiter is not included and
* if the pathname is passed as a directory, the
* tail delimiter may be included.
* char *dst The buffer to which the converted pathname is stored.
* int versionp
* If 1, version field in src is converted to UNIX
* version form. {DSK} device invokes unixpathname
* with versionp.
* int genp If 1, it indicates unixpathname is called from
* directory enumeration routine. In this case,
* trail period which is used to specify an empty
* extension field is treated specially.
*
* Value: If succeed, returns 1, otherwise 0.
*
* Side Effect: None.
*
* Description:
*
* Converts the Xerox Lisp syntax pathname to Unix syntax pathname.
* Src pathname might start with the one of the meta characters. And it
* might include Xerox Lisp pathname quote notation. The characters
* must be quoted in the Xerox Lisp file naming convention are valid in the UNIX
* file naming convention. So only skipping the quote character would be
* sufficient.
* If the trail directory delimiter, '>', is included in src, dst will also include
* UNIX trail directory delimiter '/'.
*
*/
#ifdef DOS
int unixpathname(char *src, char *dst, int versionp, int genp, char *drive, int *extlenptr, char *rawname)
#else
int unixpathname(char *src, char *dst, int versionp, int genp)
#endif /* DOS */
{
register char *cp, *dp, *np;
register int newdirflg;
char name[64];
char lfname[MAXPATHLEN], fbuf1[MAXPATHLEN], fbuf2[MAXPATHLEN];
char ver1[VERSIONLEN], ver2[VERSIONLEN];
struct passwd *pwd;
#ifdef DOS
char *rp;
int namelen = 0, extlen = 0; /* lengths of name & extension */
int extensionp = 0; /* T if we're in the extension */
int version = 1; /* version # for this file */
#endif /* DOS */
/* If there's a drive letter, it and a colon come first */
#ifdef DOS
if (drive && (*drive)) {
*dst++ = *drive;
*dst++ = DRIVESEP;
}
#endif /* DOS */
/*
* The UNIX root directory is represented as "<" in Xerox Lisp generic
* file system code.
*/
if (strcmp(src, "<") == 0) {
strcpy(dst, DIRSEPSTR);
return (1);
}
/* Copy src to protect it from destructive modification. */
strcpy(lfname, src);
/*
* If versionp is specified, we have to deal with the version field first,
* because the quotation mark which quotes the semicolon might be lost
* in the course of the following conversion.
*/
#ifdef DOS
if (versionp) LispVersionToUnixVersion(lfname, version) else version = -1;
#else
if (versionp) LispVersionToUnixVersion(lfname);
#endif /* DOS */
cp = lfname;
dp = dst;
/*
* We have to deal with the case in which the pathname is started with
* the meta character ('.', '~').
*/
switch (*cp) {
case '.':
switch (*(cp + 1)) {
case '.':
if (*(cp + 2) == '>' || *(cp + 2) == '\0') {
/*
* "..>" or ".." means the parent directory of the
* user's current working directory.
*/
if (getcwd(dst, MAXPATHLEN) == 0) return (0);
#ifdef DOS
dp = max(strrchr(dst, '/'), strrchr(dst, DIRSEP));
#else
dp = strrchr(dst, '/');
#endif /* DOS */
dp++;
if (*(cp + 2) == '\0')
cp += 2;
else
cp += 3;
} else {
/* Insert the initial directory delimiter. */
*dp++ = DIRSEP;
}
break;
#ifdef DOS
case '/':
case DIRSEP:
#endif
case '>':
/* ".>" means the user's current working directory. */
if (getcwd(dst, MAXPATHLEN) == 0) return (0);
while (*dp != '\0') dp++;
*dp++ = DIRSEP;
cp += 2;
break;
case '\0':
/* "." also means the user's current working directory. */
if (getcwd(dst, MAXPATHLEN) == 0) return (0);
while (*dp != '\0') dp++;
*dp++ = DIRSEP;
cp++;
break;
default:
/* Insert the initial directory delimiter. */
*dp++ = DIRSEP;
break;
}
break;
#ifndef DOS
case '~':
if (*(cp + 1) == '>' || *(cp + 1) == '\0') {
/* "~>" or "~" means the user's home directory. */
TIMEOUT(pwd = getpwuid(getuid()));
if (pwd == NULL) return (0);
strcpy(dst, pwd->pw_dir);
while (*dp != '\0') dp++;
if (*(dp - 1) != DIRSEP) {
/*
* Usually system administrators specify the users'
* home directories in the /etc/passwd without
* the trail directory delimiter.
*/
*dp++ = DIRSEP;
}
if (*(cp + 1) == '\0')
cp++;
else
cp += 2;
} else {
/*
* In this case, we assume some user's home directory
* is specified in the form "~username".
*/
for (++cp, np = name; *cp != '\0' && *cp != '>';) *np++ = *cp++;
*np = '\0';
TIMEOUT(pwd = getpwnam(name));
if (pwd == NULL) return (0);
strcpy(dst, pwd->pw_dir);
while (*dp != '\0') dp++;
if (*(dp - 1) != DIRSEP) {
/*
* Usually system administrators specify the users'
* home directories in the /etc/passwd without
* the trail directory delimiter.
*/
*dp++ = DIRSEP;
}
if (*cp == '>') cp++;
}
break;
#else
/* For DOS, ignore ~> or ~/ or ~ */
case '~':
if (*(cp + 1) == '>' || *(cp + 1) == '\0') {
/* "~>" or "~" means the user's home directory. */
*dp++ = DIRSEP;
if (*(cp + 1) == '\0')
cp++;
else
cp += 2;
} else {
/*
* In this case, we assume some user's home directory
* is specified in the form "~username".
*/
for (++cp, np = name; *cp != '\0' && *cp != '>';) *np++ = *cp++;
*dp++ = DIRSEP;
if (*cp == '>') cp++;
}
break;
#endif /* DOS */
default:
*dp++ = '/'; /* Insert the initial directory delimiter. */
break;
}
/*
* At this point, cp is placed at the point from which the source pathname
* will be scanned, and dp is placed at the point on dst from which the
* pathname will be copied.
*/
newdirflg = 1;
while (*cp != '\0') {
if (newdirflg) {
/*
* The new directory component starts. We have to care about
* the meta characters again. This time, the tilde character
* has no special meaning.
*/
switch (*cp) {
case '.':
switch (*(cp + 1)) {
case '.':
/* "..>" or ".." */
if (*(cp + 2) == '>' || *(cp + 2) == '\0') {
/*
* We have to check if we have already
* backed to the root directory or not.
*/
if ((dp - 1) != dst) {
/*
* We are not at the root
* directory. Back to the
* parent directory.
*/
for (dp -= 2; *dp != '/'; dp--) {}
dp++;
}
if (*(cp + 2) == '\0')
cp += 2;
else
cp += 3;
} else {
/*
* (IL:DIRECTORY "{DSK}.") is translated
* as (IL:DIRECTORY "{DSK}~>.;*").
* The Lisp directory is translated as
* like "/users/akina/..~*~" by
* unixpathname. Although such
* file name representation makes no sense,
* to avoid infinite loop, skip the
* first period here, as well as down
* a newdirflg.
*/
cp++;
newdirflg = 0;
}
break;
case '>':
/* ".>" */
cp += 2;
break;
case '\0':
/* "." */
cp++;
break;
default:
*dp++ = *cp++;
newdirflg = 0;
break;
}
break;
case '\'':
/*
* The first character of the new directory component
* is a quotation mark which is the quote character
* in the Xerox Lisp file naming convention. Copy the
* next character and skip the quoted character.
*/
*dp++ = *(cp + 1);
cp += 2;
newdirflg = 0;
break;
default:
*dp++ = *cp++;
newdirflg = 0;
break;
}
} else {
switch (*cp) {
#ifdef DOS
case '/': /* in DOS, must xlate / also. */
#endif /* DOS */
case '>':
/*
* Xerox Lisp directory delimiter '>' is translated into
* UNIX one, '/'.
*/
*dp = DIRSEP;
dp++;
cp++;
newdirflg = 1; /* Turn on the new directory flag. */
#ifdef DOS
namelen = extlen = 0;
rp = dp; /* remember where raw filename starts */
#endif /* DOS */
break;
case '\'':
/*
* The special characters in the Xerox Lisp file naming
* convention are quoted with the quote character.
* They are all valid in the UNIX file naming convention.
* So only we have to do is to skip the quotation mark
* and copy the next character.
*/
#ifdef DOS
if (NameValid) *dp++ = *(cp + 1);
CountNameChars;
#endif /* DOS */
cp += 2;
break;
#ifdef DOS
case '.': /* start of extension, if not already */
if (!extensionp)
*dp++ = *cp++;
else
cp++;
extensionp = 1;
break;
#endif /* DOS */
default:
if (NameValid)
*dp++ = *cp++;
else
cp++;
CountNameChars;
break;
}
}
}
*dp = '\0';
if (!newdirflg && !genp) {
/*
* If the last character in dst is a period, it has to be handled
* specially, because it might be used to specify that src has no
* extension field. This case can be distinguished by examining the
* character just before the period.
* If the specified pathname is one like "~>..", the last meta character
* matches this case. Thus we check newdirflg first so as not to be
* confused by this case.
*
* Only case in which genp is 1 is unixpathname is used to convert
* a pattern which is used to enumerate directory. In this case,
* for the convenience of the pattern matching routines, we don't
* care about the last period character.
*/
strcpy(fbuf1, lfname);
strcpy(fbuf2, dst);
separate_version(fbuf1, ver1, 1);
separate_version(fbuf2, ver2, 1);
for (cp = fbuf1; *cp; cp++) {}
for (dp = fbuf2; *dp; dp++) {}
if (*(cp - 1) == '.') {
if (*(cp - 2) != '\'' || ((cp - 3) > fbuf1 && *(cp - 3) == '\'')) {
/*
* The last period is not been quoted. It is used
* to specify the no extension case. We have to
* omit this period.
*/
*(dp - 1) = '\0';
}
}
#ifdef DOS
if (version >= 0)
sprintf(ver2, "%d", version);
else
*ver2 = '\0';
#endif /* DOS */
ConcNameAndVersion(fbuf2, ver2, dst);
}
return (1);
}
/*
* Name: lisppathname
*
* Argument: char *fullname UNIX full pathname.
* char *lispname The pathname following the Xerox
* Lisp naming convention.
* The first argument fullname is assumed
* the "true" name of lispname.
* The lispname is used to determine which
* character should be quoted in the result
* Xerox Lisp pathname representation.
* int dirp If 1, fullname is a directory. If 0,
* fullname is a file.
* int versionp If 1, version field is also converted
* to the Xerox Lisp version. {DSK} device
* invokes lisppathname with versionp but
* {UNIX} device without versionp. If
* versionp is 1, dirp must be 0.
*
* Value: If succeed, returns 1, otherwise 0.
* of the "true" name of the directory, otherwise Lisp NIL.
*
* Side Effect: If succeed, lispname is replaced with "true" name which follows
* the Xerox Lisp file naming convention.
*
* Description:
*
* Converts the UNIX file name to Xerox Lisp file name. The fields which might
* be included in the result filename are directory, name, extension, and version.
* The result file name can use the quotation mark to quote the characters which
* are dealt with specially in the Xerox Lisp file naming convention. These
* characters include "<", ">", ";", ".", and "'" itself. Notice that "." must be
* quoted if it is used as a part of the extension field. Also notice that "<"
* is quoted only if it is used as a first character of the initial directory.
*
*/
int lisppathname(char *fullname, char *lispname, int dirp, int versionp)
{
register char *cp, *dp, *lnamep, *cnamep;
char namebuf[MAXPATHLEN], fbuf[MAXPATHLEN], ver[VERSIONLEN];
register int i, mask, extensionp;
if (strcmp(fullname, DIRSEPSTR) == 0) {
strcpy(lispname, "<");
return (1);
}
#ifdef DOS
/* Split off the drive, if there is one. */
if (fullname[1] == DRIVESEP) {
*lispname++ = *fullname++;
*lispname++ = *fullname++;
}
#endif
if (!dirp) {
/*
* The characters which are dealt with specially (i.e. are quoted)
* in the Xerox Lisp file naming convention are all valid in UNIX
* file name convention. So the conversion rule is almost
* straightforward except the "extension" field. Only glancing
* the UNIX file name, we cannot determine which period character
* should be quoted in the result Xerox Lisp file name when more
* than one period are included in the UNIX file name. In such
* case, we have to refer to the Xerox Lisp file name representation
* which is specified the user. Thus, at first, extract the
* name field from the original Lisp file name.
*/
cp = lispname;
lnamep = cp - 1;
while (*cp != '\0') {
switch (*cp) {
case '>':
lnamep = cp + 1;
cp++;
break;
case '\'':
if (*(cp + 1) != '\0')
cp += 2;
else
cp++;
break;
default: cp++; break;
}
}
/* Name field in the UNIX file name representation. */
cnamep = strrchr(fullname, DIRSEP) + 1;
} else {
cnamep = fullname + strlen(fullname);
}
/*
* Conversion rule of file name from UNIX to Xerox Lisp.
* UNIX Lisp
* / < only if it is used as a root directory
* delimiter.
* / > if used as a directory delimiter for other
* directories than root directory.
* > '>
* ; ';
* ' ''
* . '. only if it is used as a part of the extension
* field.
* others as if
*/
cp = fullname + 1;
dp = namebuf;
*dp++ = '<';
if (*cp == '<') {
/*
* If the first character of the initial directory is '<',
* it should be quoted in the result Lisp file name.
*/
*dp++ = '\'';
*dp++ = *cp++;
}
while (cp < cnamep) {
switch (*cp) {
case '>':
case ';':
#ifndef DOS
case '\'':
#endif /* DOS */
*dp++ = '\'';
*dp++ = *cp++;
break;
#ifdef DOS
case '/':
#endif
case DIRSEP:
*dp++ = '>';
cp++;
break;
default: *dp++ = *cp++; break;
}
}
if (dirp) {
if (*(dp - 1) != '>' || *(dp - 2) == '\'') *dp++ = '>';
*dp = '\0';
strcpy(lispname, namebuf);
return (1);
}
/*
* Be careful dealing with the extension field. If we encounter with the
* period mark which was quoted in the original Lisp file name, we have
* to quote it in the result file name.
* First we count the period mark included in the Lisp file name, and
* remember the position of the quoted period. Then when we met the
* period while we are converting the UNIX file name into Lisp one,
* examine it if it is a quoted one or not, then if so, we quote it.
*/
mask = 0;
i = 1;
lnamep++;
while (*lnamep) {
if (*lnamep == '.') {
if (lnamep != lispname && *(lnamep - 1) == '\'') mask |= i;
i <<= 1;
}
lnamep++;
}
i = 1;
while (*cp) {
switch (*cp) {
#ifdef DOS
case DIRSEP:
*dp++ = '/';
cp++;
break;
#endif
case '>':
case ';':
case '\'':
*dp++ = '\'';
*dp++ = *cp++;
break;
case '.':
if ((i & mask) == i) {
/* This period should be quoted. */
*dp++ = '\'';
*dp++ = *cp++;
} else {
*dp++ = *cp++;
}
i <<= 1;
break;
default: *dp++ = *cp++; break;
}
}
*dp = '\0';
/*
* extensionp indicates whether extension field is included in a file name
* or not. If extension field is not included, we have to add a period
* to specify empty extension field.
*/
strcpy(fbuf, namebuf);
dp = cp = fbuf;
while (*cp) {
switch (*cp) {
case '>':
dp = cp;
cp++;
break;
case '\'':
if (*(cp + 1) != '\0')
cp += 2;
else
cp++;
break;
default: cp++; break;
}
}
cp = dp + 1;
if (versionp) separate_version(fbuf, ver, 1);
extensionp = 0;
while (*cp && !extensionp) {
switch (*cp) {
case '.': extensionp = 1; break;
case '\'':
if (*(cp + 1) != '\0')
cp += 2;
else
cp++;
break;
default: cp++; break;
}
}
if (!extensionp) {
*cp++ = '.';
*cp = '\0';
}
if (versionp && *ver != '\0') {
ConcNameAndVersion(fbuf, ver, namebuf);
} else {
strcpy(namebuf, fbuf);
}
/*
* Now, it's time to convert the version field.
*/
if (!dirp && versionp) UnixVersionToLispVersion(namebuf, 0);
strcpy(lispname, namebuf);
return (1);
}
/*
* Name: quote_fname
*
* Argument: char *file The root file name in UNIX format. "Root"
* file name contains the name, extension and
* version fields. A valid version field is in a
* form as ".~##~".
*
* Value: If succeed, returns 1, otherwise 0.
*
* Side Effect: If succeed, file is replaced with the file name in Xerox Lisp format
* in which special characters are quoted.
*
* Description:
*
* Converts a UNIX root file name to Xerox Lisp one. This routine only quotes special
* characters in Xerox file naming convention, does not care about the "true" name
* which might be specified directly by the user as like lisppathname. Thus, this
* routine can be invoked when you don't know how to escape the period character. This
* is the case when you convert a file name in the course of the directory enumeration.
*
* This routine is used when file is a "FILE" name and being converted to {DSK} name.
*
* The special characters which is quoted include "<", ">", ";", and "'" itself. Notice
* again that "." is not quoted, because we don't know it is a extension separator in
* Lisp sense or not.
*/
int quote_fname(char *file)
{
register char *cp, *dp;
register int extensionp;
char fbuf[MAXNAMLEN + 1], namebuf[MAXNAMLEN + 1], ver[VERSIONLEN];
cp = file;
dp = fbuf;
while (*cp) {
switch (*cp) {
case '>':
case ';':
case '\'':
*dp++ = '\'';
*dp++ = *cp++;
break;
default: *dp++ = *cp++; break;
}
}
*dp = '\0';
/*
* extensionp indicates whether extension field is included in a file
* name or not. If extension field is not included, we have to add a
* period to specify empty extension field.
*/
separate_version(fbuf, ver, 1);
cp = fbuf;
extensionp = 0;
while (*cp && !extensionp) {
switch (*cp) {
case '.':
if (*(cp + 1)) extensionp = 1;
cp++;
break;
case '\'':
if (*(cp + 1) != '\0')
cp += 2;
else
cp++;
break;
default: cp++; break;
}
}
if (!extensionp) {
if (*(cp - 1) == '.') {
*(cp - 1) = '\'';
*cp++ = '.';
}
*cp++ = '.';
*cp = '\0';
}
if (*ver != '\0') {
ConcNameAndVersion(fbuf, ver, namebuf);
} else {
strcpy(namebuf, fbuf);
}
UnixVersionToLispVersion(namebuf, 1);
strcpy(file, namebuf);
return (1);
}
/*
* Name: quote_fname_ufs
*
* Argument: char *file The root file name in UNIX format. "Root"
* file name contains the name, extension and
* version fields. A valid version field is in a
* form as ".~##~".
*
* Value: If succeed, returns 1, otherwise 0.
*
* Side Effect: If succeed, file is replaced with the file name in Xerox Lisp format
* in which special characters are quoted.
*
* Description:
*
* Similar to quote_fname, but this routine is only used when file is a "FILE" name
* and being converted to {UNIX} name.
*/
int quote_fname_ufs(char *file)
{
register char *cp, *dp;
register int extensionp;
char fbuf[MAXNAMLEN + 1];
cp = file;
dp = fbuf;
while (*cp) {
switch (*cp) {
case '>':
case ';':
case '\'':
*dp++ = '\'';
*dp++ = *cp++;
break;
default: *dp++ = *cp++; break;
}
}
*dp = '\0';
/*
* extensionp indicates whether extension field is included in a file
* name or not. If extension field is not included, we have to add a
* period to specify empty extension field.
*/
cp = fbuf;
extensionp = 0;
while (*cp && !extensionp) {
switch (*cp) {
case '.':
if (*(cp + 1)) extensionp = 1;
cp++;
break;
case '\'':
if (*(cp + 1) != '\0')
cp += 2;
else
cp++;
break;
default: cp++; break;
}
}
if (!extensionp) {
if (*(cp - 1) == '.') {
*(cp - 1) = '\'';
*cp++ = '.';
}
*cp++ = '.';
*cp = '\0';
}
strcpy(file, fbuf);
return (1);
}
/*
* Name: quote_dname
*
* Argument: char *dir The directory name in UNIX format. Does not
* include its parent name.
*
* Value: If succeed, returns 1, otherwise 0.
*
* Side Effect: If succeed, dir is replaced with the directory name in Xerox Lisp
* format in which special characters are quoted.
*
* Description:
*
* Similar to quote_fname, but this routine is only used when dir is a "DIRECTORY"
* name. Both {DSK} and {UNIX} uses this routine.
*/
int quote_dname(char *dir)
{
register char *cp, *dp;
char fbuf[MAXNAMLEN + 1];
cp = dir;
dp = fbuf;
while (*cp) {
switch (*cp) {
case '>':
case ';':
case '\'':
*dp++ = '\'';
*dp++ = *cp++;
break;
default: *dp++ = *cp++; break;
}
}
*dp = '\0';
if (*(dp - 1) == '.') {
/* Trail period should be quoted. */
*(dp - 1) = '\'';
*dp++ = '.';
}
strcpy(dir, fbuf);
return (1);
}