alias.c revision 218306
190792Sgshapiro/*-
2261363Sgshapiro * Copyright (c) 1993
390792Sgshapiro *	The Regents of the University of California.  All rights reserved.
490792Sgshapiro *
590792Sgshapiro * This code is derived from software contributed to Berkeley by
690792Sgshapiro * Kenneth Almquist.
790792Sgshapiro *
890792Sgshapiro * Redistribution and use in source and binary forms, with or without
990792Sgshapiro * modification, are permitted provided that the following conditions
1090792Sgshapiro * are met:
1190792Sgshapiro * 1. Redistributions of source code must retain the above copyright
1290792Sgshapiro *    notice, this list of conditions and the following disclaimer.
1390792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright
14266692Sgshapiro *    notice, this list of conditions and the following disclaimer in the
1590792Sgshapiro *    documentation and/or other materials provided with the distribution.
1690792Sgshapiro * 4. Neither the name of the University nor the names of its contributors
1790792Sgshapiro *    may be used to endorse or promote products derived from this software
1890792Sgshapiro *    without specific prior written permission.
1990792Sgshapiro *
2090792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2190792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2290792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2390792Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2490792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2590792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2690792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2790792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2890792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2990792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3090792Sgshapiro * SUCH DAMAGE.
3190792Sgshapiro */
3290792Sgshapiro
3390792Sgshapiro#ifndef lint
3490792Sgshapiro#if 0
3590792Sgshapirostatic char sccsid[] = "@(#)alias.c	8.3 (Berkeley) 5/4/95";
3690792Sgshapiro#endif
3790792Sgshapiro#endif /* not lint */
3890792Sgshapiro#include <sys/cdefs.h>
3990792Sgshapiro__FBSDID("$FreeBSD: head/bin/sh/alias.c 218306 2011-02-04 22:47:55Z jilles $");
4090792Sgshapiro
4190792Sgshapiro#include <stdlib.h>
4290792Sgshapiro#include "shell.h"
4390792Sgshapiro#include "output.h"
4490792Sgshapiro#include "error.h"
45120256Sgshapiro#include "memalloc.h"
46120256Sgshapiro#include "mystring.h"
4790792Sgshapiro#include "alias.h"
4890792Sgshapiro#include "options.h"	/* XXX for argptr (should remove?) */
4990792Sgshapiro
5090792Sgshapiro#define ATABSIZE 39
5190792Sgshapiro
5290792Sgshapirostatic struct alias *atab[ATABSIZE];
5390792Sgshapirostatic int aliases;
5490792Sgshapiro
55120256Sgshapirostatic void setalias(const char *, const char *);
5690792Sgshapirostatic int unalias(const char *);
5790792Sgshapirostatic struct alias **hashalias(const char *);
5890792Sgshapiro
5990792Sgshapirostatic
6090792Sgshapirovoid
6190792Sgshapirosetalias(const char *name, const char *val)
6290792Sgshapiro{
6390792Sgshapiro	struct alias *ap, **app;
6490792Sgshapiro
6590792Sgshapiro	app = hashalias(name);
6690792Sgshapiro	for (ap = *app; ap; ap = ap->next) {
6790792Sgshapiro		if (equal(name, ap->name)) {
6890792Sgshapiro			INTOFF;
6990792Sgshapiro			ckfree(ap->val);
7090792Sgshapiro			ap->val	= savestr(val);
7190792Sgshapiro			INTON;
7290792Sgshapiro			return;
7390792Sgshapiro		}
7490792Sgshapiro	}
7590792Sgshapiro	/* not found */
7690792Sgshapiro	INTOFF;
7790792Sgshapiro	ap = ckmalloc(sizeof (struct alias));
7890792Sgshapiro	ap->name = savestr(name);
7990792Sgshapiro	/*
8090792Sgshapiro	 * XXX - HACK: in order that the parser will not finish reading the
8190792Sgshapiro	 * alias value off the input before processing the next alias, we
8290792Sgshapiro	 * dummy up an extra space at the end of the alias.  This is a crock
8390792Sgshapiro	 * and should be re-thought.  The idea (if you feel inclined to help)
8490792Sgshapiro	 * is to avoid alias recursions.  The mechanism used is: when
8590792Sgshapiro	 * expanding an alias, the value of the alias is pushed back on the
8690792Sgshapiro	 * input as a string and a pointer to the alias is stored with the
8790792Sgshapiro	 * string.  The alias is marked as being in use.  When the input
8890792Sgshapiro	 * routine finishes reading the string, it marks the alias not
8990792Sgshapiro	 * in use.  The problem is synchronization with the parser.  Since
9090792Sgshapiro	 * it reads ahead, the alias is marked not in use before the
9190792Sgshapiro	 * resulting token(s) is next checked for further alias sub.  The
9290792Sgshapiro	 * H A C K is that we add a little fluff after the alias value
9390792Sgshapiro	 * so that the string will not be exhausted.  This is a good
9490792Sgshapiro	 * idea ------- ***NOT***
9590792Sgshapiro	 */
9690792Sgshapiro#ifdef notyet
9790792Sgshapiro	ap->val = savestr(val);
9890792Sgshapiro#else /* hack */
9990792Sgshapiro	{
10090792Sgshapiro	size_t len = strlen(val);
10190792Sgshapiro	ap->val = ckmalloc(len + 2);
10290792Sgshapiro	memcpy(ap->val, val, len);
10390792Sgshapiro	ap->val[len] = ' ';	/* fluff */
10490792Sgshapiro	ap->val[len+1] = '\0';
10590792Sgshapiro	}
10690792Sgshapiro#endif
10790792Sgshapiro	ap->flag = 0;
10890792Sgshapiro	ap->next = *app;
10990792Sgshapiro	*app = ap;
11090792Sgshapiro	aliases++;
11190792Sgshapiro	INTON;
11290792Sgshapiro}
11390792Sgshapiro
11490792Sgshapirostatic int
11590792Sgshapirounalias(const char *name)
11690792Sgshapiro{
11790792Sgshapiro	struct alias *ap, **app;
11890792Sgshapiro
11990792Sgshapiro	app = hashalias(name);
12090792Sgshapiro
12190792Sgshapiro	for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
12290792Sgshapiro		if (equal(name, ap->name)) {
12390792Sgshapiro			/*
12490792Sgshapiro			 * if the alias is currently in use (i.e. its
12590792Sgshapiro			 * buffer is being used by the input routine) we
12690792Sgshapiro			 * just null out the name instead of freeing it.
12790792Sgshapiro			 * We could clear it out later, but this situation
12890792Sgshapiro			 * is so rare that it hardly seems worth it.
12990792Sgshapiro			 */
13090792Sgshapiro			if (ap->flag & ALIASINUSE)
13190792Sgshapiro				*ap->name = '\0';
13290792Sgshapiro			else {
13390792Sgshapiro				INTOFF;
13490792Sgshapiro				*app = ap->next;
13590792Sgshapiro				ckfree(ap->name);
13690792Sgshapiro				ckfree(ap->val);
13790792Sgshapiro				ckfree(ap);
13890792Sgshapiro				INTON;
13990792Sgshapiro			}
14090792Sgshapiro			aliases--;
14190792Sgshapiro			return (0);
14290792Sgshapiro		}
14390792Sgshapiro	}
14490792Sgshapiro
14590792Sgshapiro	return (1);
14690792Sgshapiro}
14790792Sgshapiro
14890792Sgshapirostatic void
14990792Sgshapirormaliases(void)
15090792Sgshapiro{
15190792Sgshapiro	struct alias *ap, *tmp;
15290792Sgshapiro	int i;
15390792Sgshapiro
15490792Sgshapiro	INTOFF;
15590792Sgshapiro	for (i = 0; i < ATABSIZE; i++) {
15690792Sgshapiro		ap = atab[i];
15790792Sgshapiro		atab[i] = NULL;
15890792Sgshapiro		while (ap) {
15990792Sgshapiro			ckfree(ap->name);
16090792Sgshapiro			ckfree(ap->val);
16190792Sgshapiro			tmp = ap;
16290792Sgshapiro			ap = ap->next;
16390792Sgshapiro			ckfree(tmp);
16490792Sgshapiro		}
16590792Sgshapiro	}
16690792Sgshapiro	aliases = 0;
16790792Sgshapiro	INTON;
16890792Sgshapiro}
16990792Sgshapiro
17090792Sgshapirostruct alias *
17190792Sgshapirolookupalias(const char *name, int check)
17290792Sgshapiro{
17390792Sgshapiro	struct alias *ap = *hashalias(name);
17490792Sgshapiro
17590792Sgshapiro	for (; ap; ap = ap->next) {
17690792Sgshapiro		if (equal(name, ap->name)) {
17790792Sgshapiro			if (check && (ap->flag & ALIASINUSE))
17890792Sgshapiro				return (NULL);
17990792Sgshapiro			return (ap);
18090792Sgshapiro		}
18190792Sgshapiro	}
18290792Sgshapiro
18390792Sgshapiro	return (NULL);
18490792Sgshapiro}
18590792Sgshapiro
18690792Sgshapirostatic int
18790792Sgshapirocomparealiases(const void *p1, const void *p2)
18890792Sgshapiro{
189120256Sgshapiro	const struct alias *const *a1 = p1;
190120256Sgshapiro	const struct alias *const *a2 = p2;
191120256Sgshapiro
192132943Sgshapiro	return strcmp((*a1)->name, (*a2)->name);
193132943Sgshapiro}
194132943Sgshapiro
195132943Sgshapirostatic void
196132943Sgshapiroprintalias(const struct alias *a)
197132943Sgshapiro{
198132943Sgshapiro	char *p;
199132943Sgshapiro
200132943Sgshapiro	out1fmt("%s=", a->name);
201132943Sgshapiro	/* Don't print the space added above. */
202132943Sgshapiro	p = a->val + strlen(a->val) - 1;
203132943Sgshapiro	*p = '\0';
204132943Sgshapiro	out1qstr(a->val);
205132943Sgshapiro	*p = ' ';
206132943Sgshapiro	out1c('\n');
207132943Sgshapiro}
208132943Sgshapiro
209132943Sgshapirostatic void
210132943Sgshapiroprintaliases(void)
211132943Sgshapiro{
212132943Sgshapiro	int i, j;
213132943Sgshapiro	struct alias **sorted, *ap;
214132943Sgshapiro
215132943Sgshapiro	sorted = ckmalloc(aliases * sizeof(*sorted));
216132943Sgshapiro	j = 0;
217132943Sgshapiro	for (i = 0; i < ATABSIZE; i++)
218132943Sgshapiro		for (ap = atab[i]; ap; ap = ap->next)
219132943Sgshapiro			if (*ap->name != '\0')
220132943Sgshapiro				sorted[j++] = ap;
221132943Sgshapiro	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
222132943Sgshapiro	for (i = 0; i < aliases; i++)
223132943Sgshapiro		printalias(sorted[i]);
224132943Sgshapiro	ckfree(sorted);
225132943Sgshapiro}
226132943Sgshapiro
227132943Sgshapiroint
228132943Sgshapiroaliascmd(int argc, char **argv)
229132943Sgshapiro{
230132943Sgshapiro	char *n, *v;
231132943Sgshapiro	int ret = 0;
232132943Sgshapiro	struct alias *ap;
233132943Sgshapiro
234132943Sgshapiro	if (argc == 1) {
235132943Sgshapiro		printaliases();
236132943Sgshapiro		return (0);
237132943Sgshapiro	}
238132943Sgshapiro	while ((n = *++argv) != NULL) {
239132943Sgshapiro		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
240132943Sgshapiro			if ((ap = lookupalias(n, 0)) == NULL) {
241132943Sgshapiro				warning("%s not found", n);
242132943Sgshapiro				ret = 1;
243132943Sgshapiro			} else
244132943Sgshapiro				printalias(ap);
245132943Sgshapiro		else {
246132943Sgshapiro			*v++ = '\0';
247132943Sgshapiro			setalias(n, v);
248132943Sgshapiro		}
249132943Sgshapiro	}
250132943Sgshapiro
251132943Sgshapiro	return (ret);
252132943Sgshapiro}
253132943Sgshapiro
254132943Sgshapiroint
255132943Sgshapirounaliascmd(int argc __unused, char **argv __unused)
256132943Sgshapiro{
257132943Sgshapiro	int i;
258132943Sgshapiro
259132943Sgshapiro	while ((i = nextopt("a")) != '\0') {
260132943Sgshapiro		if (i == 'a') {
261132943Sgshapiro			rmaliases();
26290792Sgshapiro			return (0);
26390792Sgshapiro		}
264132943Sgshapiro	}
265132943Sgshapiro	for (i = 0; *argptr; argptr++)
26690792Sgshapiro		i |= unalias(*argptr);
267285303Sgshapiro
268285303Sgshapiro	return (i);
269285303Sgshapiro}
27090792Sgshapiro
27190792Sgshapirostatic struct alias **
272285303Sgshapirohashalias(const char *p)
27390792Sgshapiro{
27490792Sgshapiro	unsigned int hashval;
27590792Sgshapiro
27690792Sgshapiro	hashval = *p << 4;
27790792Sgshapiro	while (*p)
27890792Sgshapiro		hashval+= *p++;
27990792Sgshapiro	return &atab[hashval % ATABSIZE];
28090792Sgshapiro}
28190792Sgshapiro