alias.c revision 50471
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 50471 1999-08-27 23:15:48Z peter $";
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->next = *app;
113	*app = ap;
114	INTON;
115}
116
117STATIC int
118unalias(name)
119	char *name;
120	{
121	struct alias *ap, **app;
122
123	app = hashalias(name);
124
125	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
126		if (equal(name, ap->name)) {
127			/*
128			 * if the alias is currently in use (i.e. its
129			 * buffer is being used by the input routine) we
130			 * just null out the name instead of freeing it.
131			 * We could clear it out later, but this situation
132			 * is so rare that it hardly seems worth it.
133			 */
134			if (ap->flag & ALIASINUSE)
135				*ap->name = '\0';
136			else {
137				INTOFF;
138				*app = ap->next;
139				ckfree(ap->name);
140				ckfree(ap->val);
141				ckfree(ap);
142				INTON;
143			}
144			return (0);
145		}
146	}
147
148	return (1);
149}
150
151#ifdef mkinit
152MKINIT void rmaliases();
153
154SHELLPROC {
155	rmaliases();
156}
157#endif
158
159void
160rmaliases() {
161	struct alias *ap, *tmp;
162	int i;
163
164	INTOFF;
165	for (i = 0; i < ATABSIZE; i++) {
166		ap = atab[i];
167		atab[i] = NULL;
168		while (ap) {
169			ckfree(ap->name);
170			ckfree(ap->val);
171			tmp = ap;
172			ap = ap->next;
173			ckfree(tmp);
174		}
175	}
176	INTON;
177}
178
179struct alias *
180lookupalias(name, check)
181	char *name;
182	int check;
183{
184	struct alias *ap = *hashalias(name);
185
186	for (; ap; ap = ap->next) {
187		if (equal(name, ap->name)) {
188			if (check && (ap->flag & ALIASINUSE))
189				return (NULL);
190			return (ap);
191		}
192	}
193
194	return (NULL);
195}
196
197/*
198 * TODO - sort output
199 */
200int
201aliascmd(argc, argv)
202	int argc;
203	char **argv;
204{
205	char *n, *v;
206	int ret = 0;
207	struct alias *ap;
208
209	if (argc == 1) {
210		int i;
211
212		for (i = 0; i < ATABSIZE; i++)
213			for (ap = atab[i]; ap; ap = ap->next) {
214				if (*ap->name != '\0')
215				    out1fmt("alias %s=%s\n", ap->name, ap->val);
216			}
217		return (0);
218	}
219	while ((n = *++argv) != NULL) {
220		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
221			if ((ap = lookupalias(n, 0)) == NULL) {
222				outfmt(out2, "alias: %s not found\n", n);
223				ret = 1;
224			} else
225				out1fmt("alias %s=%s\n", n, ap->val);
226		else {
227			*v++ = '\0';
228			setalias(n, v);
229		}
230	}
231
232	return (ret);
233}
234
235int
236unaliascmd(argc, argv)
237	int argc __unused;
238	char **argv __unused;
239{
240	int i;
241
242	while ((i = nextopt("a")) != '\0') {
243		if (i == 'a') {
244			rmaliases();
245			return (0);
246		}
247	}
248	for (i = 0; *argptr; argptr++)
249		i = unalias(*argptr);
250
251	return (i);
252}
253
254STATIC struct alias **
255hashalias(p)
256	char *p;
257	{
258	unsigned int hashval;
259
260	hashval = *p << 4;
261	while (*p)
262		hashval+= *p++;
263	return &atab[hashval % ATABSIZE];
264}
265