1 /*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)alias.c 8.3 (Berkeley) 5/4/95 37 * $FreeBSD: head/bin/sh/alias.c 242766 2012-11-08 13:33:48Z jilles $ 38 */ 39 40 #include <stdlib.h> 41 #include "shell.h" 42 #include "output.h" 43 #include "error.h" 44 #include "memalloc.h" 45 #include "mystring.h" 46 #include "alias.h" 47 #include "options.h" /* XXX for argptr (should remove?) */ 48 #include "builtins.h" 49 50 #define ATABSIZE 39 51 52 static struct alias *atab[ATABSIZE]; 53 static int aliases; 54 55 static void setalias(const char *, const char *); 56 static int unalias(const char *); 57 static struct alias **hashalias(const char *); 58 59 static 60 void 61 setalias(const char *name, const char *val) 62 { 63 struct alias *ap, **app; 64 65 app = hashalias(name); 66 for (ap = *app; ap; ap = ap->next) { 67 if (equal(name, ap->name)) { 68 INTOFF; 69 ckfree(ap->val); 70 /* See HACK below. */ 71 #ifdef notyet 72 ap->val = savestr(val); 73 #else 74 { 75 size_t len = strlen(val); 76 ap->val = ckmalloc(len + 2); 77 memcpy(ap->val, val, len); 78 ap->val[len] = ' '; 79 ap->val[len+1] = '\0'; 80 } 81 #endif 82 INTON; 83 return; 84 } 85 } 86 /* not found */ 87 INTOFF; 88 ap = ckmalloc(sizeof (struct alias)); 89 ap->name = savestr(name); 90 /* 91 * XXX - HACK: in order that the parser will not finish reading the 92 * alias value off the input before processing the next alias, we 93 * dummy up an extra space at the end of the alias. This is a crock 94 * and should be re-thought. The idea (if you feel inclined to help) 95 * is to avoid alias recursions. The mechanism used is: when 96 * expanding an alias, the value of the alias is pushed back on the 97 * input as a string and a pointer to the alias is stored with the 98 * string. The alias is marked as being in use. When the input 99 * routine finishes reading the string, it marks the alias not 100 * in use. The problem is synchronization with the parser. Since 101 * it reads ahead, the alias is marked not in use before the 102 * resulting token(s) is next checked for further alias sub. The 103 * H A C K is that we add a little fluff after the alias value 104 * so that the string will not be exhausted. This is a good 105 * idea ------- ***NOT*** 106 */ 107 #ifdef notyet 108 ap->val = savestr(val); 109 #else /* hack */ 110 { 111 size_t len = strlen(val); 112 ap->val = ckmalloc(len + 2); 113 memcpy(ap->val, val, len); 114 ap->val[len] = ' '; /* fluff */ 115 ap->val[len+1] = '\0'; 116 } 117 #endif 118 ap->flag = 0; 119 ap->next = *app; 120 *app = ap; 121 aliases++; 122 INTON; 123 } 124 125 static int 126 unalias(const char *name) 127 { 128 struct alias *ap, **app; 129 130 app = hashalias(name); 131 132 for (ap = *app; ap; app = &(ap->next), ap = ap->next) { 133 if (equal(name, ap->name)) { 134 /* 135 * if the alias is currently in use (i.e. its 136 * buffer is being used by the input routine) we 137 * just null out the name instead of freeing it. 138 * We could clear it out later, but this situation 139 * is so rare that it hardly seems worth it. 140 */ 141 if (ap->flag & ALIASINUSE) 142 *ap->name = '\0'; 143 else { 144 INTOFF; 145 *app = ap->next; 146 ckfree(ap->name); 147 ckfree(ap->val); 148 ckfree(ap); 149 INTON; 150 } 151 aliases--; 152 return (0); 153 } 154 } 155 156 return (1); 157 } 158 159 static void 160 rmaliases(void) 161 { 162 struct alias *ap, *tmp; 163 int i; 164 165 INTOFF; 166 for (i = 0; i < ATABSIZE; i++) { 167 ap = atab[i]; 168 atab[i] = NULL; 169 while (ap) { 170 ckfree(ap->name); 171 ckfree(ap->val); 172 tmp = ap; 173 ap = ap->next; 174 ckfree(tmp); 175 } 176 } 177 aliases = 0; 178 INTON; 179 } 180 181 struct alias * 182 lookupalias(const char *name, int check) 183 { 184 struct alias *ap = *hashalias(name); 185 186 for (; ap; ap = ap->next) { 187 if (equal(name, ap->name)) { 188 if (check && (ap->flag & ALIASINUSE)) 189 return (NULL); 190 return (ap); 191 } 192 } 193 194 return (NULL); 195 } 196 197 static int 198 comparealiases(const void *p1, const void *p2) 199 { 200 const struct alias *const *a1 = p1; 201 const struct alias *const *a2 = p2; 202 203 return strcmp((*a1)->name, (*a2)->name); 204 } 205 206 static void 207 printalias(const struct alias *a) 208 { 209 char *p; 210 211 out1fmt("%s=", a->name); 212 /* Don't print the space added above. */ 213 p = a->val + strlen(a->val) - 1; 214 *p = '\0'; 215 out1qstr(a->val); 216 *p = ' '; 217 out1c('\n'); 218 } 219 220 static void 221 printaliases(void) 222 { 223 int i, j; 224 struct alias **sorted, *ap; 225 226 sorted = ckmalloc(aliases * sizeof(*sorted)); 227 j = 0; 228 for (i = 0; i < ATABSIZE; i++) 229 for (ap = atab[i]; ap; ap = ap->next) 230 if (*ap->name != '\0') 231 sorted[j++] = ap; 232 qsort(sorted, aliases, sizeof(*sorted), comparealiases); 233 for (i = 0; i < aliases; i++) 234 printalias(sorted[i]); 235 ckfree(sorted); 236 } 237 238 int 239 aliascmd(int argc, char **argv) 240 { 241 char *n, *v; 242 int ret = 0; 243 struct alias *ap; 244 245 if (argc == 1) { 246 printaliases(); 247 return (0); 248 } 249 while ((n = *++argv) != NULL) { 250 if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ 251 if ((ap = lookupalias(n, 0)) == NULL) { 252 warning("%s: not found", n); 253 ret = 1; 254 } else 255 printalias(ap); 256 else { 257 *v++ = '\0'; 258 setalias(n, v); 259 } 260 } 261 262 return (ret); 263 } 264 265 int 266 unaliascmd(int argc __unused, char **argv __unused) 267 { 268 int i; 269 270 while ((i = nextopt("a")) != '\0') { 271 if (i == 'a') { 272 rmaliases(); 273 return (0); 274 } 275 } 276 for (i = 0; *argptr; argptr++) 277 i |= unalias(*argptr); 278 279 return (i); 280 } 281 282 static struct alias ** 283 hashalias(const char *p) 284 { 285 unsigned int hashval; 286 287 hashval = *p << 4; 288 while (*p) 289 hashval+= *p++; 290 return &atab[hashval % ATABSIZE]; 291 } 292