home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
ncftp-2.3.0-base.tgz
/
ncftp-2.3.0-base.tar
/
contrib
/
ncftp
/
Util.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-26
|
15KB
|
762 lines
/* Util.c */
#include "Sys.h"
#ifdef HAVE_GETCWD
# ifndef HAVE_UNISTD_H
extern char *getcwd();
# endif
#else
# ifdef HAVE_GETWD
# include <sys/param.h>
# ifndef MAXPATHLEN
# define MAXPATHLEN 1024
# endif
extern char *getwd(char *);
# endif
#endif
#include <errno.h>
#include <ctype.h>
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include "Util.h"
#include "Main.h"
#include "Bookmark.h"
#include "Curses.h"
time_t gMailBoxTime; /* last modified time of mbox */
int gWarnShellBug = 0;
int gMarkTrailingSpace = 0;
extern int gLoggedIn, gWinInit;
extern string gOurDirectoryPath;
extern longstring gRemoteCWD;
extern string gActualHostName;
extern long gEventNumber;
extern string gHost;
extern Bookmark gRmtInfo;
extern UserInfo gUserInfo;
/* Read a line, and axe the end-of-line. */
char *FGets(char *str, size_t size, FILE *fp)
{
char *cp, *nlptr;
cp = fgets(str, ((int) size) - 1, fp);
if (cp != NULL) {
nlptr = cp + strlen(cp) - 1;
if (*nlptr == '\n')
*nlptr = '\0';
}
return cp;
} /* FGets */
/* This should only be called if the program wouldn't function
* usefully without the memory requested.
*/
void OutOfMemory(void)
{
fprintf(stderr, "Out of memory!\n");
Exit(kExitOutOfMemory);
} /* OutOfMemory */
/* A way to strcat to a dynamically allocated area of memory. */
char *PtrCat(char *dst, char *src)
{
size_t len;
len = strlen(dst) + strlen(src) + 1;
if ((dst = Realloc(dst, len)) == NULL)
return (NULL);
strcat(dst, src);
return (dst);
} /* PtrCat */
/* Extends an area of memory, then cats a '/' and a string afterward. */
char *PtrCatSlash(char *dst, char *src)
{
size_t dlen;
char *nu;
while (*src == '/')
++src;
dlen = strlen(dst);
if (dst[dlen - 1] != '/') {
dst = PtrCat(dst, "/");
if (dst == NULL)
nu = NULL;
else
nu = PtrCat(dst, src);
} else {
nu = PtrCat(dst, src);
}
return (nu);
} /* PtrCatSlash */
void *Realloc(void *ptr, size_t siz)
{
if (ptr == NULL)
return (void *) malloc(siz);
return ((void *) realloc(ptr, siz));
} /* Realloc */
void MakeStringPrintable(char *dst, unsigned char *src, size_t siz)
{
int c;
size_t i;
int endnl, numsp;
i = 0;
--siz; /* Leave room for nul. */
while ((i < siz) && (*src != '\0')) {
c = *src++;
if (isprint(c) || (c == '\n') || (c == '\t')) {
*dst++ = c;
++i;
} else if (iscntrl(c) && (c != 0x7f)) {
/* Need room for 2 characters, ^x. */
if (i < siz - 1) {
c = c + '@';
*dst++ = '^';
*dst++ = c;
i += 2;
}
} else {
/* Need room for 5 characters, \xxx.
* The fifth character will be the \0 that is written by
* sprintf, but we know we have room for that already since
* we already accounted for that above.
*/
if (i < siz - 3) {
sprintf(dst, "\\%03o", c);
i += 4;
dst += 4;
}
}
}
*dst-- = '\0';
/* See if this line ended with a \n. */
endnl = 0;
if (i > 0 && *dst == '\n') {
endnl = 1;
--i;
--dst;
}
/* The user may want to be aware if there are trailing spaces
* at the end of a line.
*/
numsp = 0;
while (i > 0) {
c = *dst;
if (c != ' ')
break;
numsp++;
--i;
--dst;
}
/* Mark trailing spaces as \x where x is a space. */
++dst;
if (gMarkTrailingSpace) {
while ((numsp > 0) && (i < siz)) {
*dst++ = '\\';
*dst++ = ' ';
i += 2;
--numsp;
}
}
/* Tack the newline back onto the end of the string, if needed. */
if (endnl)
*dst++ = '\n';
*dst = '\0';
} /* MakeStringPrintable */
/* This will abbreviate a string so that it fits into max characters.
* It will use ellipses as appropriate. Make sure the string has
* at least max + 1 characters allocated for it.
*/
void AbbrevStr(char *dst, char *src, size_t max, int mode)
{
int len;
len = (int) strlen(src);
if (len > max) {
if (mode == 0) {
/* ...Put ellipses at left */
strcpy(dst, "...");
Strncat(dst, src + len - max + 3, max + 1);
} else {
/* Put ellipses at right... */
Strncpy(dst, src, max + 1);
strcpy(dst + max - 3, "...");
}
} else {
Strncpy(dst, src, max + 1);
}
} /* AbbrevStr */
/* Converts any uppercase characters in the string to lowercase.
* Never would have guessed that, huh?
*/
void StrLCase(char *dst)
{
register char *cp;
for (cp=dst; *cp != '\0'; cp++)
if (isupper((int) *cp))
*cp = (char) tolower(*cp);
} /* StrLCase */
/* Use getcwd/getwd to get the full path of the current local
* working directory.
*/
char *GetCWD(char *buf, size_t size)
{
#ifdef HAVE_GETCWD
static char *cwdBuf = NULL;
static size_t cwdBufSize = 0;
if (cwdBufSize == 0) {
cwdBufSize = (size_t) 128;
cwdBuf = (char *) malloc(cwdBufSize);
}
for (errno = 0; ; ) {
if (cwdBuf == NULL) {
Error(kDoPerror, "Not enough free memory to get the local working directory path.\n");
(void) Strncpy(buf, ".", size);
return NULL;
}
if (getcwd(cwdBuf, cwdBufSize) != NULL)
break;
if (errno != ERANGE) {
Error(kDoPerror, "Can't get the local working directory path.\n");
(void) Strncpy(buf, ".", size);
return NULL;
}
cwdBufSize *= 2;
cwdBuf = Realloc(cwdBuf, cwdBufSize);
}
return (Strncpy(buf, cwdBuf, size));
#else
#ifdef HAVE_GETWD
static char *cwdBuf = NULL;
char *dp;
/* Due to the way getwd is usually implemented, it's
* important to have a buffer large enough to hold the
* whole thing. getwd usually starts at the end of the
* buffer, and works backwards, returning you a pointer
* to the beginning of it when it finishes.
*/
if (size < MAXPATHLEN) {
/* Buffer not big enough, so use a temporary one,
* and then copy the first 'size' bytes of the
* temporary buffer to your 'buf.'
*/
if (cwdBuf == NULL) {
cwdBuf = (char *) malloc((size_t) MAXPATHLEN);
if (cwdBuf == NULL)
OutOfMemory();
}
dp = cwdBuf;
} else {
/* Buffer is big enough already. */
dp = buf;
}
*dp = '\0';
if (getwd(dp) == NULL) {
/* getwd() should write the reason why in the buffer then,
* according to the man pages.
*/
Error(kDontPerror, "Can't get the local working directory path. %s\n", dp);
(void) Strncpy(buf, ".", size);
return (NULL);
}
return (Strncpy(buf, dp, size));
#else
/* Not really a solution, but does anybody not have either of
* getcwd or getwd?
*/
Error(kDontPerror, "Can't get the cwd path; no getwd() or getcwd().\n");
return (Strncpy(buf, ".", size));
#endif
#endif
} /* GetCWD */
char *Path(char *dst, size_t siz, char *parent, char *fname)
{
(void) Strncpy(dst, parent, siz);
(void) Strncat(dst, "/", siz);
return (Strncat(dst, fname, siz));
} /* Path */
char *OurDirectoryPath(char *dst, size_t siz, char *fname)
{
return (Path(dst, siz, gOurDirectoryPath, fname));
} /* OurDirectoryPath */
int MkDirs(char *path)
{
longstring mdCmd;
int result;
result = 0;
if (access(path, F_OK) < 0) {
STRNCPY(mdCmd, "mkdir -p "); /* -p is nice, but not mandatory. */
STRNCAT(mdCmd, path);
result = system(mdCmd);
}
return (result);
} /* MkDirs */
/* Closes the file supplied, if it isn't a std stream. */
void CloseFile(FILE **f)
{
if (*f != NULL) {
if ((*f != stdout) && (*f != stdin) && (*f != stderr))
(void) fclose(*f);
*f = NULL;
}
} /* CloseFile */
/* Returns non-zero if we are the foreground process, or 0
* if we are a background process at the time of the call.
*/
int InForeGround(void)
{
#if defined(NO_FGTEST) || !defined(HAVE_TCGETPGRP)
return (1);
#else
# ifndef GETPGRP_VOID
# define GETMYPGRP (getpgrp(getpid()))
# else
# define GETMYPGRP (getpgrp())
# endif
int result, status;
static int file = -2;
static int mode = -2;
result = 1;
if (file == -2)
file = open("/dev/tty", O_RDONLY);
if (file >= 0) {
status = tcgetpgrp(file);
if (status >= 0) {
result = (status == GETMYPGRP);
if (mode != result) {
if (mode == 0) {
TraceMsg("In background.\n");
} else
TraceMsg("In foreground.\n");
}
mode = result;
} else if (mode == -2) {
TraceMsg("Foreground check failed.\n");
mode = 0;
}
}
return (result);
#endif
} /* InForeGround */
/* Returns non-zero if it appears the user is still live at the
* terminal.
*/
int UserLoggedIn(void)
{
static int inited = 0;
static int parent_pid, stderr_was_tty;
if (!inited) {
stderr_was_tty = isatty(2);
parent_pid = getppid();
inited++;
}
if ((stderr_was_tty && !isatty(2)) || (getppid() != parent_pid))
return 0;
return 1;
} /* UserLoggedIn */
int CheckNewMail(void)
{
struct stat stbuf;
if (*gUserInfo.mail == '\0')
return 0;
if (stat(gUserInfo.mail, &stbuf) < 0) {
/* Can't find mail_path so we'll never check it again */
*gUserInfo.mail = '\0';
return 0;
}
/*
* Check if the size is non-zero and the access time is less than
* the modify time -- this indicates unread mail.
*/
if ((stbuf.st_size != 0) && (stbuf.st_atime <= stbuf.st_mtime)) {
if (stbuf.st_mtime > gMailBoxTime) {
(void) PrintF("You have new mail.\n");
gMailBoxTime = stbuf.st_mtime;
}
return 1;
}
return 0;
} /* CheckNewMail */
size_t FlagStrCopy(char *dst, size_t siz, char *src)
{
time_t now;
register char *p, *q;
int flagType;
int chType;
int nextCh;
int nPercents;
int extraChar;
size_t maxSize;
size_t onScreenLen;
size_t len;
string tmpStr;
char *copy;
nPercents = 0;
onScreenLen = 0;
extraChar = 0;
siz -= 2; /* Need room for nul, and extra char. */
maxSize = siz;
for (p = src, q = dst, *q = 0; *p != '\0'; p++) {
chType = *p;
switch (chType) {
case '%':
nPercents++;
goto copyChar;
case '@':
flagType = *++p;
nextCh = p[1];
switch (flagType) {
case '\0':
goto done;
break;
case 'Z':
/* Tell caller not to echo a final newline. */
extraChar = '@';
break;
case 'M':
if (CheckNewMail() > 0) {
copy = "(Mail)";
goto copyVisStr;
}
goto copyNothing;
case 'n':
if (gLoggedIn) {
copy = gRmtInfo.bookmarkName;
goto copyVisStr;
}
goto copyNothing;
case 'N':
copy = "\n";
goto copyVisStr;
break;
/* Probably won't implement these. */
case 'P': /* reset to no bold, no uline, no inverse, etc. */
/* copy = "plain...";
goto copyInvisStr; */
break;
case 'B': /* toggle boldface */
break;
case 'U': /* toggle underline */
break;
case 'R':
case 'I': /* toggle inverse (reverse) video */
break;
case 'D': /* insert current directory */
case 'J':
if (gLoggedIn) {
if ((flagType == 'J') && (gRmtInfo.isUnix)) {
/* Not the whole path, just the dir name. */
copy = strrchr(gRemoteCWD, '/');
if (copy == NULL)
copy = gRemoteCWD;
else if ((copy != gRemoteCWD) && (copy[1]))
++copy;
} else {
copy = gRemoteCWD;
}
goto copyVisStr;
}
goto copyNothing;
case 'H': /* insert name of connected host */
if (gLoggedIn) {
copy = gHost;
goto copyVisStr;
}
goto copyNothing;
case 'h': /* insert actual name of connected host */
if (gLoggedIn) {
copy = gActualHostName;
goto copyVisStr;
}
goto copyNothing;
case '!':
case 'E': /* insert event number */
(void) sprintf(tmpStr, "%ld", gEventNumber);
copy = tmpStr;
/*FALLTHROUGH*/
copyVisStr:
len = strlen(copy);
if (siz > len) {
q = strcpy(q, copy) + len;
siz -= len;
if (q[-1] == '\n') {
onScreenLen = 0;
} else
onScreenLen += len;
}
break;
copyNothing:
if (isspace(nextCh) || (nextCh == ':'))
++p; /* Don't insert next character. */
break;
default:
goto copyChar; /* just copy it; unknown switch */
} /* end flagType */
break;
default:
copyChar:
if (siz > 0) {
*q++ = *p;
--siz;
++onScreenLen;
}
break;
}
}
done:
*q = '\0';
#ifdef HAVE_STRFTIME
if ((nPercents > 0) && ((copy = StrDup(dst)) != NULL)) {
/* Only strftime if the user requested it (with a %something). */
(void) time(&now);
len = strlen(dst);
onScreenLen += strftime(dst, maxSize, copy, localtime(&now));
onScreenLen -= len;
free(copy);
}
#endif
if (extraChar != 0)
dst[strlen(dst) + 1] = extraChar;
return (onScreenLen);
} /* FlagStrCopy */
void OverflowAdd(long *dst, long plus)
{
#ifdef LONG_MAX
long x;
x = LONG_MAX - *dst;
if (x < plus)
*dst = LONG_MAX; /* Would overflow! */
else
*dst += plus;
#else
*dst += plus;
#endif
} /* OverflowAdd */
FILE *POpen(char *cmd, char *mode, int saveScreen)
{
FILE *fp;
#if 1
if ((++gWarnShellBug <= 2) && (gWinInit == 1) && (*mode == 'w') && (CURSES_SHELL_BUG == 1)) {
EPrintF("Sorry, that operation would crash the program with this OS.\n");
errno = 0;
return (NULL);
}
#else
if (++gWarnShellBug == 1) {
EPrintF("Warning: the screen may not update correctly on this OS.\n\n");
sleep(2);
}
#endif
if (saveScreen == 1)
SaveScreen();
fp = popen(cmd, mode);
return fp;
} /* POpen */
#ifndef HAVE_MEMMOVE
/* This code is derived from software contributed to Berkeley by
* Chris Torek.
*/
/*
* sizeof(word) MUST BE A POWER OF TWO
* SO THAT wmask BELOW IS ALL ONES
*/
typedef int word; /* "word" used for optimal copy speed */
#define wsize sizeof(word)
#define wmask (wsize - 1)
/*
* Copy a block of memory, handling overlap.
* This is the routine that actually implements
* (the portable versions of) bcopy, memcpy, and memmove.
*/
void *
MemMove(void *dst0, void *src0, size_t length)
{
register char *dst = (char *) dst0;
register const char *src = (char *) src0;
register size_t t;
if (length == 0 || dst == src) /* nothing to do */
return dst;
/*
* Macros: loop-t-times; and loop-t-times, t>0
*/
#define TLOOP(s) if (t) TLOOP1(s)
#define TLOOP1(s) do { s; } while (--t)
if ((unsigned long)dst < (unsigned long)src) {
/*
* Copy forward.
*/
t = (int)src; /* only need low bits */
if ((t | (int)dst) & wmask) {
/*
* Try to align operands. This cannot be done
* unless the low bits match.
*/
if ((t ^ (int)dst) & wmask || length < wsize)
t = length;
else
t = wsize - (t & wmask);
length -= t;
TLOOP1(*dst++ = *src++);
}
/*
* Copy whole words, then mop up any trailing bytes.
*/
t = length / wsize;
TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
t = length & wmask;
TLOOP(*dst++ = *src++);
} else {
/*
* Copy backwards. Otherwise essentially the same.
* Alignment works as before, except that it takes
* (t&wmask) bytes to align, not wsize-(t&wmask).
*/
src += length;
dst += length;
t = (int)src;
if ((t | (int)dst) & wmask) {
if ((t ^ (int)dst) & wmask || length <= wsize)
t = length;
else
t &= wmask;
length -= t;
TLOOP1(*--dst = *--src);
}
t = length / wsize;
TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
t = length & wmask;
TLOOP(*--dst = *--src);
}
return(dst0);
} /* MemMove */
#endif /* ! HAVE_MEMMOVE */
/* eof */