1 /*-
2  * Copyright (c) 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  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 "input.h"
38 #include "output.h"
39 #include "error.h"
40 #include "memalloc.h"
41 #include "mystring.h"
42 #include "alias.h"
43 #include "options.h"	/* XXX for argptr (should remove?) */
44 
45 #define ATABSIZE 39
46 
47 struct alias *atab[ATABSIZE];
48 
49 STATIC void setalias(const char *, const char *);
50 STATIC struct alias *freealias(struct alias *);
51 STATIC struct alias **__lookupalias(const char *);
52 
53 STATIC
54 void
setalias(const char * name,const char * val)55 setalias(const char *name, const char *val)
56 {
57 	struct alias *ap, **app;
58 
59 	app = __lookupalias(name);
60 	ap = *app;
61 	INTOFF;
62 	if (ap) {
63 		if (!(ap->flag & ALIASINUSE)) {
64 			ckfree(ap->val);
65 		}
66 		ap->val	= savestr(val);
67 		ap->flag &= ~ALIASDEAD;
68 	} else {
69 		/* not found */
70 		ap = ckmalloc(sizeof (struct alias));
71 		ap->name = savestr(name);
72 		ap->val = savestr(val);
73 		ap->flag = 0;
74 		ap->next = 0;
75 		*app = ap;
76 	}
77 	INTON;
78 }
79 
80 int
unalias(const char * name)81 unalias(const char *name)
82 {
83 	struct alias **app;
84 
85 	app = __lookupalias(name);
86 
87 	if (*app) {
88 		INTOFF;
89 		*app = freealias(*app);
90 		INTON;
91 		return (0);
92 	}
93 
94 	return (1);
95 }
96 
97 void
rmaliases(void)98 rmaliases(void)
99 {
100 	struct alias *ap, **app;
101 	int i;
102 
103 	INTOFF;
104 	for (i = 0; i < ATABSIZE; i++) {
105 		app = &atab[i];
106 		for (ap = *app; ap; ap = *app) {
107 			*app = freealias(*app);
108 			if (ap == *app) {
109 				app = &ap->next;
110 			}
111 		}
112 	}
113 	INTON;
114 }
115 
116 struct alias *
lookupalias(const char * name,int check)117 lookupalias(const char *name, int check)
118 {
119 	struct alias *ap = *__lookupalias(name);
120 
121 	if (check && ap && (ap->flag & ALIASINUSE))
122 		return (NULL);
123 	return (ap);
124 }
125 
126 /*
127  * TODO - sort output
128  */
129 int
aliascmd(int argc,char ** argv)130 aliascmd(int argc, char **argv)
131 {
132 	char *n, *v;
133 	int ret = 0;
134 	struct alias *ap;
135 
136 	if (argc == 1) {
137 		int i;
138 
139 		for (i = 0; i < ATABSIZE; i++)
140 			for (ap = atab[i]; ap; ap = ap->next) {
141 				printalias(ap);
142 			}
143 		return (0);
144 	}
145 	while ((n = *++argv) != NULL) {
146 		if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
147 			if ((ap = *__lookupalias(n)) == NULL) {
148 				outfmt(out2, "%s: %s not found\n", "alias", n);
149 				ret = 1;
150 			} else
151 				printalias(ap);
152 		} else {
153 			*v++ = '\0';
154 			setalias(n, v);
155 		}
156 	}
157 
158 	return (ret);
159 }
160 
161 int
unaliascmd(int argc,char ** argv)162 unaliascmd(int argc, char **argv)
163 {
164 	int i;
165 
166 	while ((i = nextopt("a")) != '\0') {
167 		if (i == 'a') {
168 			rmaliases();
169 			return (0);
170 		}
171 	}
172 	for (i = 0; *argptr; argptr++) {
173 		if (unalias(*argptr)) {
174 			outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
175 			i = 1;
176 		}
177 	}
178 
179 	return (i);
180 }
181 
182 STATIC struct alias *
freealias(struct alias * ap)183 freealias(struct alias *ap) {
184 	struct alias *next;
185 
186 	if (ap->flag & ALIASINUSE) {
187 		ap->flag |= ALIASDEAD;
188 		return ap;
189 	}
190 
191 	next = ap->next;
192 	ckfree(ap->name);
193 	ckfree(ap->val);
194 	ckfree(ap);
195 	return next;
196 }
197 
198 void
printalias(const struct alias * ap)199 printalias(const struct alias *ap) {
200 	out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
201 }
202 
203 STATIC struct alias **
__lookupalias(const char * name)204 __lookupalias(const char *name) {
205 	unsigned int hashval;
206 	struct alias **app;
207 	const char *p;
208 	unsigned int ch;
209 
210 	p = name;
211 
212 	ch = (unsigned char)*p;
213 	hashval = ch << 4;
214 	while (ch) {
215 		hashval += ch;
216 		ch = (unsigned char)*++p;
217 	}
218 	app = &atab[hashval % ATABSIZE];
219 
220 	for (; *app; app = &(*app)->next) {
221 		if (equal(name, (*app)->name)) {
222 			break;
223 		}
224 	}
225 
226 	return app;
227 }
228