]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/sh/alias.c
Merge llvm-project main llvmorg-18-init-15088-gd14ee76181fb
[FreeBSD/FreeBSD.git] / bin / sh / alias.c
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 }