master xplshn/aruu / cmd / posix / sh / alias.c
  1/*-
  2 * SPDX-License-Identifier: BSD-3-Clause
  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 "alias.h"
 36#include "builtins.h"
 37#include "error.h"
 38#include "memalloc.h"
 39#include "mystring.h"
 40#include "options.h"
 41#include "output.h"
 42#include "shell.h"
 43#include <stdlib.h>
 44
 45#define ATABSIZE 39
 46
 47static struct alias *atab[ATABSIZE];
 48static int           aliases;
 49
 50static void   setalias(const char *, const char *);
 51static int    unalias(const char *);
 52static size_t hashalias(const char *);
 53
 54static void
 55setalias(const char *name, const char *val)
 56{
 57  struct alias *ap, **app;
 58
 59  unalias(name);
 60  app = &atab[hashalias(name)];
 61  INTOFF;
 62  ap       = ckmalloc(sizeof(struct alias));
 63  ap->name = savestr(name);
 64  ap->val  = savestr(val);
 65  ap->flag = 0;
 66  ap->next = *app;
 67  *app     = ap;
 68  aliases++;
 69  INTON;
 70}
 71
 72static void
 73freealias(struct alias *ap)
 74{
 75  ckfree(ap->name);
 76  ckfree(ap->val);
 77  ckfree(ap);
 78}
 79
 80static int
 81unalias(const char *name)
 82{
 83  struct alias *ap, **app;
 84
 85  app = &atab[hashalias(name)];
 86
 87  for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
 88    if (equal(name, ap->name)) {
 89      /*
 90       * if the alias is currently in use (i.e. its
 91       * buffer is being used by the input routine) we
 92       * just null out the name instead of freeing it.
 93       * We could clear it out later, but this situation
 94       * is so rare that it hardly seems worth it.
 95       */
 96      if (ap->flag & ALIASINUSE)
 97        *ap->name = '\0';
 98      else {
 99        INTOFF;
100        *app = ap->next;
101        freealias(ap);
102        INTON;
103      }
104      aliases--;
105      return (0);
106    }
107  }
108
109  return (1);
110}
111
112static void
113rmaliases(void)
114{
115  struct alias *ap, **app;
116  int           i;
117
118  INTOFF;
119  for (i = 0; i < ATABSIZE; i++) {
120    app = &atab[i];
121    while (*app) {
122      ap = *app;
123      if (ap->flag & ALIASINUSE) {
124        *ap->name = '\0';
125        app       = &(*app)->next;
126      } else {
127        *app = ap->next;
128        freealias(ap);
129      }
130    }
131  }
132  aliases = 0;
133  INTON;
134}
135
136struct alias *
137lookupalias(const char *name, int check)
138{
139  struct alias *ap;
140
141  if (aliases == 0)
142    return (NULL);
143  for (ap = atab[hashalias(name)]; ap; ap = ap->next) {
144    if (equal(name, ap->name)) {
145      if (check && (ap->flag & ALIASINUSE))
146        return (NULL);
147      return (ap);
148    }
149  }
150
151  return (NULL);
152}
153
154static int
155comparealiases(const void *p1, const void *p2)
156{
157  const struct alias *const *a1 = p1;
158  const struct alias *const *a2 = p2;
159
160  return strcmp((*a1)->name, (*a2)->name);
161}
162
163static void
164printalias(const struct alias *a)
165{
166  out1fmt("%s=", a->name);
167  out1qstr(a->val);
168  out1c('\n');
169}
170
171static void
172printaliases(void)
173{
174  int            i, j;
175  struct alias **sorted, *ap;
176
177  INTOFF;
178  sorted = ckmalloc(aliases * sizeof(*sorted));
179  j      = 0;
180  for (i = 0; i < ATABSIZE; i++)
181    for (ap = atab[i]; ap; ap = ap->next)
182      if (*ap->name != '\0')
183        sorted[j++] = ap;
184  qsort(sorted, aliases, sizeof(*sorted), comparealiases);
185  for (i = 0; i < aliases; i++) {
186    printalias(sorted[i]);
187    if (int_pending())
188      break;
189  }
190  ckfree(sorted);
191  INTON;
192}
193
194int
195aliascmd(int argc __unused, char **argv __unused)
196{
197  char         *n, *v;
198  int           ret = 0;
199  struct alias *ap;
200
201  nextopt("");
202
203  if (*argptr == NULL) {
204    printaliases();
205    return (0);
206  }
207  while ((n = *argptr++) != NULL) {
208    if (n[0] == '\0') {
209      warning("'': not found");
210      ret = 1;
211      continue;
212    }
213    if ((v = strchr(n + 1, '=')) == NULL) /* n+1: funny ksh stuff */
214      if ((ap = lookupalias(n, 0)) == NULL) {
215        warning("%s: not found", n);
216        ret = 1;
217      } else
218        printalias(ap);
219    else {
220      *v++ = '\0';
221      setalias(n, v);
222    }
223  }
224
225  return (ret);
226}
227
228int
229unaliascmd(int argc __unused, char **argv __unused)
230{
231  int i;
232
233  while ((i = nextopt("a")) != '\0') {
234    if (i == 'a') {
235      rmaliases();
236      return (0);
237    }
238  }
239  for (i = 0; *argptr; argptr++)
240    i |= unalias(*argptr);
241
242  return (i);
243}
244
245static size_t
246hashalias(const char *p)
247{
248  unsigned int hashval;
249
250  hashval = (unsigned char)*p << 4;
251  while (*p)
252    hashval += *p++;
253  return (hashval % ATABSIZE);
254}
255
256const struct alias *
257iteralias(const struct alias *index)
258{
259  size_t i = 0;
260
261  if (index != NULL) {
262    if (index->next != NULL)
263      return (index->next);
264    i = hashalias(index->name) + 1;
265  }
266  for (; i < ATABSIZE; i++)
267    if (atab[i] != NULL)
268      return (atab[i]);
269
270  return (NULL);
271}