xref: /original-bsd/bin/sh/alias.c (revision 0842ddeb)
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
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
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
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 *
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
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
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 **
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