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 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 05/04/95";
13 #endif /* not lint */
14
15 #include <stdlib.h>
16 #include "shell.h"
17 #include "input.h"
18 #include "output.h"
19 #include "error.h"
20 #include "memalloc.h"
21 #include "mystring.h"
22 #include "alias.h"
23 #include "options.h" /* XXX for argptr (should remove?) */
24
25 #define ATABSIZE 39
26
27 struct alias *atab[ATABSIZE];
28
29 STATIC void setalias __P((char *, char *));
30 STATIC int unalias __P((char *));
31 STATIC struct alias **hashalias __P((char *));
32
33 STATIC
34 void
setalias(name,val)35 setalias(name, val)
36 char *name, *val;
37 {
38 struct alias *ap, **app;
39
40 app = hashalias(name);
41 for (ap = *app; ap; ap = ap->next) {
42 if (equal(name, ap->name)) {
43 INTOFF;
44 ckfree(ap->val);
45 ap->val = savestr(val);
46 INTON;
47 return;
48 }
49 }
50 /* not found */
51 INTOFF;
52 ap = ckmalloc(sizeof (struct alias));
53 ap->name = savestr(name);
54 /*
55 * XXX - HACK: in order that the parser will not finish reading the
56 * alias value off the input before processing the next alias, we
57 * dummy up an extra space at the end of the alias. This is a crock
58 * and should be re-thought. The idea (if you feel inclined to help)
59 * is to avoid alias recursions. The mechanism used is: when
60 * expanding an alias, the value of the alias is pushed back on the
61 * input as a string and a pointer to the alias is stored with the
62 * string. The alias is marked as being in use. When the input
63 * routine finishes reading the string, it markes the alias not
64 * in use. The problem is synchronization with the parser. Since
65 * it reads ahead, the alias is marked not in use before the
66 * resulting token(s) is next checked for further alias sub. The
67 * H A C K is that we add a little fluff after the alias value
68 * so that the string will not be exhausted. This is a good
69 * idea ------- ***NOT***
70 */
71 #ifdef notyet
72 ap->val = savestr(val);
73 #else /* hack */
74 {
75 int len = strlen(val);
76 ap->val = ckmalloc(len + 2);
77 memcpy(ap->val, val, len);
78 ap->val[len] = ' '; /* fluff */
79 ap->val[len+1] = '\0';
80 }
81 #endif
82 ap->next = *app;
83 *app = ap;
84 INTON;
85 }
86
87 STATIC int
unalias(name)88 unalias(name)
89 char *name;
90 {
91 struct alias *ap, **app;
92
93 app = hashalias(name);
94
95 for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
96 if (equal(name, ap->name)) {
97 /*
98 * if the alias is currently in use (i.e. its
99 * buffer is being used by the input routine) we
100 * just null out the name instead of freeing it.
101 * We could clear it out later, but this situation
102 * is so rare that it hardly seems worth it.
103 */
104 if (ap->flag & ALIASINUSE)
105 *ap->name = '\0';
106 else {
107 INTOFF;
108 *app = ap->next;
109 ckfree(ap->name);
110 ckfree(ap->val);
111 ckfree(ap);
112 INTON;
113 }
114 return (0);
115 }
116 }
117
118 return (1);
119 }
120
121 #ifdef mkinit
122 MKINIT void rmaliases();
123
124 SHELLPROC {
125 rmaliases();
126 }
127 #endif
128
129 void
rmaliases()130 rmaliases() {
131 struct alias *ap, *tmp;
132 int i;
133
134 INTOFF;
135 for (i = 0; i < ATABSIZE; i++) {
136 ap = atab[i];
137 atab[i] = NULL;
138 while (ap) {
139 ckfree(ap->name);
140 ckfree(ap->val);
141 tmp = ap;
142 ap = ap->next;
143 ckfree(tmp);
144 }
145 }
146 INTON;
147 }
148
149 struct alias *
lookupalias(name,check)150 lookupalias(name, check)
151 char *name;
152 int check;
153 {
154 struct alias *ap = *hashalias(name);
155
156 for (; ap; ap = ap->next) {
157 if (equal(name, ap->name)) {
158 if (check && (ap->flag & ALIASINUSE))
159 return (NULL);
160 return (ap);
161 }
162 }
163
164 return (NULL);
165 }
166
167 /*
168 * TODO - sort output
169 */
170 int
aliascmd(argc,argv)171 aliascmd(argc, argv)
172 int argc;
173 char **argv;
174 {
175 char *n, *v;
176 int ret = 0;
177 struct alias *ap;
178
179 if (argc == 1) {
180 int i;
181
182 for (i = 0; i < ATABSIZE; i++)
183 for (ap = atab[i]; ap; ap = ap->next) {
184 if (*ap->name != '\0')
185 out1fmt("alias %s=%s\n", ap->name, ap->val);
186 }
187 return (0);
188 }
189 while ((n = *++argv) != NULL) {
190 if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
191 if ((ap = lookupalias(n, 0)) == NULL) {
192 outfmt(out2, "alias: %s not found\n", n);
193 ret = 1;
194 } else
195 out1fmt("alias %s=%s\n", n, ap->val);
196 else {
197 *v++ = '\0';
198 setalias(n, v);
199 }
200 }
201
202 return (ret);
203 }
204
205 int
unaliascmd(argc,argv)206 unaliascmd(argc, argv)
207 int argc;
208 char **argv;
209 {
210 int i;
211
212 while ((i = nextopt("a")) != '\0') {
213 if (i == 'a') {
214 rmaliases();
215 return (0);
216 }
217 }
218 for (i = 0; *argptr; argptr++)
219 i = unalias(*argptr);
220
221 return (i);
222 }
223
224 STATIC struct alias **
hashalias(p)225 hashalias(p)
226 register char *p;
227 {
228 unsigned int hashval;
229
230 hashval = *p << 4;
231 while (*p)
232 hashval+= *p++;
233 return &atab[hashval % ATABSIZE];
234 }
235