xref: /freebsd/bin/sh/alias.c (revision abd87254)
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. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <stdlib.h>
34 #include "shell.h"
35 #include "output.h"
36 #include "error.h"
37 #include "memalloc.h"
38 #include "mystring.h"
39 #include "alias.h"
40 #include "options.h"
41 #include "builtins.h"
42 
43 #define ATABSIZE 39
44 
45 static struct alias *atab[ATABSIZE];
46 static int aliases;
47 
48 static void setalias(const char *, const char *);
49 static int unalias(const char *);
50 static size_t hashalias(const char *);
51 
52 static
53 void
54 setalias(const char *name, const char *val)
55 {
56 	struct alias *ap, **app;
57 
58 	unalias(name);
59 	app = &atab[hashalias(name)];
60 	INTOFF;
61 	ap = ckmalloc(sizeof (struct alias));
62 	ap->name = savestr(name);
63 	ap->val = savestr(val);
64 	ap->flag = 0;
65 	ap->next = *app;
66 	*app = ap;
67 	aliases++;
68 	INTON;
69 }
70 
71 static void
72 freealias(struct alias *ap)
73 {
74 	ckfree(ap->name);
75 	ckfree(ap->val);
76 	ckfree(ap);
77 }
78 
79 static int
80 unalias(const char *name)
81 {
82 	struct alias *ap, **app;
83 
84 	app = &atab[hashalias(name)];
85 
86 	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
87 		if (equal(name, ap->name)) {
88 			/*
89 			 * if the alias is currently in use (i.e. its
90 			 * buffer is being used by the input routine) we
91 			 * just null out the name instead of freeing it.
92 			 * We could clear it out later, but this situation
93 			 * is so rare that it hardly seems worth it.
94 			 */
95 			if (ap->flag & ALIASINUSE)
96 				*ap->name = '\0';
97 			else {
98 				INTOFF;
99 				*app = ap->next;
100 				freealias(ap);
101 				INTON;
102 			}
103 			aliases--;
104 			return (0);
105 		}
106 	}
107 
108 	return (1);
109 }
110 
111 static void
112 rmaliases(void)
113 {
114 	struct alias *ap, **app;
115 	int i;
116 
117 	INTOFF;
118 	for (i = 0; i < ATABSIZE; i++) {
119 		app = &atab[i];
120 		while (*app) {
121 			ap = *app;
122 			if (ap->flag & ALIASINUSE) {
123 				*ap->name = '\0';
124 				app = &(*app)->next;
125 			} else {
126 				*app = ap->next;
127 				freealias(ap);
128 			}
129 		}
130 	}
131 	aliases = 0;
132 	INTON;
133 }
134 
135 struct alias *
136 lookupalias(const char *name, int check)
137 {
138 	struct alias *ap;
139 
140 	if (aliases == 0)
141 		return (NULL);
142 	for (ap = atab[hashalias(name)]; ap; ap = ap->next) {
143 		if (equal(name, ap->name)) {
144 			if (check && (ap->flag & ALIASINUSE))
145 				return (NULL);
146 			return (ap);
147 		}
148 	}
149 
150 	return (NULL);
151 }
152 
153 static int
154 comparealiases(const void *p1, const void *p2)
155 {
156 	const struct alias *const *a1 = p1;
157 	const struct alias *const *a2 = p2;
158 
159 	return strcmp((*a1)->name, (*a2)->name);
160 }
161 
162 static void
163 printalias(const struct alias *a)
164 {
165 	out1fmt("%s=", a->name);
166 	out1qstr(a->val);
167 	out1c('\n');
168 }
169 
170 static void
171 printaliases(void)
172 {
173 	int i, j;
174 	struct alias **sorted, *ap;
175 
176 	INTOFF;
177 	sorted = ckmalloc(aliases * sizeof(*sorted));
178 	j = 0;
179 	for (i = 0; i < ATABSIZE; i++)
180 		for (ap = atab[i]; ap; ap = ap->next)
181 			if (*ap->name != '\0')
182 				sorted[j++] = ap;
183 	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
184 	for (i = 0; i < aliases; i++) {
185 		printalias(sorted[i]);
186 		if (int_pending())
187 			break;
188 	}
189 	ckfree(sorted);
190 	INTON;
191 }
192 
193 int
194 aliascmd(int argc __unused, char **argv __unused)
195 {
196 	char *n, *v;
197 	int ret = 0;
198 	struct alias *ap;
199 
200 	nextopt("");
201 
202 	if (*argptr == NULL) {
203 		printaliases();
204 		return (0);
205 	}
206 	while ((n = *argptr++) != NULL) {
207 		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
208 			if ((ap = lookupalias(n, 0)) == NULL) {
209 				warning("%s: not found", n);
210 				ret = 1;
211 			} else
212 				printalias(ap);
213 		else {
214 			*v++ = '\0';
215 			setalias(n, v);
216 		}
217 	}
218 
219 	return (ret);
220 }
221 
222 int
223 unaliascmd(int argc __unused, char **argv __unused)
224 {
225 	int i;
226 
227 	while ((i = nextopt("a")) != '\0') {
228 		if (i == 'a') {
229 			rmaliases();
230 			return (0);
231 		}
232 	}
233 	for (i = 0; *argptr; argptr++)
234 		i |= unalias(*argptr);
235 
236 	return (i);
237 }
238 
239 static size_t
240 hashalias(const char *p)
241 {
242 	unsigned int hashval;
243 
244 	hashval = (unsigned char)*p << 4;
245 	while (*p)
246 		hashval+= *p++;
247 	return (hashval % ATABSIZE);
248 }
249 
250 const struct alias *
251 iteralias(const struct alias *index)
252 {
253 	size_t i = 0;
254 
255 	if (index != NULL) {
256 		if (index->next != NULL)
257 			return (index->next);
258 		i = hashalias(index->name) + 1;
259 	}
260 	for (; i < ATABSIZE; i++)
261 		if (atab[i] != NULL)
262 			return (atab[i]);
263 
264 	return (NULL);
265 }
266