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
setalias(const char * name,const char * val)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
freealias(struct alias * ap)72 freealias(struct alias *ap)
73 {
74 ckfree(ap->name);
75 ckfree(ap->val);
76 ckfree(ap);
77 }
78
79 static int
unalias(const char * name)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
rmaliases(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 *
lookupalias(const char * name,int check)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
comparealiases(const void * p1,const void * p2)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
printalias(const struct alias * a)163 printalias(const struct alias *a)
164 {
165 out1fmt("%s=", a->name);
166 out1qstr(a->val);
167 out1c('\n');
168 }
169
170 static void
printaliases(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
aliascmd(int argc __unused,char ** argv __unused)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
unaliascmd(int argc __unused,char ** argv __unused)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
hashalias(const char * p)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 *
iteralias(const struct alias * index)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