xref: /csrg-svn/bin/sh/alias.c (revision 60701)
1*60701Sbostic /*-
2*60701Sbostic  * Copyright (c) 1993
3*60701Sbostic  *	The Regents of the University of California.  All rights reserved.
4*60701Sbostic  *
5*60701Sbostic  * This code is derived from software contributed to Berkeley by
6*60701Sbostic  * Kenneth Almquist.
7*60701Sbostic  *
8*60701Sbostic  * %sccs.include.redist.c%
9*60701Sbostic  */
10*60701Sbostic 
11*60701Sbostic #ifndef lint
12*60701Sbostic static char sccsid[] = "@(#)alias.c	1.3 (Berkeley) 05/31/93";
13*60701Sbostic #endif /* not lint */
14*60701Sbostic 
1553651Smarc #include "shell.h"
1653651Smarc #include "input.h"
1753651Smarc #include "output.h"
1853651Smarc #include "error.h"
1953651Smarc #include "memalloc.h"
2053651Smarc #include "mystring.h"
2153651Smarc #include "alias.h"
2253651Smarc #include "options.h"	/* XXX for argptr (should remove?) */
2353651Smarc 
2453651Smarc #define ATABSIZE 39
2553651Smarc 
2653651Smarc struct alias *atab[ATABSIZE];
2753651Smarc 
2853651Smarc STATIC struct alias **hashalias __P((char *));
2953651Smarc 
3053651Smarc STATIC
3153651Smarc setalias(name, val)
3253651Smarc 	char *name, *val;
3353651Smarc 	{
3453651Smarc 	struct alias *ap, **app;
3553651Smarc 
3653651Smarc 	app = hashalias(name);
3753651Smarc 	for (ap = *app; ap; ap = ap->next) {
3853651Smarc 		if (equal(name, ap->name)) {
3953651Smarc 			INTOFF;
4053651Smarc 			ckfree(ap->val);
4153651Smarc 			ap->val	= savestr(val);
4253651Smarc 			INTON;
4353651Smarc 			return;
4453651Smarc 		}
4553651Smarc 	}
4653651Smarc 	/* not found */
4753651Smarc 	INTOFF;
4853651Smarc 	ap = ckmalloc(sizeof (struct alias));
4953651Smarc 	ap->name = savestr(name);
5053651Smarc 	/*
5153651Smarc 	 * XXX - HACK: in order that the parser will not finish reading the
5253651Smarc 	 * alias value off the input before processing the next alias, we
5353651Smarc 	 * dummy up an extra space at the end of the alias.  This is a crock
5453651Smarc 	 * and should be re-thought.  The idea (if you feel inclined to help)
5553651Smarc 	 * is to avoid alias recursions.  The mechanism used is: when
5653651Smarc 	 * expanding an alias, the value of the alias is pushed back on the
5753651Smarc 	 * input as a string and a pointer to the alias is stored with the
5853651Smarc 	 * string.  The alias is marked as being in use.  When the input
5953651Smarc 	 * routine finishes reading the string, it markes the alias not
6053651Smarc 	 * in use.  The problem is synchronization with the parser.  Since
6153651Smarc 	 * it reads ahead, the alias is marked not in use before the
6253651Smarc 	 * resulting token(s) is next checked for further alias sub.  The
6353651Smarc 	 * H A C K is that we add a little fluff after the alias value
6453651Smarc 	 * so that the string will not be exhausted.  This is a good
6553651Smarc 	 * idea ------- ***NOT***
6653651Smarc 	 */
6753651Smarc #ifdef notyet
6853651Smarc 	ap->val = savestr(val);
6953651Smarc #else /* hack */
7053651Smarc 	{
7153651Smarc 	int len = strlen(val);
7253651Smarc 	ap->val = ckmalloc(len + 2);
7353651Smarc 	bcopy(val, ap->val, len);
7453651Smarc 	ap->val[len] = ' ';	/* fluff */
7553651Smarc 	ap->val[len+1] = '\0';
7653651Smarc 	}
7753651Smarc #endif
7853651Smarc 	ap->next = *app;
7953651Smarc 	*app = ap;
8053651Smarc 	INTON;
8153651Smarc }
8253651Smarc 
8353651Smarc STATIC int
8453651Smarc unalias(name)
8553651Smarc 	char *name;
8653651Smarc 	{
8753651Smarc 	struct alias *ap, **app;
8853651Smarc 
8953651Smarc 	app = hashalias(name);
9053651Smarc 
9153651Smarc 	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
9253651Smarc 		if (equal(name, ap->name)) {
9353651Smarc 			/*
9453651Smarc 			 * if the alias is currently in use (i.e. its
9553651Smarc 			 * buffer is being used by the input routine) we
9653651Smarc 			 * just null out the name instead of freeing it.
9753651Smarc 			 * We could clear it out later, but this situation
9853651Smarc 			 * is so rare that it hardly seems worth it.
9953651Smarc 			 */
10053651Smarc 			if (ap->flag & ALIASINUSE)
10153651Smarc 				*ap->name = '\0';
10253651Smarc 			else {
10353651Smarc 				INTOFF;
10453651Smarc 				*app = ap->next;
10553651Smarc 				ckfree(ap->name);
10653651Smarc 				ckfree(ap->val);
10753651Smarc 				ckfree(ap);
10853651Smarc 				INTON;
10953651Smarc 			}
11053651Smarc 			return (0);
11153651Smarc 		}
11253651Smarc 	}
11353651Smarc 
11453651Smarc 	return (1);
11553651Smarc }
11653651Smarc 
11753651Smarc #ifdef mkinit
11853651Smarc MKINIT void rmaliases();
11953651Smarc 
12053651Smarc SHELLPROC {
12153651Smarc 	rmaliases();
12253651Smarc }
12353651Smarc #endif
12453651Smarc 
12553651Smarc void
12653651Smarc rmaliases() {
12753651Smarc 	struct alias *ap, *tmp;
12853651Smarc 	int i;
12953651Smarc 
13053651Smarc 	INTOFF;
13153651Smarc 	for (i = 0; i < ATABSIZE; i++) {
13253651Smarc 		ap = atab[i];
13353651Smarc 		atab[i] = NULL;
13453651Smarc 		while (ap) {
13553651Smarc 			ckfree(ap->name);
13653651Smarc 			ckfree(ap->val);
13753651Smarc 			tmp = ap;
13853651Smarc 			ap = ap->next;
13953651Smarc 			ckfree(tmp);
14053651Smarc 		}
14153651Smarc 	}
14253651Smarc 	INTON;
14353651Smarc }
14453651Smarc 
14553651Smarc struct alias *
14653651Smarc lookupalias(name, check)
14753651Smarc 	char *name;
14853651Smarc 	{
14953651Smarc 	struct alias *ap = *hashalias(name);
15053651Smarc 
15153651Smarc 	for (; ap; ap = ap->next) {
15253651Smarc 		if (equal(name, ap->name)) {
15353651Smarc 			if (check && (ap->flag & ALIASINUSE))
15453651Smarc 				return (NULL);
15553651Smarc 			return (ap);
15653651Smarc 		}
15753651Smarc 	}
15853651Smarc 
15953651Smarc 	return (NULL);
16053651Smarc }
16153651Smarc 
16253651Smarc /*
16353651Smarc  * TODO - sort output
16453651Smarc  */
16553651Smarc aliascmd(argc, argv)
16653651Smarc 	char **argv;
16753651Smarc 	{
16853651Smarc 	char *n, *v;
16953651Smarc 	int ret = 0;
17053651Smarc 	struct alias *ap;
17153651Smarc 
17253651Smarc 	if (argc == 1) {
17353651Smarc 		int i;
17453651Smarc 
17553651Smarc 		for (i = 0; i < ATABSIZE; i++)
17653651Smarc 			for (ap = atab[i]; ap; ap = ap->next) {
17753651Smarc 				if (*ap->name != '\0')
17853651Smarc 				    out1fmt("alias %s=%s\n", ap->name, ap->val);
17953651Smarc 			}
18053651Smarc 		return (0);
18153651Smarc 	}
18253651Smarc 	while (n = *++argv) {
18353651Smarc 		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
18453651Smarc 			if ((ap = lookupalias(n, 0)) == NULL) {
18553651Smarc 				outfmt(out2, "alias: %s not found\n", n);
18653651Smarc 				ret = 1;
18753651Smarc 			} else
18853651Smarc 				out1fmt("alias %s=%s\n", n, ap->val);
18953651Smarc 		else {
19053651Smarc 			*v++ = '\0';
19153651Smarc 			setalias(n, v);
19253651Smarc 		}
19353651Smarc 	}
19453651Smarc 
19553651Smarc 	return (ret);
19653651Smarc }
19753651Smarc 
19853651Smarc unaliascmd(argc, argv)
19953651Smarc 	char **argv;
20053651Smarc 	{
20153651Smarc 	int i;
20253651Smarc 
20353651Smarc 	while ((i = nextopt("a")) != '\0') {
20453651Smarc 		if (i == 'a') {
20553651Smarc 			rmaliases();
20653651Smarc 			return (0);
20753651Smarc 		}
20853651Smarc 	}
20953651Smarc 	for (i = 0; *argptr; argptr++)
21053651Smarc 		i = unalias(*argptr);
21153651Smarc 
21253651Smarc 	return (i);
21353651Smarc }
21453651Smarc 
21553651Smarc STATIC struct alias **
21653651Smarc hashalias(p)
21753651Smarc 	register char *p;
21853651Smarc 	{
21953651Smarc 	unsigned int hashval;
22053651Smarc 
22153651Smarc 	hashval = *p << 4;
22253651Smarc 	while (*p)
22353651Smarc 		hashval+= *p++;
22453651Smarc 	return &atab[hashval % ATABSIZE];
22553651Smarc }
226