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$");
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);
71243402Sjilles			/* See HACK below. */
72243402Sjilles#ifdef notyet
731556Srgrimes			ap->val	= savestr(val);
74243402Sjilles#else
75243402Sjilles			{
76243402Sjilles			size_t len = strlen(val);
77243402Sjilles			ap->val = ckmalloc(len + 2);
78243402Sjilles			memcpy(ap->val, val, len);
79243402Sjilles			ap->val[len] = ' ';
80243402Sjilles			ap->val[len+1] = '\0';
81243402Sjilles			}
82243402Sjilles#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
227264629Sjilles	INTOFF;
228190284Sstefanf	sorted = ckmalloc(aliases * sizeof(*sorted));
229190284Sstefanf	j = 0;
230190284Sstefanf	for (i = 0; i < ATABSIZE; i++)
231190284Sstefanf		for (ap = atab[i]; ap; ap = ap->next)
232190284Sstefanf			if (*ap->name != '\0')
233190284Sstefanf				sorted[j++] = ap;
234190284Sstefanf	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
235264629Sjilles	for (i = 0; i < aliases; i++) {
236190284Sstefanf		printalias(sorted[i]);
237264629Sjilles		if (int_pending())
238264629Sjilles			break;
239264629Sjilles	}
240190284Sstefanf	ckfree(sorted);
241264629Sjilles	INTON;
242190284Sstefanf}
243190284Sstefanf
24417987Speterint
24590111Simpaliascmd(int argc, char **argv)
24617987Speter{
2471556Srgrimes	char *n, *v;
2481556Srgrimes	int ret = 0;
2491556Srgrimes	struct alias *ap;
2501556Srgrimes
2511556Srgrimes	if (argc == 1) {
252190284Sstefanf		printaliases();
2531556Srgrimes		return (0);
2541556Srgrimes	}
25517987Speter	while ((n = *++argv) != NULL) {
2561556Srgrimes		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
2571556Srgrimes			if ((ap = lookupalias(n, 0)) == NULL) {
258222684Sjilles				warning("%s: not found", n);
2591556Srgrimes				ret = 1;
260190284Sstefanf			} else
261190284Sstefanf				printalias(ap);
2621556Srgrimes		else {
2631556Srgrimes			*v++ = '\0';
2641556Srgrimes			setalias(n, v);
2651556Srgrimes		}
2661556Srgrimes	}
2671556Srgrimes
2681556Srgrimes	return (ret);
2691556Srgrimes}
2701556Srgrimes
27117987Speterint
27290111Simpunaliascmd(int argc __unused, char **argv __unused)
27317987Speter{
2741556Srgrimes	int i;
2758855Srgrimes
2761556Srgrimes	while ((i = nextopt("a")) != '\0') {
2771556Srgrimes		if (i == 'a') {
2781556Srgrimes			rmaliases();
2791556Srgrimes			return (0);
2801556Srgrimes		}
2811556Srgrimes	}
2821556Srgrimes	for (i = 0; *argptr; argptr++)
283149743Sstefanf		i |= unalias(*argptr);
2841556Srgrimes
2851556Srgrimes	return (i);
2861556Srgrimes}
2871556Srgrimes
288213811Sobrienstatic struct alias **
289179639Srsehashalias(const char *p)
29090111Simp{
2911556Srgrimes	unsigned int hashval;
2921556Srgrimes
2931556Srgrimes	hashval = *p << 4;
2941556Srgrimes	while (*p)
2951556Srgrimes		hashval+= *p++;
2961556Srgrimes	return &atab[hashval % ATABSIZE];
2971556Srgrimes}
298