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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)alias.c 8.2 (Berkeley) 04/28/95"; 13 #endif /* not lint */ 14 15 #include "shell.h" 16 #include "input.h" 17 #include "output.h" 18 #include "error.h" 19 #include "memalloc.h" 20 #include "mystring.h" 21 #include "alias.h" 22 #include "options.h" /* XXX for argptr (should remove?) */ 23 24 #define ATABSIZE 39 25 26 struct alias *atab[ATABSIZE]; 27 28 STATIC struct alias **hashalias __P((char *)); 29 30 STATIC 31 setalias(name, val) 32 char *name, *val; 33 { 34 struct alias *ap, **app; 35 36 app = hashalias(name); 37 for (ap = *app; ap; ap = ap->next) { 38 if (equal(name, ap->name)) { 39 INTOFF; 40 ckfree(ap->val); 41 ap->val = savestr(val); 42 INTON; 43 return; 44 } 45 } 46 /* not found */ 47 INTOFF; 48 ap = ckmalloc(sizeof (struct alias)); 49 ap->name = savestr(name); 50 /* 51 * XXX - HACK: in order that the parser will not finish reading the 52 * alias value off the input before processing the next alias, we 53 * dummy up an extra space at the end of the alias. This is a crock 54 * and should be re-thought. The idea (if you feel inclined to help) 55 * is to avoid alias recursions. The mechanism used is: when 56 * expanding an alias, the value of the alias is pushed back on the 57 * input as a string and a pointer to the alias is stored with the 58 * string. The alias is marked as being in use. When the input 59 * routine finishes reading the string, it markes the alias not 60 * in use. The problem is synchronization with the parser. Since 61 * it reads ahead, the alias is marked not in use before the 62 * resulting token(s) is next checked for further alias sub. The 63 * H A C K is that we add a little fluff after the alias value 64 * so that the string will not be exhausted. This is a good 65 * idea ------- ***NOT*** 66 */ 67 #ifdef notyet 68 ap->val = savestr(val); 69 #else /* hack */ 70 { 71 int len = strlen(val); 72 ap->val = ckmalloc(len + 2); 73 memmove(ap->val, val, len); 74 ap->val[len] = ' '; /* fluff */ 75 ap->val[len+1] = '\0'; 76 } 77 #endif 78 ap->next = *app; 79 *app = ap; 80 INTON; 81 } 82 83 STATIC int 84 unalias(name) 85 char *name; 86 { 87 struct alias *ap, **app; 88 89 app = hashalias(name); 90 91 for (ap = *app; ap; app = &(ap->next), ap = ap->next) { 92 if (equal(name, ap->name)) { 93 /* 94 * if the alias is currently in use (i.e. its 95 * buffer is being used by the input routine) we 96 * just null out the name instead of freeing it. 97 * We could clear it out later, but this situation 98 * is so rare that it hardly seems worth it. 99 */ 100 if (ap->flag & ALIASINUSE) 101 *ap->name = '\0'; 102 else { 103 INTOFF; 104 *app = ap->next; 105 ckfree(ap->name); 106 ckfree(ap->val); 107 ckfree(ap); 108 INTON; 109 } 110 return (0); 111 } 112 } 113 114 return (1); 115 } 116 117 #ifdef mkinit 118 MKINIT void rmaliases(); 119 120 SHELLPROC { 121 rmaliases(); 122 } 123 #endif 124 125 void 126 rmaliases() { 127 struct alias *ap, *tmp; 128 int i; 129 130 INTOFF; 131 for (i = 0; i < ATABSIZE; i++) { 132 ap = atab[i]; 133 atab[i] = NULL; 134 while (ap) { 135 ckfree(ap->name); 136 ckfree(ap->val); 137 tmp = ap; 138 ap = ap->next; 139 ckfree(tmp); 140 } 141 } 142 INTON; 143 } 144 145 struct alias * 146 lookupalias(name, check) 147 char *name; 148 { 149 struct alias *ap = *hashalias(name); 150 151 for (; ap; ap = ap->next) { 152 if (equal(name, ap->name)) { 153 if (check && (ap->flag & ALIASINUSE)) 154 return (NULL); 155 return (ap); 156 } 157 } 158 159 return (NULL); 160 } 161 162 /* 163 * TODO - sort output 164 */ 165 aliascmd(argc, argv) 166 char **argv; 167 { 168 char *n, *v; 169 int ret = 0; 170 struct alias *ap; 171 172 if (argc == 1) { 173 int i; 174 175 for (i = 0; i < ATABSIZE; i++) 176 for (ap = atab[i]; ap; ap = ap->next) { 177 if (*ap->name != '\0') 178 out1fmt("alias %s=%s\n", ap->name, ap->val); 179 } 180 return (0); 181 } 182 while (n = *++argv) { 183 if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ 184 if ((ap = lookupalias(n, 0)) == NULL) { 185 outfmt(out2, "alias: %s not found\n", n); 186 ret = 1; 187 } else 188 out1fmt("alias %s=%s\n", n, ap->val); 189 else { 190 *v++ = '\0'; 191 setalias(n, v); 192 } 193 } 194 195 return (ret); 196 } 197 198 unaliascmd(argc, argv) 199 char **argv; 200 { 201 int i; 202 203 while ((i = nextopt("a")) != '\0') { 204 if (i == 'a') { 205 rmaliases(); 206 return (0); 207 } 208 } 209 for (i = 0; *argptr; argptr++) 210 i = unalias(*argptr); 211 212 return (i); 213 } 214 215 STATIC struct alias ** 216 hashalias(p) 217 register char *p; 218 { 219 unsigned int hashval; 220 221 hashval = *p << 4; 222 while (*p) 223 hashval+= *p++; 224 return &atab[hashval % ATABSIZE]; 225 } 226