alias.c revision 200956
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 200956 2009-12-24 18:41:14Z 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?) */
491556Srgrimes
501556Srgrimes#define ATABSIZE 39
511556Srgrimes
52117261SddsSTATIC struct alias *atab[ATABSIZE];
53190284SstefanfSTATIC int aliases;
541556Srgrimes
55200956SjillesSTATIC void setalias(const char *, const char *);
56179639SrseSTATIC int unalias(const char *);
57179639SrseSTATIC struct alias **hashalias(const char *);
581556Srgrimes
591556SrgrimesSTATIC
6017987Spetervoid
61200956Sjillessetalias(const char *name, const char *val)
6217987Speter{
631556Srgrimes	struct alias *ap, **app;
641556Srgrimes
651556Srgrimes	app = hashalias(name);
661556Srgrimes	for (ap = *app; ap; ap = ap->next) {
671556Srgrimes		if (equal(name, ap->name)) {
681556Srgrimes			INTOFF;
691556Srgrimes			ckfree(ap->val);
701556Srgrimes			ap->val	= savestr(val);
711556Srgrimes			INTON;
721556Srgrimes			return;
731556Srgrimes		}
741556Srgrimes	}
751556Srgrimes	/* not found */
761556Srgrimes	INTOFF;
771556Srgrimes	ap = ckmalloc(sizeof (struct alias));
781556Srgrimes	ap->name = savestr(name);
791556Srgrimes	/*
801556Srgrimes	 * XXX - HACK: in order that the parser will not finish reading the
811556Srgrimes	 * alias value off the input before processing the next alias, we
821556Srgrimes	 * dummy up an extra space at the end of the alias.  This is a crock
831556Srgrimes	 * and should be re-thought.  The idea (if you feel inclined to help)
841556Srgrimes	 * is to avoid alias recursions.  The mechanism used is: when
851556Srgrimes	 * expanding an alias, the value of the alias is pushed back on the
861556Srgrimes	 * input as a string and a pointer to the alias is stored with the
871556Srgrimes	 * string.  The alias is marked as being in use.  When the input
8846684Skris	 * routine finishes reading the string, it marks the alias not
891556Srgrimes	 * in use.  The problem is synchronization with the parser.  Since
901556Srgrimes	 * it reads ahead, the alias is marked not in use before the
911556Srgrimes	 * resulting token(s) is next checked for further alias sub.  The
921556Srgrimes	 * H A C K is that we add a little fluff after the alias value
931556Srgrimes	 * so that the string will not be exhausted.  This is a good
941556Srgrimes	 * idea ------- ***NOT***
951556Srgrimes	 */
961556Srgrimes#ifdef notyet
971556Srgrimes	ap->val = savestr(val);
981556Srgrimes#else /* hack */
991556Srgrimes	{
100193221Srse	size_t len = strlen(val);
1011556Srgrimes	ap->val = ckmalloc(len + 2);
10217987Speter	memcpy(ap->val, val, len);
1031556Srgrimes	ap->val[len] = ' ';	/* fluff */
1041556Srgrimes	ap->val[len+1] = '\0';
1051556Srgrimes	}
1061556Srgrimes#endif
10763223Ssada	ap->flag = 0;
1081556Srgrimes	ap->next = *app;
1091556Srgrimes	*app = ap;
110190284Sstefanf	aliases++;
1111556Srgrimes	INTON;
1121556Srgrimes}
1131556Srgrimes
1141556SrgrimesSTATIC int
115179639Srseunalias(const char *name)
11690111Simp{
1171556Srgrimes	struct alias *ap, **app;
1181556Srgrimes
1191556Srgrimes	app = hashalias(name);
1201556Srgrimes
1211556Srgrimes	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
1221556Srgrimes		if (equal(name, ap->name)) {
1231556Srgrimes			/*
1241556Srgrimes			 * if the alias is currently in use (i.e. its
1251556Srgrimes			 * buffer is being used by the input routine) we
1261556Srgrimes			 * just null out the name instead of freeing it.
1271556Srgrimes			 * We could clear it out later, but this situation
1281556Srgrimes			 * is so rare that it hardly seems worth it.
1291556Srgrimes			 */
1301556Srgrimes			if (ap->flag & ALIASINUSE)
1311556Srgrimes				*ap->name = '\0';
1321556Srgrimes			else {
1331556Srgrimes				INTOFF;
1341556Srgrimes				*app = ap->next;
1351556Srgrimes				ckfree(ap->name);
1361556Srgrimes				ckfree(ap->val);
1371556Srgrimes				ckfree(ap);
1381556Srgrimes				INTON;
1391556Srgrimes			}
140190284Sstefanf			aliases--;
1411556Srgrimes			return (0);
1421556Srgrimes		}
1431556Srgrimes	}
1441556Srgrimes
1451556Srgrimes	return (1);
1461556Srgrimes}
1471556Srgrimes
1481556Srgrimes#ifdef mkinit
149149016SstefanfMKINIT void rmaliases(void);
1501556Srgrimes
1511556SrgrimesSHELLPROC {
1521556Srgrimes	rmaliases();
1531556Srgrimes}
1541556Srgrimes#endif
1551556Srgrimes
1561556Srgrimesvoid
15790111Simprmaliases(void)
15890111Simp{
1591556Srgrimes	struct alias *ap, *tmp;
1601556Srgrimes	int i;
1611556Srgrimes
1621556Srgrimes	INTOFF;
1631556Srgrimes	for (i = 0; i < ATABSIZE; i++) {
1641556Srgrimes		ap = atab[i];
1651556Srgrimes		atab[i] = NULL;
1661556Srgrimes		while (ap) {
1671556Srgrimes			ckfree(ap->name);
1681556Srgrimes			ckfree(ap->val);
1691556Srgrimes			tmp = ap;
1701556Srgrimes			ap = ap->next;
1711556Srgrimes			ckfree(tmp);
1721556Srgrimes		}
1731556Srgrimes	}
174190284Sstefanf	aliases = 0;
1751556Srgrimes	INTON;
1761556Srgrimes}
1771556Srgrimes
1781556Srgrimesstruct alias *
179200956Sjilleslookupalias(const char *name, int check)
18017987Speter{
1811556Srgrimes	struct alias *ap = *hashalias(name);
1821556Srgrimes
1831556Srgrimes	for (; ap; ap = ap->next) {
1841556Srgrimes		if (equal(name, ap->name)) {
1851556Srgrimes			if (check && (ap->flag & ALIASINUSE))
1861556Srgrimes				return (NULL);
1871556Srgrimes			return (ap);
1881556Srgrimes		}
1891556Srgrimes	}
1901556Srgrimes
1911556Srgrimes	return (NULL);
1921556Srgrimes}
1931556Srgrimes
194190284Sstefanfstatic int
195190284Sstefanfcomparealiases(const void *p1, const void *p2)
196190284Sstefanf{
197190284Sstefanf	const struct alias *const *a1 = p1;
198190284Sstefanf	const struct alias *const *a2 = p2;
199190284Sstefanf
200190284Sstefanf	return strcmp((*a1)->name, (*a2)->name);
201190284Sstefanf}
202190284Sstefanf
203190284Sstefanfstatic void
204190284Sstefanfprintalias(const struct alias *a)
205190284Sstefanf{
206190284Sstefanf	char *p;
207190284Sstefanf
208190284Sstefanf	out1fmt("%s=", a->name);
209190284Sstefanf	/* Don't print the space added above. */
210190284Sstefanf	p = a->val + strlen(a->val) - 1;
211190284Sstefanf	*p = '\0';
212190284Sstefanf	out1qstr(a->val);
213190284Sstefanf	*p = ' ';
214190284Sstefanf	out1c('\n');
215190284Sstefanf}
216190284Sstefanf
217190284Sstefanfstatic void
218190284Sstefanfprintaliases(void)
219190284Sstefanf{
220190284Sstefanf	int i, j;
221190284Sstefanf	struct alias **sorted, *ap;
222190284Sstefanf
223190284Sstefanf	sorted = ckmalloc(aliases * sizeof(*sorted));
224190284Sstefanf	j = 0;
225190284Sstefanf	for (i = 0; i < ATABSIZE; i++)
226190284Sstefanf		for (ap = atab[i]; ap; ap = ap->next)
227190284Sstefanf			if (*ap->name != '\0')
228190284Sstefanf				sorted[j++] = ap;
229190284Sstefanf	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
230190284Sstefanf	for (i = 0; i < aliases; i++)
231190284Sstefanf		printalias(sorted[i]);
232190284Sstefanf	ckfree(sorted);
233190284Sstefanf}
234190284Sstefanf
23517987Speterint
23690111Simpaliascmd(int argc, char **argv)
23717987Speter{
2381556Srgrimes	char *n, *v;
2391556Srgrimes	int ret = 0;
2401556Srgrimes	struct alias *ap;
2411556Srgrimes
2421556Srgrimes	if (argc == 1) {
243190284Sstefanf		printaliases();
2441556Srgrimes		return (0);
2451556Srgrimes	}
24617987Speter	while ((n = *++argv) != NULL) {
2471556Srgrimes		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
2481556Srgrimes			if ((ap = lookupalias(n, 0)) == NULL) {
2491556Srgrimes				outfmt(out2, "alias: %s not found\n", n);
2501556Srgrimes				ret = 1;
251190284Sstefanf			} else
252190284Sstefanf				printalias(ap);
2531556Srgrimes		else {
2541556Srgrimes			*v++ = '\0';
2551556Srgrimes			setalias(n, v);
2561556Srgrimes		}
2571556Srgrimes	}
2581556Srgrimes
2591556Srgrimes	return (ret);
2601556Srgrimes}
2611556Srgrimes
26217987Speterint
26390111Simpunaliascmd(int argc __unused, char **argv __unused)
26417987Speter{
2651556Srgrimes	int i;
2668855Srgrimes
2671556Srgrimes	while ((i = nextopt("a")) != '\0') {
2681556Srgrimes		if (i == 'a') {
2691556Srgrimes			rmaliases();
2701556Srgrimes			return (0);
2711556Srgrimes		}
2721556Srgrimes	}
2731556Srgrimes	for (i = 0; *argptr; argptr++)
274149743Sstefanf		i |= unalias(*argptr);
2751556Srgrimes
2761556Srgrimes	return (i);
2771556Srgrimes}
2781556Srgrimes
2791556SrgrimesSTATIC struct alias **
280179639Srsehashalias(const char *p)
28190111Simp{
2821556Srgrimes	unsigned int hashval;
2831556Srgrimes
2841556Srgrimes	hashval = *p << 4;
2851556Srgrimes	while (*p)
2861556Srgrimes		hashval+= *p++;
2871556Srgrimes	return &atab[hashval % ATABSIZE];
2881556Srgrimes}
289