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