alias.c revision 254849
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)alias.c	8.3 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/alias.c 254849 2013-08-25 11:42:53Z jilles $");
401556Srgrimes
4117987Speter#include <stdlib.h>
421556Srgrimes#include "shell.h"
431556Srgrimes#include "output.h"
441556Srgrimes#include "error.h"
451556Srgrimes#include "memalloc.h"
461556Srgrimes#include "mystring.h"
471556Srgrimes#include "alias.h"
481556Srgrimes#include "options.h"	/* XXX for argptr (should remove?) */
49223060Sjilles#include "builtins.h"
501556Srgrimes
511556Srgrimes#define ATABSIZE 39
521556Srgrimes
53213760Sobrienstatic struct alias *atab[ATABSIZE];
54213760Sobrienstatic int aliases;
551556Srgrimes
56213811Sobrienstatic void setalias(const char *, const char *);
57213811Sobrienstatic int unalias(const char *);
58213811Sobrienstatic struct alias **hashalias(const char *);
591556Srgrimes
60213811Sobrienstatic
6117987Spetervoid
62200956Sjillessetalias(const char *name, const char *val)
6317987Speter{
641556Srgrimes	struct alias *ap, **app;
651556Srgrimes
661556Srgrimes	app = hashalias(name);
671556Srgrimes	for (ap = *app; ap; ap = ap->next) {
681556Srgrimes		if (equal(name, ap->name)) {
691556Srgrimes			INTOFF;
701556Srgrimes			ckfree(ap->val);
71242766Sjilles			/* See HACK below. */
72242766Sjilles#ifdef notyet
731556Srgrimes			ap->val	= savestr(val);
74242766Sjilles#else
75242766Sjilles			{
76242766Sjilles			size_t len = strlen(val);
77242766Sjilles			ap->val = ckmalloc(len + 2);
78242766Sjilles			memcpy(ap->val, val, len);
79242766Sjilles			ap->val[len] = ' ';
80242766Sjilles			ap->val[len+1] = '\0';
81242766Sjilles			}
82242766Sjilles#endif
831556Srgrimes			INTON;
841556Srgrimes			return;
851556Srgrimes		}
861556Srgrimes	}
871556Srgrimes	/* not found */
881556Srgrimes	INTOFF;
891556Srgrimes	ap = ckmalloc(sizeof (struct alias));
901556Srgrimes	ap->name = savestr(name);
911556Srgrimes	/*
921556Srgrimes	 * XXX - HACK: in order that the parser will not finish reading the
931556Srgrimes	 * alias value off the input before processing the next alias, we
941556Srgrimes	 * dummy up an extra space at the end of the alias.  This is a crock
951556Srgrimes	 * and should be re-thought.  The idea (if you feel inclined to help)
961556Srgrimes	 * is to avoid alias recursions.  The mechanism used is: when
971556Srgrimes	 * expanding an alias, the value of the alias is pushed back on the
981556Srgrimes	 * input as a string and a pointer to the alias is stored with the
991556Srgrimes	 * string.  The alias is marked as being in use.  When the input
10046684Skris	 * routine finishes reading the string, it marks the alias not
1011556Srgrimes	 * in use.  The problem is synchronization with the parser.  Since
1021556Srgrimes	 * it reads ahead, the alias is marked not in use before the
1031556Srgrimes	 * resulting token(s) is next checked for further alias sub.  The
1041556Srgrimes	 * H A C K is that we add a little fluff after the alias value
1051556Srgrimes	 * so that the string will not be exhausted.  This is a good
1061556Srgrimes	 * idea ------- ***NOT***
1071556Srgrimes	 */
1081556Srgrimes#ifdef notyet
1091556Srgrimes	ap->val = savestr(val);
1101556Srgrimes#else /* hack */
1111556Srgrimes	{
112193221Srse	size_t len = strlen(val);
1131556Srgrimes	ap->val = ckmalloc(len + 2);
11417987Speter	memcpy(ap->val, val, len);
1151556Srgrimes	ap->val[len] = ' ';	/* fluff */
1161556Srgrimes	ap->val[len+1] = '\0';
1171556Srgrimes	}
1181556Srgrimes#endif
11963223Ssada	ap->flag = 0;
1201556Srgrimes	ap->next = *app;
1211556Srgrimes	*app = ap;
122190284Sstefanf	aliases++;
1231556Srgrimes	INTON;
1241556Srgrimes}
1251556Srgrimes
126213811Sobrienstatic int
127179639Srseunalias(const char *name)
12890111Simp{
1291556Srgrimes	struct alias *ap, **app;
1301556Srgrimes
1311556Srgrimes	app = hashalias(name);
1321556Srgrimes
1331556Srgrimes	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
1341556Srgrimes		if (equal(name, ap->name)) {
1351556Srgrimes			/*
1361556Srgrimes			 * if the alias is currently in use (i.e. its
1371556Srgrimes			 * buffer is being used by the input routine) we
1381556Srgrimes			 * just null out the name instead of freeing it.
1391556Srgrimes			 * We could clear it out later, but this situation
1401556Srgrimes			 * is so rare that it hardly seems worth it.
1411556Srgrimes			 */
1421556Srgrimes			if (ap->flag & ALIASINUSE)
1431556Srgrimes				*ap->name = '\0';
1441556Srgrimes			else {
1451556Srgrimes				INTOFF;
1461556Srgrimes				*app = ap->next;
1471556Srgrimes				ckfree(ap->name);
1481556Srgrimes				ckfree(ap->val);
1491556Srgrimes				ckfree(ap);
1501556Srgrimes				INTON;
1511556Srgrimes			}
152190284Sstefanf			aliases--;
1531556Srgrimes			return (0);
1541556Srgrimes		}
1551556Srgrimes	}
1561556Srgrimes
1571556Srgrimes	return (1);
1581556Srgrimes}
1591556Srgrimes
160218306Sjillesstatic void
16190111Simprmaliases(void)
16290111Simp{
1631556Srgrimes	struct alias *ap, *tmp;
1641556Srgrimes	int i;
1651556Srgrimes
1661556Srgrimes	INTOFF;
1671556Srgrimes	for (i = 0; i < ATABSIZE; i++) {
1681556Srgrimes		ap = atab[i];
1691556Srgrimes		atab[i] = NULL;
1701556Srgrimes		while (ap) {
1711556Srgrimes			ckfree(ap->name);
1721556Srgrimes			ckfree(ap->val);
1731556Srgrimes			tmp = ap;
1741556Srgrimes			ap = ap->next;
1751556Srgrimes			ckfree(tmp);
1761556Srgrimes		}
1771556Srgrimes	}
178190284Sstefanf	aliases = 0;
1791556Srgrimes	INTON;
1801556Srgrimes}
1811556Srgrimes
1821556Srgrimesstruct alias *
183200956Sjilleslookupalias(const char *name, int check)
18417987Speter{
1851556Srgrimes	struct alias *ap = *hashalias(name);
1861556Srgrimes
1871556Srgrimes	for (; ap; ap = ap->next) {
1881556Srgrimes		if (equal(name, ap->name)) {
1891556Srgrimes			if (check && (ap->flag & ALIASINUSE))
1901556Srgrimes				return (NULL);
1911556Srgrimes			return (ap);
1921556Srgrimes		}
1931556Srgrimes	}
1941556Srgrimes
1951556Srgrimes	return (NULL);
1961556Srgrimes}
1971556Srgrimes
198213811Sobrienstatic int
199190284Sstefanfcomparealiases(const void *p1, const void *p2)
200190284Sstefanf{
201190284Sstefanf	const struct alias *const *a1 = p1;
202190284Sstefanf	const struct alias *const *a2 = p2;
203190284Sstefanf
204190284Sstefanf	return strcmp((*a1)->name, (*a2)->name);
205190284Sstefanf}
206190284Sstefanf
207213811Sobrienstatic void
208190284Sstefanfprintalias(const struct alias *a)
209190284Sstefanf{
210190284Sstefanf	char *p;
211190284Sstefanf
212190284Sstefanf	out1fmt("%s=", a->name);
213190284Sstefanf	/* Don't print the space added above. */
214190284Sstefanf	p = a->val + strlen(a->val) - 1;
215190284Sstefanf	*p = '\0';
216190284Sstefanf	out1qstr(a->val);
217190284Sstefanf	*p = ' ';
218190284Sstefanf	out1c('\n');
219190284Sstefanf}
220190284Sstefanf
221213811Sobrienstatic void
222190284Sstefanfprintaliases(void)
223190284Sstefanf{
224190284Sstefanf	int i, j;
225190284Sstefanf	struct alias **sorted, *ap;
226190284Sstefanf
227190284Sstefanf	sorted = ckmalloc(aliases * sizeof(*sorted));
228190284Sstefanf	j = 0;
229190284Sstefanf	for (i = 0; i < ATABSIZE; i++)
230190284Sstefanf		for (ap = atab[i]; ap; ap = ap->next)
231190284Sstefanf			if (*ap->name != '\0')
232190284Sstefanf				sorted[j++] = ap;
233190284Sstefanf	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
234190284Sstefanf	for (i = 0; i < aliases; i++)
235190284Sstefanf		printalias(sorted[i]);
236190284Sstefanf	ckfree(sorted);
237190284Sstefanf}
238190284Sstefanf
23917987Speterint
240254849Sjillesaliascmd(int argc __unused, char **argv __unused)
24117987Speter{
2421556Srgrimes	char *n, *v;
2431556Srgrimes	int ret = 0;
2441556Srgrimes	struct alias *ap;
2451556Srgrimes
246254849Sjilles	nextopt("");
247254849Sjilles
248254849Sjilles	if (*argptr == NULL) {
249190284Sstefanf		printaliases();
2501556Srgrimes		return (0);
2511556Srgrimes	}
252254849Sjilles	while ((n = *argptr++) != NULL) {
2531556Srgrimes		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
2541556Srgrimes			if ((ap = lookupalias(n, 0)) == NULL) {
255222684Sjilles				warning("%s: not found", n);
2561556Srgrimes				ret = 1;
257190284Sstefanf			} else
258190284Sstefanf				printalias(ap);
2591556Srgrimes		else {
2601556Srgrimes			*v++ = '\0';
2611556Srgrimes			setalias(n, v);
2621556Srgrimes		}
2631556Srgrimes	}
2641556Srgrimes
2651556Srgrimes	return (ret);
2661556Srgrimes}
2671556Srgrimes
26817987Speterint
26990111Simpunaliascmd(int argc __unused, char **argv __unused)
27017987Speter{
2711556Srgrimes	int i;
2728855Srgrimes
2731556Srgrimes	while ((i = nextopt("a")) != '\0') {
2741556Srgrimes		if (i == 'a') {
2751556Srgrimes			rmaliases();
2761556Srgrimes			return (0);
2771556Srgrimes		}
2781556Srgrimes	}
2791556Srgrimes	for (i = 0; *argptr; argptr++)
280149743Sstefanf		i |= unalias(*argptr);
2811556Srgrimes
2821556Srgrimes	return (i);
2831556Srgrimes}
2841556Srgrimes
285213811Sobrienstatic struct alias **
286179639Srsehashalias(const char *p)
28790111Simp{
2881556Srgrimes	unsigned int hashval;
2891556Srgrimes
2901556Srgrimes	hashval = *p << 4;
2911556Srgrimes	while (*p)
2921556Srgrimes		hashval+= *p++;
2931556Srgrimes	return &atab[hashval % ATABSIZE];
2941556Srgrimes}
295