alias.c revision 213760
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3436150Scharnier#if 0 3536150Scharnierstatic char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95"; 3636150Scharnier#endif 371556Srgrimes#endif /* not lint */ 3899110Sobrien#include <sys/cdefs.h> 3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/alias.c 213760 2010-10-13 04:01:01Z obrien $"); 401556Srgrimes 4117987Speter#include <stdlib.h> 421556Srgrimes#include "shell.h" 431556Srgrimes#include "output.h" 441556Srgrimes#include "error.h" 451556Srgrimes#include "memalloc.h" 461556Srgrimes#include "mystring.h" 471556Srgrimes#include "alias.h" 481556Srgrimes#include "options.h" /* XXX for argptr (should remove?) */ 491556Srgrimes 501556Srgrimes#define ATABSIZE 39 511556Srgrimes 52213760Sobrienstatic struct alias *atab[ATABSIZE]; 53213760Sobrienstatic int aliases; 541556Srgrimes 55200956SjillesSTATIC void setalias(const char *, const char *); 56179639SrseSTATIC int unalias(const char *); 57179639SrseSTATIC struct alias **hashalias(const char *); 581556Srgrimes 591556SrgrimesSTATIC 6017987Spetervoid 61200956Sjillessetalias(const char *name, const char *val) 6217987Speter{ 631556Srgrimes struct alias *ap, **app; 641556Srgrimes 651556Srgrimes app = hashalias(name); 661556Srgrimes for (ap = *app; ap; ap = ap->next) { 671556Srgrimes if (equal(name, ap->name)) { 681556Srgrimes INTOFF; 691556Srgrimes ckfree(ap->val); 701556Srgrimes ap->val = savestr(val); 711556Srgrimes INTON; 721556Srgrimes return; 731556Srgrimes } 741556Srgrimes } 751556Srgrimes /* not found */ 761556Srgrimes INTOFF; 771556Srgrimes ap = ckmalloc(sizeof (struct alias)); 781556Srgrimes ap->name = savestr(name); 791556Srgrimes /* 801556Srgrimes * XXX - HACK: in order that the parser will not finish reading the 811556Srgrimes * alias value off the input before processing the next alias, we 821556Srgrimes * dummy up an extra space at the end of the alias. This is a crock 831556Srgrimes * and should be re-thought. The idea (if you feel inclined to help) 841556Srgrimes * is to avoid alias recursions. The mechanism used is: when 851556Srgrimes * expanding an alias, the value of the alias is pushed back on the 861556Srgrimes * input as a string and a pointer to the alias is stored with the 871556Srgrimes * string. The alias is marked as being in use. When the input 8846684Skris * routine finishes reading the string, it marks the alias not 891556Srgrimes * in use. The problem is synchronization with the parser. Since 901556Srgrimes * it reads ahead, the alias is marked not in use before the 911556Srgrimes * resulting token(s) is next checked for further alias sub. The 921556Srgrimes * H A C K is that we add a little fluff after the alias value 931556Srgrimes * so that the string will not be exhausted. This is a good 941556Srgrimes * idea ------- ***NOT*** 951556Srgrimes */ 961556Srgrimes#ifdef notyet 971556Srgrimes ap->val = savestr(val); 981556Srgrimes#else /* hack */ 991556Srgrimes { 100193221Srse size_t len = strlen(val); 1011556Srgrimes ap->val = ckmalloc(len + 2); 10217987Speter memcpy(ap->val, val, len); 1031556Srgrimes ap->val[len] = ' '; /* fluff */ 1041556Srgrimes ap->val[len+1] = '\0'; 1051556Srgrimes } 1061556Srgrimes#endif 10763223Ssada ap->flag = 0; 1081556Srgrimes ap->next = *app; 1091556Srgrimes *app = ap; 110190284Sstefanf aliases++; 1111556Srgrimes INTON; 1121556Srgrimes} 1131556Srgrimes 1141556SrgrimesSTATIC int 115179639Srseunalias(const char *name) 11690111Simp{ 1171556Srgrimes struct alias *ap, **app; 1181556Srgrimes 1191556Srgrimes app = hashalias(name); 1201556Srgrimes 1211556Srgrimes for (ap = *app; ap; app = &(ap->next), ap = ap->next) { 1221556Srgrimes if (equal(name, ap->name)) { 1231556Srgrimes /* 1241556Srgrimes * if the alias is currently in use (i.e. its 1251556Srgrimes * buffer is being used by the input routine) we 1261556Srgrimes * just null out the name instead of freeing it. 1271556Srgrimes * We could clear it out later, but this situation 1281556Srgrimes * is so rare that it hardly seems worth it. 1291556Srgrimes */ 1301556Srgrimes if (ap->flag & ALIASINUSE) 1311556Srgrimes *ap->name = '\0'; 1321556Srgrimes else { 1331556Srgrimes INTOFF; 1341556Srgrimes *app = ap->next; 1351556Srgrimes ckfree(ap->name); 1361556Srgrimes ckfree(ap->val); 1371556Srgrimes ckfree(ap); 1381556Srgrimes INTON; 1391556Srgrimes } 140190284Sstefanf aliases--; 1411556Srgrimes return (0); 1421556Srgrimes } 1431556Srgrimes } 1441556Srgrimes 1451556Srgrimes return (1); 1461556Srgrimes} 1471556Srgrimes 1481556Srgrimes#ifdef mkinit 149149016SstefanfMKINIT void rmaliases(void); 1501556Srgrimes 1511556SrgrimesSHELLPROC { 1521556Srgrimes rmaliases(); 1531556Srgrimes} 1541556Srgrimes#endif 1551556Srgrimes 1561556Srgrimesvoid 15790111Simprmaliases(void) 15890111Simp{ 1591556Srgrimes struct alias *ap, *tmp; 1601556Srgrimes int i; 1611556Srgrimes 1621556Srgrimes INTOFF; 1631556Srgrimes for (i = 0; i < ATABSIZE; i++) { 1641556Srgrimes ap = atab[i]; 1651556Srgrimes atab[i] = NULL; 1661556Srgrimes while (ap) { 1671556Srgrimes ckfree(ap->name); 1681556Srgrimes ckfree(ap->val); 1691556Srgrimes tmp = ap; 1701556Srgrimes ap = ap->next; 1711556Srgrimes ckfree(tmp); 1721556Srgrimes } 1731556Srgrimes } 174190284Sstefanf aliases = 0; 1751556Srgrimes INTON; 1761556Srgrimes} 1771556Srgrimes 1781556Srgrimesstruct alias * 179200956Sjilleslookupalias(const char *name, int check) 18017987Speter{ 1811556Srgrimes struct alias *ap = *hashalias(name); 1821556Srgrimes 1831556Srgrimes for (; ap; ap = ap->next) { 1841556Srgrimes if (equal(name, ap->name)) { 1851556Srgrimes if (check && (ap->flag & ALIASINUSE)) 1861556Srgrimes return (NULL); 1871556Srgrimes return (ap); 1881556Srgrimes } 1891556Srgrimes } 1901556Srgrimes 1911556Srgrimes return (NULL); 1921556Srgrimes} 1931556Srgrimes 194213760SobrienSTATIC int 195190284Sstefanfcomparealiases(const void *p1, const void *p2) 196190284Sstefanf{ 197190284Sstefanf const struct alias *const *a1 = p1; 198190284Sstefanf const struct alias *const *a2 = p2; 199190284Sstefanf 200190284Sstefanf return strcmp((*a1)->name, (*a2)->name); 201190284Sstefanf} 202190284Sstefanf 203213760SobrienSTATIC void 204190284Sstefanfprintalias(const struct alias *a) 205190284Sstefanf{ 206190284Sstefanf char *p; 207190284Sstefanf 208190284Sstefanf out1fmt("%s=", a->name); 209190284Sstefanf /* Don't print the space added above. */ 210190284Sstefanf p = a->val + strlen(a->val) - 1; 211190284Sstefanf *p = '\0'; 212190284Sstefanf out1qstr(a->val); 213190284Sstefanf *p = ' '; 214190284Sstefanf out1c('\n'); 215190284Sstefanf} 216190284Sstefanf 217213760SobrienSTATIC void 218190284Sstefanfprintaliases(void) 219190284Sstefanf{ 220190284Sstefanf int i, j; 221190284Sstefanf struct alias **sorted, *ap; 222190284Sstefanf 223190284Sstefanf sorted = ckmalloc(aliases * sizeof(*sorted)); 224190284Sstefanf j = 0; 225190284Sstefanf for (i = 0; i < ATABSIZE; i++) 226190284Sstefanf for (ap = atab[i]; ap; ap = ap->next) 227190284Sstefanf if (*ap->name != '\0') 228190284Sstefanf sorted[j++] = ap; 229190284Sstefanf qsort(sorted, aliases, sizeof(*sorted), comparealiases); 230190284Sstefanf for (i = 0; i < aliases; i++) 231190284Sstefanf printalias(sorted[i]); 232190284Sstefanf ckfree(sorted); 233190284Sstefanf} 234190284Sstefanf 23517987Speterint 23690111Simpaliascmd(int argc, char **argv) 23717987Speter{ 2381556Srgrimes char *n, *v; 2391556Srgrimes int ret = 0; 2401556Srgrimes struct alias *ap; 2411556Srgrimes 2421556Srgrimes if (argc == 1) { 243190284Sstefanf printaliases(); 2441556Srgrimes return (0); 2451556Srgrimes } 24617987Speter while ((n = *++argv) != NULL) { 2471556Srgrimes if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ 2481556Srgrimes if ((ap = lookupalias(n, 0)) == NULL) { 2491556Srgrimes outfmt(out2, "alias: %s not found\n", n); 2501556Srgrimes ret = 1; 251190284Sstefanf } else 252190284Sstefanf printalias(ap); 2531556Srgrimes else { 2541556Srgrimes *v++ = '\0'; 2551556Srgrimes setalias(n, v); 2561556Srgrimes } 2571556Srgrimes } 2581556Srgrimes 2591556Srgrimes return (ret); 2601556Srgrimes} 2611556Srgrimes 26217987Speterint 26390111Simpunaliascmd(int argc __unused, char **argv __unused) 26417987Speter{ 2651556Srgrimes int i; 2668855Srgrimes 2671556Srgrimes while ((i = nextopt("a")) != '\0') { 2681556Srgrimes if (i == 'a') { 2691556Srgrimes rmaliases(); 2701556Srgrimes return (0); 2711556Srgrimes } 2721556Srgrimes } 2731556Srgrimes for (i = 0; *argptr; argptr++) 274149743Sstefanf i |= unalias(*argptr); 2751556Srgrimes 2761556Srgrimes return (i); 2771556Srgrimes} 2781556Srgrimes 2791556SrgrimesSTATIC struct alias ** 280179639Srsehashalias(const char *p) 28190111Simp{ 2821556Srgrimes unsigned int hashval; 2831556Srgrimes 2841556Srgrimes hashval = *p << 4; 2851556Srgrimes while (*p) 2861556Srgrimes hashval+= *p++; 2871556Srgrimes return &atab[hashval % ATABSIZE]; 2881556Srgrimes} 289