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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <stdlib.h>
34#include "shell.h"
35#include "output.h"
36#include "error.h"
37#include "memalloc.h"
38#include "mystring.h"
39#include "alias.h"
40#include "options.h"
41#include "builtins.h"
42
43#define ATABSIZE 39
44
45static struct alias *atab[ATABSIZE];
46static int aliases;
47
48static void setalias(const char *, const char *);
49static int unalias(const char *);
50static size_t hashalias(const char *);
51
52static
53void
54setalias(const char *name, const char *val)
55{
56	struct alias *ap, **app;
57
58	unalias(name);
59	app = &atab[hashalias(name)];
60	INTOFF;
61	ap = ckmalloc(sizeof (struct alias));
62	ap->name = savestr(name);
63	ap->val = savestr(val);
64	ap->flag = 0;
65	ap->next = *app;
66	*app = ap;
67	aliases++;
68	INTON;
69}
70
71static void
72freealias(struct alias *ap)
73{
74	ckfree(ap->name);
75	ckfree(ap->val);
76	ckfree(ap);
77}
78
79static int
80unalias(const char *name)
81{
82	struct alias *ap, **app;
83
84	app = &atab[hashalias(name)];
85
86	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
87		if (equal(name, ap->name)) {
88			/*
89			 * if the alias is currently in use (i.e. its
90			 * buffer is being used by the input routine) we
91			 * just null out the name instead of freeing it.
92			 * We could clear it out later, but this situation
93			 * is so rare that it hardly seems worth it.
94			 */
95			if (ap->flag & ALIASINUSE)
96				*ap->name = '\0';
97			else {
98				INTOFF;
99				*app = ap->next;
100				freealias(ap);
101				INTON;
102			}
103			aliases--;
104			return (0);
105		}
106	}
107
108	return (1);
109}
110
111static void
112rmaliases(void)
113{
114	struct alias *ap, **app;
115	int i;
116
117	INTOFF;
118	for (i = 0; i < ATABSIZE; i++) {
119		app = &atab[i];
120		while (*app) {
121			ap = *app;
122			if (ap->flag & ALIASINUSE) {
123				*ap->name = '\0';
124				app = &(*app)->next;
125			} else {
126				*app = ap->next;
127				freealias(ap);
128			}
129		}
130	}
131	aliases = 0;
132	INTON;
133}
134
135struct alias *
136lookupalias(const char *name, int check)
137{
138	struct alias *ap;
139
140	if (aliases == 0)
141		return (NULL);
142	for (ap = atab[hashalias(name)]; ap; ap = ap->next) {
143		if (equal(name, ap->name)) {
144			if (check && (ap->flag & ALIASINUSE))
145				return (NULL);
146			return (ap);
147		}
148	}
149
150	return (NULL);
151}
152
153static int
154comparealiases(const void *p1, const void *p2)
155{
156	const struct alias *const *a1 = p1;
157	const struct alias *const *a2 = p2;
158
159	return strcmp((*a1)->name, (*a2)->name);
160}
161
162static void
163printalias(const struct alias *a)
164{
165	out1fmt("%s=", a->name);
166	out1qstr(a->val);
167	out1c('\n');
168}
169
170static void
171printaliases(void)
172{
173	int i, j;
174	struct alias **sorted, *ap;
175
176	INTOFF;
177	sorted = ckmalloc(aliases * sizeof(*sorted));
178	j = 0;
179	for (i = 0; i < ATABSIZE; i++)
180		for (ap = atab[i]; ap; ap = ap->next)
181			if (*ap->name != '\0')
182				sorted[j++] = ap;
183	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
184	for (i = 0; i < aliases; i++) {
185		printalias(sorted[i]);
186		if (int_pending())
187			break;
188	}
189	ckfree(sorted);
190	INTON;
191}
192
193int
194aliascmd(int argc __unused, char **argv __unused)
195{
196	char *n, *v;
197	int ret = 0;
198	struct alias *ap;
199
200	nextopt("");
201
202	if (*argptr == NULL) {
203		printaliases();
204		return (0);
205	}
206	while ((n = *argptr++) != NULL) {
207		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
208			if ((ap = lookupalias(n, 0)) == NULL) {
209				warning("%s: not found", n);
210				ret = 1;
211			} else
212				printalias(ap);
213		else {
214			*v++ = '\0';
215			setalias(n, v);
216		}
217	}
218
219	return (ret);
220}
221
222int
223unaliascmd(int argc __unused, char **argv __unused)
224{
225	int i;
226
227	while ((i = nextopt("a")) != '\0') {
228		if (i == 'a') {
229			rmaliases();
230			return (0);
231		}
232	}
233	for (i = 0; *argptr; argptr++)
234		i |= unalias(*argptr);
235
236	return (i);
237}
238
239static size_t
240hashalias(const char *p)
241{
242	unsigned int hashval;
243
244	hashval = (unsigned char)*p << 4;
245	while (*p)
246		hashval+= *p++;
247	return (hashval % ATABSIZE);
248}
249
250const struct alias *
251iteralias(const struct alias *index)
252{
253	size_t i = 0;
254
255	if (index != NULL) {
256		if (index->next != NULL)
257			return (index->next);
258		i = hashalias(index->name) + 1;
259	}
260	for (; i < ATABSIZE; i++)
261		if (atab[i] != NULL)
262			return (atab[i]);
263
264	return (NULL);
265}
266