]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - bin/sh/alias.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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  * 4. 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$");
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"    /* XXX for argptr (should remove?) */
49
50 #define ATABSIZE 39
51
52 STATIC struct alias *atab[ATABSIZE];
53 STATIC int aliases;
54
55 STATIC void setalias(char *, char *);
56 STATIC int unalias(const char *);
57 STATIC struct alias **hashalias(const char *);
58
59 STATIC
60 void
61 setalias(char *name, char *val)
62 {
63         struct alias *ap, **app;
64
65         app = hashalias(name);
66         for (ap = *app; ap; ap = ap->next) {
67                 if (equal(name, ap->name)) {
68                         INTOFF;
69                         ckfree(ap->val);
70                         ap->val = savestr(val);
71                         INTON;
72                         return;
73                 }
74         }
75         /* not found */
76         INTOFF;
77         ap = ckmalloc(sizeof (struct alias));
78         ap->name = savestr(name);
79         /*
80          * XXX - HACK: in order that the parser will not finish reading the
81          * alias value off the input before processing the next alias, we
82          * dummy up an extra space at the end of the alias.  This is a crock
83          * and should be re-thought.  The idea (if you feel inclined to help)
84          * is to avoid alias recursions.  The mechanism used is: when
85          * expanding an alias, the value of the alias is pushed back on the
86          * input as a string and a pointer to the alias is stored with the
87          * string.  The alias is marked as being in use.  When the input
88          * routine finishes reading the string, it marks the alias not
89          * in use.  The problem is synchronization with the parser.  Since
90          * it reads ahead, the alias is marked not in use before the
91          * resulting token(s) is next checked for further alias sub.  The
92          * H A C K is that we add a little fluff after the alias value
93          * so that the string will not be exhausted.  This is a good
94          * idea ------- ***NOT***
95          */
96 #ifdef notyet
97         ap->val = savestr(val);
98 #else /* hack */
99         {
100         size_t len = strlen(val);
101         ap->val = ckmalloc(len + 2);
102         memcpy(ap->val, val, len);
103         ap->val[len] = ' ';     /* fluff */
104         ap->val[len+1] = '\0';
105         }
106 #endif
107         ap->flag = 0;
108         ap->next = *app;
109         *app = ap;
110         aliases++;
111         INTON;
112 }
113
114 STATIC int
115 unalias(const char *name)
116 {
117         struct alias *ap, **app;
118
119         app = hashalias(name);
120
121         for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
122                 if (equal(name, ap->name)) {
123                         /*
124                          * if the alias is currently in use (i.e. its
125                          * buffer is being used by the input routine) we
126                          * just null out the name instead of freeing it.
127                          * We could clear it out later, but this situation
128                          * is so rare that it hardly seems worth it.
129                          */
130                         if (ap->flag & ALIASINUSE)
131                                 *ap->name = '\0';
132                         else {
133                                 INTOFF;
134                                 *app = ap->next;
135                                 ckfree(ap->name);
136                                 ckfree(ap->val);
137                                 ckfree(ap);
138                                 INTON;
139                         }
140                         aliases--;
141                         return (0);
142                 }
143         }
144
145         return (1);
146 }
147
148 #ifdef mkinit
149 MKINIT void rmaliases(void);
150
151 SHELLPROC {
152         rmaliases();
153 }
154 #endif
155
156 void
157 rmaliases(void)
158 {
159         struct alias *ap, *tmp;
160         int i;
161
162         INTOFF;
163         for (i = 0; i < ATABSIZE; i++) {
164                 ap = atab[i];
165                 atab[i] = NULL;
166                 while (ap) {
167                         ckfree(ap->name);
168                         ckfree(ap->val);
169                         tmp = ap;
170                         ap = ap->next;
171                         ckfree(tmp);
172                 }
173         }
174         aliases = 0;
175         INTON;
176 }
177
178 struct alias *
179 lookupalias(char *name, int check)
180 {
181         struct alias *ap = *hashalias(name);
182
183         for (; ap; ap = ap->next) {
184                 if (equal(name, ap->name)) {
185                         if (check && (ap->flag & ALIASINUSE))
186                                 return (NULL);
187                         return (ap);
188                 }
189         }
190
191         return (NULL);
192 }
193
194 static int
195 comparealiases(const void *p1, const void *p2)
196 {
197         const struct alias *const *a1 = p1;
198         const struct alias *const *a2 = p2;
199
200         return strcmp((*a1)->name, (*a2)->name);
201 }
202
203 static void
204 printalias(const struct alias *a)
205 {
206         char *p;
207
208         out1fmt("%s=", a->name);
209         /* Don't print the space added above. */
210         p = a->val + strlen(a->val) - 1;
211         *p = '\0';
212         out1qstr(a->val);
213         *p = ' ';
214         out1c('\n');
215 }
216
217 static void
218 printaliases(void)
219 {
220         int i, j;
221         struct alias **sorted, *ap;
222
223         sorted = ckmalloc(aliases * sizeof(*sorted));
224         j = 0;
225         for (i = 0; i < ATABSIZE; i++)
226                 for (ap = atab[i]; ap; ap = ap->next)
227                         if (*ap->name != '\0')
228                                 sorted[j++] = ap;
229         qsort(sorted, aliases, sizeof(*sorted), comparealiases);
230         for (i = 0; i < aliases; i++)
231                 printalias(sorted[i]);
232         ckfree(sorted);
233 }
234
235 int
236 aliascmd(int argc, char **argv)
237 {
238         char *n, *v;
239         int ret = 0;
240         struct alias *ap;
241
242         if (argc == 1) {
243                 printaliases();
244                 return (0);
245         }
246         while ((n = *++argv) != NULL) {
247                 if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
248                         if ((ap = lookupalias(n, 0)) == NULL) {
249                                 outfmt(out2, "alias: %s not found\n", n);
250                                 ret = 1;
251                         } else
252                                 printalias(ap);
253                 else {
254                         *v++ = '\0';
255                         setalias(n, v);
256                 }
257         }
258
259         return (ret);
260 }
261
262 int
263 unaliascmd(int argc __unused, char **argv __unused)
264 {
265         int i;
266
267         while ((i = nextopt("a")) != '\0') {
268                 if (i == 'a') {
269                         rmaliases();
270                         return (0);
271                 }
272         }
273         for (i = 0; *argptr; argptr++)
274                 i |= unalias(*argptr);
275
276         return (i);
277 }
278
279 STATIC struct alias **
280 hashalias(const char *p)
281 {
282         unsigned int hashval;
283
284         hashval = *p << 4;
285         while (*p)
286                 hashval+= *p++;
287         return &atab[hashval % ATABSIZE];
288 }