xref: /dragonfly/bin/sh/alias.c (revision 3e3895bf4584c1562faf4533cbd97026ee6a8dcf)
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 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)alias.c     8.3 (Berkeley) 5/4/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: head/bin/sh/alias.c 317039 2017-04-16 22:10:02Z jilles $");
40 
41 #include <stdlib.h>
42 #include "shell.h"
43 #include "output.h"
44 #include "error.h"
45 #include "memalloc.h"
46 #include "mystring.h"
47 #include "alias.h"
48 #include "options.h"
49 #include "builtins.h"
50 
51 #define ATABSIZE 39
52 
53 static struct alias *atab[ATABSIZE];
54 static int aliases;
55 
56 static void setalias(const char *, const char *);
57 static int unalias(const char *);
58 static struct alias **hashalias(const char *);
59 
60 static
61 void
setalias(const char * name,const char * val)62 setalias(const char *name, const char *val)
63 {
64           struct alias *ap, **app;
65 
66           unalias(name);
67           app = hashalias(name);
68           INTOFF;
69           ap = ckmalloc(sizeof (struct alias));
70           ap->name = savestr(name);
71           ap->val = savestr(val);
72           ap->flag = 0;
73           ap->next = *app;
74           *app = ap;
75           aliases++;
76           INTON;
77 }
78 
79 static void
freealias(struct alias * ap)80 freealias(struct alias *ap)
81 {
82           ckfree(ap->name);
83           ckfree(ap->val);
84           ckfree(ap);
85 }
86 
87 static int
unalias(const char * name)88 unalias(const char *name)
89 {
90           struct alias *ap, **app;
91 
92           app = hashalias(name);
93 
94           for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
95                     if (equal(name, ap->name)) {
96                               /*
97                                * if the alias is currently in use (i.e. its
98                                * buffer is being used by the input routine) we
99                                * just null out the name instead of freeing it.
100                                * We could clear it out later, but this situation
101                                * is so rare that it hardly seems worth it.
102                                */
103                               if (ap->flag & ALIASINUSE)
104                                         *ap->name = '\0';
105                               else {
106                                         INTOFF;
107                                         *app = ap->next;
108                                         freealias(ap);
109                                         INTON;
110                               }
111                               aliases--;
112                               return (0);
113                     }
114           }
115 
116           return (1);
117 }
118 
119 static void
rmaliases(void)120 rmaliases(void)
121 {
122           struct alias *ap, **app;
123           int i;
124 
125           INTOFF;
126           for (i = 0; i < ATABSIZE; i++) {
127                     app = &atab[i];
128                     while (*app) {
129                               ap = *app;
130                               if (ap->flag & ALIASINUSE) {
131                                         *ap->name = '\0';
132                                         app = &(*app)->next;
133                               } else {
134                                         *app = ap->next;
135                                         freealias(ap);
136                               }
137                     }
138           }
139           aliases = 0;
140           INTON;
141 }
142 
143 struct alias *
lookupalias(const char * name,int check)144 lookupalias(const char *name, int check)
145 {
146           struct alias *ap;
147 
148           if (aliases == 0)
149                     return (NULL);
150           for (ap = *hashalias(name); ap; ap = ap->next) {
151                     if (equal(name, ap->name)) {
152                               if (check && (ap->flag & ALIASINUSE))
153                                         return (NULL);
154                               return (ap);
155                     }
156           }
157 
158           return (NULL);
159 }
160 
161 static int
comparealiases(const void * p1,const void * p2)162 comparealiases(const void *p1, const void *p2)
163 {
164           const struct alias *const *a1 = p1;
165           const struct alias *const *a2 = p2;
166 
167           return strcmp((*a1)->name, (*a2)->name);
168 }
169 
170 static void
printalias(const struct alias * a)171 printalias(const struct alias *a)
172 {
173           out1fmt("%s=", a->name);
174           out1qstr(a->val);
175           out1c('\n');
176 }
177 
178 static void
printaliases(void)179 printaliases(void)
180 {
181           int i, j;
182           struct alias **sorted, *ap;
183 
184           INTOFF;
185           sorted = ckmalloc(aliases * sizeof(*sorted));
186           j = 0;
187           for (i = 0; i < ATABSIZE; i++)
188                     for (ap = atab[i]; ap; ap = ap->next)
189                               if (*ap->name != '\0')
190                                         sorted[j++] = ap;
191           qsort(sorted, aliases, sizeof(*sorted), comparealiases);
192           for (i = 0; i < aliases; i++) {
193                     printalias(sorted[i]);
194                     if (int_pending())
195                               break;
196           }
197           ckfree(sorted);
198           INTON;
199 }
200 
201 int
aliascmd(int argc __unused,char ** argv __unused)202 aliascmd(int argc __unused, char **argv __unused)
203 {
204           char *n, *v;
205           int ret = 0;
206           struct alias *ap;
207 
208           nextopt("");
209 
210           if (*argptr == NULL) {
211                     printaliases();
212                     return (0);
213           }
214           while ((n = *argptr++) != NULL) {
215                     if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
216                               if ((ap = lookupalias(n, 0)) == NULL) {
217                                         warning("%s: not found", n);
218                                         ret = 1;
219                               } else
220                                         printalias(ap);
221                     else {
222                               *v++ = '\0';
223                               setalias(n, v);
224                     }
225           }
226 
227           return (ret);
228 }
229 
230 int
unaliascmd(int argc __unused,char ** argv __unused)231 unaliascmd(int argc __unused, char **argv __unused)
232 {
233           int i;
234 
235           while ((i = nextopt("a")) != '\0') {
236                     if (i == 'a') {
237                               rmaliases();
238                               return (0);
239                     }
240           }
241           for (i = 0; *argptr; argptr++)
242                     i |= unalias(*argptr);
243 
244           return (i);
245 }
246 
247 static struct alias **
hashalias(const char * p)248 hashalias(const char *p)
249 {
250           unsigned int hashval;
251 
252           hashval = (unsigned char)*p << 4;
253           while (*p)
254                     hashval+= *p++;
255           return &atab[hashval % ATABSIZE];
256 }
257