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$"); 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?) */ 49223060Sjilles#include "builtins.h" 501556Srgrimes 511556Srgrimes#define ATABSIZE 39 521556Srgrimes 53213760Sobrienstatic struct alias *atab[ATABSIZE]; 54213760Sobrienstatic int aliases; 551556Srgrimes 56213811Sobrienstatic void setalias(const char *, const char *); 57213811Sobrienstatic int unalias(const char *); 58213811Sobrienstatic struct alias **hashalias(const char *); 591556Srgrimes 60213811Sobrienstatic 6117987Spetervoid 62200956Sjillessetalias(const char *name, const char *val) 6317987Speter{ 641556Srgrimes struct alias *ap, **app; 651556Srgrimes 661556Srgrimes app = hashalias(name); 671556Srgrimes for (ap = *app; ap; ap = ap->next) { 681556Srgrimes if (equal(name, ap->name)) { 691556Srgrimes INTOFF; 701556Srgrimes ckfree(ap->val); 71243402Sjilles /* See HACK below. */ 72243402Sjilles#ifdef notyet 731556Srgrimes ap->val = savestr(val); 74243402Sjilles#else 75243402Sjilles { 76243402Sjilles size_t len = strlen(val); 77243402Sjilles ap->val = ckmalloc(len + 2); 78243402Sjilles memcpy(ap->val, val, len); 79243402Sjilles ap->val[len] = ' '; 80243402Sjilles ap->val[len+1] = '\0'; 81243402Sjilles } 82243402Sjilles#endif 831556Srgrimes INTON; 841556Srgrimes return; 851556Srgrimes } 861556Srgrimes } 871556Srgrimes /* not found */ 881556Srgrimes INTOFF; 891556Srgrimes ap = ckmalloc(sizeof (struct alias)); 901556Srgrimes ap->name = savestr(name); 911556Srgrimes /* 921556Srgrimes * XXX - HACK: in order that the parser will not finish reading the 931556Srgrimes * alias value off the input before processing the next alias, we 941556Srgrimes * dummy up an extra space at the end of the alias. This is a crock 951556Srgrimes * and should be re-thought. The idea (if you feel inclined to help) 961556Srgrimes * is to avoid alias recursions. The mechanism used is: when 971556Srgrimes * expanding an alias, the value of the alias is pushed back on the 981556Srgrimes * input as a string and a pointer to the alias is stored with the 991556Srgrimes * string. The alias is marked as being in use. When the input 10046684Skris * routine finishes reading the string, it marks the alias not 1011556Srgrimes * in use. The problem is synchronization with the parser. Since 1021556Srgrimes * it reads ahead, the alias is marked not in use before the 1031556Srgrimes * resulting token(s) is next checked for further alias sub. The 1041556Srgrimes * H A C K is that we add a little fluff after the alias value 1051556Srgrimes * so that the string will not be exhausted. This is a good 1061556Srgrimes * idea ------- ***NOT*** 1071556Srgrimes */ 1081556Srgrimes#ifdef notyet 1091556Srgrimes ap->val = savestr(val); 1101556Srgrimes#else /* hack */ 1111556Srgrimes { 112193221Srse size_t len = strlen(val); 1131556Srgrimes ap->val = ckmalloc(len + 2); 11417987Speter memcpy(ap->val, val, len); 1151556Srgrimes ap->val[len] = ' '; /* fluff */ 1161556Srgrimes ap->val[len+1] = '\0'; 1171556Srgrimes } 1181556Srgrimes#endif 11963223Ssada ap->flag = 0; 1201556Srgrimes ap->next = *app; 1211556Srgrimes *app = ap; 122190284Sstefanf aliases++; 1231556Srgrimes INTON; 1241556Srgrimes} 1251556Srgrimes 126213811Sobrienstatic int 127179639Srseunalias(const char *name) 12890111Simp{ 1291556Srgrimes struct alias *ap, **app; 1301556Srgrimes 1311556Srgrimes app = hashalias(name); 1321556Srgrimes 1331556Srgrimes for (ap = *app; ap; app = &(ap->next), ap = ap->next) { 1341556Srgrimes if (equal(name, ap->name)) { 1351556Srgrimes /* 1361556Srgrimes * if the alias is currently in use (i.e. its 1371556Srgrimes * buffer is being used by the input routine) we 1381556Srgrimes * just null out the name instead of freeing it. 1391556Srgrimes * We could clear it out later, but this situation 1401556Srgrimes * is so rare that it hardly seems worth it. 1411556Srgrimes */ 1421556Srgrimes if (ap->flag & ALIASINUSE) 1431556Srgrimes *ap->name = '\0'; 1441556Srgrimes else { 1451556Srgrimes INTOFF; 1461556Srgrimes *app = ap->next; 1471556Srgrimes ckfree(ap->name); 1481556Srgrimes ckfree(ap->val); 1491556Srgrimes ckfree(ap); 1501556Srgrimes INTON; 1511556Srgrimes } 152190284Sstefanf aliases--; 1531556Srgrimes return (0); 1541556Srgrimes } 1551556Srgrimes } 1561556Srgrimes 1571556Srgrimes return (1); 1581556Srgrimes} 1591556Srgrimes 160218306Sjillesstatic void 16190111Simprmaliases(void) 16290111Simp{ 1631556Srgrimes struct alias *ap, *tmp; 1641556Srgrimes int i; 1651556Srgrimes 1661556Srgrimes INTOFF; 1671556Srgrimes for (i = 0; i < ATABSIZE; i++) { 1681556Srgrimes ap = atab[i]; 1691556Srgrimes atab[i] = NULL; 1701556Srgrimes while (ap) { 1711556Srgrimes ckfree(ap->name); 1721556Srgrimes ckfree(ap->val); 1731556Srgrimes tmp = ap; 1741556Srgrimes ap = ap->next; 1751556Srgrimes ckfree(tmp); 1761556Srgrimes } 1771556Srgrimes } 178190284Sstefanf aliases = 0; 1791556Srgrimes INTON; 1801556Srgrimes} 1811556Srgrimes 1821556Srgrimesstruct alias * 183200956Sjilleslookupalias(const char *name, int check) 18417987Speter{ 1851556Srgrimes struct alias *ap = *hashalias(name); 1861556Srgrimes 1871556Srgrimes for (; ap; ap = ap->next) { 1881556Srgrimes if (equal(name, ap->name)) { 1891556Srgrimes if (check && (ap->flag & ALIASINUSE)) 1901556Srgrimes return (NULL); 1911556Srgrimes return (ap); 1921556Srgrimes } 1931556Srgrimes } 1941556Srgrimes 1951556Srgrimes return (NULL); 1961556Srgrimes} 1971556Srgrimes 198213811Sobrienstatic int 199190284Sstefanfcomparealiases(const void *p1, const void *p2) 200190284Sstefanf{ 201190284Sstefanf const struct alias *const *a1 = p1; 202190284Sstefanf const struct alias *const *a2 = p2; 203190284Sstefanf 204190284Sstefanf return strcmp((*a1)->name, (*a2)->name); 205190284Sstefanf} 206190284Sstefanf 207213811Sobrienstatic void 208190284Sstefanfprintalias(const struct alias *a) 209190284Sstefanf{ 210190284Sstefanf char *p; 211190284Sstefanf 212190284Sstefanf out1fmt("%s=", a->name); 213190284Sstefanf /* Don't print the space added above. */ 214190284Sstefanf p = a->val + strlen(a->val) - 1; 215190284Sstefanf *p = '\0'; 216190284Sstefanf out1qstr(a->val); 217190284Sstefanf *p = ' '; 218190284Sstefanf out1c('\n'); 219190284Sstefanf} 220190284Sstefanf 221213811Sobrienstatic void 222190284Sstefanfprintaliases(void) 223190284Sstefanf{ 224190284Sstefanf int i, j; 225190284Sstefanf struct alias **sorted, *ap; 226190284Sstefanf 227264629Sjilles INTOFF; 228190284Sstefanf sorted = ckmalloc(aliases * sizeof(*sorted)); 229190284Sstefanf j = 0; 230190284Sstefanf for (i = 0; i < ATABSIZE; i++) 231190284Sstefanf for (ap = atab[i]; ap; ap = ap->next) 232190284Sstefanf if (*ap->name != '\0') 233190284Sstefanf sorted[j++] = ap; 234190284Sstefanf qsort(sorted, aliases, sizeof(*sorted), comparealiases); 235264629Sjilles for (i = 0; i < aliases; i++) { 236190284Sstefanf printalias(sorted[i]); 237264629Sjilles if (int_pending()) 238264629Sjilles break; 239264629Sjilles } 240190284Sstefanf ckfree(sorted); 241264629Sjilles INTON; 242190284Sstefanf} 243190284Sstefanf 24417987Speterint 24590111Simpaliascmd(int argc, char **argv) 24617987Speter{ 2471556Srgrimes char *n, *v; 2481556Srgrimes int ret = 0; 2491556Srgrimes struct alias *ap; 2501556Srgrimes 2511556Srgrimes if (argc == 1) { 252190284Sstefanf printaliases(); 2531556Srgrimes return (0); 2541556Srgrimes } 25517987Speter while ((n = *++argv) != NULL) { 2561556Srgrimes if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ 2571556Srgrimes if ((ap = lookupalias(n, 0)) == NULL) { 258222684Sjilles warning("%s: not found", n); 2591556Srgrimes ret = 1; 260190284Sstefanf } else 261190284Sstefanf printalias(ap); 2621556Srgrimes else { 2631556Srgrimes *v++ = '\0'; 2641556Srgrimes setalias(n, v); 2651556Srgrimes } 2661556Srgrimes } 2671556Srgrimes 2681556Srgrimes return (ret); 2691556Srgrimes} 2701556Srgrimes 27117987Speterint 27290111Simpunaliascmd(int argc __unused, char **argv __unused) 27317987Speter{ 2741556Srgrimes int i; 2758855Srgrimes 2761556Srgrimes while ((i = nextopt("a")) != '\0') { 2771556Srgrimes if (i == 'a') { 2781556Srgrimes rmaliases(); 2791556Srgrimes return (0); 2801556Srgrimes } 2811556Srgrimes } 2821556Srgrimes for (i = 0; *argptr; argptr++) 283149743Sstefanf i |= unalias(*argptr); 2841556Srgrimes 2851556Srgrimes return (i); 2861556Srgrimes} 2871556Srgrimes 288213811Sobrienstatic struct alias ** 289179639Srsehashalias(const char *p) 29090111Simp{ 2911556Srgrimes unsigned int hashval; 2921556Srgrimes 2931556Srgrimes hashval = *p << 4; 2941556Srgrimes while (*p) 2951556Srgrimes hashval+= *p++; 2961556Srgrimes return &atab[hashval % ATABSIZE]; 2971556Srgrimes} 298