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