/* 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;
/*
* 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 */
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;
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;
}
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_isdst = t->tm_isdst;
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;
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
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;
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;
/*
* 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.
*/