1 /* $NetBSD: alias.c,v 1.21 2019/02/09 09:11:07 kre Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 5 * The Regents of the University of California. 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 <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95"; 39 #else 40 __RCSID("$NetBSD: alias.c,v 1.21 2019/02/09 09:11:07 kre Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <stdlib.h> 45 #include "shell.h" 46 #include "input.h" 47 #include "output.h" 48 #include "error.h" 49 #include "memalloc.h" 50 #include "mystring.h" 51 #include "alias.h" 52 #include "options.h" /* XXX for argptr (should remove?) */ 53 #include "builtins.h" 54 #include "var.h" 55 56 #define ATABSIZE 39 57 58 struct alias *atab[ATABSIZE]; 59 60 STATIC void setalias(char *, char *); 61 STATIC int by_name(const void *, const void *); 62 STATIC void list_aliases(void); 63 STATIC int unalias(char *); 64 STATIC struct alias **freealias(struct alias **, int); 65 STATIC struct alias **hashalias(const char *); 66 STATIC int countaliases(void); 67 68 STATIC 69 void 70 setalias(char *name, char *val) 71 { 72 struct alias *ap, **app; 73 74 (void) unalias(name); /* old one (if any) is now gone */ 75 app = hashalias(name); 76 77 INTOFF; 78 ap = ckmalloc(sizeof (struct alias)); 79 ap->name = savestr(name); 80 ap->flag = 0; 81 ap->val = savestr(val); 82 ap->next = *app; 83 *app = ap; 84 INTON; 85 } 86 87 STATIC struct alias ** 88 freealias(struct alias **app, int force) 89 { 90 struct alias *ap = *app; 91 92 if (ap == NULL) 93 return app; 94 95 /* 96 * if the alias is currently in use (i.e. its 97 * buffer is being used by the input routine) we 98 * just null out the name instead of discarding it. 99 * If we encounter it later, when it is idle, 100 * we will finish freeing it then. 101 * 102 * Unless we want to simply free everything (INIT) 103 */ 104 if (ap->flag & ALIASINUSE && !force) { 105 *ap->name = '\0'; 106 return &ap->next; 107 } 108 109 INTOFF; 110 *app = ap->next; 111 ckfree(ap->name); 112 ckfree(ap->val); 113 ckfree(ap); 114 INTON; 115 116 return app; 117 } 118 119 STATIC int 120 unalias(char *name) 121 { 122 struct alias *ap, **app; 123 124 app = hashalias(name); 125 while ((ap = *app) != NULL) { 126 if (equal(name, ap->name)) { 127 (void) freealias(app, 0); 128 return 0; 129 } 130 app = &ap->next; 131 } 132 133 return 1; 134 } 135 136 #ifdef mkinit 137 MKINIT void rmaliases(int); 138 139 SHELLPROC { 140 rmaliases(1); 141 } 142 #endif 143 144 void 145 rmaliases(int force) 146 { 147 struct alias **app; 148 int i; 149 150 INTOFF; 151 for (i = 0; i < ATABSIZE; i++) { 152 app = &atab[i]; 153 while (*app) 154 app = freealias(app, force); 155 } 156 INTON; 157 } 158 159 struct alias * 160 lookupalias(const char *name, int check) 161 { 162 struct alias *ap = *hashalias(name); 163 164 while (ap != NULL) { 165 if (equal(name, ap->name)) { 166 if (check && (ap->flag & ALIASINUSE)) 167 return NULL; 168 return ap; 169 } 170 ap = ap->next; 171 } 172 173 return NULL; 174 } 175 176 const char * 177 alias_text(void *dummy __unused, const char *name) 178 { 179 struct alias *ap; 180 181 ap = lookupalias(name, 0); 182 if (ap == NULL) 183 return NULL; 184 return ap->val; 185 } 186 187 STATIC int 188 by_name(const void *a, const void *b) 189 { 190 191 return strcmp( 192 (*(const struct alias * const *)a)->name, 193 (*(const struct alias * const *)b)->name); 194 } 195 196 STATIC void 197 list_aliases(void) 198 { 199 int i, j, n; 200 const struct alias **aliases; 201 const struct alias *ap; 202 203 INTOFF; 204 n = countaliases(); 205 aliases = stalloc(n * (int)(sizeof aliases[0])); 206 207 j = 0; 208 for (i = 0; i < ATABSIZE; i++) 209 for (ap = atab[i]; ap != NULL; ap = ap->next) 210 if (ap->name[0] != '\0') 211 aliases[j++] = ap; 212 if (j != n) 213 error("Alias count botch"); 214 INTON; 215 216 qsort(aliases, n, sizeof aliases[0], by_name); 217 218 for (i = 0; i < n; i++) { 219 out1fmt("alias %s=", aliases[i]->name); 220 print_quoted(aliases[i]->val); 221 out1c('\n'); 222 } 223 224 stunalloc(aliases); 225 } 226 227 /* 228 * Count how many aliases are defined (skipping any 229 * that have been deleted, but don't know it yet). 230 * Use this opportunity to clean up any of those 231 * zombies that are no longer needed. 232 */ 233 STATIC int 234 countaliases(void) 235 { 236 struct alias *ap, **app; 237 size_t n; 238 int i; 239 240 n = 0; 241 for (i = 0; i < ATABSIZE; i++) 242 for (app = &atab[i]; (ap = *app) != NULL;) { 243 if (ap->name[0] != '\0') 244 n++; 245 else { 246 app = freealias(app, 0); 247 continue; 248 } 249 app = &ap->next; 250 } 251 252 return n; 253 } 254 255 int 256 aliascmd(int argc, char **argv) 257 { 258 char *n, *v; 259 int ret = 0; 260 struct alias *ap; 261 262 if (argc == 1) { 263 list_aliases(); 264 return 0; 265 } 266 267 while ((n = *++argv) != NULL) { 268 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ 269 if ((ap = lookupalias(n, 0)) == NULL) { 270 outfmt(out2, "alias: %s not found\n", n); 271 ret = 1; 272 } else { 273 out1fmt("alias %s=", n); 274 print_quoted(ap->val); 275 out1c('\n'); 276 } 277 } else { 278 *v++ = '\0'; 279 setalias(n, v); 280 } 281 } 282 283 return ret; 284 } 285 286 int 287 unaliascmd(int argc, char **argv) 288 { 289 int i; 290 291 while ((i = nextopt("a")) != '\0') { 292 if (i == 'a') { 293 rmaliases(0); 294 return 0; 295 } 296 } 297 298 (void)countaliases(); /* delete any dead ones */ 299 for (i = 0; *argptr; argptr++) 300 i |= unalias(*argptr); 301 302 return i; 303 } 304 305 STATIC struct alias ** 306 hashalias(const char *p) 307 { 308 unsigned int hashval; 309 310 hashval = *(const unsigned char *)p << 4; 311 while (*p) 312 hashval += *p++; 313 return &atab[hashval % ATABSIZE]; 314 } 315