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