923 lines
19 KiB
C
923 lines
19 KiB
C
/* Util.c */
|
|
|
|
/* $RCSfile: util.c,v $
|
|
* $Revision: 14020.13 $
|
|
* $Date: 93/05/23 09:38:13 $
|
|
*/
|
|
|
|
#include "sys.h"
|
|
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <pwd.h>
|
|
|
|
#ifndef NO_VARARGS
|
|
# ifdef NO_STDARGH
|
|
# include <varargs.h>
|
|
# else
|
|
# include <stdarg.h>
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef READLINE
|
|
# include <readline/readline.h>
|
|
#endif /* READLINE */
|
|
|
|
#ifdef GETLINE
|
|
# include <getline.h>
|
|
#endif
|
|
|
|
#include "util.h"
|
|
#include "cmds.h"
|
|
#include "main.h"
|
|
#include "ftp.h"
|
|
#include "ftprc.h"
|
|
#include "defaults.h"
|
|
#include "copyright.h"
|
|
|
|
/* Util.c globals */
|
|
int Opterr = 1; /* if error message should be printed */
|
|
int Optind = 1; /* index into parent argv vector */
|
|
int Optopt; /* character checked for validity */
|
|
char *Optarg; /* argument associated with option */
|
|
char *Optplace = EMSG; /* saved position in an arg */
|
|
|
|
/* Util.c externs */
|
|
extern int toatty, fromatty;
|
|
extern int verbose, doingInitMacro;
|
|
extern string prompt2;
|
|
extern char *line, *margv[];
|
|
extern int margc;
|
|
extern int debug, mprompt, activemcmd;
|
|
extern string progname;
|
|
extern struct cmd cmdtab[];
|
|
extern struct userinfo uinfo;
|
|
|
|
#ifndef NO_VARARGS
|
|
/*VARARGS*/
|
|
#ifdef NO_STDARGH
|
|
void dbprintf(va_alist)
|
|
va_dcl
|
|
#else
|
|
void dbprintf(char *fmt0, ...)
|
|
#endif
|
|
{
|
|
va_list ap;
|
|
char *fmt;
|
|
|
|
#ifdef NO_STDARGH
|
|
va_start(ap);
|
|
fmt = va_arg(ap, char *);
|
|
#else
|
|
va_start(ap, fmt0);
|
|
fmt = fmt0;
|
|
#endif
|
|
|
|
if (debug) {
|
|
(void) fprintf(DB_STREAM, "#DB# ");
|
|
(void) vfprintf(DB_STREAM, fmt, ap);
|
|
(void) fflush(DB_STREAM);
|
|
}
|
|
va_end(ap);
|
|
} /* dbprintf */
|
|
|
|
#endif /* have varargs */
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Concatenate src on the end of dst. The resulting string will have at most
|
|
* n-1 characters, not counting the NUL terminator which is always appended
|
|
* unlike strncat. The other big difference is that strncpy uses n as the
|
|
* max number of characters _appended_, while this routine uses n to limit
|
|
* the overall length of dst.
|
|
*/
|
|
char *_Strncat(char *dst, char *src, register size_t n)
|
|
{
|
|
register size_t i;
|
|
register char *d, *s;
|
|
|
|
if (n != 0 && ((i = strlen(dst)) < (n - 1))) {
|
|
d = dst + i;
|
|
s = src;
|
|
/* If they specified a maximum of n characters, use n - 1 chars to
|
|
* hold the copy, and the last character in the array as a NUL.
|
|
* This is the difference between the regular strncpy routine.
|
|
* strncpy doesn't guarantee that your new string will have a
|
|
* NUL terminator, but this routine does.
|
|
*/
|
|
for (++i; i<n; i++) {
|
|
if ((*d++ = *s++) == 0) {
|
|
/* Pad with zeros. */
|
|
for (; i<n; i++)
|
|
*d++ = 0;
|
|
return dst;
|
|
}
|
|
}
|
|
/* If we get here, then we have a full string, with n - 1 characters,
|
|
* so now we NUL terminate it and go home.
|
|
*/
|
|
*d = 0;
|
|
}
|
|
return (dst);
|
|
} /* _Strncat */
|
|
|
|
|
|
/*
|
|
* Copy src to dst, truncating or null-padding to always copy n-1 bytes.
|
|
* Return dst.
|
|
*/
|
|
char *_Strncpy(char *dst, char *src, register size_t n)
|
|
{
|
|
register char *d;
|
|
register char *s;
|
|
register size_t i;
|
|
|
|
d = dst;
|
|
*d = 0;
|
|
if (n != 0) {
|
|
s = src;
|
|
/* If they specified a maximum of n characters, use n - 1 chars to
|
|
* hold the copy, and the last character in the array as a NUL.
|
|
* This is the difference between the regular strncpy routine.
|
|
* strncpy doesn't guarantee that your new string will have a
|
|
* NUL terminator, but this routine does.
|
|
*/
|
|
for (i=1; i<n; i++) {
|
|
if ((*d++ = *s++) == 0) {
|
|
/* Pad with zeros. */
|
|
for (; i<n; i++)
|
|
*d++ = 0;
|
|
return dst;
|
|
}
|
|
}
|
|
/* If we get here, then we have a full string, with n - 1 characters,
|
|
* so now we NUL terminate it and go home.
|
|
*/
|
|
*d = 0;
|
|
}
|
|
return (dst);
|
|
} /* _Strncpy */
|
|
|
|
|
|
|
|
/* 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);
|
|
}
|
|
|
|
|
|
|
|
|
|
char *Strpcpy(char *dst, char *src)
|
|
{
|
|
while ((*dst++ = *src++) != '\0')
|
|
;
|
|
return (--dst); /* return current value of dst, NOT original value! */
|
|
} /* Strpcpy */
|
|
|
|
|
|
|
|
/*
|
|
* malloc's a copy of oldstr.
|
|
*/
|
|
char *NewString(char *oldstr)
|
|
{
|
|
size_t howLong;
|
|
char *newstr;
|
|
|
|
howLong = strlen(oldstr);
|
|
if ((newstr = malloc(howLong + 1)) != NULL)
|
|
(void) strcpy(newstr, oldstr);
|
|
return newstr;
|
|
} /* NewString */
|
|
|
|
|
|
|
|
|
|
|
|
void Getopt_Reset(void)
|
|
{
|
|
Optind = 1;
|
|
Optplace = "";
|
|
} /* Getopt_Reset */
|
|
|
|
static char *NextOption(char *ostr)
|
|
{
|
|
if ((Optopt = (int) *Optplace++) == (int) ':')
|
|
return 0;
|
|
return index(ostr, Optopt);
|
|
}
|
|
|
|
int Getopt(int nargc, char **nargv, char *ostr)
|
|
{
|
|
register char *oli; /* Option letter list index */
|
|
|
|
if (!*Optplace) { /* update scanning pointer */
|
|
if (Optind >= nargc || *(Optplace = nargv[Optind]) != '-')
|
|
return (EOF);
|
|
if (Optplace[1] && *++Optplace == '-') { /* found "--" */
|
|
++Optind;
|
|
return (EOF);
|
|
}
|
|
} /* Option letter okay? */
|
|
oli = NextOption(ostr);
|
|
if (oli == NULL) {
|
|
if (!*Optplace)
|
|
++Optind;
|
|
if (Opterr) {
|
|
(void) fprintf(stderr, "%s%s%c\n", *nargv, ": illegal option -- ", Optopt);
|
|
return(BADCH);
|
|
}
|
|
}
|
|
if (*++oli != ':') { /* don't need argument */
|
|
Optarg = NULL;
|
|
if (!*Optplace)
|
|
++Optind;
|
|
} else { /* need an argument */
|
|
if (*Optplace) /* no white space */
|
|
Optarg = Optplace;
|
|
else if (nargc <= ++Optind) { /* no arg */
|
|
Optplace = EMSG;
|
|
if (Opterr) {
|
|
(void) fprintf(stderr, "%s%s%c\n", *nargv, ": option requires an argument -- ", Optopt);
|
|
return(BADCH);
|
|
}
|
|
} else /* white space */
|
|
Optarg = nargv[Optind];
|
|
Optplace = EMSG;
|
|
++Optind;
|
|
}
|
|
return (Optopt); /* dump back Option letter */
|
|
} /* Getopt */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Converts an ls date, in either the "Feb 4 1992" or "Jan 16 13:42"
|
|
* format to a time_t.
|
|
*/
|
|
unsigned long UnLSDate(char *dstr)
|
|
{
|
|
#ifdef NO_MKTIME
|
|
return (MDTM_UNKNOWN);
|
|
#else
|
|
char *cp = dstr;
|
|
int mon, day, year, hr, min;
|
|
time_t now, mt;
|
|
unsigned long result = MDTM_UNKNOWN;
|
|
struct tm ut, *t;
|
|
|
|
switch (*cp++) {
|
|
case 'A':
|
|
mon = (*cp == 'u') ? 7 : 3;
|
|
break;
|
|
case 'D':
|
|
mon = 11;
|
|
break;
|
|
case 'F':
|
|
mon = 1;
|
|
break;
|
|
default: /* shut up un-init warning */
|
|
case 'J':
|
|
if (*cp++ == 'u')
|
|
mon = (*cp == 'l') ? 6 : 5;
|
|
else
|
|
mon = 0;
|
|
break;
|
|
case 'M':
|
|
mon = (*++cp == 'r') ? 2 : 4;
|
|
break;
|
|
case 'N':
|
|
mon = 10;
|
|
break;
|
|
case 'O':
|
|
mon = 9;
|
|
break;
|
|
case 'S':
|
|
mon = 8;
|
|
}
|
|
cp = dstr + 4;
|
|
day = 0;
|
|
if (*cp != ' ')
|
|
day = 10 * (*cp - '0');
|
|
cp++;
|
|
day += *cp++ - '0';
|
|
min = 0;
|
|
|
|
(void) time(&now);
|
|
t = localtime(&now);
|
|
|
|
if (*++cp != ' ') {
|
|
/* It's a time, XX:YY, not a year. */
|
|
cp[2] = ' ';
|
|
(void) sscanf(cp, "%d %d", &hr, &min);
|
|
cp[2] = ':';
|
|
year = t->tm_year;
|
|
if (mon > t->tm_mon)
|
|
--year;
|
|
} else {
|
|
hr = min = 0;
|
|
(void) sscanf(cp, "%d", &year);
|
|
year -= 1900;
|
|
}
|
|
/* Copy the whole structure of the 'tm' pointed to by t, so it will
|
|
* also set all fields we don't specify explicitly to be the same as
|
|
* they were in t. That way we copy non-standard fields such as
|
|
* tm_gmtoff, if it exists or not.
|
|
*/
|
|
ut = *t;
|
|
ut.tm_sec = 1;
|
|
ut.tm_min = min;
|
|
ut.tm_hour = hr;
|
|
ut.tm_mday = day;
|
|
ut.tm_mon = mon;
|
|
ut.tm_year = year;
|
|
ut.tm_wday = ut.tm_yday = 0;
|
|
mt = mktime(&ut);
|
|
if (mt != (time_t) -1)
|
|
result = (unsigned long) mt;
|
|
return (result);
|
|
#endif /* NO_MKTIME */
|
|
} /* UnLSDate */
|
|
|
|
|
|
|
|
/*
|
|
* Converts a MDTM date, like "213 19930602204445\n"
|
|
* format to a time_t.
|
|
*/
|
|
unsigned long UnMDTMDate(char *dstr)
|
|
{
|
|
#ifdef NO_MKTIME
|
|
return (MDTM_UNKNOWN);
|
|
#else
|
|
struct tm ut;
|
|
time_t mt;
|
|
unsigned long result = MDTM_UNKNOWN;
|
|
|
|
/* Clear out the whole structure, along with any non-standard fields. */
|
|
bzero((char *)&ut, sizeof (struct tm));
|
|
|
|
if (sscanf(dstr, "%*s %04d%02d%02d%02d%02d%02d",
|
|
&ut.tm_year,
|
|
&ut.tm_mon,
|
|
&ut.tm_mday,
|
|
&ut.tm_hour,
|
|
&ut.tm_min,
|
|
&ut.tm_sec) == 6)
|
|
{
|
|
--ut.tm_mon;
|
|
ut.tm_year -= 1900;
|
|
mt = mktime(&ut);
|
|
if (mt != (time_t) -1)
|
|
result = (unsigned long) mt;
|
|
}
|
|
return result;
|
|
#endif /* NO_MKTIME */
|
|
} /* UnMDTMDate */
|
|
|
|
|
|
|
|
void Perror(
|
|
#ifdef DB_ERRS
|
|
char *fromProc
|
|
,
|
|
#ifdef __LINE__
|
|
int lineNum,
|
|
#endif
|
|
#endif
|
|
char *msg
|
|
)
|
|
{
|
|
extern int errno;
|
|
|
|
if (NOT_VQUIET) {
|
|
#ifdef sun
|
|
/*
|
|
* There is a problem in the SunOS headers when compiling with an ANSI
|
|
* compiler. The problem is that there are macros in the form of
|
|
* #define MAC(x) 'x', and this will always be the character x instead
|
|
* of whatever parameter was passed to MAC. If we get these errors, it
|
|
* usually means that you are trying to compile with gcc when you haven't
|
|
* run the 'fixincludes' script that fixes these macros. We will ignore
|
|
* the error, but it means that the echo() function won't work correctly,
|
|
* and you will see your password echo.
|
|
*/
|
|
if (errno == ENOTTY)
|
|
return;
|
|
#endif
|
|
(void) fprintf(stderr, "NcFTP");
|
|
#ifdef DB_ERRS
|
|
if (fromProc != NULL)
|
|
(void) fprintf(stderr, "/%s", fromProc);
|
|
#ifdef __LINE__
|
|
(void) fprintf(stderr, "/%d", lineNum);
|
|
#endif
|
|
#endif
|
|
(void) fprintf(stderr, ": ");
|
|
if (msg != NULL)
|
|
(void) fprintf(stderr, "%s (%d): ", msg, errno);
|
|
perror(NULL);
|
|
}
|
|
} /* Perror */
|
|
|
|
|
|
|
|
|
|
size_t RemoveTrailingNewline(char *cp, int *stripped)
|
|
{
|
|
size_t len;
|
|
int nBytesStripped = 0;
|
|
|
|
if (cp != NULL) {
|
|
cp += (len = strlen(cp)) - 1;
|
|
if (*cp == '\n') {
|
|
*cp-- = 0; /* get rid of the newline. */
|
|
nBytesStripped++;
|
|
}
|
|
if (*cp == '\r') { /* no returns either, please. */
|
|
*cp = 0;
|
|
nBytesStripped++;
|
|
}
|
|
if (stripped != NULL)
|
|
*stripped = nBytesStripped;
|
|
return len;
|
|
}
|
|
return (size_t)0;
|
|
} /* RemoveTrailingNewline */
|
|
|
|
|
|
|
|
#ifdef GETLINE
|
|
extern size_t epromptlen;
|
|
|
|
/*
|
|
* The Getline library doesn't detect the ANSI escape sequences, so the
|
|
* library would think that a string is longer than actually appears on
|
|
* screen. This function lets Getline work properly. This function is
|
|
* intended to fix that problem for the main command prompt only. If any
|
|
* other prompts want to use ANSI escapes, a (costly) function would have
|
|
* to scan the prompt for all escape sequences.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static size_t MainPromptLen(char *pr)
|
|
{
|
|
return (int)epromptlen;
|
|
}
|
|
#endif
|
|
|
|
static char *StdioGets(char *promptstr, char *sline, size_t size)
|
|
{
|
|
char *cp;
|
|
|
|
if (fromatty) {
|
|
/* It's okay to print a prompt if we are redirecting stdout,
|
|
* as long as stdin is still a tty. Otherwise, don't print
|
|
* a prompt at all if stdin is redirected.
|
|
*/
|
|
#ifdef CURSES
|
|
tcap_put(promptstr);
|
|
#else
|
|
(void) fputs(promptstr, stdout);
|
|
#endif
|
|
}
|
|
sline[0] = 0;
|
|
(void) fflush(stdout); /* for svr4 */
|
|
cp = fgets(sline, (int)(size - 2), stdin);
|
|
(void) RemoveTrailingNewline(sline, NULL);
|
|
return cp;
|
|
} /* StdioGets */
|
|
|
|
|
|
/* Given a prompt string, a destination string, and it's size, return feedback
|
|
* from the user in the destination string, with any trailing newlines
|
|
* stripped. Returns NULL if EOF encountered.
|
|
*/
|
|
char *Gets(char *promptstr, char *sline, size_t size)
|
|
{
|
|
char *cp, ch;
|
|
string plines;
|
|
#ifdef GETLINE
|
|
int ismainprompt = (promptstr == prompt2);
|
|
#endif
|
|
|
|
if (!fromatty || !toatty) {
|
|
/* Don't worry about a cmdline/history editor if you redirected a
|
|
* file at me.
|
|
*/
|
|
return (StdioGets(promptstr, sline, size));
|
|
}
|
|
|
|
sline[0] = 0; /* Clear it, in case of an error later. */
|
|
|
|
/*
|
|
* The prompt string may actually be several lines if the user put a
|
|
* newline in it with the @N option. In this case we only want to print
|
|
* the very last line, so the command-line editors won't screw up. So
|
|
* now we print all the lines except the last line.
|
|
*/
|
|
cp = rindex(promptstr, '\n');
|
|
if (cp != NULL) {
|
|
ch = *++cp;
|
|
*cp = 0;
|
|
(void) Strncpy(plines, promptstr);
|
|
*cp = ch;
|
|
promptstr = cp;
|
|
#ifdef CURSES
|
|
tcap_put(plines);
|
|
#else
|
|
(void) fputs(plines, stdout);
|
|
#endif
|
|
}
|
|
|
|
#ifdef READLINE
|
|
if ((cp = readline(promptstr)) != NULL) {
|
|
(void) _Strncpy(sline, cp, size);
|
|
free(cp);
|
|
(void) RemoveTrailingNewline(cp = sline, NULL);
|
|
if (*cp != 0) /* Don't add blank lines to history buffer. */
|
|
add_history(cp);
|
|
}
|
|
#else /* READLINE */
|
|
|
|
#ifdef GETLINE
|
|
if (toatty) {
|
|
if (ismainprompt)
|
|
gl_strwidth(MainPromptLen);
|
|
if ((cp = getline(promptstr)) != NULL) {
|
|
if (*cp == '\0') /* You hit ^D. */
|
|
return NULL;
|
|
cp = _Strncpy(sline, cp, size);
|
|
(void) RemoveTrailingNewline(cp, NULL);
|
|
if (*cp != '\0') { /* Don't add blank lines to history buffer. */
|
|
gl_histadd(cp);
|
|
}
|
|
}
|
|
/* Hope your strlen is declared as returning a size_t. */
|
|
gl_strwidth(strlen);
|
|
} else {
|
|
cp = StdioGets(promptstr, sline, size);
|
|
}
|
|
#else /* !GETLINE */
|
|
cp = StdioGets(promptstr, sline, size);
|
|
#endif /* !GETLINE */
|
|
#endif /* !READLINE */
|
|
return cp;
|
|
} /* Gets */
|
|
|
|
|
|
|
|
|
|
char **re_makeargv(char *promptstr, int *argc)
|
|
{
|
|
size_t sz;
|
|
|
|
(void) strcat(line, " ");
|
|
sz = strlen(line);
|
|
(void) Gets(promptstr, &line[sz], (size_t) (CMDLINELEN - sz)) ;
|
|
(void) makeargv();
|
|
*argc = margc;
|
|
return (margv);
|
|
} /* re_makeargv */
|
|
|
|
|
|
|
|
#ifndef HAS_GETCWD
|
|
extern char *getwd(char *);
|
|
#endif
|
|
|
|
char *get_cwd(char *buf, int size)
|
|
{
|
|
#ifdef HAS_GETCWD
|
|
# ifdef NO_UNISTDH
|
|
# ifdef GETCWDSIZET
|
|
extern char *getcwd(char *, size_t);
|
|
# else
|
|
extern char *getcwd(char *, int);
|
|
# endif
|
|
# endif
|
|
return (getcwd(buf, size - 1));
|
|
#else
|
|
#ifndef MAXPATHLEN
|
|
# define MAXPATHLEN (1024)
|
|
#endif
|
|
static char *cwdbuf = NULL;
|
|
|
|
if (cwdbuf == NULL) {
|
|
cwdbuf = (char *)malloc((size_t) MAXPATHLEN);
|
|
if (cwdbuf == NULL)
|
|
fatal("out of memory for getwd buffer.");
|
|
}
|
|
getwd(cwdbuf);
|
|
return (_Strncpy(buf, cwdbuf, (size_t)size));
|
|
#endif
|
|
} /* get_cwd */
|
|
|
|
|
|
|
|
int tmp_name(char *str)
|
|
{
|
|
(void) strcpy(str, "/tmp/ncftpXXXXXX");
|
|
return (!mktemp(str));
|
|
} /* tmp_name */
|
|
|
|
|
|
|
|
|
|
char *onoff(int boolf)
|
|
{
|
|
return (boolf ? "on" : "off");
|
|
} /* onoff */
|
|
|
|
|
|
|
|
|
|
int StrToBool(char *s)
|
|
{
|
|
int c;
|
|
int result;
|
|
|
|
c = tolower(*s);
|
|
result = 0;
|
|
switch (c) {
|
|
case 'f': /* false */
|
|
case 'n': /* no */
|
|
break;
|
|
case 'o': /* test for "off" and "on" */
|
|
c = tolower(s[1]);
|
|
if (c == 'f')
|
|
break;
|
|
/* fall through */
|
|
case 't': /* true */
|
|
case 'y': /* yes */
|
|
result = 1;
|
|
break;
|
|
default: /* 1, 0, -1, other number? */
|
|
if (atoi(s) != 0)
|
|
result = 1;
|
|
}
|
|
return result;
|
|
} /* StrToBool */
|
|
|
|
|
|
|
|
|
|
int confirm(char *cmd, char *file)
|
|
{
|
|
string str, pr;
|
|
|
|
if (!fromatty || (activemcmd && !mprompt) || (doingInitMacro))
|
|
return 1;
|
|
(void) sprintf(pr, "%s %s? ", cmd, file);
|
|
(void) Gets(pr, str, sizeof(str));
|
|
return (*str != 'n' && *str != 'N');
|
|
} /* confirm */
|
|
|
|
|
|
|
|
void fatal(char *msg)
|
|
{
|
|
(void) fprintf(stderr, "%s: %s\n", progname, msg);
|
|
close_up_shop();
|
|
exit(1);
|
|
} /* fatal */
|
|
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
|
|
struct cmd *getcmd(char *name)
|
|
{
|
|
struct cmd *c, *found;
|
|
int nmatches;
|
|
size_t len;
|
|
char *p;
|
|
|
|
found = (struct cmd *)0;
|
|
if (name != NULL) {
|
|
len = strlen(name);
|
|
nmatches = 0;
|
|
for (c = cmdtab; (p = c->c_name) != NULL; c++) {
|
|
if (strcmp(name, p) == 0) {
|
|
/* Exact match. */
|
|
found = c;
|
|
goto xx;
|
|
}
|
|
if (c->c_handler == unimpl)
|
|
continue;
|
|
if (strncmp(name, p, len) == 0) {
|
|
if (++nmatches > 1) {
|
|
found = ((struct cmd *) -1);
|
|
goto xx;
|
|
}
|
|
found = c;
|
|
} else if (found != NULL)
|
|
break;
|
|
}
|
|
}
|
|
xx:
|
|
return (found);
|
|
} /* getcmd */
|
|
|
|
|
|
|
|
|
|
void cmd_help(struct cmd *c)
|
|
{
|
|
(void) printf("%s: %s.\n",
|
|
c->c_name,
|
|
c->c_help
|
|
);
|
|
} /* cmd_help */
|
|
|
|
|
|
|
|
|
|
void cmd_usage(struct cmd *c)
|
|
{
|
|
if (c->c_usage != NULL)
|
|
(void) printf("Usage: %s%s\n",
|
|
c->c_name,
|
|
c->c_usage
|
|
);
|
|
} /* cmd_usage */
|
|
|
|
|
|
|
|
|
|
/*
|
|
* A simple function that translates most pathnames with ~, ~user, or
|
|
* environment variables as the first item. It won't do paths with env vars
|
|
* or ~s in the middle of the path, but those are extremely rare.
|
|
*/
|
|
char *LocalPath(char *path)
|
|
{
|
|
longstring orig;
|
|
struct passwd *pw;
|
|
char *firstent;
|
|
char *cp, *dp, *rest;
|
|
|
|
(void) Strncpy(orig, path);
|
|
firstent = orig;
|
|
if ((cp = index(orig, '/')) != NULL) {
|
|
if (cp == orig) {
|
|
/* If we got here, the path is actually a full path name,
|
|
* with the first character as a slash, so just leave it
|
|
* alone.
|
|
*/
|
|
return (path);
|
|
}
|
|
/* Otherwise we can look at the first word of the path, and
|
|
* try to expand it, like $HOME/ or ~/, or it is a relative path,
|
|
* which is okay since we won't really do anything with it.
|
|
*/
|
|
*cp = 0;
|
|
rest = cp + 1;
|
|
/* 'firstent' now contains the first 'word' in the path. */
|
|
} else {
|
|
/* Path was just a single word, or it is a full path, like:
|
|
* /usr/tmp/zz, so firstent is just the entire given "path."
|
|
*/
|
|
rest = NULL;
|
|
}
|
|
if (orig[0] == '~') {
|
|
if (orig[1] == 0) {
|
|
firstent = uinfo.homedir;
|
|
} else {
|
|
pw = getpwnam(orig + 1);
|
|
if (pw != NULL)
|
|
firstent = pw->pw_dir;
|
|
}
|
|
} else if (orig[0] == '$') {
|
|
cp = orig + 1;
|
|
dp = orig + strlen(orig) - 1;
|
|
if ((*cp == '(' && *dp == ')') || (*cp == '{' && *dp == '}')) {
|
|
cp++;
|
|
*dp = 0;
|
|
}
|
|
firstent = getenv(cp);
|
|
if (firstent == NULL) {
|
|
(void) fprintf(stderr, "%s: no such environment variable.\n", cp);
|
|
firstent = "badEnvVar";
|
|
}
|
|
}
|
|
if (rest == NULL)
|
|
(void) strcpy(path, firstent);
|
|
else
|
|
(void) sprintf(path, "%s/%s", firstent, rest);
|
|
return (path);
|
|
} /* LocalPath */
|
|
|
|
|
|
|
|
/*
|
|
* A special case, where invisible dot-files that would normally appear in
|
|
* your home directory will appear instead as visible files in your $DOTDIR
|
|
* directory if you have one.
|
|
*/
|
|
|
|
#define LCMP(b) (strncmp(path, (b), (o = sizeof(b) - 1)) == 0)
|
|
|
|
char *LocalDotPath(char *path)
|
|
{
|
|
size_t o;
|
|
longstring s, s2;
|
|
char *cp = getenv("DOTDIR");
|
|
|
|
if (cp == NULL) {
|
|
goto aa;
|
|
} else {
|
|
if (*cp != '/' && *cp != '~') {
|
|
/* then maybe they mean relative to $HOME. */
|
|
(void) sprintf(s2, "%s/%s", uinfo.homedir, cp);
|
|
cp = s2;
|
|
}
|
|
if (LCMP("~/.") ||
|
|
LCMP("$HOME/.") ||
|
|
LCMP("$home/.") ||
|
|
LCMP("$(HOME)/.") ||
|
|
LCMP("${HOME}/.")
|
|
) {
|
|
(void) Strncpy(s, path);
|
|
(void) sprintf(path, "%s/%s", cp, s + o);
|
|
cp = path;
|
|
} else {
|
|
aa: cp = LocalPath(path);
|
|
}
|
|
}
|
|
return cp;
|
|
} /* LocalDotPath */
|
|
|
|
#ifdef NO_STRSTR
|
|
|
|
/*
|
|
* The Elm Mail System - $Revision: 5.1 $ $State: Exp $
|
|
*
|
|
* Copyright (c) 1988-1992 USENET Community Trust
|
|
* Copyright (c) 1986,1987 Dave Taylor
|
|
*/
|
|
|
|
char *strstr(s1, s2)
|
|
char *s1, *s2;
|
|
{
|
|
int len;
|
|
char *ptr;
|
|
char *tmpptr;
|
|
|
|
ptr = NULL;
|
|
len = strlen(s2);
|
|
|
|
if ( len <= strlen(s1)) {
|
|
tmpptr = s1;
|
|
while ((ptr = index(tmpptr, (int)*s2)) != NULL) {
|
|
if (strncmp(ptr, s2, len) == 0) {
|
|
break;
|
|
}
|
|
tmpptr = ptr+1;
|
|
}
|
|
}
|
|
return (ptr);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef NO_RENAME
|
|
int rename(oldname, newname)
|
|
const char *oldname, *newname;
|
|
{
|
|
return (link(oldname, newname) == 0 ? unlink(oldname) : -1);
|
|
}
|
|
#endif /*NO_RENAME*/
|
|
|
|
|
|
/* eof Util.c */
|