xref: /original-bsd/bin/sh/alias.c (revision 00695d63)
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.2 (Berkeley) 04/28/95";
13 #endif /* not lint */
14 
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 
26 struct alias *atab[ATABSIZE];
27 
28 STATIC struct alias **hashalias __P((char *));
29 
30 STATIC
31 setalias(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 	memmove(ap->val, 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 
83 STATIC int
84 unalias(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
118 MKINIT void rmaliases();
119 
120 SHELLPROC {
121 	rmaliases();
122 }
123 #endif
124 
125 void
126 rmaliases() {
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 
145 struct alias *
146 lookupalias(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  */
165 aliascmd(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 
198 unaliascmd(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 
215 STATIC struct alias **
216 hashalias(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 }
226