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