1275 lines
27 KiB
Plaintext
1275 lines
27 KiB
Plaintext
#line 2 "osdep/dosgen" /* So compiler knows orig name of this file.*/
|
|
/*
|
|
* $Id: dosgen 13636 2004-05-05 22:01:21Z hubert $
|
|
*
|
|
* Program: Operating system dependent routines - MS DOS Generic
|
|
*
|
|
*
|
|
* Michael Seibel
|
|
* Networks and Distributed Computing
|
|
* Computing and Communications
|
|
* University of Washington
|
|
* Administration Builiding, AG-44
|
|
* Seattle, Washington, 98195, USA
|
|
* Internet: mikes@cac.washington.edu
|
|
*
|
|
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
|
|
*
|
|
*
|
|
* Pine and Pico are registered trademarks of the University of Washington.
|
|
* No commercial use of these trademarks may be made without prior written
|
|
* permission of the University of Washington.
|
|
*
|
|
* Pine, Pico, and Pilot software and its included text are Copyright
|
|
* 1989-2001 by the University of Washington.
|
|
*
|
|
* The full text of our legal notices is contained in the file called
|
|
* CPYRIGHT, included with this distribution.
|
|
*
|
|
*
|
|
* Notes:
|
|
* - This file should contain the cross section of functions useful
|
|
* in both DOS and Windows ports of pico.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* picosigs - Install any handlers for the signals we're interested
|
|
* in catching.
|
|
*/
|
|
void
|
|
picosigs()
|
|
{
|
|
/* no op */
|
|
}
|
|
|
|
|
|
/*
|
|
* Useful definitions...
|
|
*/
|
|
#ifdef MOUSE
|
|
static int mexist = 0; /* is the mouse driver installed? */
|
|
static int nbuttons; /* number of buttons on the mouse */
|
|
static unsigned mnoop;
|
|
#endif
|
|
static unsigned char okinfname[32] = {
|
|
0, 0, /* ^@ - ^G, ^H - ^O */
|
|
0, 0, /* ^P - ^W, ^X - ^_ */
|
|
0x80, 0x17, /* SP - ' , ( - / */
|
|
0xff, 0xe4, /* 0 - 7 , 8 - ? */
|
|
0x7f, 0xff, /* @ - G , H - O */
|
|
0xff, 0xe9, /* P - W , X - _ */
|
|
0x7f, 0xff, /* ` - g , h - o */
|
|
0xff, 0xf6, /* p - w , x - DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0 /* > DEL */
|
|
};
|
|
|
|
|
|
/*
|
|
* fallowc - returns TRUE if c is allowable in filenames, FALSE otw
|
|
*/
|
|
fallowc(c)
|
|
int c;
|
|
{
|
|
return(okinfname[c>>3] & 0x80>>(c&7));
|
|
}
|
|
|
|
|
|
#ifdef MOUSE
|
|
/*
|
|
* end_mouse - a no-op on DOS/Windows
|
|
*/
|
|
void
|
|
end_mouse()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* mouseexist - function to let outsiders know if mouse is turned on
|
|
* or not.
|
|
*/
|
|
mouseexist()
|
|
{
|
|
return(mexist);
|
|
}
|
|
#endif /* MOUSE */
|
|
|
|
|
|
/*
|
|
* fexist - returns TRUE if the file exists, FALSE otherwise
|
|
*/
|
|
fexist(file, m, l)
|
|
char *file, *m;
|
|
off_t *l;
|
|
{
|
|
struct stat sbuf;
|
|
|
|
if(l != NULL)
|
|
*l = (off_t)0;
|
|
|
|
if(stat(file, &sbuf) < 0){
|
|
if(errno == ENOENT) /* File not found */
|
|
return(FIOFNF);
|
|
else
|
|
return(FIOERR);
|
|
}
|
|
|
|
if(l != NULL)
|
|
*l = (off_t)sbuf.st_size;
|
|
|
|
if(sbuf.st_mode & S_IFDIR)
|
|
return(FIODIR);
|
|
else if(*m == 't') /* no links, just say yes */
|
|
return(FIOSUC);
|
|
|
|
if(m[0] == 'r') /* read access? */
|
|
return((S_IREAD & sbuf.st_mode) ? FIOSUC : FIONRD);
|
|
else if(m[0] == 'w') /* write access? */
|
|
return((S_IWRITE & sbuf.st_mode) ? FIOSUC : FIONWT);
|
|
else if(m[0] == 'x') /* execute access? */
|
|
return((S_IEXEC & sbuf.st_mode) ? FIOSUC : FIONEX);
|
|
return(FIOERR); /* what? */
|
|
}
|
|
|
|
|
|
/*
|
|
* isdir - returns true if fn is a readable directory, false otherwise
|
|
* silent on errors (we'll let someone else notice the problem;)).
|
|
*/
|
|
isdir(fn, l, d)
|
|
char *fn;
|
|
long *l;
|
|
time_t *d;
|
|
{
|
|
struct stat sbuf;
|
|
|
|
if(l)
|
|
*l = 0;
|
|
|
|
if(stat(fn, &sbuf) < 0)
|
|
return(0);
|
|
|
|
if(l)
|
|
*l = sbuf.st_size;
|
|
|
|
if(d)
|
|
*d = sbuf.st_mtime;
|
|
|
|
return(sbuf.st_mode & S_IFDIR);
|
|
}
|
|
|
|
|
|
/*
|
|
* gethomedir - returns the users home directory
|
|
* Note: home is malloc'd for life of pico
|
|
*/
|
|
char *gethomedir(l)
|
|
int *l;
|
|
{
|
|
static char *home = NULL;
|
|
static short hlen = 0;
|
|
|
|
if(home == NULL){
|
|
char buf[NLINE], *p;
|
|
if(Pmaster && Pmaster->home_dir)
|
|
p = Pmaster->home_dir;
|
|
else {
|
|
sprintf(buf, "%c:\\", _getdrive() + 'A' - 1);
|
|
p = buf;
|
|
}
|
|
hlen = strlen(p);
|
|
if((home=(char *)malloc(((size_t)hlen + 1) * sizeof(char))) == NULL){
|
|
emlwrite("Problem allocating space for home dir", NULL);
|
|
return(0);
|
|
}
|
|
strcpy(home, p);
|
|
}
|
|
|
|
if(l)
|
|
*l = hlen;
|
|
|
|
return(home);
|
|
}
|
|
|
|
|
|
/*
|
|
* homeless - returns true if given file does not reside in the current
|
|
* user's home directory tree.
|
|
*/
|
|
homeless(f)
|
|
char *f;
|
|
{
|
|
char *home;
|
|
int len;
|
|
|
|
home = gethomedir(&len);
|
|
return(strncmp(home, f, len));
|
|
}
|
|
|
|
|
|
/*
|
|
* errstr - return system error string corresponding to given errno
|
|
* Note: strerror() is not provided on all systems, so it's
|
|
* done here once and for all.
|
|
*/
|
|
char *errstr(err)
|
|
int err;
|
|
{
|
|
return((err >= 0 && err < sys_nerr) ? sys_errlist[err] : NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* getfnames - return all file names in the given directory in a single
|
|
* malloc'd string. n contains the number of names
|
|
*/
|
|
char *getfnames(dn, pat, n, e)
|
|
char *dn, *pat, *e;
|
|
int *n;
|
|
{
|
|
int status;
|
|
long l;
|
|
size_t avail, alloced, incr = 1024;
|
|
char *names, *np, *p;
|
|
char buf[NLINE];
|
|
struct stat sbuf;
|
|
#ifdef WIN32
|
|
struct _finddata_t dbuf;
|
|
long findrv;
|
|
#else
|
|
struct find_t dbuf; /* opened directory */
|
|
#endif
|
|
|
|
*n = 0;
|
|
|
|
if(stat(dn, &sbuf) < 0){
|
|
if(e)
|
|
sprintf(e, "\007Dir \"%s\": %s", dn, strerror(errno));
|
|
|
|
return(NULL);
|
|
}
|
|
else{
|
|
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
|
avail = alloced = MAX(sbuf.st_size, incr);
|
|
if(!(sbuf.st_mode & S_IFDIR)){
|
|
if(e)
|
|
sprintf(e, "\007Not a directory: \"%s\"", dn);
|
|
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
if((names=(char *)malloc(alloced * sizeof(char))) == NULL){
|
|
if(e)
|
|
sprintf(e, "\007Can't malloc space for file names");
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
np = names;
|
|
|
|
strcpy(buf, dn);
|
|
sprintf(buf, "%s%s%s*%s%s", dn,
|
|
(dn[strlen(dn)-1] == '\\') ? "" : "\\",
|
|
(pat && *pat) ? pat : "",
|
|
(pat && *pat && strchr(pat, '.')) ? "" : ".",
|
|
(pat && *pat && strchr(pat, '.')) ? "" : "*");
|
|
#ifdef WIN32
|
|
if((findrv = _findfirst(buf, &dbuf)) < 0){
|
|
#else
|
|
if(_dos_findfirst(buf, _A_NORMAL|_A_SUBDIR, &dbuf) != 0){
|
|
#endif
|
|
if(e)
|
|
sprintf(e, "Can't find first file in \"%s\"", dn);
|
|
|
|
free((char *) names);
|
|
return(NULL);
|
|
}
|
|
|
|
do{
|
|
(*n)++;
|
|
p = dbuf.name;
|
|
l = strlen(p);
|
|
while(avail < l+1){
|
|
char *oldnames;
|
|
|
|
alloced += incr;
|
|
avail += incr;
|
|
oldnames = names;
|
|
if((names = (char *)realloc((void *)names, alloced * sizeof(char)))
|
|
== NULL){
|
|
if(e)
|
|
sprintf(e, "\007Can't malloc enough space for file names");
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
np = names + (np-oldnames);
|
|
}
|
|
|
|
avail -= (l+1);
|
|
|
|
while((*np++ = *p++) != '\0')
|
|
;
|
|
}
|
|
#ifdef WIN32
|
|
while(_findnext(findrv, &dbuf) == 0);
|
|
_findclose(findrv);
|
|
#else
|
|
while(_dos_findnext(&dbuf) == 0);
|
|
#endif
|
|
|
|
return(names);
|
|
}
|
|
|
|
|
|
/*
|
|
* fioperr - given the error number and file name, display error
|
|
*/
|
|
void
|
|
fioperr(e, f)
|
|
int e;
|
|
char *f;
|
|
{
|
|
switch(e){
|
|
case FIOFNF: /* File not found */
|
|
emlwrite("\007File \"%s\" not found", f);
|
|
break;
|
|
case FIOEOF: /* end of file */
|
|
emlwrite("\007End of file \"%s\" reached", f);
|
|
break;
|
|
case FIOLNG: /* name too long */
|
|
emlwrite("\007File name \"%s\" too long", f);
|
|
break;
|
|
case FIODIR: /* file is a directory */
|
|
emlwrite("\007File \"%s\" is a directory", f);
|
|
break;
|
|
case FIONWT:
|
|
emlwrite("\007Write permission denied: %s", f);
|
|
break;
|
|
case FIONRD:
|
|
emlwrite("\007Read permission denied: %s", f);
|
|
break;
|
|
case FIONEX:
|
|
emlwrite("\007Execute permission denied: %s", f);
|
|
break;
|
|
default:
|
|
emlwrite("\007File I/O error: %s", f);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* pfnexpand - pico's function to expand the given file name if there is
|
|
* a leading '~'
|
|
*/
|
|
char *pfnexpand(fn, len)
|
|
char *fn;
|
|
size_t len;
|
|
{
|
|
register char *x, *y, *z;
|
|
char *home = NULL;
|
|
char name[_MAX_PATH];
|
|
|
|
if(*fn == '~' && *(x = fn + 1) == '\\') {
|
|
if(!(home = (char *) getenv("HOME"))
|
|
&& getenv("HOMEDRIVE") && getenv("HOMEPATH"))
|
|
sprintf(home = name, "%s%s",
|
|
(char *) getenv("HOMEDRIVE"), (char *) getenv("HOMEPATH"));
|
|
|
|
if(home && strlen(home)+strlen(x)<len){
|
|
/* make room for expanded path */
|
|
for(z = x + strlen(x), y = fn + strlen(x) + strlen(home);
|
|
z >= x;
|
|
*y-- = *z--)
|
|
;
|
|
|
|
/* and insert the expanded address */
|
|
for(x = fn, y = home; *y != '\0'; *x++ = *y++)
|
|
;
|
|
}
|
|
}
|
|
|
|
return(fn);
|
|
}
|
|
|
|
|
|
/*
|
|
* fixpath - make the given pathname into an absolute path
|
|
*/
|
|
void
|
|
fixpath(name, len)
|
|
char *name;
|
|
size_t len;
|
|
{
|
|
char file[_MAX_PATH];
|
|
int dr;
|
|
|
|
if(!len)
|
|
return;
|
|
|
|
/* return the full path of given file, so drive spec? */
|
|
if(name[1] == ':' && isalpha((unsigned char) name[0])){
|
|
if(name[2] != '\\'){ /* including path? */
|
|
dr = toupper((unsigned char)name[0]) - 'A' + 1;
|
|
if(_getdcwd(dr, file, _MAX_PATH) != NULL){
|
|
if(file[strlen(file)-1] != '\\')
|
|
strncat(file, "\\", sizeof(file)-1-strlen(file));
|
|
|
|
/* add file name */
|
|
strncat(file, &name[2], sizeof(file)-1-strlen(file));
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
else
|
|
return; /* fully qualified with drive and path! */
|
|
}
|
|
else if(name[0] == '\\' && name[1] != '\\') { /* no drive spec! */
|
|
sprintf(file, "%c:%.*s", _getdrive()+'A'-1, len-3, name);
|
|
}
|
|
else if(name[0] == '\\' && name[1] == '\\'){ /* Windows network drive */
|
|
return;
|
|
}
|
|
else{
|
|
if(Pmaster && !(gmode & MDCURDIR)){
|
|
strncpy(file, ((gmode & MDTREE) || opertree[0])
|
|
? opertree : gethomedir(NULL), sizeof(file)-1);
|
|
file[sizeof(file)-1] = '\0';
|
|
}
|
|
else if(!_getcwd(file, sizeof(file))) /* no qualification */
|
|
return;
|
|
|
|
if(*name){ /* if name, append it */
|
|
if(*file && file[strlen(file)-1] != '\\')
|
|
strncat(file, "\\", sizeof(file)-1-strlen(file));
|
|
|
|
strncat(file, name, sizeof(file)-1-strlen(file));
|
|
}
|
|
}
|
|
|
|
strncpy(name, file, len-1); /* copy back to real buffer */
|
|
name[len-1] = '\0'; /* tie off just in case */
|
|
}
|
|
|
|
|
|
/*
|
|
* compresspath - given a base path and an additional directory, collapse
|
|
* ".." and "." elements and return absolute path (appending
|
|
* base if necessary).
|
|
*
|
|
* returns 1 if OK,
|
|
* 0 if there's a problem
|
|
* new path, by side effect, if things went OK
|
|
*/
|
|
compresspath(base, path, len)
|
|
char *base, *path;
|
|
int len;
|
|
{
|
|
register int i;
|
|
int depth = 0;
|
|
char *p;
|
|
char *stack[32];
|
|
char pathbuf[NLINE];
|
|
|
|
#define PUSHD(X) (stack[depth++] = X)
|
|
#define POPD() ((depth > 0) ? stack[--depth] : "")
|
|
|
|
strcpy(pathbuf, path);
|
|
fixpath(pathbuf, len);
|
|
|
|
p = pathbuf;
|
|
for(i=0; pathbuf[i] != '\0'; i++){ /* pass thru path name */
|
|
if(pathbuf[i] == C_FILESEP){
|
|
if(p != pathbuf)
|
|
PUSHD(p); /* push dir entry */
|
|
p = &pathbuf[i+1]; /* advance p */
|
|
pathbuf[i] = '\0'; /* cap old p off */
|
|
continue;
|
|
}
|
|
|
|
if(pathbuf[i] == '.'){ /* special cases! */
|
|
if(pathbuf[i+1] == '.' /* parent */
|
|
&& (pathbuf[i+2] == C_FILESEP || pathbuf[i+2] == '\0')){
|
|
if(!strcmp(POPD(),"")) /* bad news! */
|
|
return(0);
|
|
|
|
i += 2;
|
|
p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
|
|
}
|
|
else if(pathbuf[i+1] == C_FILESEP || pathbuf[i+1] == '\0'){
|
|
i++;
|
|
p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(*p != '\0')
|
|
PUSHD(p); /* get last element */
|
|
|
|
path[0] = '\0';
|
|
for(i = 0; i < depth; i++){
|
|
strcat(path, S_FILESEP);
|
|
strcat(path, stack[i]);
|
|
}
|
|
|
|
return(1); /* everything's ok */
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine is derived from BSD4.3 code,
|
|
* Copyright (c) 1987 Regents of the University of California.
|
|
* All rights reserved.
|
|
*/
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
static char sccsid[] = "@(#)mktemp.c 5.7 (Berkeley) 6/27/88";
|
|
#endif /* LIBC_SCCS and not lint */
|
|
|
|
static char *
|
|
was_nonexistent_tmp_name(as, create_it, ext)
|
|
char *as;
|
|
int create_it;
|
|
char *ext;
|
|
{
|
|
register char *start, *trv;
|
|
char treplace;
|
|
struct stat sbuf;
|
|
unsigned pid;
|
|
static unsigned n = 0;
|
|
int fd, tries = 0;
|
|
|
|
pid = ((unsigned)getpid() * 100) + n++;
|
|
|
|
/* extra X's get set to 0's */
|
|
for(trv = as; *trv; ++trv)
|
|
;
|
|
|
|
/*
|
|
* We should probably make the name random instead of having it
|
|
* be the pid.
|
|
*/
|
|
while(*--trv == 'X'){
|
|
*trv = (pid % 10) + '0';
|
|
pid /= 10;
|
|
}
|
|
|
|
/* add the extension, enough room guaranteed by caller */
|
|
if(ext){
|
|
strcat(as, ".");
|
|
strcat(as, ext);
|
|
}
|
|
|
|
/*
|
|
* Check for write permission on target directory; if you have
|
|
* six X's and you can't write the directory, this will run for
|
|
* a *very* long time.
|
|
*/
|
|
for(start = ++trv; trv > as && *trv != '\\'; --trv)
|
|
;
|
|
|
|
if(*trv == '\\'){
|
|
if((trv - as == 2) && isalpha(as[0]) && as[1] == ':')
|
|
trv++;
|
|
treplace = *trv;
|
|
*trv = '\0';
|
|
if(stat(as==trv ? "\\" : as, &sbuf) || !(sbuf.st_mode & S_IFDIR))
|
|
return((char *)NULL);
|
|
|
|
*trv = treplace;
|
|
}
|
|
else if (stat(".", &sbuf) == -1)
|
|
return((char *)NULL);
|
|
|
|
for(;;){
|
|
if(stat(as, &sbuf)){ /* stat failed */
|
|
if(errno == ENOENT){ /* no such file, success */
|
|
/*
|
|
* If create_it is set, create the file so that the
|
|
* evil ones don't have a chance to put something there
|
|
* that they can read or write before we create it
|
|
* ourselves.
|
|
*/
|
|
if(!create_it ||
|
|
((fd=open(as, O_CREAT|O_EXCL|O_WRONLY,0600)) >= 0
|
|
&& close(fd) == 0))
|
|
return(as);
|
|
else if(++tries > 3) /* open failed unexpectedly */
|
|
return((char *)NULL);
|
|
}
|
|
else /* failed for unknown reason */
|
|
return((char *)NULL);
|
|
}
|
|
|
|
for(trv = start;;){
|
|
if(!*trv)
|
|
return((char *)NULL);
|
|
|
|
/*
|
|
* Change the digits from the initial values into
|
|
* lower case letters and try again.
|
|
*/
|
|
if(*trv == 'z')
|
|
*trv++ = 'a';
|
|
else{
|
|
if(isdigit((unsigned char)*trv))
|
|
*trv = 'a';
|
|
else
|
|
++*trv;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine is derived from BSD4.3 code,
|
|
* Copyright (c) 1988 Regents of the University of California.
|
|
* All rights reserved.
|
|
*/
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
static char sccsid[] = "@(#)tmpnam.c 4.5 (Berkeley) 6/27/88";
|
|
#endif /* LIBC_SCCS and not lint */
|
|
/*----------------------------------------------------------------------
|
|
Return a unique file name in a given directory. This is not quite
|
|
the same as the usual tempnam() function, though it is similar.
|
|
We want it to use the TMP/TMPDIR environment variable only if dir
|
|
is NULL, instead of using it regardless if it is set.
|
|
We also want it to be safer than tempnam().
|
|
If we return a filename, we are saying that the file did not exist
|
|
at the time this function was called (and it wasn't a symlink pointing
|
|
to a file that didn't exist, either).
|
|
If dir is NULL this is a temp file in a public directory. In that
|
|
case we create the file with permission 0600 before returning.
|
|
|
|
Args: dir -- The directory to create the name in
|
|
prefix -- Prefix of the name
|
|
|
|
Result: Malloc'd string equal to new name is returned. It must be free'd
|
|
by the caller. Returns the string on success and NULL on failure.
|
|
----*/
|
|
char *
|
|
temp_nam(dir, prefix)
|
|
char *dir, *prefix;
|
|
{
|
|
struct stat buf;
|
|
size_t l, ll;
|
|
char *f, *name;
|
|
|
|
if(!(name = (char *)malloc((unsigned int)NFILEN)))
|
|
return((char *)NULL);
|
|
|
|
if(!dir && (f = getenv("TMPDIR")) && !stat(f, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(f, WRITE_ACCESS)){
|
|
strncpy(name, f, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
if(!dir && (f = getenv("TMP")) && !stat(f, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(f, WRITE_ACCESS)){
|
|
strncpy(name, f, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
if(!dir && (f = getenv("TEMP")) && !stat(f, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(f, WRITE_ACCESS)){
|
|
strncpy(name, f, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
if(dir){
|
|
strncpy(name, dir, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
if(!*dir || (isalpha(*dir) && *(dir+1) == ':' && !*(dir+2)))
|
|
strcat(name, "\\");
|
|
|
|
if((!stat(name, &buf) && (buf.st_mode&S_IFMT) == S_IFDIR)
|
|
&& !can_access(name, WRITE_ACCESS)){
|
|
strncpy(name, dir, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
#ifndef P_tmpdir
|
|
#define P_tmpdir "\\tmp"
|
|
#endif
|
|
if(!stat(P_tmpdir, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(P_tmpdir, WRITE_ACCESS)){
|
|
strncpy(name, P_tmpdir, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
free(name);
|
|
return((char *)NULL);
|
|
|
|
done:
|
|
if(name[0] && *((f = &name[l=strlen(name)]) - 1) != '\\' && l+1 < NFILEN){
|
|
*f++ = '\\';
|
|
*f = '\0';
|
|
l++;
|
|
}
|
|
|
|
if(prefix && (ll = strlen(prefix)) && l+ll < NFILEN){
|
|
strcpy(f, prefix);
|
|
f += ll;
|
|
l += ll;
|
|
}
|
|
|
|
if(l+6 < NFILEN)
|
|
strcpy(f, "XXXXXX");
|
|
else{
|
|
free(name);
|
|
return((char *)NULL);
|
|
}
|
|
|
|
return(was_nonexistent_tmp_name(name, 1, NULL));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Like temp_nam but create a unique name with an extension.
|
|
|
|
Result: Malloc'd string equal to new name is returned. It must be free'd
|
|
by the caller. Returns the string on success and NULL on failure.
|
|
----*/
|
|
char *
|
|
temp_nam_ext(dir, prefix, ext)
|
|
char *dir, *prefix, *ext;
|
|
{
|
|
struct stat buf;
|
|
size_t l, ll;
|
|
char *f, *name;
|
|
|
|
if(ext == NULL || *ext == '\0')
|
|
return(temp_nam(dir, prefix));
|
|
|
|
if(!(name = (char *)malloc((unsigned int)NFILEN)))
|
|
return((char *)NULL);
|
|
|
|
if(!dir && (f = getenv("TMPDIR")) && !stat(f, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(f, WRITE_ACCESS)){
|
|
strncpy(name, f, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
if(!dir && (f = getenv("TMP")) && !stat(f, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(f, WRITE_ACCESS)){
|
|
strncpy(name, f, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
if(!dir && (f = getenv("TEMP")) && !stat(f, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(f, WRITE_ACCESS)){
|
|
strncpy(name, f, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
if(dir){
|
|
strncpy(name, dir, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
if(!*dir || (isalpha(*dir) && *(dir+1) == ':' && !*(dir+2)))
|
|
strcat(name, "\\");
|
|
|
|
if((!stat(name, &buf) && (buf.st_mode&S_IFMT) == S_IFDIR)
|
|
&& !can_access(name, WRITE_ACCESS)){
|
|
strncpy(name, dir, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
#ifndef P_tmpdir
|
|
#define P_tmpdir "\\tmp"
|
|
#endif
|
|
if(!stat(P_tmpdir, &buf) &&
|
|
(buf.st_mode&S_IFMT) == S_IFDIR &&
|
|
!can_access(P_tmpdir, WRITE_ACCESS)){
|
|
strncpy(name, P_tmpdir, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
goto done;
|
|
}
|
|
|
|
free(name);
|
|
return((char *)NULL);
|
|
|
|
done:
|
|
if(name[0] && *((f = &name[l=strlen(name)]) - 1) != '\\' && l+1 < NFILEN){
|
|
*f++ = '\\';
|
|
*f = '\0';
|
|
l++;
|
|
}
|
|
|
|
if(prefix && (ll = strlen(prefix)) && l+ll < NFILEN){
|
|
strcpy(f, prefix);
|
|
f += ll;
|
|
l += ll;
|
|
}
|
|
|
|
if(l+6+strlen(ext)+1 < NFILEN)
|
|
strcpy(f, "XXXXXX");
|
|
else{
|
|
free(name);
|
|
return((char *)NULL);
|
|
}
|
|
|
|
return(was_nonexistent_tmp_name(name, 1, ext));
|
|
}
|
|
|
|
|
|
/*
|
|
* tmpname - return a temporary file name in the given buffer, the filename
|
|
* is in the directory dir unless dir is NULL
|
|
*/
|
|
void
|
|
tmpname(dir, name)
|
|
char *dir;
|
|
char *name;
|
|
{
|
|
char tmp[_MAX_PATH];
|
|
char *t;
|
|
|
|
if(!((dir && *dir) ||
|
|
(dir = getenv("TMPDIR")) ||
|
|
(dir = getenv("TMP")) ||
|
|
(dir = getenv("TEMP"))))
|
|
if(!(getcwd(dir = tmp, _MAX_PATH)
|
|
&& fexist(dir, "w", (off_t *) NULL) == FIOSUC))
|
|
dir = "c:\\";
|
|
|
|
if(t = temp_nam_ext(dir, "ae", "txt")){
|
|
strncpy(name, t, NFILEN-1);
|
|
name[NFILEN-1] = '\0';
|
|
free(t);
|
|
}
|
|
else{
|
|
emlwrite("Unable to construct temp file name", NULL);
|
|
name[0] = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Take a file name, and from it
|
|
* fabricate a buffer name. This routine knows
|
|
* about the syntax of file names on the target system.
|
|
* I suppose that this information could be put in
|
|
* a better place than a line of code.
|
|
*/
|
|
void
|
|
makename(bname, fname)
|
|
char bname[];
|
|
char fname[];
|
|
{
|
|
register char *cp1;
|
|
register char *cp2;
|
|
|
|
cp1 = &fname[0];
|
|
while (*cp1 != 0)
|
|
++cp1;
|
|
|
|
while (cp1!=&fname[0] && cp1[-1]!='\\')
|
|
--cp1;
|
|
cp2 = &bname[0];
|
|
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
|
|
*cp2++ = *cp1++;
|
|
*cp2 = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* copy - copy contents of file 'a' into a file named 'b'. Return error
|
|
* if either isn't accessible or is a directory
|
|
*/
|
|
copy(a, b)
|
|
char *a, *b;
|
|
{
|
|
int in, out, n, rv = 0;
|
|
char *cb;
|
|
struct stat tsb, fsb;
|
|
|
|
if(stat(a, &fsb) < 0){ /* get source file info */
|
|
emlwrite("Can't Copy: %s", errstr(errno));
|
|
return(-1);
|
|
}
|
|
|
|
if(!(fsb.st_mode&S_IREAD)){ /* can we read it? */
|
|
emlwrite("\007Read permission denied: %s", a);
|
|
return(-1);
|
|
}
|
|
|
|
if((fsb.st_mode&S_IFMT) == S_IFDIR){ /* is it a directory? */
|
|
emlwrite("\007Can't copy: %s is a directory", a);
|
|
return(-1);
|
|
}
|
|
|
|
if(stat(b, &tsb) < 0){ /* get dest file's mode */
|
|
switch(errno){
|
|
case ENOENT:
|
|
break; /* these are OK */
|
|
default:
|
|
emlwrite("\007Can't Copy: %s", errstr(errno));
|
|
return(-1);
|
|
}
|
|
}
|
|
else{
|
|
if(!(tsb.st_mode&S_IWRITE)){ /* can we write it? */
|
|
emlwrite("\007Write permission denied: %s", b);
|
|
return(-1);
|
|
}
|
|
|
|
if((tsb.st_mode&S_IFMT) == S_IFDIR){ /* is it directory? */
|
|
emlwrite("\007Can't copy: %s is a directory", b);
|
|
return(-1);
|
|
}
|
|
|
|
if(fsb.st_dev == tsb.st_dev && fsb.st_ino == tsb.st_ino){
|
|
emlwrite("\007Identical files. File not copied", NULL);
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
if((in = open(a, _O_RDONLY)) < 0){
|
|
emlwrite("Copy Failed: %s", errstr(errno));
|
|
return(-1);
|
|
}
|
|
|
|
if((out=creat(b, fsb.st_mode&0xfff)) < 0){
|
|
emlwrite("Can't Copy: %s", errstr(errno));
|
|
close(in);
|
|
return(-1);
|
|
}
|
|
|
|
if((cb = (char *)malloc(NLINE*sizeof(char))) == NULL){
|
|
emlwrite("Can't allocate space for copy buffer!", NULL);
|
|
close(in);
|
|
close(out);
|
|
return(-1);
|
|
}
|
|
|
|
while(1){ /* do the copy */
|
|
if((n = read(in, cb, NLINE)) < 0){
|
|
emlwrite("Can't Read Copy: %s", errstr(errno));
|
|
rv = -1;
|
|
break; /* get out now */
|
|
}
|
|
|
|
if(n == 0) /* done! */
|
|
break;
|
|
|
|
if(write(out, cb, n) != n){
|
|
emlwrite("Can't Write Copy: %s", errstr(errno));
|
|
rv = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(cb);
|
|
close(in);
|
|
close(out);
|
|
return(rv);
|
|
}
|
|
|
|
|
|
/*
|
|
* Open a file for writing. Return TRUE if all is well, and FALSE on error
|
|
* (cannot create).
|
|
*/
|
|
ffwopen(fn, readonly)
|
|
char *fn;
|
|
int readonly;
|
|
{
|
|
extern FIOINFO g_pico_fio;
|
|
|
|
g_pico_fio.flags = FIOINFO_WRITE;
|
|
if ((g_pico_fio.fp = fopen(g_pico_fio.name = fn, "w")) == NULL) {
|
|
emlwrite("Cannot open file for writing", NULL);
|
|
return (FIOERR);
|
|
}
|
|
|
|
#ifdef MODE_READONLY
|
|
if(readonly)
|
|
chmod(fn, MODE_READONLY); /* fix access rights */
|
|
#endif
|
|
|
|
return (FIOSUC);
|
|
}
|
|
|
|
|
|
/*
|
|
* Close a file. Should look at the status in all systems.
|
|
*/
|
|
ffclose()
|
|
{
|
|
extern FIOINFO g_pico_fio;
|
|
|
|
if (fclose(g_pico_fio.fp) != FALSE) {
|
|
emlwrite("Error closing file", NULL);
|
|
return(FIOERR);
|
|
}
|
|
|
|
return(FIOSUC);
|
|
}
|
|
|
|
|
|
/*
|
|
* ffelbowroom - make sure the destination's got enough room to receive
|
|
* what we're about to write...
|
|
*/
|
|
ffelbowroom()
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* worthit - generic sort of test to roughly gage usefulness of using
|
|
* optimized scrolling.
|
|
*
|
|
* note:
|
|
* returns the line on the screen, l, that the dot is currently on
|
|
*/
|
|
worthit(l)
|
|
int *l;
|
|
{
|
|
int i; /* l is current line */
|
|
unsigned below; /* below is avg # of ch/line under . */
|
|
|
|
*l = doton(&i, &below);
|
|
below = (i > 0) ? below/(unsigned)i : 0;
|
|
|
|
return(below > 3);
|
|
}
|
|
|
|
|
|
/*
|
|
* o_insert - optimize screen insert of char c
|
|
*/
|
|
o_insert(c)
|
|
int c;
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* o_delete - optimized character deletion
|
|
*/
|
|
o_delete()
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* pico_new_mail - just checks mtime and atime of mail file and notifies user
|
|
* if it's possible that they have new mail.
|
|
*/
|
|
pico_new_mail()
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* time_to_check - checks the current time against the last time called
|
|
* and returns true if the elapsed time is > below.
|
|
* Newmail won't necessarily check, but we want to give it
|
|
* a chance to check or do a keepalive.
|
|
*/
|
|
time_to_check()
|
|
{
|
|
static time_t lasttime = 0L;
|
|
|
|
if(!timeo)
|
|
return(FALSE);
|
|
|
|
if(time((time_t *) 0) - lasttime > (Pmaster ? (time_t)(FUDGE-10) : timeo)){
|
|
lasttime = time((time_t *) 0);
|
|
return(TRUE);
|
|
}
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* sstrcasecmp - compare two pointers to strings case independently
|
|
*/
|
|
sstrcasecmp(s1, s2)
|
|
QcompType *s1, *s2;
|
|
{
|
|
return((*pcollator)(*(char **)s1, *(char **)s2));
|
|
}
|
|
|
|
|
|
int
|
|
strucmp(o, r)
|
|
char *o, *r;
|
|
{
|
|
return(o ? (r ? stricmp(o, r) : 1) : (r ? -1 : 0));
|
|
}
|
|
|
|
|
|
int
|
|
struncmp(o, r, n)
|
|
char *o, *r;
|
|
int n;
|
|
{
|
|
return(o ? (r ? strnicmp(o, r, n) : 1) : (r ? -1 : 0));
|
|
}
|
|
|
|
|
|
/*
|
|
* chkptinit -- initialize anything we need to support composer
|
|
* checkpointing
|
|
*/
|
|
void
|
|
chkptinit(file, n)
|
|
char *file;
|
|
int n;
|
|
{
|
|
if(!file[0]){
|
|
long gmode_save = gmode;
|
|
|
|
if(gmode&MDCURDIR)
|
|
gmode &= ~MDCURDIR; /* so fixpath will use home dir */
|
|
|
|
strcpy(file, "#picoTM0.txt");
|
|
fixpath(file, NLINE);
|
|
gmode = gmode_save;
|
|
}
|
|
else{
|
|
int l = strlen(file);
|
|
|
|
if(file[l-1] != '\\'){
|
|
file[l++] = '\\';
|
|
file[l] = '\0';
|
|
}
|
|
|
|
strcpy(file + l, "#picoTM0.txt");
|
|
}
|
|
|
|
if(fexist(file, "r", (off_t *)NULL) == FIOSUC){ /* does file exist? */
|
|
char copy[NLINE];
|
|
|
|
strcpy(copy, "#picoTM1.txt");
|
|
fixpath(copy, NLINE);
|
|
rename(file, copy); /* save so we don't overwrite it */
|
|
}
|
|
|
|
unlink(file);
|
|
}
|
|
|
|
|
|
void
|
|
set_collation(collation, ctype)
|
|
int collation;
|
|
int ctype;
|
|
{
|
|
extern int collator(); /* strcoll isn't declared on all systems */
|
|
#ifdef LC_COLLATE
|
|
char *status = NULL;
|
|
#endif
|
|
|
|
pcollator = strucmp;
|
|
|
|
#ifdef LC_COLLATE
|
|
if(collation){
|
|
/*
|
|
* This may not have the desired effect, if collator is not
|
|
* defined to be strcoll in os.h and strcmp and friends
|
|
* don't know about locales. If your system does have strcoll
|
|
* but we haven't defined collator to be strcoll in os.h, let us know.
|
|
*/
|
|
status = setlocale(LC_COLLATE, "");
|
|
|
|
/*
|
|
* If there is an error or if the locale is the "C" locale, then we
|
|
* don't want to use strcoll because in the default "C" locale strcoll
|
|
* uses strcmp ordering and we want strucmp ordering.
|
|
*
|
|
* The test for "C" isn't really correct, since status does not have to
|
|
* be "C" even if we're in the "C" locale. But this works on some systems.
|
|
*/
|
|
if(status && !(status[0] == 'C' && status[1] == '\0'))
|
|
pcollator = collator;
|
|
}
|
|
#endif
|
|
#ifdef LC_CTYPE
|
|
if(ctype){
|
|
(void)setlocale(LC_CTYPE, "");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* sleep the given number of microseconds
|
|
*/
|
|
ssleep(s)
|
|
clock_t s;
|
|
{
|
|
s += clock();
|
|
while(s > clock())
|
|
;
|
|
}
|
|
|
|
|
|
/*
|
|
* sleep the given number of seconds
|
|
*/
|
|
sleep(t)
|
|
int t;
|
|
{
|
|
time_t out = (time_t)t + time((long *) 0);
|
|
while(out > time((long *) 0))
|
|
;
|
|
}
|
|
|
|
|
|
/*
|
|
* map the ftruncate call into DOS' chsize
|
|
*/
|
|
int
|
|
truncate(file, size)
|
|
char *file;
|
|
long size;
|
|
{
|
|
int fd, rv = -1;
|
|
|
|
if((fd = open(file, O_RDWR | O_CREAT | S_IREAD | S_IWRITE)) != -1){
|
|
if(chsize(fd, size) == 0)
|
|
rv = 0;
|
|
|
|
close(fd);
|
|
}
|
|
|
|
return(rv);
|
|
}
|