alias.c revision 286813
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 * 4. 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#ifndef lint
34#if 0
35static char sccsid[] = "@(#)alias.c	8.3 (Berkeley) 5/4/95";
36#endif
37#endif /* not lint */
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: stable/10/bin/sh/alias.c 286813 2015-08-15 19:58:00Z jilles $");
40
41#include <stdlib.h>
42#include "shell.h"
43#include "output.h"
44#include "error.h"
45#include "memalloc.h"
46#include "mystring.h"
47#include "alias.h"
48#include "options.h"	/* XXX for argptr (should remove?) */
49#include "builtins.h"
50
51#define ATABSIZE 39
52
53static struct alias *atab[ATABSIZE];
54static int aliases;
55
56static void setalias(const char *, const char *);
57static int unalias(const char *);
58static struct alias **hashalias(const char *);
59
60static
61void
62setalias(const char *name, const char *val)
63{
64	struct alias *ap, **app;
65
66	app = hashalias(name);
67	for (ap = *app; ap; ap = ap->next) {
68		if (equal(name, ap->name)) {
69			INTOFF;
70			ckfree(ap->val);
71			ap->val	= savestr(val);
72			INTON;
73			return;
74		}
75	}
76	/* not found */
77	INTOFF;
78	ap = ckmalloc(sizeof (struct alias));
79	ap->name = savestr(name);
80	ap->val = savestr(val);
81	ap->flag = 0;
82	ap->next = *app;
83	*app = ap;
84	aliases++;
85	INTON;
86}
87
88static int
89unalias(const 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			aliases--;
115			return (0);
116		}
117	}
118
119	return (1);
120}
121
122static void
123rmaliases(void)
124{
125	struct alias *ap, *tmp;
126	int i;
127
128	INTOFF;
129	for (i = 0; i < ATABSIZE; i++) {
130		ap = atab[i];
131		atab[i] = NULL;
132		while (ap) {
133			ckfree(ap->name);
134			ckfree(ap->val);
135			tmp = ap;
136			ap = ap->next;
137			ckfree(tmp);
138		}
139	}
140	aliases = 0;
141	INTON;
142}
143
144struct alias *
145lookupalias(const char *name, int check)
146{
147	struct alias *ap = *hashalias(name);
148
149	for (; ap; ap = ap->next) {
150		if (equal(name, ap->name)) {
151			if (check && (ap->flag & ALIASINUSE))
152				return (NULL);
153			return (ap);
154		}
155	}
156
157	return (NULL);
158}
159
160static int
161comparealiases(const void *p1, const void *p2)
162{
163	const struct alias *const *a1 = p1;
164	const struct alias *const *a2 = p2;
165
166	return strcmp((*a1)->name, (*a2)->name);
167}
168
169static void
170printalias(const struct alias *a)
171{
172	out1fmt("%s=", a->name);
173	out1qstr(a->val);
174	out1c('\n');
175}
176
177static void
178printaliases(void)
179{
180	int i, j;
181	struct alias **sorted, *ap;
182
183	INTOFF;
184	sorted = ckmalloc(aliases * sizeof(*sorted));
185	j = 0;
186	for (i = 0; i < ATABSIZE; i++)
187		for (ap = atab[i]; ap; ap = ap->next)
188			if (*ap->name != '\0')
189				sorted[j++] = ap;
190	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
191	for (i = 0; i < aliases; i++) {
192		printalias(sorted[i]);
193		if (int_pending())
194			break;
195	}
196	ckfree(sorted);
197	INTON;
198}
199
200int
201aliascmd(int argc __unused, char **argv __unused)
202{
203	char *n, *v;
204	int ret = 0;
205	struct alias *ap;
206
207	nextopt("");
208
209	if (*argptr == NULL) {
210		printaliases();
211		return (0);
212	}
213	while ((n = *argptr++) != NULL) {
214		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
215			if ((ap = lookupalias(n, 0)) == NULL) {
216				warning("%s: not found", n);
217				ret = 1;
218			} else
219				printalias(ap);
220		else {
221			*v++ = '\0';
222			setalias(n, v);
223		}
224	}
225
226	return (ret);
227}
228
229int
230unaliascmd(int argc __unused, char **argv __unused)
231{
232	int i;
233
234	while ((i = nextopt("a")) != '\0') {
235		if (i == 'a') {
236			rmaliases();
237			return (0);
238		}
239	}
240	for (i = 0; *argptr; argptr++)
241		i |= unalias(*argptr);
242
243	return (i);
244}
245
246static struct alias **
247hashalias(const char *p)
248{
249	unsigned int hashval;
250
251	hashval = (unsigned char)*p << 4;
252	while (*p)
253		hashval+= *p++;
254	return &atab[hashval % ATABSIZE];
255}
256