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