ftp.nice.ch/pub/next/unix/communication/TipTop-goodies.s.tar.gz#/TipTop-goodies-src/ncftp/util.c

This is util.c in view mode; [Download] [Up]

/* Util.c */

/*  $RCSfile: util.c,v $
 *  $Revision: 14020.13 $
 *  $Date: 93/05/23 09:38:13 $
 */

#include "sys.h"

#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/time.h>
#include <time.h>
#include <pwd.h>

#ifndef NO_VARARGS
#	include <stdarg.h>
#endif

#ifndef NO_UNISTDH
#	include <unistd.h>
#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;
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
void dbprintf(char *fmt, ...)
{
	va_list ap;

	if (debug) {
		(void) fprintf(DB_STREAM, "#DB# ");
		va_start(ap, fmt);
		(void) vfprintf(DB_STREAM, fmt, ap);
		va_end(ap);
		(void) fflush(DB_STREAM);
	}
}	/* dbprintf */
#endif




/*
 * 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 */




char *Strpcpy(char *dst, char *src)
{
	while (*dst++ = *src++)
		;
	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 (0);
#else
	char *cp = dstr;
	int long mon, day, year, hr, min;
	time_t now;
	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, "%ld %ld", &hr, &min);
		cp[2] = ':';
		year = t->tm_year;
		if (mon > t->tm_mon)
			--year;
	} else {
		hr = min = 0;
		(void) sscanf(cp, "%ld", &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;
	return ((unsigned long) mktime(&ut));
#endif	/* NO_MKTIME */
}	/* UnLSDate */




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

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.
		 */
		if (!toatty && 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
		}
		cp = fgets(sline, (int)size, stdin);
		(void) RemoveTrailingNewline(cp, NULL);
		return cp;
	}

	/*
	 * 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) {
			(void) _Strncpy(sline, cp, size);
			if (*cp != 0) {		/* Don't add blank lines to history buffer. */
				gl_histadd(cp);
				cp = sline;
			}
		}
		/* Hope your strlen is declared as returning a size_t. */
		gl_strwidth(strlen);
	} else {
#ifdef CURSES
		tcap_put(promptstr);
#else
		(void) fputs(promptstr, stdout);
#endif
		cp = fgets(sline, (int) (size - 1), stdin);
	}
	(void) RemoveTrailingNewline(cp, NULL);
#else /* !GETLINE */

#ifdef CURSES
	tcap_put(promptstr);
#else
	(void) fputs(promptstr, stdout);
#endif

	cp = fgets(sline, (int) (size - 1), stdin);
	(void) RemoveTrailingNewline(cp, NULL);
#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 */




char *get_cwd(char *buf, int size)
{
#ifdef SYSV
#	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
	extern char *getwd(char *);
	return (getwd(buf));
#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)
{
	str32 str, pr;

	if (!fromatty || (activemcmd && !mprompt))
		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 */




char *GetHomeDir(char *home)
{
	struct passwd *pw;
	pw = getpwuid(getuid());
	return (strcpy(home, pw->pw_dir));
}	/* GetHomeDir */




/*
 * 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 = NULL;
	char *cp, *dp, *rest;

	(void) Strncpy(orig, path);
	if (((cp = index(orig, '/')) != NULL) && (cp != orig)) {
		*cp = 0;
		rest = cp + 1;
		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) 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, h;
    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", GetHomeDir(h), 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 */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.