alias.c revision 63223
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
38#if 0
39static char sccsid[] = "@(#)alias.c	8.3 (Berkeley) 5/4/95";
40#endif
41static const char rcsid[] =
42  "$FreeBSD: head/bin/sh/alias.c 63223 2000-07-15 14:34:37Z sada $";
43#endif /* not lint */
44
45#include <stdlib.h>
46#include "shell.h"
47#include "input.h"
48#include "output.h"
49#include "error.h"
50#include "memalloc.h"
51#include "mystring.h"
52#include "alias.h"
53#include "options.h"	/* XXX for argptr (should remove?) */
54
55#define ATABSIZE 39
56
57struct alias *atab[ATABSIZE];
58
59STATIC void setalias __P((char *, char *));
60STATIC int unalias __P((char *));
61STATIC struct alias **hashalias __P((char *));
62
63STATIC
64void
65setalias(name, val)
66	char *name, *val;
67{
68	struct alias *ap, **app;
69
70	app = hashalias(name);
71	for (ap = *app; ap; ap = ap->next) {
72		if (equal(name, ap->name)) {
73			INTOFF;
74			ckfree(ap->val);
75			ap->val	= savestr(val);
76			INTON;
77			return;
78		}
79	}
80	/* not found */
81	INTOFF;
82	ap = ckmalloc(sizeof (struct alias));
83	ap->name = savestr(name);
84	/*
85	 * XXX - HACK: in order that the parser will not finish reading the
86	 * alias value off the input before processing the next alias, we
87	 * dummy up an extra space at the end of the alias.  This is a crock
88	 * and should be re-thought.  The idea (if you feel inclined to help)
89	 * is to avoid alias recursions.  The mechanism used is: when
90	 * expanding an alias, the value of the alias is pushed back on the
91	 * input as a string and a pointer to the alias is stored with the
92	 * string.  The alias is marked as being in use.  When the input
93	 * routine finishes reading the string, it marks the alias not
94	 * in use.  The problem is synchronization with the parser.  Since
95	 * it reads ahead, the alias is marked not in use before the
96	 * resulting token(s) is next checked for further alias sub.  The
97	 * H A C K is that we add a little fluff after the alias value
98	 * so that the string will not be exhausted.  This is a good
99	 * idea ------- ***NOT***
100	 */
101#ifdef notyet
102	ap->val = savestr(val);
103#else /* hack */
104	{
105	int len = strlen(val);
106	ap->val = ckmalloc(len + 2);
107	memcpy(ap->val, val, len);
108	ap->val[len] = ' ';	/* fluff */
109	ap->val[len+1] = '\0';
110	}
111#endif
112	ap->flag = 0;
113	ap->next = *app;
114	*app = ap;
115	INTON;
116}
117
118STATIC int
119unalias(name)
120	char *name;
121	{
122	struct alias *ap, **app;
123
124	app = hashalias(name);
125
126	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
127		if (equal(name, ap->name)) {
128			/*
129			 * if the alias is currently in use (i.e. its
130			 * buffer is being used by the input routine) we
131			 * just null out the name instead of freeing it.
132			 * We could clear it out later, but this situation
133			 * is so rare that it hardly seems worth it.
134			 */
135			if (ap->flag & ALIASINUSE)
136				*ap->name = '\0';
137			else {
138				INTOFF;
139				*app = ap->next;
140				ckfree(ap->name);
141				ckfree(ap->val);
142				ckfree(ap);
143				INTON;
144			}
145			return (0);
146		}
147	}
148
149	return (1);
150}
151
152#ifdef mkinit
153MKINIT void rmaliases();
154
155SHELLPROC {
156	rmaliases();
157}
158#endif
159
160void
161rmaliases() {
162	struct alias *ap, *tmp;
163	int i;
164
165	INTOFF;
166	for (i = 0; i < ATABSIZE; i++) {
167		ap = atab[i];
168		atab[i] = NULL;
169		while (ap) {
170			ckfree(ap->name);
171			ckfree(ap->val);
172			tmp = ap;
173			ap = ap->next;
174			ckfree(tmp);
175		}
176	}
177	INTON;
178}
179
180struct alias *
181lookupalias(name, check)
182	char *name;
183	int check;
184{
185	struct alias *ap = *hashalias(name);
186
187	for (; ap; ap = ap->next) {
188		if (equal(name, ap->name)) {
189			if (check && (ap->flag & ALIASINUSE))
190				return (NULL);
191			return (ap);
192		}
193	}
194
195	return (NULL);
196}
197
198/*
199 * TODO - sort output
200 */
201int
202aliascmd(argc, argv)
203	int argc;
204	char **argv;
205{
206	char *n, *v;
207	int ret = 0;
208	struct alias *ap;
209
210	if (argc == 1) {
211		int i;
212
213		for (i = 0; i < ATABSIZE; i++)
214			for (ap = atab[i]; ap; ap = ap->next) {
215				if (*ap->name != '\0')
216				    out1fmt("alias %s=%s\n", ap->name, ap->val);
217			}
218		return (0);
219	}
220	while ((n = *++argv) != NULL) {
221		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
222			if ((ap = lookupalias(n, 0)) == NULL) {
223				outfmt(out2, "alias: %s not found\n", n);
224				ret = 1;
225			} else
226				out1fmt("alias %s=%s\n", n, ap->val);
227		else {
228			*v++ = '\0';
229			setalias(n, v);
230		}
231	}
232
233	return (ret);
234}
235
236int
237unaliascmd(argc, argv)
238	int argc __unused;
239	char **argv __unused;
240{
241	int i;
242
243	while ((i = nextopt("a")) != '\0') {
244		if (i == 'a') {
245			rmaliases();
246			return (0);
247		}
248	}
249	for (i = 0; *argptr; argptr++)
250		i = unalias(*argptr);
251
252	return (i);
253}
254
255STATIC struct alias **
256hashalias(p)
257	char *p;
258	{
259	unsigned int hashval;
260
261	hashval = *p << 4;
262	while (*p)
263		hashval+= *p++;
264	return &atab[hashval % ATABSIZE];
265}
266