master xplshn/aruu / cmd / posix / sh / show.c
  1/*-
  2 * SPDX-License-Identifier: BSD-3-Clause
  3 *
  4 * Copyright (c) 1991, 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 <errno.h>
 36#include <fcntl.h>
 37#include <stdarg.h>
 38#include <stdio.h>
 39#include <stdlib.h>
 40
 41#include "mystring.h"
 42#include "nodes.h"
 43#include "parser.h"
 44#include "shell.h"
 45#include "show.h"
 46
 47#ifdef DEBUG
 48static void shtree(union node *, int, char *, FILE *);
 49static void shcmd(union node *, FILE *);
 50static void sharg(union node *, FILE *);
 51static void indent(int, char *, FILE *);
 52static void trstring(char *);
 53
 54void
 55showtree(union node *n)
 56{
 57  trputs("showtree called\n");
 58  shtree(n, 1, NULL, stdout);
 59}
 60
 61static void
 62shtree(union node *n, int ind, char *pfx, FILE *fp)
 63{
 64  struct nodelist *lp;
 65  const char      *s;
 66
 67  if (n == NULL)
 68    return;
 69
 70  indent(ind, pfx, fp);
 71  switch (n->type) {
 72    case NSEMI:
 73      s = "; ";
 74      goto binop;
 75    case NAND:
 76      s = " && ";
 77      goto binop;
 78    case NOR:
 79      s = " || ";
 80    binop:
 81      shtree(n->nbinary.ch1, ind, NULL, fp);
 82      /*    if (ind < 0) */
 83      fputs(s, fp);
 84      shtree(n->nbinary.ch2, ind, NULL, fp);
 85      break;
 86    case NCMD:
 87      shcmd(n, fp);
 88      if (ind >= 0)
 89        putc('\n', fp);
 90      break;
 91    case NPIPE:
 92      for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
 93        shcmd(lp->n, fp);
 94        if (lp->next)
 95          fputs(" | ", fp);
 96      }
 97      if (n->npipe.backgnd)
 98        fputs(" &", fp);
 99      if (ind >= 0)
100        putc('\n', fp);
101      break;
102    default:
103      fprintf(fp, "<node type %d>", n->type);
104      if (ind >= 0)
105        putc('\n', fp);
106      break;
107  }
108}
109
110static void
111shcmd(union node *cmd, FILE *fp)
112{
113  union node *np;
114  int         first;
115  const char *s;
116  int         dftfd;
117
118  first = 1;
119  for (np = cmd->ncmd.args; np; np = np->narg.next) {
120    if (!first)
121      putchar(' ');
122    sharg(np, fp);
123    first = 0;
124  }
125  for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
126    if (!first)
127      putchar(' ');
128    switch (np->nfile.type) {
129      case NTO:
130        s     = ">";
131        dftfd = 1;
132        break;
133      case NAPPEND:
134        s     = ">>";
135        dftfd = 1;
136        break;
137      case NTOFD:
138        s     = ">&";
139        dftfd = 1;
140        break;
141      case NCLOBBER:
142        s     = ">|";
143        dftfd = 1;
144        break;
145      case NFROM:
146        s     = "<";
147        dftfd = 0;
148        break;
149      case NFROMTO:
150        s     = "<>";
151        dftfd = 0;
152        break;
153      case NFROMFD:
154        s     = "<&";
155        dftfd = 0;
156        break;
157      case NHERE:
158        s     = "<<";
159        dftfd = 0;
160        break;
161      case NXHERE:
162        s     = "<<";
163        dftfd = 0;
164        break;
165      default:
166        s     = "*error*";
167        dftfd = 0;
168        break;
169    }
170    if (np->nfile.fd != dftfd)
171      fprintf(fp, "%d", np->nfile.fd);
172    fputs(s, fp);
173    if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
174      if (np->ndup.dupfd >= 0)
175        fprintf(fp, "%d", np->ndup.dupfd);
176      else
177        fprintf(fp, "-");
178    } else if (np->nfile.type == NHERE) {
179      fprintf(fp, "HERE");
180    } else if (np->nfile.type == NXHERE) {
181      fprintf(fp, "XHERE");
182    } else {
183      sharg(np->nfile.fname, fp);
184    }
185    first = 0;
186  }
187}
188
189static void
190sharg(union node *arg, FILE *fp)
191{
192  char            *p;
193  struct nodelist *bqlist;
194  int              subtype;
195
196  if (arg->type != NARG) {
197    printf("<node type %d>\n", arg->type);
198    fflush(stdout);
199    abort();
200  }
201  bqlist = arg->narg.backquote;
202  for (p = arg->narg.text; *p; p++) {
203    switch (*p) {
204      case CTLESC:
205        putc(*++p, fp);
206        break;
207      case CTLVAR:
208        putc('$', fp);
209        putc('{', fp);
210        subtype = *++p;
211        if (subtype == VSLENGTH)
212          putc('#', fp);
213
214        while (*p != '=')
215          putc(*p++, fp);
216
217        if (subtype & VSNUL)
218          putc(':', fp);
219
220        switch (subtype & VSTYPE) {
221          case VSNORMAL:
222            putc('}', fp);
223            break;
224          case VSMINUS:
225            putc('-', fp);
226            break;
227          case VSPLUS:
228            putc('+', fp);
229            break;
230          case VSQUESTION:
231            putc('?', fp);
232            break;
233          case VSASSIGN:
234            putc('=', fp);
235            break;
236          case VSTRIMLEFT:
237            putc('#', fp);
238            break;
239          case VSTRIMLEFTMAX:
240            putc('#', fp);
241            putc('#', fp);
242            break;
243          case VSTRIMRIGHT:
244            putc('%', fp);
245            break;
246          case VSTRIMRIGHTMAX:
247            putc('%', fp);
248            putc('%', fp);
249            break;
250          case VSLENGTH:
251            break;
252          default:
253            printf("<subtype %d>", subtype);
254        }
255        break;
256      case CTLENDVAR:
257        putc('}', fp);
258        break;
259      case CTLBACKQ:
260      case CTLBACKQ | CTLQUOTE:
261        putc('$', fp);
262        putc('(', fp);
263        shtree(bqlist->n, -1, NULL, fp);
264        putc(')', fp);
265        break;
266      default:
267        putc(*p, fp);
268        break;
269    }
270  }
271}
272
273static void
274indent(int amount, char *pfx, FILE *fp)
275{
276  int i;
277
278  for (i = 0; i < amount; i++) {
279    if (pfx && i == amount - 1)
280      fputs(pfx, fp);
281    putc('\t', fp);
282  }
283}
284
285/*
286 * Debugging stuff.
287 */
288
289static FILE *tracefile;
290#if DEBUG >= 2
291int debug = 1;
292#else
293int debug = 0;
294#endif
295
296void
297trputc(int c)
298{
299  if (tracefile == NULL)
300    return;
301  putc(c, tracefile);
302  if (c == '\n')
303    fflush(tracefile);
304}
305
306void
307sh_trace(const char *fmt, ...)
308{
309  va_list va;
310  va_start(va, fmt);
311  if (tracefile != NULL) {
312    (void)vfprintf(tracefile, fmt, va);
313    if (strchr(fmt, '\n'))
314      (void)fflush(tracefile);
315  }
316  va_end(va);
317}
318
319void
320trputs(const char *s)
321{
322  if (tracefile == NULL)
323    return;
324  fputs(s, tracefile);
325  if (strchr(s, '\n'))
326    fflush(tracefile);
327}
328
329static void
330trstring(char *s)
331{
332  char *p;
333  char  c;
334
335  if (tracefile == NULL)
336    return;
337  putc('"', tracefile);
338  for (p = s; *p; p++) {
339    switch (*p) {
340      case '\n':
341        c = 'n';
342        goto backslash;
343      case '\t':
344        c = 't';
345        goto backslash;
346      case '\r':
347        c = 'r';
348        goto backslash;
349      case '"':
350        c = '"';
351        goto backslash;
352      case '\\':
353        c = '\\';
354        goto backslash;
355      case CTLESC:
356        c = 'e';
357        goto backslash;
358      case CTLVAR:
359        c = 'v';
360        goto backslash;
361      case CTLVAR + CTLQUOTE:
362        c = 'V';
363        goto backslash;
364      case CTLBACKQ:
365        c = 'q';
366        goto backslash;
367      case CTLBACKQ + CTLQUOTE:
368        c = 'Q';
369        goto backslash;
370      backslash:
371        putc('\\', tracefile);
372        putc(c, tracefile);
373        break;
374      default:
375        if (*p >= ' ' && *p <= '~')
376          putc(*p, tracefile);
377        else {
378          putc('\\', tracefile);
379          putc(*p >> 6 & 03, tracefile);
380          putc(*p >> 3 & 07, tracefile);
381          putc(*p & 07, tracefile);
382        }
383        break;
384    }
385  }
386  putc('"', tracefile);
387}
388
389void
390trargs(char **ap)
391{
392  if (tracefile == NULL)
393    return;
394  while (*ap) {
395    trstring(*ap++);
396    if (*ap)
397      putc(' ', tracefile);
398    else
399      putc('\n', tracefile);
400  }
401  fflush(tracefile);
402}
403
404void
405opentrace(void)
406{
407  char s[100];
408  int  flags;
409
410  if (!debug)
411    return;
412#ifdef not_this_way
413  {
414    char *p;
415    if ((p = getenv("HOME")) == NULL) {
416      if (geteuid() == 0)
417        p = "/";
418      else
419        p = "/tmp";
420    }
421    strcpy(s, p);
422    strcat(s, "/trace");
423  }
424#else
425  strcpy(s, "./trace");
426#endif /* not_this_way */
427  if ((tracefile = fopen(s, "a")) == NULL) {
428    fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
429    return;
430  }
431  if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
432    fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
433  fputs("\nTracing started.\n", tracefile);
434  fflush(tracefile);
435}
436#endif /* DEBUG */