]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20070802 snapshot
authorChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:11:08 +0000 (09:11 -0500)
committerChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:11:08 +0000 (09:11 -0500)
50 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
Makefile.in
Makefile.in~
examples/loadables/Makefile.in
examples/loadables/Makefile.in~
examples/loadables/basename.c
examples/loadables/basename.c~ [new file with mode: 0644]
examples/loadables/cut.c
examples/loadables/cut.c~ [new file with mode: 0644]
examples/loadables/dirname.c
examples/loadables/dirname.c~ [new file with mode: 0644]
examples/loadables/finfo.c
examples/loadables/finfo.c~ [new file with mode: 0644]
examples/loadables/head.c
examples/loadables/head.c~ [new file with mode: 0644]
examples/loadables/ln.c
examples/loadables/ln.c~ [new file with mode: 0644]
examples/loadables/logname.c
examples/loadables/logname.c~ [new file with mode: 0644]
examples/loadables/mkdir.c
examples/loadables/mkdir.c~ [new file with mode: 0644]
examples/loadables/pathchk.c
examples/loadables/pathchk.c~ [new file with mode: 0644]
examples/loadables/print.c
examples/loadables/print.c~ [new file with mode: 0644]
examples/loadables/printenv.c
examples/loadables/printenv.c~ [new file with mode: 0644]
examples/loadables/push.c
examples/loadables/push.c~ [new file with mode: 0644]
examples/loadables/realpath.c
examples/loadables/realpath.c~ [new file with mode: 0644]
examples/loadables/rmdir.c
examples/loadables/rmdir.c~ [new file with mode: 0644]
examples/loadables/sleep.c
examples/loadables/sleep.c~ [new file with mode: 0644]
examples/loadables/tee.c
examples/loadables/tee.c~ [new file with mode: 0644]
examples/loadables/truefalse.c
examples/loadables/truefalse.c~ [new file with mode: 0644]
examples/loadables/tty.c
examples/loadables/tty.c~ [new file with mode: 0644]
examples/loadables/uname.c
examples/loadables/uname.c~ [new file with mode: 0644]
examples/loadables/unlink.c
examples/loadables/unlink.c~ [new file with mode: 0644]
examples/loadables/whoami.c
examples/loadables/whoami.c~ [new file with mode: 0644]
lib/readline/histexpand.c
lib/readline/util.c

index 658257ec0b3a390517dd78e4ab1eb1afeafa3ce3..0b023ace3cd4624b93f6a92b7abde021195f9158 100644 (file)
@@ -14790,7 +14790,7 @@ lib/sh/getcwd.c
 builtins/common.c
        - change sh_invalidnum to be a little smarter about octal and hex
          numbers and change the message appropriately.  Bug originally
-         reported on coreutils list by Jürgen Niinre<Jyrgen.Niinre@emt.ee>
+         reported on coreutils list by Jürgen Niinre <Jyrgen.Niinre@emt.ee>
 
                                   7/26
                                   ----
@@ -14813,3 +14813,21 @@ trap.c
          trapped and issue a warning if the shell was compiled with
          debugging enabled.  Fixes bug reported by Fergus Henderson
          <fergus@google.com>
+
+                                   8/1
+                                   ---
+lib/readline/{util,histexpand}.c
+       - fixes for small memory leaks from Michael Snyder <msnyder@sonic.net>
+
+                                  8/18
+                                  ----
+Makefile.in
+       - add dependency on builtins/builtext.h to nojobs.o list.  Fixes
+         `make -j 5' issue reported by Chris MacGregor <chris@bouncingdog.com>
+
+examples/loadables/Makefile.in
+       - add @LDFLAGS@ to SHOBJ_LDFLAGS assignment -- experimental.  Suggested
+         by Mike Frysinger <vapier@gentoo.org>
+
+examples/loadables/{basename,cut,dirname,finfo,head,ln,logname,mkdir,pathchk,print,printenv,push,realpath,rmdir,sleep,tee,truefalse,tty,uname,unlink,whoami}.c
+       - fix up some includes.  Fix from Mike Frysinger <vapier@gentoo.org>
index 3246dcc0336db11286e5bce94ecf5daada16adc8..80943e812fcc819ca51fa2c6b2457f8705535511 100644 (file)
@@ -14790,7 +14790,7 @@ lib/sh/getcwd.c
 builtins/common.c
        - change sh_invalidnum to be a little smarter about octal and hex
          numbers and change the message appropriately.  Bug originally
-         reported on coreutils list by Jürgen Niinre<Jyrgen.Niinre@emt.ee>
+         reported on coreutils list by Jürgen Niinre <Jyrgen.Niinre@emt.ee>
 
                                   7/26
                                   ----
@@ -14802,3 +14802,31 @@ test.c
 parse.y
        - better input validation: make sure a word looks like a conditional
          unary operator (-X) before calling test_unop
+
+                                  7/28
+                                  ----
+trap.c
+       - in trap_handler, if it's called directly from the signal handler
+         (e.g., SIGINT sighandler, set by set_sigint_handler), but the
+         trap disposition has been reset to the default between the
+         assignment and receipt of the signal, check that the signal is
+         trapped and issue a warning if the shell was compiled with
+         debugging enabled.  Fixes bug reported by Fergus Henderson
+         <fergus@google.com>
+
+                                   8/1
+                                   ---
+lib/readline/{util,histexpand}.c
+       - fixes for small memory leaks from Michael Snyder <msnyder@sonic.net>
+
+                                  8/18
+                                  ----
+Makefile.in
+       - add dependency on builtins/builtext.h to nojobs.o list.  Fixes
+         `make -j 5' issue reported by Chris MacGregor <chris@bouncingdog.com>
+
+examples/loadables/Makefile.in
+       - add @LDFLAGS@ to SHOBJ_LDFLAGS assignment -- experimental.  Suggested
+         by Mike Frysinger <vapier@gentoo.org>
+
+examples/loadables/{
index a90fb00f0a8d2fec1745010552bf18f2e703c4f8..c215b623573c77688f5d169f805f2d0a65aebd20 100644 (file)
@@ -1055,6 +1055,7 @@ jobs.o: ${BASHINCDIR}/posixtime.h
 nojobs.o: config.h bashtypes.h ${BASHINCDIR}/filecntl.h bashjmp.h ${BASHINCDIR}/posixjmp.h
 nojobs.o: command.h ${BASHINCDIR}/stdc.h general.h xmalloc.h jobs.h quit.h siglist.h externs.h
 nojobs.o: sig.h error.h ${BASHINCDIR}/shtty.h input.h
+nojobs.o: $(DEFDIR)/builtext.h
 
 # shell features that may be compiled in
 
index c9726f93933576391d6790ffb519959bd84b7d7c..a90fb00f0a8d2fec1745010552bf18f2e703c4f8 100644 (file)
@@ -39,7 +39,7 @@ libdir = @libdir@
 infodir = @infodir@
 includedir = @includedir@
 datadir = @datadir@
-localedir = $(datadir)/locale
+localedir = @localedir@
 
 mandir = @mandir@
 manpfx = man
index 8092d20df0d97e7e8274fa09dcad496fd66a2ea5..d076803b24e7ea3691f894da5748d5bc1adde4e3 100644 (file)
@@ -70,7 +70,7 @@ CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
 SHOBJ_CC = @SHOBJ_CC@
 SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
 SHOBJ_LD = @SHOBJ_LD@
-SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
+SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ @LDFLAGS@
 SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
 SHOBJ_LIBS = @SHOBJ_LIBS@
 SHOBJ_STATUS = @SHOBJ_STATUS@
index c505263ebf87436e66928cbcafc65758ca8072f1..8092d20df0d97e7e8274fa09dcad496fd66a2ea5 100644 (file)
@@ -26,6 +26,8 @@ libdir = @libdir@
 infodir = @infodir@
 includedir = @includedir@
 
+datarootdir = @datarootdir@
+
 topdir = @top_srcdir@
 BUILD_DIR = @BUILD_DIR@
 srcdir = @srcdir@
index 7f254c7679f59e23f763f12a8c96ba889f708fd1..bec68a751dbf88fc36982815a287a2081a7de4e9 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include "builtins.h"
 #include "shell.h"
+#include "common.h"
 
 basename_builtin (list)
      WORD_LIST *list;
diff --git a/examples/loadables/basename.c~ b/examples/loadables/basename.c~
new file mode 100644 (file)
index 0000000..7f254c7
--- /dev/null
@@ -0,0 +1,108 @@
+/* basename - return nondirectory portion of pathname */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "builtins.h"
+#include "shell.h"
+
+basename_builtin (list)
+     WORD_LIST *list;
+{
+  int slen, sufflen, off;
+  char *string, *suffix, *fn;
+
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (no_options (list))
+    return (EX_USAGE);
+
+  string = list->word->word;
+  suffix = (char *)NULL;
+  if (list->next)
+    {
+      list = list->next;
+      suffix = list->word->word;
+    }
+
+  if (list->next)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  slen = strlen (string);
+
+  /* Strip trailing slashes */
+  while (slen > 0 && string[slen - 1] == '/')
+    slen--;
+
+  /* (2) If string consists entirely of slash characters, string shall be
+        set to a single slash character.  In this case, skip steps (3)
+        through (5). */
+  if (slen == 0)
+    {
+      fputs ("/\n", stdout);
+      return (EXECUTION_SUCCESS);
+    }
+
+  /* (3) If there are any trailing slash characters in string, they
+        shall be removed. */
+  string[slen] = '\0';
+
+  /* (4) If there are any slash characters remaining in string, the prefix
+        of string up to an including the last slash character in string
+        shall be removed. */
+  while (--slen >= 0)
+    if (string[slen] == '/')
+      break;
+
+  fn = string + slen + 1;
+
+  /* (5) If the suffix operand is present, is not identical to the
+        characters remaining in string, and is identical to a suffix
+        of the characters remaining in string, the suffix suffix
+        shall be removed from string.  Otherwise, string shall not be
+        modified by this step. */
+  if (suffix)
+    {
+      sufflen = strlen (suffix);
+      slen = strlen (fn);
+      if (sufflen < slen)
+        {
+          off = slen - sufflen;
+          if (strcmp (fn + off, suffix) == 0)
+            fn[off] = '\0';
+        }
+    }
+  printf ("%s\n", fn);
+  return (EXECUTION_SUCCESS);
+}
+
+char *basename_doc[] = {
+       "The STRING is converted to a filename corresponding to the last",
+       "pathname component in STRING.  If the suffix string SUFFIX is",
+       "supplied, it is removed.",
+       (char *)NULL
+};
+
+/* The standard structure describing a builtin command.  bash keeps an array
+   of these structures. */
+struct builtin basename_struct = {
+       "basename",             /* builtin name */
+       basename_builtin,       /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       basename_doc,           /* array of long documentation strings. */
+       "basename string [suffix]",     /* usage synopsis */
+       0                       /* reserved for internal use */
+};
index d874034a854aa67fe48ec136a91892ecd2da22a7..f358cba3c565c9e24ad1db34491f410cbc525cef 100644 (file)
@@ -63,6 +63,7 @@ static const char sccsid[] = "@(#)cut.c       8.3 (Berkeley) 5/4/95";
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int     errno;
diff --git a/examples/loadables/cut.c~ b/examples/loadables/cut.c~
new file mode 100644 (file)
index 0000000..d874034
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static const char sccsid[] = "@(#)cut.c        8.3 (Berkeley) 5/4/95";
+#endif /* not lint */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "bashansi.h"
+
+#ifdef HAVE_LIMITS_H
+#  include <limits.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int     errno;
+#endif
+
+#if !defined (_POSIX2_LINE_MAX)
+#  define _POSIX2_LINE_MAX 2048
+#endif
+
+static int     cflag;
+static char    dchar;
+static int     dflag;
+static int     fflag;
+static int     sflag;
+
+static int autostart, autostop, maxval;
+static char positions[_POSIX2_LINE_MAX + 1];
+
+static int     c_cut __P((FILE *, char *));
+static int     f_cut __P((FILE *, char *));
+static int     get_list __P((char *));
+static char    *_cut_strsep __P((char **, const char *));
+
+int
+cut_builtin(list)
+       WORD_LIST *list;
+{
+       FILE *fp;
+       int (*fcn) __P((FILE *, char *)) = NULL;
+       int ch;
+
+       fcn = NULL;
+       dchar = '\t';                   /* default delimiter is \t */
+
+       /* Since we don't support multi-byte characters, the -c and -b 
+          options are equivalent, and the -n option is meaningless. */
+       reset_internal_getopt ();
+       while ((ch = internal_getopt (list, "b:c:d:f:sn")) != -1)
+               switch(ch) {
+               case 'b':
+               case 'c':
+                       fcn = c_cut;
+                       if (get_list(list_optarg) < 0)
+                               return (EXECUTION_FAILURE);
+                       cflag = 1;
+                       break;
+               case 'd':
+                       dchar = *list_optarg;
+                       dflag = 1;
+                       break;
+               case 'f':
+                       fcn = f_cut;
+                       if (get_list(list_optarg) < 0)
+                               return (EXECUTION_FAILURE);
+                       fflag = 1;
+                       break;
+               case 's':
+                       sflag = 1;
+                       break;
+               case 'n':
+                       break;
+               case '?':
+               default:
+                       builtin_usage();
+                       return (EX_USAGE);
+               }
+
+       list = loptend;
+
+       if (fflag) {
+               if (cflag) {
+                       builtin_usage();
+                       return (EX_USAGE);
+               }
+       } else if (!cflag || dflag || sflag) {
+               builtin_usage();
+               return (EX_USAGE);
+       }
+
+       if (list) {
+               while (list) {
+                       fp = fopen(list->word->word, "r");
+                       if (fp == 0) {
+                               builtin_error("%s", list->word->word);
+                               return (EXECUTION_FAILURE);
+                       }
+                       ch = (*fcn)(fp, list->word->word);
+                       (void)fclose(fp);
+                       if (ch < 0)
+                               return (EXECUTION_FAILURE);
+                       list = list->next;
+               }
+       } else {
+               ch = (*fcn)(stdin, "stdin");
+               if (ch < 0)
+                       return (EXECUTION_FAILURE);
+       }
+
+       return (EXECUTION_SUCCESS);
+}
+
+static int
+get_list(list)
+       char *list;
+{
+       int setautostart, start, stop;
+       char *pos;
+       char *p;
+
+       /*
+        * set a byte in the positions array to indicate if a field or
+        * column is to be selected; use +1, it's 1-based, not 0-based.
+        * This parser is less restrictive than the Draft 9 POSIX spec.
+        * POSIX doesn't allow lists that aren't in increasing order or
+        * overlapping lists.  We also handle "-3-5" although there's no
+        * real reason too.
+        */
+       for (; (p = _cut_strsep(&list, ", \t")) != NULL;) {
+               setautostart = start = stop = 0;
+               if (*p == '-') {
+                       ++p;
+                       setautostart = 1;
+               }
+               if (isdigit((unsigned char)*p)) {
+                       start = stop = strtol(p, &p, 10);
+                       if (setautostart && start > autostart)
+                               autostart = start;
+               }
+               if (*p == '-') {
+                       if (isdigit((unsigned char)p[1]))
+                               stop = strtol(p + 1, &p, 10);
+                       if (*p == '-') {
+                               ++p;
+                               if (!autostop || autostop > stop)
+                                       autostop = stop;
+                       }
+               }
+               if (*p) {
+                       builtin_error("[-cf] list: illegal list value");
+                       return -1;
+               }
+               if (!stop || !start) {
+                       builtin_error("[-cf] list: values may not include zero");
+                       return -1;
+               }
+               if (stop > _POSIX2_LINE_MAX) {
+                       builtin_error("[-cf] list: %d too large (max %d)",
+                                      stop, _POSIX2_LINE_MAX);
+                       return -1;
+               }
+               if (maxval < stop)
+                       maxval = stop;
+               for (pos = positions + start; start++ <= stop; *pos++ = 1);
+       }
+
+       /* overlapping ranges */
+       if (autostop && maxval > autostop)
+               maxval = autostop;
+
+       /* set autostart */
+       if (autostart)
+               memset(positions + 1, '1', autostart);
+
+       return 0;
+}
+
+/* ARGSUSED */
+static int
+c_cut(fp, fname)
+       FILE *fp;
+       char *fname;
+{
+       int ch, col;
+       char *pos;
+
+       ch = 0;
+       for (;;) {
+               pos = positions + 1;
+               for (col = maxval; col; --col) {
+                       if ((ch = getc(fp)) == EOF)
+                               return;
+                       if (ch == '\n')
+                               break;
+                       if (*pos++)
+                               (void)putchar(ch);
+               }
+               if (ch != '\n') {
+                       if (autostop)
+                               while ((ch = getc(fp)) != EOF && ch != '\n')
+                                       (void)putchar(ch);
+                       else
+                               while ((ch = getc(fp)) != EOF && ch != '\n');
+               }
+               (void)putchar('\n');
+       }
+       return (0);
+}
+
+static int
+f_cut(fp, fname)
+       FILE *fp;
+       char *fname;
+{
+       int ch, field, isdelim;
+       char *pos, *p, sep;
+       int output;
+       char lbuf[_POSIX2_LINE_MAX + 1];
+
+       for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) {
+               output = 0;
+               for (isdelim = 0, p = lbuf;; ++p) {
+                       if (!(ch = *p)) {
+                               builtin_error("%s: line too long.", fname);
+                               return -1;
+                       }
+                       /* this should work if newline is delimiter */
+                       if (ch == sep)
+                               isdelim = 1;
+                       if (ch == '\n') {
+                               if (!isdelim && !sflag)
+                                       (void)printf("%s", lbuf);
+                               break;
+                       }
+               }
+               if (!isdelim)
+                       continue;
+
+               pos = positions + 1;
+               for (field = maxval, p = lbuf; field; --field, ++pos) {
+                       if (*pos) {
+                               if (output++)
+                                       (void)putchar(sep);
+                               while ((ch = *p++) != '\n' && ch != sep)
+                                       (void)putchar(ch);
+                       } else {
+                               while ((ch = *p++) != '\n' && ch != sep)
+                                       continue;
+                       }
+                       if (ch == '\n')
+                               break;
+               }
+               if (ch != '\n') {
+                       if (autostop) {
+                               if (output)
+                                       (void)putchar(sep);
+                               for (; (ch = *p) != '\n'; ++p)
+                                       (void)putchar(ch);
+                       } else
+                               for (; (ch = *p) != '\n'; ++p);
+               }
+               (void)putchar('\n');
+       }
+       return (0);
+}
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+static char *
+_cut_strsep(stringp, delim)
+       register char **stringp;
+       register const char *delim;
+{
+       register char *s;
+       register const char *spanp;
+       register int c, sc;
+       char *tok;
+
+       if ((s = *stringp) == NULL)
+               return (NULL);
+       for (tok = s;;) {
+               c = *s++;
+               spanp = delim;
+               do {
+                       if ((sc = *spanp++) == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else
+                                       s[-1] = 0;
+                               *stringp = s;
+                               return (tok);
+                       }
+               } while (sc != 0);
+       }
+       /* NOTREACHED */
+}
+
+static char *cut_doc[] = {
+       "Select portions of each line (as specified by LIST) from each FILE",
+       "(by default, the standard input), and write them to the standard output.",
+       "Items specified by LIST are either column positions or fields delimited",
+       "by a special character.  Column numbering starts at 1.",
+       (char *)0
+};
+
+struct builtin cut_struct = {
+       "cut",
+       cut_builtin,
+       BUILTIN_ENABLED,
+       cut_doc,
+       "cut -b list [-n] [file ...] OR cut -c list [file ...] OR cut -f list [-s] [-d delim] [file ...]",
+       0
+};
index 6159560e54f1538fe8b2b730f4cf2280abe613b8..129ae7a992d5fafab1ae2940d39b332ccacb91a1 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include "builtins.h"
 #include "shell.h"
+#include "common.h"
 
 dirname_builtin (list)
      WORD_LIST *list;
diff --git a/examples/loadables/dirname.c~ b/examples/loadables/dirname.c~
new file mode 100644 (file)
index 0000000..6159560
--- /dev/null
@@ -0,0 +1,95 @@
+/* dirname - return directory portion of pathname */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "builtins.h"
+#include "shell.h"
+
+dirname_builtin (list)
+     WORD_LIST *list;
+{
+  int slen;
+  char *string;
+
+  if (list == 0 || list->next)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (no_options (list))
+    return (EX_USAGE);
+
+  string = list->word->word;
+  slen = strlen (string);
+
+  /* Strip trailing slashes */
+  while (slen > 0 && string[slen - 1] == '/')
+    slen--;
+
+  /* (2) If string consists entirely of slash characters, string shall be
+        set to a single slash character.  In this case, skip steps (3)
+        through (8). */
+  if (slen == 0)
+    {
+      fputs ("/\n", stdout);
+      return (EXECUTION_SUCCESS);
+    }
+
+  /* (3) If there are any trailing slash characters in string, they
+        shall be removed. */
+  string[slen] = '\0';
+
+  /* (4) If there are no slash characters remaining in string, string
+        shall be set to a single period character.  In this case, skip
+        steps (5) through (8).
+
+     (5) If there are any trailing nonslash characters in string,
+        they shall be removed. */
+
+  while (--slen >= 0)
+    if (string[slen] == '/')
+      break;
+
+  if (slen < 0)
+    {
+      fputs (".\n", stdout);
+      return (EXECUTION_SUCCESS);
+    }
+
+  /* (7) If there are any trailing slash characters in string, they
+        shall be removed. */
+  while (--slen >= 0)
+    if (string[slen] != '/')
+      break;
+  string[++slen] = '\0';
+
+  /* (8) If the remaining string is empty, string shall be set to a single
+        slash character. */
+  printf ("%s\n", (slen == 0) ? "/" : string);
+  return (EXECUTION_SUCCESS);
+}
+
+char *dirname_doc[] = {
+       "The STRING is converted to the name of the directory containing",      
+       "the filename corresponding to the last pathname component in STRING.",
+       (char *)NULL
+};
+
+/* The standard structure describing a builtin command.  bash keeps an array
+   of these structures. */
+struct builtin dirname_struct = {
+       "dirname",              /* builtin name */
+       dirname_builtin,        /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       dirname_doc,            /* array of long documentation strings. */
+       "dirname string",       /* usage synopsis */
+       0                       /* reserved for internal use */
+};
index c1682eda4756b80826ea70dd1ecf0ab107124e08..99d73e2770554c6540ca43978cc2e63ea9ee58b8 100644 (file)
@@ -12,6 +12,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <errno.h>
+#include "posixtime.h"
 
 #include "bashansi.h"
 #include "shell.h"
diff --git a/examples/loadables/finfo.c~ b/examples/loadables/finfo.c~
new file mode 100644 (file)
index 0000000..c1682ed
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * finfo - print file info
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include "posixstat.h"
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+
+#include "bashansi.h"
+#include "shell.h"
+#include "builtins.h"
+#include "common.h"
+
+#ifndef errno
+extern int     errno;
+#endif
+
+extern char    **make_builtin_argv ();
+
+static int     printst();
+static int     printsome();
+static int     printfinfo();
+static int     finfo_main();
+
+extern int     sh_optind;
+extern char    *sh_optarg;
+extern char    *this_command_name;
+
+static char    *prog;
+static int     pmask;
+
+#define OPT_UID                0x00001
+#define OPT_GID                0x00002
+#define OPT_DEV                0x00004
+#define OPT_INO                0x00008
+#define OPT_PERM       0x00010
+#define OPT_LNKNAM     0x00020
+#define OPT_FID                0x00040
+#define OPT_NLINK      0x00080
+#define OPT_RDEV       0x00100
+#define OPT_SIZE       0x00200
+#define OPT_ATIME      0x00400
+#define OPT_MTIME      0x00800
+#define OPT_CTIME      0x01000
+#define OPT_BLKSIZE    0x02000
+#define OPT_BLKS       0x04000
+#define OPT_FTYPE      0x08000
+#define OPT_PMASK      0x10000
+#define OPT_OPERM      0x20000
+
+#define OPT_ASCII      0x1000000
+
+#define OPTIONS                "acdgiflmnopsuACGMP:U"
+
+static int
+octal(s)
+char   *s;
+{
+       int     r;
+
+       r = *s - '0';
+       while (*++s >= '0' && *s <= '7')
+               r = (r * 8) + (*s - '0');
+       return r;
+}
+
+static int
+finfo_main(argc, argv)
+int    argc;
+char   **argv;
+{
+       register int    i;
+       int     mode, flags, opt;
+
+       sh_optind = 0;  /* XXX */
+       prog = base_pathname(argv[0]);
+       if (argc == 1) {
+               builtin_usage();
+               return(1);
+       }
+       flags = 0;
+       while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) {
+               switch(opt) {
+               case 'a': flags |= OPT_ATIME; break;
+               case 'A': flags |= OPT_ATIME|OPT_ASCII; break;
+               case 'c': flags |= OPT_CTIME; break;
+               case 'C': flags |= OPT_CTIME|OPT_ASCII; break;
+               case 'd': flags |= OPT_DEV; break;
+               case 'i': flags |= OPT_INO; break;
+               case 'f': flags |= OPT_FID; break;
+               case 'g': flags |= OPT_GID; break;
+               case 'G': flags |= OPT_GID|OPT_ASCII; break;
+               case 'l': flags |= OPT_LNKNAM; break;
+               case 'm': flags |= OPT_MTIME; break;
+               case 'M': flags |= OPT_MTIME|OPT_ASCII; break;
+               case 'n': flags |= OPT_NLINK; break;
+               case 'o': flags |= OPT_OPERM; break;
+               case 'p': flags |= OPT_PERM; break;
+               case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break;
+               case 's': flags |= OPT_SIZE; break;
+               case 'u': flags |= OPT_UID; break;
+               case 'U': flags |= OPT_UID|OPT_ASCII; break;
+               default: builtin_usage (); return(1);
+               }
+       }
+
+       argc -= sh_optind;
+       argv += sh_optind;
+
+       if (argc == 0) {
+               builtin_usage();
+               return(1);
+       }
+
+       for (i = 0; i < argc; i++)
+               opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]);
+
+       return(opt);
+}
+
+static struct stat *
+getstat(f)
+char   *f;
+{
+       static struct stat st;
+       int     fd, r;
+       intmax_t lfd;
+
+       if (strncmp(f, "/dev/fd/", 8) == 0) {
+               if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) {
+                       builtin_error("%s: invalid fd", f + 8);
+                       return ((struct stat *)0);
+               }
+               fd = lfd;
+               r = fstat(fd, &st);
+       } else
+#ifdef HAVE_LSTAT
+               r = lstat(f, &st);
+#else
+               r = stat(f, &st);
+#endif
+       if (r < 0) {
+               builtin_error("%s: cannot stat: %s", f, strerror(errno));
+               return ((struct stat *)0);
+       }
+       return (&st);
+}
+
+static int
+printfinfo(f)
+char   *f;
+{
+       struct stat *st;
+
+       st = getstat(f);
+       return (st ? printst(st) : 1);
+}
+
+static int
+getperm(m)
+int    m;
+{
+       return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID));
+}
+
+static int
+perms(m)
+int    m;
+{
+       char ubits[4], gbits[4], obits[4];      /* u=rwx,g=rwx,o=rwx */
+       int i;
+
+       i = 0;
+       if (m & S_IRUSR)
+               ubits[i++] = 'r';
+       if (m & S_IWUSR)
+               ubits[i++] = 'w';
+       if (m & S_IXUSR)
+               ubits[i++] = 'x';
+       ubits[i] = '\0';
+
+       i = 0;
+       if (m & S_IRGRP)
+               gbits[i++] = 'r';
+       if (m & S_IWGRP)
+               gbits[i++] = 'w';
+       if (m & S_IXGRP)
+               gbits[i++] = 'x';
+       gbits[i] = '\0';
+
+       i = 0;
+       if (m & S_IROTH)
+               obits[i++] = 'r';
+       if (m & S_IWOTH)
+               obits[i++] = 'w';
+       if (m & S_IXOTH)
+               obits[i++] = 'x';
+       obits[i] = '\0';
+
+       if (m & S_ISUID)
+               ubits[2] = (m & S_IXUSR) ? 's' : 'S';
+       if (m & S_ISGID)
+               gbits[2] = (m & S_IXGRP) ? 's' : 'S';
+       if (m & S_ISVTX)
+               obits[2] = (m & S_IXOTH) ? 't' : 'T';
+
+       printf ("u=%s,g=%s,o=%s", ubits, gbits, obits);
+}
+
+static int
+printmode(mode)
+int    mode;
+{
+       if (S_ISBLK(mode))
+               printf("S_IFBLK ");
+       if (S_ISCHR(mode))
+               printf("S_IFCHR ");
+       if (S_ISDIR(mode))
+               printf("S_IFDIR ");
+       if (S_ISREG(mode))
+               printf("S_IFREG ");
+       if (S_ISFIFO(mode))
+               printf("S_IFIFO ");
+       if (S_ISLNK(mode))
+               printf("S_IFLNK ");
+       if (S_ISSOCK(mode))
+               printf("S_IFSOCK ");
+#ifdef S_ISWHT
+       if (S_ISWHT(mode))
+               printf("S_ISWHT ");
+#endif
+       perms(getperm(mode));
+       printf("\n");
+}
+
+static int     
+printst(st)
+struct stat *st;
+{
+       struct passwd   *pw;
+       struct group    *gr;
+       char    *owner;
+       int     ma, mi, d;
+
+       ma = major (st->st_rdev);
+       mi = minor (st->st_rdev);
+#if defined (makedev)
+       d = makedev (ma, mi);
+#else
+       d = st->st_rdev & 0xFF;
+#endif
+       printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi);
+
+       printf("Inode: %d\n", (int) st->st_ino);
+       printf("Mode: (%o) ", (int) st->st_mode);
+       printmode((int) st->st_mode);
+       printf("Link count: %d\n", (int) st->st_nlink);
+       pw = getpwuid(st->st_uid);
+       owner = pw ? pw->pw_name : "unknown";
+       printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner);
+       gr = getgrgid(st->st_gid);
+       owner = gr ? gr->gr_name : "unknown";
+       printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner);
+       printf("Device type: %d\n", (int) st->st_rdev);
+       printf("File size: %ld\n", (long) st->st_size);
+       printf("File last access time: %s", ctime (&st->st_atime));
+       printf("File last modify time: %s", ctime (&st->st_mtime));
+       printf("File last status change time: %s", ctime (&st->st_ctime));
+       fflush(stdout);
+       return(0);
+}
+
+static int
+printsome(f, flags)
+char   *f;
+int    flags;
+{
+       struct stat *st;
+       struct passwd *pw;
+       struct group *gr;
+       int     p;
+       char    *b;
+
+       st = getstat(f);
+       if (st == NULL)
+               return (1);
+
+       /* Print requested info */
+       if (flags & OPT_ATIME) {
+               if (flags & OPT_ASCII)
+                       printf("%s", ctime(&st->st_atime));
+               else
+                       printf("%ld\n", st->st_atime);
+       } else if (flags & OPT_MTIME) {
+               if (flags & OPT_ASCII)
+                       printf("%s", ctime(&st->st_mtime));
+               else
+                       printf("%ld\n", st->st_mtime);
+       } else if (flags & OPT_CTIME) {
+               if (flags & OPT_ASCII)
+                       printf("%s", ctime(&st->st_ctime));
+               else
+                       printf("%ld\n", st->st_ctime);
+       } else if (flags & OPT_DEV)
+               printf("%d\n", st->st_dev);
+       else if (flags & OPT_INO)
+               printf("%d\n", st->st_ino);
+       else if (flags & OPT_FID)
+               printf("%d:%ld\n", st->st_dev, st->st_ino);
+       else if (flags & OPT_NLINK)
+               printf("%d\n", st->st_nlink);
+       else if (flags & OPT_LNKNAM) {
+#ifdef S_ISLNK
+               b = xmalloc(4096);
+               p = readlink(f, b, 4096);
+               if (p >= 0 && p < 4096)
+                       b[p] = '\0';
+               else {
+                       p = errno;
+                       strcpy(b, prog);
+                       strcat(b, ": ");
+                       strcat(b, strerror(p));
+               }
+               printf("%s\n", b);
+               free(b);
+#else
+               printf("%s\n", f);
+#endif
+       } else if (flags & OPT_PERM) {
+               perms(st->st_mode);
+               printf("\n");
+       } else if (flags & OPT_OPERM)
+               printf("%o\n", getperm(st->st_mode));
+       else if (flags & OPT_PMASK)
+               printf("%o\n", getperm(st->st_mode) & pmask);
+       else if (flags & OPT_UID) {
+               pw = getpwuid(st->st_uid);
+               if (flags & OPT_ASCII)
+                       printf("%s\n", pw ? pw->pw_name : "unknown");
+               else
+                       printf("%d\n", st->st_uid);
+       } else if (flags & OPT_GID) {
+               gr = getgrgid(st->st_gid);
+               if (flags & OPT_ASCII)
+                       printf("%s\n", gr ? gr->gr_name : "unknown");
+               else
+                       printf("%d\n", st->st_gid);
+       } else if (flags & OPT_SIZE)
+               printf("%ld\n", st->st_size);
+
+       return (0);
+}
+
+#ifndef NOBUILTIN
+int
+finfo_builtin(list)
+     WORD_LIST *list;
+{
+  int c, r;
+  char **v;
+  WORD_LIST *l;
+
+  v = make_builtin_argv (list, &c);
+  r = finfo_main (c, v);
+  free (v);
+
+  return r;
+}
+
+static char *finfo_doc[] = {
+  "Display information about each FILE.  Only single operators should",
+  "be supplied.  If no options are supplied, a summary of the info",
+  "available about each FILE is printed.  If FILE is of the form",
+  "/dev/fd/XX, file descriptor XX is described.  Operators, if supplied,",
+  "have the following meanings:",
+  "",
+  "    -a      last file access time",
+  "    -A      last file access time in ctime format",
+  "    -c      last file status change time",
+  "    -C      last file status change time in ctime format",
+  "    -m      last file modification time",
+  "    -M      last file modification time in ctime format",
+  "    -d      device",
+  "    -i      inode",
+  "    -f      composite file identifier (device:inode)",
+  "    -g      gid of owner",
+  "    -G      group name of owner",
+  "    -l      name of file pointed to by symlink",
+  "    -n      link count",
+  "    -o      permissions in octal",
+  "    -p      permissions in ascii",
+  "    -P mask permissions ANDed with MASK (like with umask)",
+  "    -s      file size in bytes",
+  "    -u      uid of owner",
+  "    -U      user name of owner",
+  (char *)0
+};
+
+struct builtin finfo_struct = {
+       "finfo",
+       finfo_builtin,
+       BUILTIN_ENABLED,
+       finfo_doc,
+       "finfo [-acdgiflmnopsuACGMPU] file [file...]",
+       0
+};
+#endif
+
+#ifdef NOBUILTIN
+#if defined (PREFER_STDARG)
+#  include <stdarg.h>
+#else
+#  if defined (PREFER_VARARGS)
+#    include <varargs.h>
+#  endif
+#endif
+
+char *this_command_name;
+
+main(argc, argv)
+int    argc;
+char   **argv;
+{
+       this_command_name = argv[0];
+       exit(finfo_main(argc, argv));
+}
+
+void
+builtin_usage()
+{
+       fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, OPTIONS);
+}
+
+#ifndef HAVE_STRERROR
+char *
+strerror(e)
+int    e;
+{
+       static char     ebuf[40];
+       extern int      sys_nerr;
+       extern char     *sys_errlist[];
+
+       if (e < 0 || e > sys_nerr) {
+               sprintf(ebuf,"Unknown error code %d", e);
+               return (&ebuf[0]);
+       }
+       return (sys_errlist[e]);
+}
+#endif
+
+char *
+xmalloc(s)
+size_t s;
+{
+       char    *ret;
+       extern char *malloc();
+
+       ret = malloc(s);
+       if (ret)
+               return (ret);
+       fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s);
+       exit(1);
+}
+
+char *
+base_pathname(p)
+char   *p;
+{
+       char    *t;
+
+       if (t = strrchr(p, '/'))
+               return(++t);
+       return(p);
+}
+
+int
+legal_number (string, result)
+     char *string;
+     long *result;
+{
+  int sign;
+  long value;
+
+  sign = 1;
+  value = 0;
+
+  if (result)
+    *result = 0;
+
+  /* Skip leading whitespace characters. */
+  while (whitespace (*string))
+    string++;
+
+  if (!*string)
+    return (0);
+
+  /* We allow leading `-' or `+'. */
+  if (*string == '-' || *string == '+')
+    {
+      if (!digit (string[1]))
+        return (0);
+
+      if (*string == '-')
+        sign = -1;
+
+      string++;
+    }
+
+  while (digit (*string))
+    {
+      if (result)
+        value = (value * 10) + digit_value (*string);
+      string++;
+    }
+
+  /* Skip trailing whitespace, if any. */
+  while (whitespace (*string))
+    string++;
+
+  /* Error if not at end of string. */
+  if (*string)
+    return (0);
+
+  if (result)
+    *result = value * sign;
+
+  return (1);
+}
+
+int sh_optind;
+char *sh_optarg;
+int sh_opterr;
+
+extern int optind;
+extern char *optarg;
+
+int
+sh_getopt(c, v, o)
+int    c;
+char   **v, *o;
+{
+       int     r;
+
+       r = getopt(c, v, o);
+       sh_optind = optind;
+       sh_optarg = optarg;
+       return r;
+}
+
+#if defined (USE_VARARGS)
+void
+#if defined (PREFER_STDARG)
+builtin_error (const char *format, ...)
+#else
+builtin_error (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  if (this_command_name && *this_command_name)
+    fprintf (stderr, "%s: ", this_command_name);
+
+#if defined (PREFER_STDARG)
+  va_start (args, format);
+#else
+  va_start (args);
+#endif
+
+  vfprintf (stderr, format, args);
+  va_end (args);
+  fprintf (stderr, "\n");
+}
+#else
+void
+builtin_error (format, arg1, arg2, arg3, arg4, arg5)
+     char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
+{
+  if (this_command_name && *this_command_name)
+    fprintf (stderr, "%s: ", this_command_name);
+
+  fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
+  fprintf (stderr, "\n");
+  fflush (stderr);
+}
+#endif /* !USE_VARARGS */
+
+#endif
index 90526895534f1ee6b3b398ec863110bf836a0212..5dc5d70d0ddb2d9edada52ba3a641a4785605f2a 100644 (file)
@@ -21,6 +21,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/head.c~ b/examples/loadables/head.c~
new file mode 100644 (file)
index 0000000..9052689
--- /dev/null
@@ -0,0 +1,143 @@
+/* head - copy first part of files. */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+#include "posixstat.h"
+#include "filecntl.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include "chartypes.h"
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+static void
+munge_list (list)
+     WORD_LIST *list;
+{
+  WORD_LIST *l, *nl;
+  WORD_DESC *wd;
+  char *arg;
+
+  for (l = list; l; l = l->next)
+    {
+      arg = l->word->word;
+      if (arg[0] != '-' || arg[1] == '-' || (DIGIT(arg[1]) == 0))
+        return;
+      /* We have -[0-9]* */
+      wd = make_bare_word (arg+1);
+      nl = make_word_list (wd, l->next);
+      l->word->word[1] = 'n';
+      l->word->word[2] = '\0';
+      l->next = nl;
+      l = nl;  /* skip over new argument */
+    }
+}
+
+static int
+file_head (fp, cnt)
+     FILE *fp;
+     int cnt;
+{
+  int ch;
+
+  while (cnt--)
+    {
+      while ((ch = getc (fp)) != EOF)
+       {
+         if (putchar (ch) == EOF)
+           {
+             builtin_error ("write error: %s", strerror (errno));
+             return EXECUTION_FAILURE;
+           }
+         if (ch == '\n')
+           break;
+       }
+    }
+}
+
+head_builtin (list)
+     WORD_LIST *list;
+{
+  int nline, opt, rval;
+  WORD_LIST *l;
+  FILE *fp;
+
+  char *t;
+
+  munge_list (list);   /* change -num into -n num */
+
+  reset_internal_getopt ();
+  nline = 10;
+  while ((opt = internal_getopt (list, "n:")) != -1)
+    {
+      switch (opt)
+       {
+       case 'n':
+         nline = atoi (list_optarg);
+         if (nline <= 0)
+           {
+             builtin_error ("bad line count: %s", list_optarg);
+             return (EX_USAGE);
+           }
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list == 0)
+    return (file_head (stdin, nline));
+
+  for (rval = EXECUTION_SUCCESS, opt = 1, l = list; l; l = l->next)
+    {
+      fp = fopen (l->word->word, "r");
+      if (fp == NULL)
+       {
+         builtin_error ("%s: %s", l->word->word, strerror (errno));
+         continue;
+       }
+      if (list->next)  /* more than one file */
+       {
+         printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word);
+         opt = 0;
+       }
+      rval = file_head (fp, nline);
+      fclose (fp);
+    }
+   
+  return (rval);
+}
+
+char *head_doc[] = {
+       "Copy the first N lines from the input files to the standard output.",
+       "N is supplied as an argument to the `-n' option.  If N is not given,",
+       "the first ten lines are copied.",
+       (char *)NULL
+};
+
+struct builtin head_struct = {
+       "head",                 /* builtin name */
+       head_builtin,           /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       head_doc,               /* array of long documentation strings. */
+       "head [-n num] [file ...]", /* usage synopsis; becomes short_doc */
+       0                       /* reserved for internal use */
+};
index e3234e3c9f4ee8c3886a649590aba84be01d17e7..80adf5fb3c9a5ae206465d9b066366140c4d3104 100644 (file)
@@ -18,6 +18,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/ln.c~ b/examples/loadables/ln.c~
new file mode 100644 (file)
index 0000000..e3234e3
--- /dev/null
@@ -0,0 +1,205 @@
+/* ln - make links */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "posixstat.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+typedef int unix_link_syscall_t __P((const char *, const char *));
+
+#define LN_SYMLINK 0x01
+#define LN_UNLINK  0x02
+
+static unix_link_syscall_t *linkfn;
+static int dolink ();
+
+ln_builtin (list)
+     WORD_LIST *list;
+{
+  int rval, opt, flags;
+  WORD_LIST *l;
+  char *sdir;
+  struct stat sb;
+
+  flags = 0;
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "fs")) != -1)
+    {
+      switch (opt)
+       {
+       case 'f':
+         flags |= LN_UNLINK;
+         break;
+       case 's':
+         flags |= LN_SYMLINK;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+    
+  linkfn = (flags & LN_SYMLINK) ? symlink : link;  
+
+  if (list->next == 0)                 /* ln target, equivalent to ln target . */
+    return (dolink (list->word->word, ".", flags));
+
+  if (list->next->next == 0)           /* ln target source */
+    return (dolink (list->word->word, list->next->word->word, flags));
+
+  /* ln target1 target2 ... directory */
+
+  /* find last argument: target directory, and make sure it's an existing
+     directory. */
+  for (l = list; l->next; l = l->next)  
+    ;
+  sdir = l->word->word;
+
+  if (stat(sdir, &sb) < 0)
+    {
+      builtin_error ("%s", sdir);
+      return (EXECUTION_FAILURE);
+    }
+
+  if (S_ISDIR (sb.st_mode) == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  for (rval = EXECUTION_SUCCESS; list != l; list = list->next)
+    rval += dolink (list->word->word, sdir, flags);
+  
+  return rval;
+}
+
+static char *
+mkdirpath (dir, file)
+     char *dir, *file;
+{
+  int dlen, flen;
+  char *ret;
+
+  dlen = strlen (dir);
+  flen = strlen (file);
+
+  ret = xmalloc (2 + dlen + flen);
+
+  strcpy (ret, dir);
+  if (ret[dlen - 1] != '/')
+    ret[dlen++] = '/';
+  strcpy (ret + dlen, file);
+  return ret;
+}
+
+#if defined (HAVE_LSTAT)
+#  define LSTAT lstat
+#else
+#  define LSTAT stat
+#endif
+
+static int
+dolink (src, dst, flags)
+     char *src, *dst;
+     int flags;
+{
+  struct stat ssb, dsb;
+  int exists;
+  char *dst_path, *p;
+
+  /* If we're not doing symlinks, the source must exist and not be a 
+     directory. */
+  if ((flags & LN_SYMLINK) == 0)
+    {
+      if (stat (src, &ssb) != 0)
+       {
+         builtin_error ("%s: %s", src, strerror (errno));
+         return (EXECUTION_FAILURE);
+       }
+      if (S_ISDIR (ssb.st_mode))
+       {
+         errno = EISDIR;
+         builtin_error ("%s: %s", src, strerror (errno));
+         return (EXECUTION_FAILURE);
+       }
+    }
+
+  /* If the destination is a directory, create the final filename by appending
+     the basename of the source to the destination. */
+  dst_path = 0;
+  if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode))
+    {
+      if ((p = strrchr (src, '/')) == 0)
+       p = src;
+      else
+       p++;
+
+      dst_path = mkdirpath (dst, p);
+      dst = dst_path;
+    }
+
+  exists = LSTAT (dst, &dsb) == 0;
+
+  /* If -f was specified, and the destination exists, unlink it. */
+  if ((flags & LN_UNLINK) && exists && unlink (dst) != 0)
+    {
+      builtin_error ("%s: cannot unlink: %s", dst, strerror (errno));
+      FREE (dst_path);
+      return (EXECUTION_FAILURE);
+    }
+
+  /* Perform the link. */
+  if ((*linkfn) (src, dst) != 0)
+    {
+      builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno));
+      FREE (dst_path);
+      return (EXECUTION_FAILURE);
+    }
+
+  FREE (dst_path);
+  return (EXECUTION_SUCCESS);
+}
+
+char *ln_doc[] = {
+       "Create a new directory entry with the same modes as the original",
+       "file.  The -f option means to unlink any existing file, permitting",
+       "the link to occur.  The -s option means to create a symbolic link.",
+       "By default, ln makes hard links.",
+       (char *)NULL
+};
+
+/* The standard structure describing a builtin command.  bash keeps an array
+   of these structures. */
+struct builtin ln_struct = {
+       "ln",           /* builtin name */
+       ln_builtin,             /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       ln_doc,         /* array of long documentation strings. */
+       "ln [-fs] file1 [file2] OR ln [-fs] file ... directory",        /* usage synopsis; becomes short_doc */
+       0                       /* reserved for internal use */
+};
index 00cfd19a9f7012f0e7a01647735145c4658dce67..3baecb24ff29268b04f9d4cc122862c472f98b6d 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "builtins.h"
 #include "shell.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/logname.c~ b/examples/loadables/logname.c~
new file mode 100644 (file)
index 0000000..00cfd19
--- /dev/null
@@ -0,0 +1,52 @@
+/* logname - print login name of current user */
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+logname_builtin (list)
+     WORD_LIST *list;
+{
+  char *np;
+
+  if (no_options (list))
+    return (EX_USAGE);
+
+  np = getlogin ();
+  if (np == 0)
+    {
+      builtin_error ("cannot find username: %s", strerror (errno));
+      return (EXECUTION_FAILURE);
+    }
+  printf ("%s\n", np);
+  return (EXECUTION_SUCCESS);
+}
+
+char *logname_doc[] = {
+       "write the current user's login name to the standard output",
+       "and exit.  logname ignores the LOGNAME and USER variables.",
+       "logname ignores any non-option arguments.",
+       (char *)NULL
+};
+       
+struct builtin logname_struct = {
+       "logname",
+       logname_builtin,
+       BUILTIN_ENABLED,
+       logname_doc,
+       "logname",
+       0
+};
+       
index cd6e5f96db2d2fd83b0455489571b6e5c9a6be1f..6ccffdbe0718cd8f083094925e4eda3951e00950 100644 (file)
@@ -16,6 +16,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/mkdir.c~ b/examples/loadables/mkdir.c~
new file mode 100644 (file)
index 0000000..cd6e5f9
--- /dev/null
@@ -0,0 +1,216 @@
+/* mkdir - make directories */
+
+/* See Makefile for compilation details. */
+
+#include <config.h>
+
+#include "bashtypes.h"
+#include "posixstat.h"
+#include <errno.h>
+#include <stdio.h>
+#include "bashansi.h"
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define ISOCTAL(c)     ((c) >= '0' && (c) <= '7')
+
+extern int parse_symbolic_mode ();
+
+static int make_path ();
+
+static int original_umask;
+
+int
+mkdir_builtin (list)
+     WORD_LIST *list;
+{
+  int opt, pflag, omode, rval, octal, nmode, parent_mode, um;
+  char *mode;
+  WORD_LIST *l;
+
+  reset_internal_getopt ();
+  pflag = 0;
+  mode = (char *)NULL;
+  while ((opt = internal_getopt(list, "m:p")) != -1)
+    switch (opt)
+      {
+       case 'p':
+         pflag = 1;
+         break;
+       case 'm':
+         mode = list_optarg;
+         break;
+       default:
+         builtin_usage();
+         return (EX_USAGE);
+      }
+  list = loptend;
+
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (mode == NULL)
+    omode = S_IRWXU | S_IRWXG | S_IRWXO;       /* a=rwx */
+  else if (ISOCTAL (*mode))    /* octal number */
+    {
+      omode = read_octal (mode);
+      if (omode < 0)
+       {
+         builtin_error ("invalid file mode: %s", mode);
+         return (EXECUTION_FAILURE);
+       }
+      octal = 1;
+    }
+  else if (mode)
+    {
+      /* initial bits are a=rwx; the mode argument modifies them */
+      omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
+      if (omode < 0)
+       {
+         builtin_error ("invalid file mode: %s", mode);
+         return (EXECUTION_FAILURE);
+       }
+      octal = 0;
+    }
+
+  /* Make the new mode */
+  original_umask = umask (0);
+  umask (original_umask);
+
+  nmode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask;
+  parent_mode = nmode | (S_IWRITE|S_IEXEC);    /* u+wx */
+
+  /* Adjust new mode based on mode argument */
+  nmode &= omode;
+
+  for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
+    {
+      if (pflag && make_path (l->word->word, nmode, parent_mode))
+       {
+         rval = EXECUTION_FAILURE;
+         continue;
+       }
+      else if (pflag == 0 && mkdir (l->word->word, nmode) < 0)
+        {
+          builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno));
+          rval = EXECUTION_FAILURE;
+        }
+    }
+  return rval;
+}
+
+/* Make all the directories leading up to PATH, then create PATH.  Note that
+   this changes the process's umask; make sure that all paths leading to a
+   return reset it to ORIGINAL_UMASK */
+static int
+make_path (path, nmode, parent_mode)
+     char *path;
+     int nmode, parent_mode;
+{
+  int oumask;
+  struct stat sb;
+  char *p, *npath;
+
+  if (stat (path, &sb) == 0)
+    {
+      if (S_ISDIR (sb.st_mode) == 0)
+       {
+         builtin_error ("`%s': file exists but is not a directory", path);
+         return 1;
+       }
+       
+      if (chmod (path, nmode))
+        {
+          builtin_error ("%s: %s", path, strerror (errno));
+          return 1;
+        }
+
+      return 0;
+    }
+
+  oumask = umask (0);
+  npath = savestring (path);   /* So we can write to it. */
+    
+  /* Check whether or not we need to do anything with intermediate dirs. */
+
+  /* Skip leading slashes. */
+  p = npath;
+  while (*p == '/')
+    p++;
+
+  while (p = strchr (p, '/'))
+    {
+      *p = '\0';
+      if (stat (npath, &sb) != 0)
+       {
+         if (mkdir (npath, parent_mode))
+           {
+             builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
+             umask (original_umask);
+             free (npath);
+             return 1;
+           }
+       }
+      else if (S_ISDIR (sb.st_mode) == 0)
+        {
+          builtin_error ("`%s': file exists but is not a directory", npath);
+          umask (original_umask);
+          free (npath);
+          return 1;
+        }
+
+      *p++ = '/';      /* restore slash */
+      while (*p == '/')
+       p++;
+    }
+
+  /* Create the final directory component. */
+  if (stat (npath, &sb) && mkdir (npath, nmode))
+    {
+      builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
+      umask (original_umask);
+      free (npath);
+      return 1;
+    }
+
+  umask (original_umask);
+  free (npath);
+  return 0;
+}
+
+char *mkdir_doc[] = {
+       "Make directories.  Create the directories named as arguments, in",
+       "the order specified, using mode rwxrwxrwx as modified by the current",
+       "umask (see `help umask').  The -m option causes the file permission",
+       "bits of the final directory to be MODE.  The MODE argument may be",
+       "an octal number or a symbolic mode like that used by chmod(1).  If",
+       "a symbolic mode is used, the operations are interpreted relative to",
+       "an initial mode of \"a=rwx\".  The -p option causes any required",
+       "intermediate directories in PATH to be created.  The directories",
+       "are created with permssion bits of rwxrwxrwx as modified by the current",
+       "umask, plus write and search permissions for the owner.  mkdir",
+       "returns 0 if the directories are created successfully, and non-zero",
+       "if an error occurs.",
+       (char *)NULL
+};
+
+struct builtin mkdir_struct = {
+       "mkdir",
+       mkdir_builtin,
+       BUILTIN_ENABLED,
+       mkdir_doc,
+       "mkdir [-p] [-m mode] directory [directory ...]",
+       0
+};
index 2e36f8f6b69b3e3fd661a93cd5a9515deb2cfe32..5b29c35af7b315be2a4eb5f7acc6cfe4463c0565 100644 (file)
@@ -45,6 +45,7 @@
 #include "stdc.h"
 #include "bashgetopt.h"
 #include "maxpath.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/pathchk.c~ b/examples/loadables/pathchk.c~
new file mode 100644 (file)
index 0000000..2e36f8f
--- /dev/null
@@ -0,0 +1,358 @@
+/* pathchk - check pathnames for validity and portability */
+
+/* Usage: pathchk [-p] path ...
+
+   For each PATH, print a message if any of these conditions are false:
+   * all existing leading directories in PATH have search (execute) permission
+   * strlen (PATH) <= PATH_MAX
+   * strlen (each_directory_in_PATH) <= NAME_MAX
+
+   Exit status:
+   0                   All PATH names passed all of the tests.
+   1                   An error occurred.
+
+   Options:
+   -p                  Instead of performing length checks on the
+                       underlying filesystem, test the length of the
+                       pathname and its components against the POSIX.1
+                       minimum limits for portability, _POSIX_NAME_MAX
+                       and _POSIX_PATH_MAX in 2.9.2.  Also check that
+                       the pathname contains no character not in the
+                       portable filename character set. */
+
+/* See Makefile for compilation details. */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#if defined (HAVE_LIMITS_H)
+#  include <limits.h>
+#endif
+
+#include "bashansi.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "stdc.h"
+#include "bashgetopt.h"
+#include "maxpath.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#if !defined (_POSIX_PATH_MAX)
+#  define _POSIX_PATH_MAX 255
+#endif
+#if !defined (_POSIX_NAME_MAX)
+#  define _POSIX_NAME_MAX 14
+#endif
+
+/* How do we get PATH_MAX? */
+#if defined (_POSIX_VERSION) && !defined (PATH_MAX)
+#  define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
+#endif
+
+/* How do we get NAME_MAX? */
+#if defined (_POSIX_VERSION) && !defined (NAME_MAX)
+#  define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX)
+#endif
+
+#if !defined (PATH_MAX_FOR)
+#  define PATH_MAX_FOR(p)      PATH_MAX
+#endif
+
+#if !defined (NAME_MAX_FOR)
+#  define NAME_MAX_FOR(p)      NAME_MAX
+#endif
+
+extern char *strerror ();
+
+static int validate_path ();
+
+pathchk_builtin (list)
+     WORD_LIST *list;
+{
+  int retval, pflag, opt;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "p")) != -1)
+    {
+      switch (opt)
+       {
+       case 'p':
+         pflag = 1;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  for (retval = 0; list; list = list->next)
+    retval |= validate_path (list->word->word, pflag);
+
+  return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+char *pathchk_doc[] = {
+       "Check each pathname argument for validity (i.e., it may be used to",
+       "create or access a file without casuing syntax errors) and portability",
+       "(i.e., no filename truncation will result).  If the `-p' option is",
+       "supplied, more extensive portability checks are performed.",
+       (char *)NULL
+};
+
+/* The standard structure describing a builtin command.  bash keeps an array
+   of these structures. */
+struct builtin pathchk_struct = {
+       "pathchk",              /* builtin name */
+       pathchk_builtin,        /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       pathchk_doc,            /* array of long documentation strings. */
+       "pathchk [-p] pathname ...",    /* usage synopsis */
+       0                       /* reserved for internal use */
+};
+
+/* The remainder of this file is stolen shamelessly from `pathchk.c' in
+   the sh-utils-1.12 distribution, by 
+
+   David MacKenzie <djm@gnu.ai.mit.edu>
+   and Jim Meyering <meyering@cs.utexas.edu> */
+
+/* Each element is nonzero if the corresponding ASCII character is
+   in the POSIX portable character set, and zero if it is not.
+   In addition, the entry for `/' is nonzero to simplify checking. */
+static char const portable_chars[256] =
+{
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* If PATH contains only portable characters, return 1, else 0.  */
+
+static int
+portable_chars_only (path)
+     const char *path;
+{
+  const char *p;
+
+  for (p = path; *p; ++p)
+    if (portable_chars[(const unsigned char) *p] == 0)
+      {
+       builtin_error ("path `%s' contains nonportable character `%c'", path, *p);
+       return 0;
+      }
+  return 1;
+}
+
+/* On some systems, stat can return EINTR.  */
+
+#ifndef EINTR
+# define SAFE_STAT(name, buf) stat (name, buf)
+#else
+# define SAFE_STAT(name, buf) safe_stat (name, buf)
+static inline int
+safe_stat (name, buf)
+     const char *name;
+     struct stat *buf;
+{
+  int ret;
+
+  do
+    ret = stat (name, buf);
+  while (ret < 0 && errno == EINTR);
+
+  return ret;
+}
+#endif
+
+/* Return 1 if PATH is a usable leading directory, 0 if not,
+   2 if it doesn't exist.  */
+
+static int
+dir_ok (path)
+     const char *path;
+{
+  struct stat stats;
+
+  if (SAFE_STAT (path, &stats))
+    return 2;
+
+  if (!S_ISDIR (stats.st_mode))
+    {
+      builtin_error ("`%s' is not a directory", path);
+      return 0;
+    }
+
+  /* Use access to test for search permission because
+     testing permission bits of st_mode can lose with new
+     access control mechanisms.  Of course, access loses if you're
+     running setuid. */
+  if (access (path, X_OK) != 0)
+    {
+      if (errno == EACCES)
+       builtin_error ("directory `%s' is not searchable", path);
+      else
+       builtin_error ("%s: %s", path, strerror (errno));
+      return 0;
+    }
+
+  return 1;
+}
+
+static char *
+xstrdup (s)
+     char *s;
+{
+  return (savestring (s));
+}
+
+/* Make sure that
+   strlen (PATH) <= PATH_MAX
+   && strlen (each-existing-directory-in-PATH) <= NAME_MAX
+
+   If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
+   _POSIX_NAME_MAX instead, and make sure that PATH contains no
+   characters not in the POSIX portable filename character set, which
+   consists of A-Z, a-z, 0-9, ., _, -.
+
+   Make sure that all leading directories along PATH that exist have
+   `x' permission.
+
+   Return 0 if all of these tests are successful, 1 if any fail. */
+
+static int
+validate_path (path, portability)
+     char *path;
+     int portability;
+{
+  int path_max;
+  int last_elem;               /* Nonzero if checking last element of path. */
+  int exists;                  /* 2 if the path element exists.  */
+  char *slash;
+  char *parent;                        /* Last existing leading directory so far.  */
+
+  if (portability && !portable_chars_only (path))
+    return 1;
+
+  if (*path == '\0')
+    return 0;
+
+#ifdef lint
+  /* Suppress `used before initialized' warning.  */
+  exists = 0;
+#endif
+
+  /* Figure out the parent of the first element in PATH.  */
+  parent = xstrdup (*path == '/' ? "/" : ".");
+
+  slash = path;
+  last_elem = 0;
+  while (1)
+    {
+      int name_max;
+      int length;              /* Length of partial path being checked. */
+      char *start;             /* Start of path element being checked. */
+
+      /* Find the end of this element of the path.
+        Then chop off the rest of the path after this element. */
+      while (*slash == '/')
+       slash++;
+      start = slash;
+      slash = strchr (slash, '/');
+      if (slash != NULL)
+       *slash = '\0';
+      else
+       {
+         last_elem = 1;
+         slash = strchr (start, '\0');
+       }
+
+      if (!last_elem)
+       {
+         exists = dir_ok (path);
+         if (dir_ok == 0)
+           {
+             free (parent);
+             return 1;
+           }
+       }
+
+      length = slash - start;
+      /* Since we know that `parent' is a directory, it's ok to call
+        pathconf with it as the argument.  (If `parent' isn't a directory
+        or doesn't exist, the behavior of pathconf is undefined.)
+        But if `parent' is a directory and is on a remote file system,
+        it's likely that pathconf can't give us a reasonable value
+        and will return -1.  (NFS and tempfs are not POSIX . . .)
+        In that case, we have no choice but to assume the pessimal
+        POSIX minimums.  */
+      name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
+      if (name_max < 0)
+       name_max = _POSIX_NAME_MAX;
+      if (length > name_max)
+       {
+         builtin_error ("name `%s' has length %d; exceeds limit of %d",
+                start, length, name_max);
+         free (parent);
+         return 1;
+       }
+
+      if (last_elem)
+       break;
+
+      if (exists == 1)
+       {
+         free (parent);
+         parent = xstrdup (path);
+       }
+
+      *slash++ = '/';
+    }
+
+  /* `parent' is now the last existing leading directory in the whole path,
+     so it's ok to call pathconf with it as the argument.  */
+  path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
+  if (path_max < 0)
+    path_max = _POSIX_PATH_MAX;
+  free (parent);
+  if (strlen (path) > path_max)
+    {
+      builtin_error ("path `%s' has length %d; exceeds limit of %d",
+            path, strlen (path), path_max);
+      return 1;
+    }
+
+  return 0;
+}
index ad658a7f861af4381c91c8299ca5db2d1f8878e7..02d3c92a72d0199ff28cb701a9f1b600c1f2093a 100644 (file)
@@ -17,6 +17,8 @@
 #include "builtins.h"
 #include "stdc.h"
 #include "bashgetopt.h"
+#include "builtext.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/print.c~ b/examples/loadables/print.c~
new file mode 100644 (file)
index 0000000..ad658a7
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * print -- loadable ksh-93 style print builtin
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "bashtypes.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "bashansi.h"
+#include "shell.h"
+#include "builtins.h"
+#include "stdc.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+int print_builtin ();
+static int printargs ();
+
+static FILE *ofp;
+
+extern char *this_command_name;
+
+static char *print_doc[] = {
+  "Output the arguments.  The -f option means to use the argument as a",
+  "format string as would be supplied to printf(1).  The rest of the",
+  "options are as in ksh.",
+  (char *)NULL
+};
+
+struct builtin print_struct = {
+       "print",
+       print_builtin,
+       BUILTIN_ENABLED,
+       print_doc,
+       "print [-Rnprs] [-u unit] [-f format] [arguments]",
+       (char *)0
+};
+
+#ifndef ISOPTION
+#define ISOPTION(s, c) (s[0] == '-' && s[2] == '\0' && s[1] == c)
+#endif
+
+int
+print_builtin (list)
+     WORD_LIST *list;
+{
+  int c, r, nflag, raw, ofd, sflag;
+  intmax_t lfd;
+  char **v, *pfmt, *arg;
+  WORD_LIST *l;
+
+  nflag = raw = sflag = 0;
+  ofd = 1;
+  pfmt = 0;
+
+  reset_internal_getopt ();
+  while ((c = internal_getopt (list, "Rnprsu:f:")) != -1)
+    {
+      switch (c)
+       {
+       case 'R':
+         raw = 2;
+         loptend = lcurrent;
+         if (loptend && ISOPTION (loptend->word->word, 'n'))
+           {
+             loptend = loptend->next;
+             nflag = 1;
+           }
+         goto opt_end;
+       case 'r':
+         raw = 1;
+         break;
+       case 'n':
+         nflag = 1;
+         break;
+       case 's':
+         sflag = 1;
+         break;
+       case 'p':
+         break;        /* NOP */
+       case 'u':
+         if (all_digits (list_optarg) && legal_number (list_optarg, &lfd) && lfd == (int)lfd)
+           ofd = lfd;
+         else
+           {
+             for (l = list; l->next && l->next != lcurrent; l = l->next);
+             lcurrent = loptend = l;
+             goto opt_end;
+           }
+         break;
+       case 'f':
+         pfmt = list_optarg;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+
+opt_end:
+  list = loptend;
+
+  ofp = (ofd == 1) ? stdout : fdopen (dup (ofd), "w");
+
+  if (pfmt)
+    {
+      WORD_DESC *w;
+      WORD_LIST *nlist;
+
+      w = make_word (pfmt);
+      nlist = make_word_list (w, list);
+      r = printf_builtin (nlist);
+      nlist->next = (WORD_LIST *)NULL;
+      dispose_words (nlist);
+      return (r);
+    }
+
+  if (raw)
+    {
+      for (l = list; l; l = l->next)
+       {
+         fprintf (ofp, "%s", l->word->word);
+         if (l->next)
+           fprintf (ofp, " ");
+       }
+      if (nflag == 0)
+       fprintf (ofp, "\n");
+      fflush (ofp);
+      return (0);      
+    }
+        
+  r = printargs (list, ofp);
+  if (r && nflag == 0)
+    fprintf (ofp, "\n");
+  if (ofd != 1)
+    fclose (ofp);
+  return 0;
+}
+
+static int
+printargs (list, ofp)
+     WORD_LIST *list;
+     FILE *ofp;
+{
+  WORD_LIST *l;
+  char *ostr;
+  int sawc;
+
+  for (sawc = 0, l = list; l; l = l->next)
+    {
+      ostr = ansicstr (l->word->word, strlen (l->word->word), 0, &sawc, (int *)0);
+      fprintf (ofp, "%s", ostr);
+      free (ostr);
+      if (sawc)
+        return (0);
+      if (l->next)
+        fprintf (ofp, " ");
+    }
+  return (1);
+}
index 16f398fc82a7ab8b3286476a304448ff913ff810..29a82dc09da969891e8c095fbbad8e73977baed0 100644 (file)
@@ -11,6 +11,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 extern char **export_env;
 
diff --git a/examples/loadables/printenv.c~ b/examples/loadables/printenv.c~
new file mode 100644 (file)
index 0000000..16f398f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * printenv -- minimal builtin clone of BSD printenv(1).
+ *
+ * usage: printenv [varname]
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+extern char **export_env;
+
+int
+printenv_builtin (list) 
+     WORD_LIST *list;
+{
+  register char **envp;
+  int opt;
+  SHELL_VAR *var;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "")) != -1)
+    {
+      switch (opt)
+       {
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  /* printenv */
+  if (list == 0)
+    {
+      maybe_make_export_env ();                /* this allows minimal code */
+      for (envp = export_env; *envp; envp++)
+       printf ("%s\n", *envp);
+      return (EXECUTION_SUCCESS);
+    }
+
+  /* printenv varname */
+  var = find_variable (list->word->word);
+  if (var == 0 || (exported_p (var) == 0))
+    return (EXECUTION_FAILURE);
+
+  if (function_p (var))
+    print_var_function (var);
+  else
+    print_var_value (var, 0);
+
+  return (EXECUTION_SUCCESS);
+}
+
+char *printenv_doc[] = {
+       "print values of environment variables",
+       (char *)NULL
+};
+
+struct builtin printenv_struct = {
+       "printenv",
+       printenv_builtin,
+       BUILTIN_ENABLED,
+       printenv_doc,
+       "printenv [varname]",
+       0
+};
index 497ecd0e7e0da8a9641630e7241e62394f1c7d6d..fea4b008451f11f4a733c45aa9a2c513d7459a6c 100644 (file)
@@ -11,6 +11,7 @@
 #include "shell.h"
 #include "jobs.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #ifndef errno
 extern int errno;
diff --git a/examples/loadables/push.c~ b/examples/loadables/push.c~
new file mode 100644 (file)
index 0000000..497ecd0
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * push - anyone remember TOPS-20?
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "jobs.h"
+#include "bashgetopt.h"
+
+#ifndef errno
+extern int errno;
+#endif
+
+extern int dollar_dollar_pid;
+extern int last_command_exit_value;
+
+int
+push_builtin (list)
+     WORD_LIST *list;
+{
+  pid_t pid;
+  int xstatus, opt;
+
+  xstatus = EXECUTION_SUCCESS;
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "")) != -1)
+    {
+      switch (opt)
+       {
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;  
+
+  pid = make_child (savestring ("push"), 0);
+  if (pid == -1)
+    {
+      builtin_error ("cannot fork: %s", strerror (errno));
+      return (EXECUTION_FAILURE);
+    }
+  else if (pid == 0)
+    {
+      /* Shell variable adjustments: $SHLVL, $$, $PPID, $! */
+      adjust_shell_level (1);
+      dollar_dollar_pid = getpid ();
+      set_ppid ();
+
+      /* Clean up job control stuff. */
+      stop_making_children ();
+      cleanup_the_pipeline ();
+      delete_all_jobs (0);
+
+      last_asynchronous_pid = NO_PID;
+
+      /* Make sure the job control code has the right values for
+        the shell's process group and tty process group, and that
+        the signals are set correctly for job control. */
+      initialize_job_control (0);
+      initialize_job_signals ();
+
+      /* And read commands until exit. */
+      reader_loop ();
+      exit_shell (last_command_exit_value);
+    }
+  else
+    {
+      stop_pipeline (0, (COMMAND *)NULL);
+      xstatus = wait_for (pid);
+      return (xstatus);
+    }   
+}
+
+char *push_doc[] = {
+       "Create a child that is an exact duplicate of the running shell",
+       "and wait for it to exit.  The $SHLVL, $!, $$, and $PPID variables",
+       "are adjusted in the child.  The return value is the exit status",
+       "of the child.",
+       (char *)NULL
+};
+
+struct builtin push_struct = {
+       "push",
+       push_builtin,
+       BUILTIN_ENABLED,
+       push_doc,
+       "push",
+       0
+};
index 16478b79fe3cd1a8181bc8775d56720a4664bb30..d9454402512e2c651bf562bfa72716c2768d74a3 100644 (file)
@@ -34,6 +34,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #ifndef errno
 extern int     errno;
@@ -67,14 +68,14 @@ WORD_LIST   *list;
                        vflag = 1;
                        break;
                default:
-                       usage();
+                       builtin_usage();
                }
        }
 
        list = loptend;
 
        if (list == 0)
-               usage();
+               builtin_usage();
 
        for (es = EXECUTION_SUCCESS; list; list = list->next) {
                p = list->word->word;
diff --git a/examples/loadables/realpath.c~ b/examples/loadables/realpath.c~
new file mode 100644 (file)
index 0000000..16478b7
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * realpath -- canonicalize pathnames, resolving symlinks
+ *
+ * usage: realpath [-csv] pathname [pathname...]
+ *
+ * options:    -c      check whether or not each resolved path exists
+ *             -s      no output, exit status determines whether path is valid
+ *             -v      produce verbose output
+ *
+ *
+ * exit status:        0       if all pathnames resolved
+ *             1       if any of the pathname arguments could not be resolved
+ *
+ *
+ * Bash loadable builtin version
+ *
+ * Chet Ramey
+ * chet@po.cwru.edu
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+#include "bashansi.h"
+#include <maxpath.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#ifndef errno
+extern int     errno;
+#endif
+
+extern char    *sh_realpath();
+
+realpath_builtin(list)
+WORD_LIST      *list;
+{
+       int     opt, cflag, vflag, sflag, es;
+       char    *r, realbuf[PATH_MAX], *p;
+       struct stat sb;
+
+       if (list == 0) {
+               builtin_usage();
+               return (EX_USAGE);
+       }
+
+       vflag = cflag = sflag = 0;
+       reset_internal_getopt();
+       while ((opt = internal_getopt (list, "csv")) != -1) {
+               switch (opt) {
+               case 'c':
+                       cflag = 1;
+                       break;
+               case 's':
+                       sflag = 1;
+                       break;
+               case 'v':
+                       vflag = 1;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       list = loptend;
+
+       if (list == 0)
+               usage();
+
+       for (es = EXECUTION_SUCCESS; list; list = list->next) {
+               p = list->word->word;
+               r = sh_realpath(p, realbuf);
+               if (r == 0) {
+                       es = EXECUTION_FAILURE;
+                       if (sflag == 0)
+                               builtin_error("%s: cannot resolve: %s", p, strerror(errno));
+                       continue;
+               }
+               if (cflag && (stat(realbuf, &sb) < 0)) {
+                       es = EXECUTION_FAILURE;
+                       if (sflag == 0)
+                               builtin_error("%s: %s", p, strerror(errno));
+                       continue;
+               }
+               if (sflag == 0) {
+                       if (vflag)
+                               printf ("%s -> ", p);
+                       printf("%s\n", realbuf);
+               }
+       }
+       return es;
+}
+
+char *realpath_doc[] = {
+       "Display the canonicalized version of each PATHNAME argument, resolving",
+       "symbolic links.  The -c option checks whether or not each resolved name",
+       "exists.  The -s option produces no output; the exit status determines the",
+       "valididty of each PATHNAME.  The -v option produces verbose output.  The",
+       "exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
+       (char *)NULL
+};
+
+struct builtin realpath_struct = {
+       "realpath",             /* builtin name */
+       realpath_builtin,       /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       realpath_doc,           /* array of long documentation strings */
+       "realpath [-csv] pathname [pathname...]",       /* usage synopsis */
+       0                       /* reserved for internal use */
+};
index 8d0f06ac6f5a18cfa18a4d225d0f50062d059110..e52247c3bbd9c371ab41d71cab516de6eb7d71a0 100644 (file)
@@ -8,6 +8,7 @@
 #include <errno.h>
 #include "builtins.h"
 #include "shell.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/rmdir.c~ b/examples/loadables/rmdir.c~
new file mode 100644 (file)
index 0000000..8d0f06a
--- /dev/null
@@ -0,0 +1,50 @@
+/* rmdir - remove directory */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include "builtins.h"
+#include "shell.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+rmdir_builtin (list)
+     WORD_LIST *list;
+{
+  int rval;
+  WORD_LIST *l;
+
+  if (no_options (list))
+    return (EX_USAGE);
+
+  for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
+    if (rmdir (l->word->word) < 0)
+      {
+       builtin_error ("%s: %s", l->word->word, strerror (errno));
+       rval = EXECUTION_FAILURE;
+      }
+
+  return rval;
+}
+
+char *rmdir_doc[] = {
+       "rmdir removes the directory entry specified by each argument,",
+       "provided the directory is empty.",
+       (char *)NULL
+};
+
+/* The standard structure describing a builtin command.  bash keeps an array
+   of these structures. */
+struct builtin rmdir_struct = {
+       "rmdir",                /* builtin name */
+       rmdir_builtin,          /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       rmdir_doc,              /* array of long documentation strings. */
+       "rmdir directory ...",  /* usage synopsis; becomes short_doc */
+       0                       /* reserved for internal use */
+};
index 10a62cf14ddc17f0ccf25b2d375ab77493d967f3..427298026153007a963bb3064c647dd987bb9d01 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "shell.h"
 #include "builtins.h"
+#include "common.h"
 
 #define RETURN(x) \
        do { \
diff --git a/examples/loadables/sleep.c~ b/examples/loadables/sleep.c~
new file mode 100644 (file)
index 0000000..10a62cf
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * sleep -- sleep for fractions of a second
+ *
+ * usage: sleep seconds[.fraction]
+ */
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (TIME_WITH_SYS_TIME)
+#  include <sys/time.h>
+#  include <time.h>
+#else
+#  if defined (HAVE_SYS_TIME_H)
+#    include <sys/time.h>
+#  else
+#    include <time.h>
+#  endif
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "chartypes.h"
+
+#include "shell.h"
+#include "builtins.h"
+
+#define RETURN(x) \
+       do { \
+               if (sp) *sp = sec; \
+               if (usp) *usp = usec; \
+               return (x); \
+       } while (0)
+
+#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
+static int
+fsleep(sec, usec)
+long   sec, usec;
+{
+       struct timeval tv;
+
+       tv.tv_sec = sec;
+       tv.tv_usec = usec;
+
+       return select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv);
+}
+#else /* !HAVE_TIMEVAL || !HAVE_SELECT */
+static int
+fsleep(sec, usec)
+long   sec, usec;
+{
+       if (usec >= 500000)     /* round */
+               sec++;
+       return (sleep(sec));
+}
+#endif /* !HAVE_TIMEVAL || !HAVE_SELECT */
+
+/*
+ * An incredibly simplistic floating point converter.
+ */
+static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 };
+
+static int
+convert(s, sp, usp)
+char   *s;
+long   *sp, *usp;
+{
+       int n;
+       long sec, usec;
+       char    *p;
+
+       sec = usec = 0;
+
+#define DECIMAL        '.'
+
+       for (p = s; p && *p; p++) {
+               if (*p == DECIMAL)              /* decimal point */
+                       break;
+               if (DIGIT(*p) == 0)
+                       RETURN(0);
+               sec = (sec * 10) + (*p - '0');
+       }
+
+       if (*p == 0)
+               RETURN(1);
+
+       if (*p == DECIMAL)
+               p++;
+
+       /* Look for up to six digits past a decimal point. */
+       for (n = 0; n < 6 && p[n]; n++) {
+               if (DIGIT(p[n]) == 0)
+                       RETURN(0);
+               usec = (usec * 10) + (p[n] - '0');
+       }
+
+       /* Now convert to millionths */
+       usec *= multiplier[n];
+
+       if (n == 6 && p[6] >= '5' && p[6] <= '9')
+               usec++;                 /* round up 1 */
+
+       RETURN(1);
+}
+
+int
+sleep_builtin (list)
+WORD_LIST      *list;
+{
+       long    sec, usec;
+
+       if (list == 0) {
+               builtin_usage();
+               return(EX_USAGE);
+       }
+
+       if (*list->word->word == '-' || list->next) {
+               builtin_usage ();
+               return (EX_USAGE);
+       }
+
+       if (convert(list->word->word, &sec, &usec)) {
+               fsleep(sec, usec);
+               return(EXECUTION_SUCCESS);
+       }
+
+       builtin_error("%s: bad sleep interval", list->word->word);
+       return (EXECUTION_FAILURE);
+}
+
+static char *sleep_doc[] = {
+       "sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.",
+       (char *)NULL
+};
+
+struct builtin sleep_struct = {
+       "sleep",
+       sleep_builtin,
+       BUILTIN_ENABLED,
+       sleep_doc,
+       "sleep seconds[.fraction]",
+       0
+};
index 934abdab1682f70ea3d25feeb832b6b93b7dceea..6e2ea355d2fdf2b02eb92f6c36bb1b7fb1fab120 100644 (file)
@@ -22,6 +22,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #if !defined (errno)
 extern int errno;
diff --git a/examples/loadables/tee.c~ b/examples/loadables/tee.c~
new file mode 100644 (file)
index 0000000..934abda
--- /dev/null
@@ -0,0 +1,157 @@
+/* tee - duplicate standard input */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+#include "posixstat.h"
+#include "filecntl.h"
+
+#include <signal.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+typedef struct flist {
+  struct flist *next;
+  int fd;
+  char *fname;
+} FLIST;
+
+static FLIST *tee_flist;
+
+#define TEE_BUFSIZE    8192
+
+extern int interrupt_immediately;
+
+extern char *strerror ();
+
+tee_builtin (list)
+     WORD_LIST *list;
+{
+  int opt, append, nointr, rval, fd, fflags;
+  int n, nr, nw;
+  FLIST *fl;
+  char *buf, *bp;
+
+  char *t;
+
+  reset_internal_getopt ();
+  append = nointr = 0;
+  tee_flist = (FLIST *)NULL;
+  while ((opt = internal_getopt (list, "ai")) != -1)
+    {
+      switch (opt)
+       {
+       case 'a':
+         append = 1;
+         break;
+       case 'i':
+         nointr = 1;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (nointr == 0)
+    interrupt_immediately++;
+
+  buf = xmalloc (TEE_BUFSIZE);
+
+  /* Initialize output file list. */
+  fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
+  tee_flist->fd = 1;
+  tee_flist->fname = "stdout";
+  tee_flist->next = (FLIST *)NULL;
+
+  /* Add file arguments to list of output files. */
+  fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
+  for (rval = EXECUTION_SUCCESS; list; list = list->next)
+    {
+      fd = open (list->word->word, fflags, 0666);
+      if (fd < 0)
+        {
+          builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
+          rval = EXECUTION_FAILURE;
+        }
+      else
+        {
+          fl->next = (FLIST *)xmalloc (sizeof(FLIST));
+          fl->next->fd = fd;
+          fl->next->fname = list->word->word;
+          fl = fl->next;
+          fl->next = (FLIST *)NULL;
+        }
+    }
+
+  while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
+    for (fl = tee_flist; fl; fl = fl->next)
+      {
+       n = nr;
+       bp = buf;
+       do
+         {
+           if ((nw = write (fl->fd, bp, n)) == -1)
+             {
+               builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
+               rval = EXECUTION_FAILURE;
+               break;
+             }
+            bp += nw;
+         }
+       while (n -= nw);
+      }
+  if (nr < 0)
+    builtin_error ("read error: %s", strerror (errno));
+
+  /* Deallocate resources -- this is a builtin command. */
+  tee_flist = tee_flist->next;         /* skip bogus close of stdout */
+  while (tee_flist)
+    {
+      fl = tee_flist;
+      if (close (fl->fd) < 0)
+       {
+         builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
+         rval = EXECUTION_FAILURE;
+       }
+      tee_flist = tee_flist->next;
+      free (fl);
+    }
+  
+  return (rval);
+}
+
+char *tee_doc[] = {
+       "Copy standard input to standard output, making a copy in each",
+       "filename argument.  If the `-a' option is gived, the specified",
+       "files are appended to, otherwise they are overwritten.  If the",
+       "`-i' option is supplied, tee ignores interrupts.",
+       (char *)NULL
+};
+
+struct builtin tee_struct = {
+       "tee",                  /* builtin name */
+       tee_builtin,            /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       tee_doc,                /* array of long documentation strings. */
+       "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
+       0                       /* reserved for internal use */
+};
index 4b31decbbb5629dd3229e16bc39fc26090c779c6..a6ae7aa8d90758aea23829ff36d6482f9ae69535 100644 (file)
@@ -4,6 +4,7 @@
 #include "bashtypes.h"
 #include "shell.h"
 #include "builtins.h"
+#include "common.h"
 
 true_builtin (list)
      WORD_LIST *list;
diff --git a/examples/loadables/truefalse.c~ b/examples/loadables/truefalse.c~
new file mode 100644 (file)
index 0000000..4b31dec
--- /dev/null
@@ -0,0 +1,46 @@
+/* true and false builtins */
+#include <config.h>
+
+#include "bashtypes.h"
+#include "shell.h"
+#include "builtins.h"
+
+true_builtin (list)
+     WORD_LIST *list;
+{
+  return EXECUTION_SUCCESS;
+}
+
+false_builtin (list)
+     WORD_LIST *list;
+{
+  return EXECUTION_FAILURE;
+}
+
+static char *true_doc[] = {
+       "Return a successful result.",
+       (char *)NULL
+};
+
+static char *false_doc[] = {
+       "Return an unsuccessful result.",
+       (char *)NULL
+};
+
+struct builtin true_struct = {
+       "true",
+       true_builtin,
+       BUILTIN_ENABLED,
+       true_doc,
+       "true",
+       0
+};
+
+struct builtin false_struct = {
+       "false",
+       false_builtin,
+       BUILTIN_ENABLED,
+       false_doc,
+       "false",
+       0
+};
index 2183123f2f6820e63b8f123956c08307181d2bf8..1ce7afebcf1c4d3f431caf0e2fb6ae554e94a5a4 100644 (file)
@@ -8,6 +8,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 extern char *ttyname ();
 
diff --git a/examples/loadables/tty.c~ b/examples/loadables/tty.c~
new file mode 100644 (file)
index 0000000..2183123
--- /dev/null
@@ -0,0 +1,59 @@
+/* tty - return terminal name */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+extern char *ttyname ();
+
+tty_builtin (list)
+     WORD_LIST *list;
+{
+  int opt, sflag;
+  char *t;
+
+  reset_internal_getopt ();
+  sflag = 0;
+  while ((opt = internal_getopt (list, "s")) != -1)
+    {
+      switch (opt)
+       {
+       case 's':
+         sflag = 1;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  t = ttyname (0);
+  if (sflag == 0)
+    puts (t ? t : "not a tty");
+  return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
+char *tty_doc[] = {
+       "tty writes the name of the terminal that is opened for standard",
+       "input to standard output.  If the `-s' option is supplied, nothing",
+       "is written; the exit status determines whether or not the standard",
+       "input is connected to a tty.",
+       (char *)NULL
+};
+
+/* The standard structure describing a builtin command.  bash keeps an array
+   of these structures. */
+struct builtin tty_struct = {
+       "tty",                  /* builtin name */
+       tty_builtin,            /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       tty_doc,                /* array of long documentation strings. */
+       "tty [-s]",             /* usage synopsis; becomes short_doc */
+       0                       /* reserved for internal use */
+};
index 9f450cdad1c39d2ff683db9bb97f59175192dd11..25ad497efdc981a2ab3a04978bad2104a233a668 100644 (file)
@@ -27,6 +27,7 @@ struct utsname {
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 #define FLAG_SYSNAME   0x01    /* -s */
 #define FLAG_NODENAME  0x02    /* -n */
diff --git a/examples/loadables/uname.c~ b/examples/loadables/uname.c~
new file mode 100644 (file)
index 0000000..9f450cd
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * uname - print system information
+ *
+ * usage: uname [-amnrsv]
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNAME)
+#  include <sys/utsname.h>
+#else
+struct utsname {
+       char    sysname[32];
+       char    nodename[32];
+       char    release[32];
+       char    version[32];
+       char    machine[32];
+};
+#endif
+
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#define FLAG_SYSNAME   0x01    /* -s */
+#define FLAG_NODENAME  0x02    /* -n */
+#define FLAG_RELEASE   0x04    /* -r */
+#define FLAG_VERSION   0x08    /* -v */
+#define FLAG_MACHINE   0x10    /* -m, -p */
+
+#define FLAG_ALL       0x1f
+
+#ifndef errno
+extern int errno;
+#endif
+
+static void uprint();
+
+static int uname_flags;
+
+uname_builtin (list)
+     WORD_LIST *list;
+{
+  int opt, r;
+  struct utsname uninfo;
+
+  uname_flags = 0;
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "amnprsv")) != -1)
+    {
+      switch (opt)
+       {
+       case 'a':
+         uname_flags |= FLAG_ALL;
+         break;
+       case 'm':
+       case 'p':
+         uname_flags |= FLAG_MACHINE;
+         break;
+       case 'n':
+         uname_flags |= FLAG_NODENAME;
+         break;
+       case 'r':
+         uname_flags |= FLAG_RELEASE;
+         break;
+       case 's':
+         uname_flags |= FLAG_SYSNAME;
+         break;
+       case 'v':
+         uname_flags |= FLAG_VERSION;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (uname_flags == 0)
+    uname_flags = FLAG_SYSNAME;
+
+  /* Only ancient systems will not have uname(2). */
+#ifdef HAVE_UNAME
+  if (uname (&uninfo) < 0)
+    {
+      builtin_error ("cannot get system name: %s", strerror (errno));
+      return (EXECUTION_FAILURE);
+    }
+#else
+  builtin_error ("cannot get system information: uname(2) not available");
+  return (EXECUTION_FAILURE);
+#endif
+
+  uprint (FLAG_SYSNAME, uninfo.sysname);
+  uprint (FLAG_NODENAME, uninfo.nodename);
+  uprint (FLAG_RELEASE, uninfo.release);
+  uprint (FLAG_VERSION, uninfo.version);
+  uprint (FLAG_MACHINE, uninfo.machine);
+
+  return (EXECUTION_SUCCESS);
+}
+
+static void
+uprint (flag, info)
+     int flag;
+     char *info;
+{
+  if (uname_flags & flag)
+    {
+      uname_flags &= ~flag;
+      printf ("%s%c", info, uname_flags ? ' ' : '\n');
+    }
+}
+
+char *uname_doc[] = {
+       "display information about the system",
+       (char *)NULL
+};
+
+struct builtin uname_struct = {
+       "uname",
+       uname_builtin,
+       BUILTIN_ENABLED,
+       uname_doc,
+       "uname [-amnrsv]",
+       0
+};
index 8c81ad02d596fcefd107db253ccaef12b32314b8..3b5aafba31532c8bdfff0e8c46bb139bb56fd2dd 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "builtins.h"
 #include "shell.h"
+#include "common.h"
 
 #ifndef errno
 extern int errno;
diff --git a/examples/loadables/unlink.c~ b/examples/loadables/unlink.c~
new file mode 100644 (file)
index 0000000..8c81ad0
--- /dev/null
@@ -0,0 +1,52 @@
+/* unlink - remove a directory entry */
+
+/* Should only be used to remove directories by a superuser prepared to let
+   fsck clean up the file system. */
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+
+#ifndef errno
+extern int errno;
+#endif
+
+unlink_builtin (list)
+     WORD_LIST *list;
+{
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (unlink (list->word->word) != 0)
+    {
+      builtin_error ("%s: cannot unlink: %s", list->word->word, strerror (errno));
+      return (EXECUTION_FAILURE);
+    }
+
+  return (EXECUTION_SUCCESS);
+}
+
+char *unlink_doc[] = {
+       "Remove a directory entry.",
+       (char *)NULL
+};
+
+struct builtin unlink_struct = {
+       "unlink",               /* builtin name */
+       unlink_builtin,         /* function implementing the builtin */
+       BUILTIN_ENABLED,        /* initial flags for builtin */
+       unlink_doc,             /* array of long documentation strings. */
+       "unlink name",          /* usage synopsis; becomes short_doc */
+       0                       /* reserved for internal use */
+};
index 41fd5c4878be1a9be63532fa5a4b1cc425cc0a06..e89d872f9c4be48b7c140fe9155d4b590ce6e6b4 100644 (file)
@@ -8,6 +8,7 @@
 #include "builtins.h"
 #include "shell.h"
 #include "bashgetopt.h"
+#include "common.h"
 
 whoami_builtin (list)
      WORD_LIST *list;
diff --git a/examples/loadables/whoami.c~ b/examples/loadables/whoami.c~
new file mode 100644 (file)
index 0000000..41fd5c4
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * whoami - print out username of current user
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+whoami_builtin (list)
+     WORD_LIST *list;
+{
+  int opt;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "")) != -1)
+    {
+      switch (opt)
+       {
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+  if (list)
+    {
+      builtin_usage ();
+      return (EX_USAGE);
+    }
+
+  if (current_user.user_name == 0)
+    get_current_user_info ();
+  printf ("%s\n", current_user.user_name);
+  return (EXECUTION_SUCCESS);
+}
+
+char *whoami_doc[] = {
+       "display name of current user",
+       (char *)NULL
+};
+
+struct builtin whoami_struct = {
+       "whoami",
+       whoami_builtin,
+       BUILTIN_ENABLED,
+       whoami_doc,
+       "whoami",
+       0
+};
index f46c0b2a45d810c95e7578012b51e0d80a375364..c07d769bd93253bf0cfed16f3ffccdde6af8cd3b 100644 (file)
@@ -1,6 +1,6 @@
 /* histexpand.c -- history expansion. */
 
-/* Copyright (C) 1989-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2007 Free Software Foundation, Inc.
 
    This file contains the GNU History Library (the Library), a set of
    routines for managing the text of previously typed lines.
@@ -66,6 +66,7 @@ static int subst_rhs_len;
 static char *get_history_word_specifier PARAMS((char *, char *, int *));
 static char *history_find_word PARAMS((char *, int));
 static int history_tokenize_word PARAMS((const char *, int));
+static char **history_tokenize_internal PARAMS((const char *, int, int *));
 static char *history_substring PARAMS((const char *, int, int));
 
 static char *quote_breaks PARAMS((char *));
@@ -1582,7 +1583,10 @@ history_find_word (line, ind)
 
   words = history_tokenize_internal (line, ind, &wind);
   if (wind == -1 || words == 0)
-    return ((char *)NULL);
+    {
+      FREE (words);
+      return ((char *)NULL);
+    }
   s = words[wind];
   for (i = 0; i < wind; i++)
     free (words[i]);
index 396007f437bcdc9347b13ca83f4f1039b713280e..922f038aeb553b9cb0bd4401275868a82261ce46 100644 (file)
@@ -1,6 +1,6 @@
 /* util.c -- readline utility functions */
 
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library, a library for
    reading lines of text with interactive input and history editing.
@@ -185,6 +185,7 @@ rl_tilde_expand (ignore, key)
     {
       homedir = tilde_expand ("~");
       _rl_replace_text (homedir, start, end);
+      xfree (homedir);
       return (0);
     }
   else if (rl_line_buffer[start] != '~')
@@ -215,6 +216,7 @@ rl_tilde_expand (ignore, key)
       xfree (temp);
 
       _rl_replace_text (homedir, start, end);
+      xfree (homedir);
     }
 
   return (0);