alias.c revision 1556
1/*-
2 * Copyright (c) 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char sccsid[] = "@(#)alias.c	8.1 (Berkeley) 5/31/93";
39#endif /* not lint */
40
41#include "shell.h"
42#include "input.h"
43#include "output.h"
44#include "error.h"
45#include "memalloc.h"
46#include "mystring.h"
47#include "alias.h"
48#include "options.h"	/* XXX for argptr (should remove?) */
49
50#define ATABSIZE 39
51
52struct alias *atab[ATABSIZE];
53
54STATIC struct alias **hashalias __P((char *));
55
56STATIC
57setalias(name, val)
58	char *name, *val;
59	{
60	struct alias *ap, **app;
61
62	app = hashalias(name);
63	for (ap = *app; ap; ap = ap->next) {
64		if (equal(name, ap->name)) {
65			INTOFF;
66			ckfree(ap->val);
67			ap->val	= savestr(val);
68			INTON;
69			return;
70		}
71	}
72	/* not found */
73	INTOFF;
74	ap = ckmalloc(sizeof (struct alias));
75	ap->name = savestr(name);
76	/*
77	 * XXX - HACK: in order that the parser will not finish reading the
78	 * alias value off the input before processing the next alias, we
79	 * dummy up an extra space at the end of the alias.  This is a crock
80	 * and should be re-thought.  The idea (if you feel inclined to help)
81	 * is to avoid alias recursions.  The mechanism used is: when
82	 * expanding an alias, the value of the alias is pushed back on the
83	 * input as a string and a pointer to the alias is stored with the
84	 * string.  The alias is marked as being in use.  When the input
85	 * routine finishes reading the string, it markes the alias not
86	 * in use.  The problem is synchronization with the parser.  Since
87	 * it reads ahead, the alias is marked not in use before the
88	 * resulting token(s) is next checked for further alias sub.  The
89	 * H A C K is that we add a little fluff after the alias value
90	 * so that the string will not be exhausted.  This is a good
91	 * idea ------- ***NOT***
92	 */
93#ifdef notyet
94	ap->val = savestr(val);
95#else /* hack */
96	{
97	int len = strlen(val);
98	ap->val = ckmalloc(len + 2);
99	bcopy(val, ap->val, len);
100	ap->val[len] = ' ';	/* fluff */
101	ap->val[len+1] = '\0';
102	}
103#endif
104	ap->next = *app;
105	*app = ap;
106	INTON;
107}
108
109STATIC int
110unalias(name)
111	char *name;
112	{
113	struct alias *ap, **app;
114
115	app = hashalias(name);
116
117	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
118		if (equal(name, ap->name)) {
119			/*
120			 * if the alias is currently in use (i.e. its
121			 * buffer is being used by the input routine) we
122			 * just null out the name instead of freeing it.
123			 * We could clear it out later, but this situation
124			 * is so rare that it hardly seems worth it.
125			 */
126			if (ap->flag & ALIASINUSE)
127				*ap->name = '\0';
128			else {
129				INTOFF;
130				*app = ap->next;
131				ckfree(ap->name);
132				ckfree(ap->val);
133				ckfree(ap);
134				INTON;
135			}
136			return (0);
137		}
138	}
139
140	return (1);
141}
142
143#ifdef mkinit
144MKINIT void rmaliases();
145
146SHELLPROC {
147	rmaliases();
148}
149#endif
150
151void
152rmaliases() {
153	struct alias *ap, *tmp;
154	int i;
155
156	INTOFF;
157	for (i = 0; i < ATABSIZE; i++) {
158		ap = atab[i];
159		atab[i] = NULL;
160		while (ap) {
161			ckfree(ap->name);
162			ckfree(ap->val);
163			tmp = ap;
164			ap = ap->next;
165			ckfree(tmp);
166		}
167	}
168	INTON;
169}
170
171struct alias *
172lookupalias(name, check)
173	char *name;
174	{
175	struct alias *ap = *hashalias(name);
176
177	for (; ap; ap = ap->next) {
178		if (equal(name, ap->name)) {
179			if (check && (ap->flag & ALIASINUSE))
180				return (NULL);
181			return (ap);
182		}
183	}
184
185	return (NULL);
186}
187
188/*
189 * TODO - sort output
190 */
191aliascmd(argc, argv)
192	char **argv;
193	{
194	char *n, *v;
195	int ret = 0;
196	struct alias *ap;
197
198	if (argc == 1) {
199		int i;
200
201		for (i = 0; i < ATABSIZE; i++)
202			for (ap = atab[i]; ap; ap = ap->next) {
203				if (*ap->name != '\0')
204				    out1fmt("alias %s=%s\n", ap->name, ap->val);
205			}
206		return (0);
207	}
208	while (n = *++argv) {
209		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
210			if ((ap = lookupalias(n, 0)) == NULL) {
211				outfmt(out2, "alias: %s not found\n", n);
212				ret = 1;
213			} else
214				out1fmt("alias %s=%s\n", n, ap->val);
215		else {
216			*v++ = '\0';
217			setalias(n, v);
218		}
219	}
220
221	return (ret);
222}
223
224unaliascmd(argc, argv)
225	char **argv;
226	{
227	int i;
228
229	while ((i = nextopt("a")) != '\0') {
230		if (i == 'a') {
231			rmaliases();
232			return (0);
233		}
234	}
235	for (i = 0; *argptr; argptr++)
236		i = unalias(*argptr);
237
238	return (i);
239}
240
241STATIC struct alias **
242hashalias(p)
243	register char *p;
244	{
245	unsigned int hashval;
246
247	hashval = *p << 4;
248	while (*p)
249		hashval+= *p++;
250	return &atab[hashval % ATABSIZE];
251}
252