[BACK]Return to value.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tip

File: [local] / src / usr.bin / tip / Attic / value.c (download)

Revision 1.33, Mon Aug 23 19:05:08 2010 UTC (13 years, 9 months ago) by nicm
Branch: MAIN
CVS Tags: OPENBSD_5_7_BASE, OPENBSD_5_7, OPENBSD_5_6_BASE, OPENBSD_5_6, OPENBSD_5_5_BASE, OPENBSD_5_5, OPENBSD_5_4_BASE, OPENBSD_5_4, OPENBSD_5_3_BASE, OPENBSD_5_3, OPENBSD_5_2_BASE, OPENBSD_5_2, OPENBSD_5_1_BASE, OPENBSD_5_1, OPENBSD_5_0_BASE, OPENBSD_5_0, OPENBSD_4_9_BASE, OPENBSD_4_9
Changes since 1.32: +14 -14 lines

Clear options before setting up HOME and SHELL, not after. Fixes parsing
.tiprc reported by nick@.

/*	$OpenBSD: value.c,v 1.33 2010/08/23 19:05:08 nicm Exp $	*/
/*	$NetBSD: value.c,v 1.6 1997/02/11 09:24:09 mrg Exp $	*/

/*
 * Copyright (c) 1983, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <paths.h>

#include "tip.h"

/*
 * Variable manipulation.
 */

value_t vtable[] = {
	{ "beautify",	  V_BOOL,	       "be",     NULL, 0 },
	{ "baudrate",	  V_NUMBER,	       "ba",     NULL, 0 },
	{ "connect",      V_STRING|V_READONLY, "cm",     NULL, 0 },
	{ "device",       V_STRING|V_READONLY, "dv",     NULL, 0 },
	{ "eofread",	  V_STRING,	       "eofr",   NULL, 0 },
	{ "eofwrite",	  V_STRING,	       "eofw",   NULL, 0 },
	{ "eol",	  V_STRING,	       NULL,     NULL, 0 },
	{ "escape",	  V_CHAR,	       "es",     NULL, 0 },
	{ "exceptions",	  V_STRING,	       "ex",     NULL, 0 },
	{ "force",	  V_CHAR,	       "fo",     NULL, 0 },
	{ "framesize",	  V_NUMBER,	       "fr",     NULL, 0 },
	{ "host",	  V_STRING|V_READONLY, "ho",     NULL, 0 },
	{ "log",	  V_STRING,	       NULL,     NULL, 0 },
	{ "prompt",	  V_CHAR,	       "pr",     NULL, 0 },
	{ "raise",	  V_BOOL,	       "ra",     NULL, 0 },
	{ "raisechar",	  V_CHAR,	       "rc",     NULL, 0 },
	{ "record",	  V_STRING,	       "rec",    NULL, 0 },
	{ "remote",	  V_STRING|V_READONLY, NULL,     NULL, 0 },
	{ "script",	  V_BOOL,	       "sc",     NULL, 0 },
	{ "tabexpand",	  V_BOOL,	       "tab",    NULL, 0 },
	{ "verbose",	  V_BOOL,	       "verb",   NULL, 0 },
	{ "SHELL",	  V_STRING,	       NULL,     NULL, 0 },
	{ "HOME",	  V_STRING,	       NULL,	 NULL, 0 },
	{ "echocheck",	  V_BOOL,	       "ec",	 NULL, 0 },
	{ "disconnect",	  V_STRING,	       "di",	 NULL, 0 },
	{ "tandem",	  V_BOOL,	       "ta",	 NULL, 0 },
	{ "linedelay",	  V_NUMBER,	       "ldelay", NULL, 0 },
	{ "chardelay",	  V_NUMBER,	       "cdelay", NULL, 0 },
	{ "etimeout",	  V_NUMBER,	       "et",	 NULL, 0 },
	{ "rawftp",	  V_BOOL,	       "raw",	 NULL, 0 },
	{ "halfduplex",	  V_BOOL,	       "hdx",	 NULL, 0 },
	{ "localecho",	  V_BOOL,	       "le",	 NULL, 0 },
	{ "parity",	  V_STRING,	       "par",	 NULL, 0 },
	{ "hardwareflow", V_BOOL,	       "hf",	 NULL, 0 },
	{ "linedisc",	  V_NUMBER,	       "ld",	 NULL, 0 },
	{ "direct",	  V_BOOL,	       "dc",	 NULL, 0 },
	{ NULL,           0,	                NULL,    NULL, 0 },
};

static int	vlookup(char *);
static void	vtoken(char *);
static size_t	vprint(value_t *);
static void	vprintall(void);
static char    *vinterp(char *, int);

/* Get a string value. */
char *
vgetstr(int value)
{
	value_t	*vp = &vtable[value];
	int	 type;

	type = vp->v_flags & V_TYPEMASK;
	if (type != V_STRING)
		errx(1, "variable %s not a string", vp->v_name);
	return (vp->v_string);
}

/* Get a number value. */
int
vgetnum(int value)
{
	value_t	*vp = &vtable[value];
	int	 type;

	type = vp->v_flags & V_TYPEMASK;
	if (type != V_NUMBER && type != V_BOOL && type != V_CHAR)
		errx(1, "variable %s not a number", vp->v_name);
	return (vp->v_number);
}

/* Set a string value. */
void
vsetstr(int value, char *string)
{
	value_t	*vp = &vtable[value];
	int	 type;

	type = vp->v_flags & V_TYPEMASK;
	if (type != V_STRING)
		errx(1, "variable %s not a string", vp->v_name);

	if (value == RECORD && string != NULL)
		string = expand(string);

	free(vp->v_string);
	if (string != NULL) {
		vp->v_string = strdup(string);
		if (vp->v_string == NULL)
			err(1, "strdup");
	} else
		vp->v_string = NULL;
}

/* Set a number value. */
void
vsetnum(int value, int number)
{
	value_t	*vp = &vtable[value];
	int	 type;

	type = vp->v_flags & V_TYPEMASK;
	if (type != V_NUMBER && type != V_BOOL && type != V_CHAR)
		errx(1, "variable %s not a number", vp->v_name);

	vp->v_number = number;
}

/* Print a single variable and its value. */
static size_t
vprint(value_t *p)
{
	char	*cp;
	size_t	 width;

	width = size(p->v_name);
	switch (p->v_flags & V_TYPEMASK) {
	case V_BOOL:
		if (!p->v_number) {
			width++;
			putchar('!');
		}
		printf("%s", p->v_name);
		break;
	case V_STRING:
		printf("%s=", p->v_name);
		width++;
		if (p->v_string) {
			cp = interp(p->v_string);
			width += size(cp);
			printf("%s", cp);
		}
		break;
	case V_NUMBER:
		width += 6;
		printf("%s=%-5d", p->v_name, p->v_number);
		break;
	case V_CHAR:
		printf("%s=", p->v_name);
		width++;
		if (p->v_number) {
			cp = ctrl(p->v_number);
			width += size(cp);
			printf("%s", cp);
		}
		break;
	}
	return (width);
}

/* Print all variables. */
static void
vprintall(void)
{
	value_t	*vp;
	size_t	 width;

#define MIDDLE 35
	width = 0;
	for (vp = vtable; vp->v_name; vp++) {
		if (vp->v_flags & V_READONLY)
			continue;
		if (width > 0 && width < MIDDLE) {
			while (width++ < MIDDLE)
				putchar(' ');
		}
		width += vprint(vp);
		if (width > MIDDLE) {
			printf("\r\n");
			width = 0;
		}
	}
#undef MIDDLE
}

/* Find index of variable by name or abbreviation. */
static int
vlookup(char *s)
{
	value_t *vp;
	u_int	 i;

	for (i = 0; vtable[i].v_name != NULL; i++) {
		vp = &vtable[i];
		if (strcmp(vp->v_name, s) == 0 ||
		    (vp->v_abbrev != NULL && strcmp(vp->v_abbrev, s) == 0))
			return (i);
	}
	return (-1);
}

void
vinit(void)
{
	struct passwd	*pw;
	value_t		*vp;
	char		 file[FILENAME_MAX], *cp;
	int		 written;
	FILE		*fp;

	/* Clear the table and set the defaults. */
	for (vp = vtable; vp->v_name != NULL; vp++) {
		vp->v_string = NULL;
		vp->v_number = 0;
	}
	vsetnum(BEAUTIFY, 1);
	vsetnum(ESCAPE, '~');
	vsetnum(FORCE, CTRL('p'));
	vsetnum(PROMPT, '\n');
	vsetnum(TAND, 1);
	vsetnum(VERBOSE, 1);
	vsetstr(LOG, _PATH_ACULOG);

	/* Read environment variables. */
	if ((cp = getenv("HOME")) != NULL)
		vsetstr(HOME, cp);
	else {
		pw = getpwuid(getuid());
		if (pw != NULL && pw->pw_dir != NULL)
			vsetstr(HOME, pw->pw_dir);
		else
			vsetstr(HOME, "/");
	}
	if ((cp = getenv("SHELL")) != NULL)
		vsetstr(SHELL, cp);
	else
		vsetstr(SHELL, _PATH_BSHELL);

	/* Read the .tiprc file in the HOME directory. */
	written = snprintf(file, sizeof(file), "%s/.tiprc", vgetstr(HOME));
	if (written < 0 || written >= sizeof(file)) {
		(void)fprintf(stderr, "Home directory path too long: %s\n",
		    vgetstr(HOME));
	} else {
		if ((fp = fopen(file, "r")) != NULL) {
			char *tp;

			while (fgets(file, sizeof(file), fp) != NULL) {
				if (vflag)
					printf("set %s", file);
				if ((tp = strrchr(file, '\n')))
					*tp = '\0';
				vlex(file);
			}
			fclose(fp);
		}
	}
}

void
vlex(char *s)
{
	char *cp;

	if (strcmp(s, "all") == 0)
		vprintall();
	else {
		do {
			if ((cp = vinterp(s, ' ')))
				cp++;
			vtoken(s);
			s = cp;
		} while (s);
	}
}

/* Set a variable from a token. */
static void
vtoken(char *s)
{
	value_t 	*vp;
	int	 	i, value;
	char		*cp;
	const char	*cause;

	if ((cp = strchr(s, '='))) {
		*cp = '\0';
		if ((i = vlookup(s)) != -1) {
			vp = &vtable[i];
			if (vp->v_flags & V_READONLY) {
				printf("access denied\r\n");
				return;
			}
			cp++;
			switch (vp->v_flags & V_TYPEMASK) {
			case V_STRING:
				vsetstr(i, cp);
				break;
			case V_BOOL:
				vsetnum(i, 1);
				break;
			case V_NUMBER:
				value = strtonum(cp, 0, INT_MAX, &cause);
				if (cause != NULL) {
					printf("%s: number %s\r\n", s, cause);
					return;
				}
				vsetnum(i, value);
				break;
			case V_CHAR:
				if (cp[0] != '\0' && cp[1] != '\0') {
					printf("%s: character too big\r\n", s);
					return;
				}
				vsetnum(i, *cp);
			}
			vp->v_flags |= V_CHANGED;
			return;
		}
	} else if ((cp = strchr(s, '?'))) {
		*cp = '\0';
		if ((i = vlookup(s)) != -1) {
			if (vprint(&vtable[i]) > 0)
				printf("\r\n");
			return;
		}
	} else {
		if (*s != '!')
			i = vlookup(s);
		else
			i = vlookup(s + 1);
		if (i != -1) {
			vp = &vtable[i];
			if (vp->v_flags & V_READONLY) {
				printf("%s: access denied\r\n", s);
				return;
			}
			if ((vp->v_flags & V_TYPEMASK) != V_BOOL) {
				printf("%s: not a boolean\r\n", s);
				return;
			}
			vsetnum(i, *s != '!');
			vp->v_flags |= V_CHANGED;
			return;
		}
	}
	printf("%s: unknown variable\r\n", s);
}

static char *
vinterp(char *s, int stop)
{
	char *p = s, c;
	int num;

	while ((c = *s++) && c != stop) {
		switch (c) {

		case '^':
			if (*s)
				*p++ = *s++ - 0100;
			else
				*p++ = c;
			break;

		case '\\':
			num = 0;
			c = *s++;
			if (c >= '0' && c <= '7')
				num = (num<<3)+(c-'0');
			else {
				char *q = "n\nr\rt\tb\bf\f";

				for (; *q; q++)
					if (c == *q++) {
						*p++ = *q;
						goto cont;
					}
				*p++ = c;
			cont:
				break;
			}
			if ((c = *s++) >= '0' && c <= '7') {
				num = (num<<3)+(c-'0');
				if ((c = *s++) >= '0' && c <= '7')
					num = (num<<3)+(c-'0');
				else
					s--;
			} else
				s--;
			*p++ = num;
			break;

		default:
			*p++ = c;
		}
	}
	*p = '\0';
	return (c == stop ? s-1 : NULL);
}