summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/functions/autoload.v22
-rw-r--r--examples/functions/autoload.v48
-rw-r--r--examples/functions/csh-compat2
-rw-r--r--examples/functions/isnum22
-rw-r--r--examples/functions/shcat2
-rw-r--r--examples/functions/shcat24
-rw-r--r--examples/functions/sort-pos-params2
-rw-r--r--examples/loadables/Makefile.in34
-rw-r--r--examples/loadables/README2
-rw-r--r--examples/loadables/accept.c234
-rw-r--r--examples/loadables/asort.c279
-rw-r--r--examples/loadables/basename.c11
-rw-r--r--examples/loadables/csv.c206
-rw-r--r--examples/loadables/cut.c625
-rw-r--r--examples/loadables/fdflags.c40
-rw-r--r--examples/loadables/finfo.c12
-rw-r--r--examples/loadables/ln.c4
-rw-r--r--examples/loadables/mkdir.c2
-rw-r--r--examples/loadables/mkfifo.c146
-rw-r--r--examples/loadables/mktemp.c212
-rw-r--r--examples/loadables/push.c6
-rw-r--r--examples/loadables/realpath.c2
-rw-r--r--examples/loadables/rm.c8
-rw-r--r--examples/loadables/seq.c8
-rw-r--r--examples/loadables/setpgid.c2
-rw-r--r--examples/loadables/sleep.c11
-rw-r--r--examples/loadables/strftime.c13
-rw-r--r--examples/loadables/tee.c2
-rw-r--r--examples/startup-files/Bash_aliases2
29 files changed, 1833 insertions, 50 deletions
diff --git a/examples/functions/autoload.v2 b/examples/functions/autoload.v2
index e8f34335..e29c6958 100644
--- a/examples/functions/autoload.v2
+++ b/examples/functions/autoload.v2
@@ -29,7 +29,7 @@ _aindex=0
#
# Declare a function ($1) to be autoloaded from a file ($2) when it is first
# called. This defines a `temporary' function that will `.' the file
-# containg the real function definition, then execute that new definition with
+# containing the real function definition, then execute that new definition with
# the arguments given to this `fake' function. The autoload function defined
# by the file and the file itself *must* be named identically.
#
diff --git a/examples/functions/autoload.v4 b/examples/functions/autoload.v4
index a172e612..7f60563b 100644
--- a/examples/functions/autoload.v4
+++ b/examples/functions/autoload.v4
@@ -383,7 +383,7 @@ OPTIONS
'theCharCount=\$(wc -c \$theFuncFile)'
- for each funcion and
+ for each function and
if \$theCharCount < \$AUTOLOAD_SHIM_OVERHEAD
@@ -416,7 +416,7 @@ NOTES
backticks or $(), or in a script that is not being sourced into the
current environment. If you have not previously called the function
in question at your command line or in a script that was sourced into
- the current envirnoment, then the various subshells are going to
+ the current environment, then the various subshells are going to
encounter the shim and replace with the real code before executing.
Remember, however, that environment modifications that occur in a
@@ -490,9 +490,9 @@ NOTES
matter how hard you try, your autoloaded functions will be
unavailable to you, even if you run 'autoload -x -f'. The typical
condition for this is starting up not a subshell, but a brand new
- DIFFERENT shell. And the typical example of this is git extentions.
+ DIFFERENT shell. And the typical example of this is git extensions.
- At the time of this writing, git extentions work by taking a command
+ At the time of this writing, git extensions work by taking a command
'git foo' and looking for a file 'git-foo' on the path. 'git' then
executes 'git-foo' in a new shell - it executes your command in
/bin/sh. That's not a subshell of your process. It will not get your
diff --git a/examples/functions/csh-compat b/examples/functions/csh-compat
index b8dcf8f7..54c8488c 100644
--- a/examples/functions/csh-compat
+++ b/examples/functions/csh-compat
@@ -1,4 +1,4 @@
-# C-shell compatabilty package.
+# C-shell compatibilty package.
# setenv VAR VALUE
function setenv ()
{
diff --git a/examples/functions/isnum2 b/examples/functions/isnum2
index 583e3749..b21974db 100644
--- a/examples/functions/isnum2
+++ b/examples/functions/isnum2
@@ -20,7 +20,7 @@
isnum2()
{
case "$1" in
- '[-+]' | '') return 1;; # empty or bare `-' or `+'
+ [-+] | '') return 1;; # empty or bare `-' or `+'
[-+]*[!0-9]*) return 1;; # non-digit with leading sign
[-+]*) return 0;; # OK
*[!0-9]*) return 1;; # non-digit
diff --git a/examples/functions/shcat b/examples/functions/shcat
index c5d3d630..84f0391e 100644
--- a/examples/functions/shcat
+++ b/examples/functions/shcat
@@ -1,6 +1,6 @@
shcat()
{
- while read -r line
+ while IFS= read -r line
do
echo "$line"
done
diff --git a/examples/functions/shcat2 b/examples/functions/shcat2
index 6fe90f40..8ceff330 100644
--- a/examples/functions/shcat2
+++ b/examples/functions/shcat2
@@ -1,8 +1,8 @@
shcat()
{
- while read -r line
+ while read -r
do
- echo "$line"
+ echo "$REPLY"
done
}
diff --git a/examples/functions/sort-pos-params b/examples/functions/sort-pos-params
index 3fbf7dba..95acd85f 100644
--- a/examples/functions/sort-pos-params
+++ b/examples/functions/sort-pos-params
@@ -17,7 +17,7 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-# Sort the positional paramters.
+# Sort the positional parameters.
# Make sure the positional parameters are passed as arguments to the function.
# If -u is the first arg, remove duplicate array members.
sort_posparams()
diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in
index cc3d3a7f..be46121b 100644
--- a/examples/loadables/Makefile.in
+++ b/examples/loadables/Makefile.in
@@ -1,7 +1,7 @@
#
# Simple makefile for the sample loadable builtins
#
-# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# Copyright (C) 1996-2019 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ INTL_BUILDDIR = ${LIBBUILD}/intl
INTL_INC = @INTL_INC@
LIBINTL_H = @LIBINTL_H@
-CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
+CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(CFLAGS)
#
# These values are generated for configure by ${topdir}/support/shobj-conf.
@@ -101,9 +101,10 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \
- tty pathchk tee head mkdir rmdir printenv id whoami \
- uname sync push ln unlink realpath strftime mypid setpgid seq
-OTHERPROG = necho hello cat pushd stat rm
+ tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \
+ uname sync push ln unlink realpath strftime mypid setpgid seq rm \
+ accept csv cut
+OTHERPROG = necho hello cat pushd stat asort
all: $(SHOBJ_STATUS)
@@ -133,6 +134,9 @@ hello: hello.o
truefalse: truefalse.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
+accept: accept.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ accept.o $(SHOBJ_LIBS)
+
sleep: sleep.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
@@ -175,6 +179,12 @@ mkdir: mkdir.o
rmdir: rmdir.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
+mkfifo: mkfifo.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkfifo.o $(SHOBJ_LIBS)
+
+mktemp: mktemp.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mktemp.o $(SHOBJ_LIBS)
+
head: head.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
@@ -205,6 +215,12 @@ unlink: unlink.o
realpath: realpath.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
+csv: csv.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ csv.o $(SHOBJ_LIBS)
+
+cut: cut.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
+
strftime: strftime.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
@@ -217,6 +233,9 @@ setpgid: setpgid.o
stat: stat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ stat.o $(SHOBJ_LIBS)
+asort: asort.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ asort.o $(SHOBJ_LIBS)
+
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
@@ -272,6 +291,7 @@ uninstall: uninstall-$(SHOBJ_STATUS)
print.o: print.c
truefalse.o: truefalse.c
+accept.o: accept.c
sleep.o: sleep.c
finfo.o: finfo.c
logname.o: logname.c
@@ -285,6 +305,8 @@ rmdir.o: rmdir.c
necho.o: necho.c
hello.o: hello.c
cat.o: cat.c
+csv.o: csv.c
+cut.o: cut.c
printenv.o: printenv.c
id.o: id.c
whoami.o: whoami.c
@@ -292,9 +314,11 @@ uname.o: uname.c
sync.o: sync.c
push.o: push.c
mkdir.o: mkdir.c
+mktemp.o: mktemp.c
realpath.o: realpath.c
strftime.o: strftime.c
setpgid.o: setpgid.c
stat.o: stat.c
fdflags.o: fdflags.c
seq.o: seq.c
+asort.o: asort.c
diff --git a/examples/loadables/README b/examples/loadables/README
index f9bcfac6..6820c960 100644
--- a/examples/loadables/README
+++ b/examples/loadables/README
@@ -41,7 +41,7 @@ without having to search for the right CFLAGS and LDFLAGS.
basename.c Return non-directory portion of pathname.
cat.c cat(1) replacement with no options - the way cat was intended.
dirname.c Return directory portion of pathname.
-fdflags.c Change the flag associated with one of bash's open file desriptors.
+fdflags.c Change the flag associated with one of bash's open file descriptors.
finfo.c Print file info.
head.c Copy first part of files.
hello.c Obligatory "Hello World" / sample loadable.
diff --git a/examples/loadables/accept.c b/examples/loadables/accept.c
new file mode 100644
index 00000000..54cf38c8
--- /dev/null
+++ b/examples/loadables/accept.c
@@ -0,0 +1,234 @@
+/* accept - listen for and accept a remote network connection on a given port */
+
+/*
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash.
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "bashtypes.h"
+#include <errno.h>
+#include <time.h>
+#include "typemax.h"
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "loadables.h"
+
+static int accept_bind_variable (char *, int);
+
+int
+accept_builtin (list)
+ WORD_LIST *list;
+{
+ WORD_LIST *l;
+ SHELL_VAR *v;
+ intmax_t iport;
+ int opt;
+ char *tmoutarg, *fdvar, *rhostvar, *rhost;
+ unsigned short uport;
+ int servsock, clisock;
+ struct sockaddr_in server, client;
+ socklen_t clientlen;
+ struct timeval timeval;
+ struct linger linger = { 0, 0 };
+
+ rhostvar = tmoutarg = fdvar = rhost = (char *)NULL;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "r:t:v:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'r':
+ rhostvar = list_optarg;
+ break;
+ case 't':
+ tmoutarg = list_optarg;
+ break;
+ case 'v':
+ fdvar = list_optarg;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ /* Validate input and variables */
+ if (tmoutarg)
+ {
+ long ival, uval;
+ opt = uconvert (tmoutarg, &ival, &uval, (char **)0);
+ if (opt == 0 || ival < 0 || uval < 0)
+ {
+ builtin_error ("%s: invalid timeout specification", tmoutarg);
+ return (EXECUTION_FAILURE);
+ }
+ timeval.tv_sec = ival;
+ timeval.tv_usec = uval;
+ /* XXX - should we warn if ival == uval == 0 ? */
+ }
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (legal_number (list->word->word, &iport) == 0 || iport < 0 || iport > TYPE_MAXIMUM (unsigned short))
+ {
+ builtin_error ("%s: invalid port number", list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ uport = (unsigned short)iport;
+
+ if (fdvar == 0)
+ fdvar = "ACCEPT_FD";
+
+ unbind_variable (fdvar);
+ if (rhostvar)
+ unbind_variable (rhostvar);
+
+ if ((servsock = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
+ {
+ builtin_error ("cannot create socket: %s", strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+
+ memset ((char *)&server, 0, sizeof (server));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(uport);
+ server.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind (servsock, (struct sockaddr *)&server, sizeof (server)) < 0)
+ {
+ builtin_error ("socket bind failure: %s", strerror (errno));
+ close (servsock);
+ return (EXECUTION_FAILURE);
+ }
+
+ opt = 1;
+ setsockopt (servsock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt));
+ setsockopt (servsock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof (linger));
+
+ if (listen (servsock, 1) < 0)
+ {
+ builtin_error ("listen failure: %s", strerror (errno));
+ close (servsock);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (tmoutarg)
+ {
+ fd_set iofds;
+
+ FD_ZERO(&iofds);
+ FD_SET(servsock, &iofds);
+
+ opt = select (servsock+1, &iofds, 0, 0, &timeval);
+ if (opt < 0)
+ builtin_error ("select failure: %s", strerror (errno));
+ if (opt <= 0)
+ {
+ close (servsock);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ clientlen = sizeof (client);
+ if ((clisock = accept (servsock, (struct sockaddr *)&client, &clientlen)) < 0)
+ {
+ builtin_error ("client accept failure: %s", strerror (errno));
+ close (servsock);
+ return (EXECUTION_FAILURE);
+ }
+
+ close (servsock);
+
+ accept_bind_variable (fdvar, clisock);
+ if (rhostvar)
+ {
+ rhost = inet_ntoa (client.sin_addr);
+ v = builtin_bind_variable (rhostvar, rhost, 0);
+ if (v == 0 || readonly_p (v) || noassign_p (v))
+ builtin_error ("%s: cannot set variable", rhostvar);
+ }
+
+ return (EXECUTION_SUCCESS);
+}
+
+static int
+accept_bind_variable (varname, intval)
+ char *varname;
+ int intval;
+{
+ SHELL_VAR *v;
+ char ibuf[INT_STRLEN_BOUND (int) + 1], *p;
+
+ p = fmtulong (intval, 10, ibuf, sizeof (ibuf), 0);
+ v = builtin_bind_variable (varname, p, 0);
+ if (v == 0 || readonly_p (v) || noassign_p (v))
+ builtin_error ("%s: cannot set variable", varname);
+ return (v != 0);
+}
+
+char *accept_doc[] = {
+ "Accept a network connection on a specified port.",
+ ""
+ "This builtin allows a bash script to act as a TCP/IP server.",
+ "",
+ "Options, if supplied, have the following meanings:",
+ " -t timeout wait TIMEOUT seconds for a connection. TIMEOUT may",
+ " be a decimal number including a fractional portion",
+ " -v varname store the numeric file descriptor of the connected",
+ " socket into VARNAME. The default VARNAME is ACCEPT_FD",
+ " -r rhost store the IP address of the remote host into the shell",
+ " variable RHOST, in dotted-decimal notation",
+ "",
+ "If successful, the shell variable ACCEPT_FD, or the variable named by the",
+ "-v option, will be set to the fd of the connected socket, suitable for",
+ "use as 'read -u$ACCEPT_FD'. RHOST, if supplied, will hold the IP address",
+ "of the remote client. The return status is 0.",
+ "",
+ "On failure, the return status is 1 and ACCEPT_FD (or VARNAME) and RHOST,",
+ "if supplied, will be unset.",
+ "",
+ "The server socket fd will be closed before accept returns.",
+ (char *) NULL
+};
+
+struct builtin accept_struct = {
+ "accept", /* builtin name */
+ accept_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ accept_doc, /* array of long documentation strings. */
+ "accept [-t timeout] [-v varname] [-r addrvar ] port", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/asort.c b/examples/loadables/asort.c
new file mode 100644
index 00000000..e847ef86
--- /dev/null
+++ b/examples/loadables/asort.c
@@ -0,0 +1,279 @@
+/*
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "bashtypes.h"
+#include "shell.h"
+#include "builtins.h"
+#include "common.h"
+#include "xmalloc.h"
+#include "bashgetopt.h"
+
+typedef struct sort_element {
+ ARRAY_ELEMENT *v; // used when sorting array in-place
+ char *key; // used when sorting assoc array
+ char *value; // points to value of array element or assoc entry
+ double num; // used for numeric sort
+} sort_element;
+
+static int reverse_flag;
+static int numeric_flag;
+
+static int
+compare(const void *p1, const void *p2) {
+ const sort_element e1 = *(sort_element *) p1;
+ const sort_element e2 = *(sort_element *) p2;
+
+ if (numeric_flag) {
+ if (reverse_flag)
+ return (e2.num > e1.num) ? 1 : (e2.num < e1.num) ? -1 : 0;
+ else
+ return (e1.num > e2.num) ? 1 : (e1.num < e2.num) ? -1 : 0;
+ }
+ else {
+ if (reverse_flag)
+ return strcoll(e2.value, e1.value);
+ else
+ return strcoll(e1.value, e2.value);
+ }
+}
+
+static int
+sort_index(SHELL_VAR *dest, SHELL_VAR *source) {
+ HASH_TABLE *hash;
+ BUCKET_CONTENTS *bucket;
+ sort_element *sa;
+ ARRAY *array, *dest_array;
+ ARRAY_ELEMENT *ae;
+ size_t i, j, n;
+ char ibuf[INT_STRLEN_BOUND (intmax_t) + 1]; // used by fmtulong
+ char *key;
+
+ dest_array = array_cell(dest);
+
+ if (assoc_p(source)) {
+ hash = assoc_cell(source);
+ n = hash->nentries;
+ sa = xmalloc(n * sizeof(sort_element));
+ i = 0;
+ for ( j = 0; j < hash->nbuckets; ++j ) {
+ bucket = hash->bucket_array[j];
+ while ( bucket ) {
+ sa[i].v = NULL;
+ sa[i].key = bucket->key;
+ if ( numeric_flag )
+ sa[i].num = strtod(bucket->data, NULL);
+ else
+ sa[i].value = bucket->data;
+ i++;
+ bucket = bucket->next;
+ }
+ }
+ }
+ else {
+ array = array_cell(source);
+ n = array_num_elements(array);
+ sa = xmalloc(n * sizeof(sort_element));
+ i = 0;
+
+ for (ae = element_forw(array->head); ae != array->head; ae = element_forw(ae)) {
+ sa[i].v = ae;
+ if (numeric_flag)
+ sa[i].num = strtod(element_value(ae), NULL);
+ else
+ sa[i].value = element_value(ae);
+ i++;
+ }
+ }
+
+ // sanity check
+ if ( i != n ) {
+ builtin_error("%s: corrupt array", source->name);
+ return EXECUTION_FAILURE;
+ }
+
+ qsort(sa, n, sizeof(sort_element), compare);
+
+ array_flush(dest_array);
+
+ for ( i = 0; i < n; ++i ) {
+ if ( assoc_p(source) )
+ key = sa[i].key;
+ else
+ key = fmtulong((long unsigned)sa[i].v->ind, 10, ibuf, sizeof(ibuf), 0);
+
+ array_insert(dest_array, i, key);
+ }
+
+ return EXECUTION_SUCCESS;
+}
+
+static int
+sort_inplace(SHELL_VAR *var) {
+ size_t i, n;
+ ARRAY *a;
+ ARRAY_ELEMENT *ae;
+ sort_element *sa = 0;
+
+ a = array_cell(var);
+ n = array_num_elements(a);
+
+ if ( n == 0 )
+ return EXECUTION_SUCCESS;
+
+ sa = xmalloc(n * sizeof(sort_element));
+
+ i = 0;
+ for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
+ sa[i].v = ae;
+ if (numeric_flag)
+ sa[i].num = strtod(element_value(ae), NULL);
+ else
+ sa[i].value = element_value(ae);
+ i++;
+ }
+
+ // sanity check
+ if ( i != n ) {
+ builtin_error("%s: corrupt array", var->name);
+ return EXECUTION_FAILURE;
+ }
+
+ qsort(sa, n, sizeof(sort_element), compare);
+
+ // for in-place sort, simply "rewire" the array elements
+ sa[0].v->prev = sa[n-1].v->next = a->head;
+ a->head->next = sa[0].v;
+ a->head->prev = sa[n-1].v;
+ a->max_index = n - 1;
+ for (i = 0; i < n; i++) {
+ sa[i].v->ind = i;
+ if (i > 0)
+ sa[i].v->prev = sa[i-1].v;
+ if (i < n - 1)
+ sa[i].v->next = sa[i+1].v;
+ }
+ xfree(sa);
+ return EXECUTION_SUCCESS;
+}
+
+int
+asort_builtin(WORD_LIST *list) {
+ SHELL_VAR *var, *var2;
+ char *word;
+ int opt, ret;
+ int index_flag = 0;
+
+ numeric_flag = 0;
+ reverse_flag = 0;
+
+ reset_internal_getopt();
+ while ((opt = internal_getopt(list, "inr")) != -1) {
+ switch (opt) {
+ case 'i': index_flag = 1; break;
+ case 'n': numeric_flag = 1; break;
+ case 'r': reverse_flag = 1; break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list == 0) {
+ builtin_usage();
+ return EX_USAGE;
+ }
+
+ if (legal_identifier (list->word->word) == 0) {
+ sh_invalidid (list->word->word);
+ return EXECUTION_FAILURE;
+ }
+
+ if ( index_flag ) {
+ if ( list->next == 0 || list->next->next ) {
+ builtin_usage();
+ return EX_USAGE;
+ }
+ if (legal_identifier (list->next->word->word) == 0) {
+ sh_invalidid (list->next->word->word);
+ return EXECUTION_FAILURE;
+ }
+ var = find_or_make_array_variable(list->word->word, 1);
+ if (var == 0)
+ return EXECUTION_FAILURE;
+ var2 = find_variable(list->next->word->word);
+ if ( !var2 || ( !array_p(var2) && !assoc_p(var2) ) ) {
+ builtin_error("%s: Not an array", list->next->word->word);
+ return EXECUTION_FAILURE;
+ }
+ return sort_index(var, var2);
+ }
+
+ while (list) {
+ word = list->word->word;
+ var = find_variable(word);
+ list = list->next;
+
+ if (var == 0 || array_p(var) == 0) {
+ builtin_error("%s: Not an array", word);
+ continue;
+ }
+ if (readonly_p(var) || noassign_p(var)) {
+ if (readonly_p(var))
+ err_readonly(word);
+ continue;
+ }
+
+ if ( (ret = sort_inplace(var)) != EXECUTION_SUCCESS )
+ return ret;
+ }
+ return EXECUTION_SUCCESS;
+
+}
+
+char *asort_doc[] = {
+ "Sort arrays in-place.",
+ "",
+ "Options:",
+ " -n compare according to string numerical value",
+ " -r reverse the result of comparisons",
+ " -i sort using indices/keys",
+ "",
+ "If -i is supplied, SOURCE is not sorted in-place, but the indices (or keys",
+ "if associative) of SOURCE, after sorting it by its values, are placed as",
+ "values in the indexed array DEST",
+ "",
+ "Associative arrays may not be sorted in-place.",
+ "",
+ "Exit status:",
+ "Return value is zero unless an error happened (like invalid variable name",
+ "or readonly array).",
+ (char *)NULL
+};
+
+struct builtin asort_struct = {
+ "asort",
+ asort_builtin,
+ BUILTIN_ENABLED,
+ asort_doc,
+ "asort [-nr] array ... or asort [-nr] -i dest source",
+ 0
+};
diff --git a/examples/loadables/basename.c b/examples/loadables/basename.c
index 0734322d..29dd1a6d 100644
--- a/examples/loadables/basename.c
+++ b/examples/loadables/basename.c
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
- Copyright (C) 1999-2009 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -39,15 +39,14 @@ basename_builtin (list)
int slen, sufflen, off;
char *string, *suffix, *fn;
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
- }
-
- if (no_options (list))
- return (EX_USAGE);
- list = loptend;
+ }
string = list->word->word;
suffix = (char *)NULL;
diff --git a/examples/loadables/csv.c b/examples/loadables/csv.c
new file mode 100644
index 00000000..11228f1a
--- /dev/null
+++ b/examples/loadables/csv.c
@@ -0,0 +1,206 @@
+/* csv - process a line of csv data and populate an indexed array with the
+ fields */
+
+/*
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* See Makefile for compilation details. */
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#include "bashansi.h"
+#include <stdio.h>
+
+#include "loadables.h"
+
+#define CSV_ARRAY_DEFAULT "CSV"
+
+#define NQUOTE 0
+#define DQUOTE 1
+
+/* Split LINE into comma-separated fields, storing each field into a separate
+ element of array variable CSV, starting at index 0. The format of LINE is
+ as described in RFC 4180. */
+static int
+csvsplit (csv, line)
+ SHELL_VAR *csv;
+ char *line;
+{
+ arrayind_t ind;
+ char *field, *prev, *buf, *xbuf;
+ int delim, qstate;
+ int b, rval;
+
+ xbuf = 0;
+ ind = 0;
+ field = prev = line;
+
+ do
+ {
+ if (*prev == '"')
+ {
+ if (xbuf == 0)
+ xbuf = xmalloc (strlen (prev) + 1);
+ buf = xbuf;
+ b = 0;
+ qstate = DQUOTE;
+ for (field = ++prev; *field; field++)
+ {
+ if (qstate == DQUOTE && *field == '"' && field[1] == '"')
+ buf[b++] = *field++; /* skip double quote */
+ else if (qstate == DQUOTE && *field == '"')
+ qstate = NQUOTE;
+ else if (qstate == NQUOTE && *field == ',')
+ break;
+ else
+ /* This copies any text between a closing double quote and the
+ delimiter. If you want to change that, make sure to do the
+ copy only if qstate == DQUOTE. */
+ buf[b++] = *field;
+ }
+ buf[b] = '\0';
+ }
+ else
+ {
+ buf = prev;
+ field = prev + strcspn (prev, ",");
+ }
+
+ delim = *field;
+ *field = '\0';
+
+ bind_array_element (csv, ind, buf, 0);
+ ind++;
+
+ *field = delim;
+
+ if (delim == ',')
+ prev = field + 1;
+ }
+ while (delim == ',');
+
+ if (xbuf)
+ free (xbuf);
+
+ return (rval = ind); /* number of fields */
+}
+
+int
+csv_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, rval;
+ char *array_name, *csvstring;
+ SHELL_VAR *v;
+
+ array_name = 0;
+ rval = EXECUTION_SUCCESS;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "a:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ array_name = list_optarg;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (array_name == 0)
+ array_name = CSV_ARRAY_DEFAULT;
+
+ if (legal_identifier (array_name) == 0)
+ {
+ sh_invalidid (array_name);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (list == 0)
+ {
+ builtin_error ("csv string argument required");
+ return (EX_USAGE);
+ }
+
+ v = find_or_make_array_variable (array_name, 1);
+ if (v == 0 || readonly_p (v) || noassign_p (v))
+ {
+ if (v && readonly_p (v))
+ err_readonly (array_name);
+ return (EXECUTION_FAILURE);
+ }
+ else if (array_p (v) == 0)
+ {
+ builtin_error ("%s: not an indexed array", array_name);
+ return (EXECUTION_FAILURE);
+ }
+ if (invisible_p (v))
+ VUNSETATTR (v, att_invisible);
+ array_flush (array_cell (v));
+
+ csvstring = list->word->word;
+
+ if (csvstring == 0 || *csvstring == 0)
+ return (EXECUTION_SUCCESS);
+
+ opt = csvsplit (v, csvstring);
+ /* Maybe do something with OPT here, it's the number of fields */
+
+ return (rval);
+}
+
+/* Called when builtin is enabled and loaded from the shared object. If this
+ function returns 0, the load fails. */
+int
+csv_builtin_load (name)
+ char *name;
+{
+ return (1);
+}
+
+/* Called when builtin is disabled. */
+void
+csv_builtin_unload (name)
+ char *name;
+{
+}
+
+char *csv_doc[] = {
+ "Read comma-separated fields from a string.",
+ "",
+ "Parse STRING, a line of comma-separated values, into individual fields,",
+ "and store them into the indexed array ARRAYNAME starting at index 0.",
+ "If ARRAYNAME is not supplied, \"CSV\" is the default array name.",
+ (char *)NULL
+};
+
+struct builtin csv_struct = {
+ "csv", /* builtin name */
+ csv_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ csv_doc, /* array of long documentation strings. */
+ "csv [-a ARRAY] string", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/cut.c b/examples/loadables/cut.c
new file mode 100644
index 00000000..ad9a8335
--- /dev/null
+++ b/examples/loadables/cut.c
@@ -0,0 +1,625 @@
+/* cut,lcut - extract specified fields from a line and assign them to an array
+ or print them to the standard output */
+
+/*
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* See Makefile for compilation details. */
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#include "bashansi.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "loadables.h"
+#include "shmbutil.h"
+
+#define CUT_ARRAY_DEFAULT "CUTFIELDS"
+
+#define NOPOS -2 /* sentinel for unset startpos/endpos */
+
+#define BOL 0
+#define EOL INT_MAX
+#define NORANGE -1 /* just a position, no range */
+
+#define BFLAG (1 << 0)
+#define CFLAG (1 << 1)
+#define DFLAG (1 << 2)
+#define FFLAG (1 << 3)
+#define SFLAG (1 << 4)
+
+struct cutpos
+{
+ int startpos, endpos; /* zero-based, correction done in getlist() */
+};
+
+struct cutop
+{
+ int flags;
+ int delim;
+ int npos;
+ struct cutpos *poslist;
+};
+
+static int
+poscmp (a, b)
+ void *a, *b;
+{
+ struct cutpos *p1, *p2;
+
+ p1 = (struct cutpos *)a;
+ p2 = (struct cutpos *)b;
+ return (p1->startpos - p2->startpos);
+}
+
+static int
+getlist (arg, opp)
+ char *arg;
+ struct cutpos **opp;
+{
+ char *ntok, *ltok, *larg;
+ int s, e;
+ intmax_t num;
+ struct cutpos *poslist;
+ int npos, nsize;
+
+ poslist = 0;
+ nsize = npos = 0;
+ s = e = 0;
+ larg = arg;
+ while (ltok = strsep (&larg, ","))
+ {
+ if (*ltok == 0)
+ continue;
+
+ ntok = strsep (&ltok, "-");
+ if (*ntok == 0)
+ s = BOL;
+ else
+ {
+ if (legal_number (ntok, &num) == 0 || (int)num != num || num <= 0)
+ {
+ builtin_error ("%s: invalid list value", ntok);
+ *opp = poslist;
+ return -1;
+ }
+ s = num;
+ s--; /* fields are 1-based */
+ }
+ if (ltok == 0)
+ e = NORANGE;
+ else if (*ltok == 0)
+ e = EOL;
+ else
+ {
+ if (legal_number (ltok, &num) == 0 || (int)num != num || num <= 0)
+ {
+ builtin_error ("%s: invalid list value", ltok);
+ *opp = poslist;
+ return -1;
+ }
+ e = num;
+ e--;
+ if (e == s)
+ e = NORANGE;
+ }
+
+ if (npos == nsize)
+ {
+ nsize += 4;
+ poslist = (struct cutpos *)xrealloc (poslist, nsize * sizeof (struct cutpos));
+ }
+ poslist[npos].startpos = s;
+ poslist[npos].endpos = e;
+ npos++;
+ }
+ if (npos == 0)
+ {
+ builtin_error ("missing list of positions");
+ *opp = poslist;
+ return -1;
+ }
+
+ qsort (poslist, npos, sizeof(poslist[0]), poscmp);
+ *opp = poslist;
+
+ return npos;
+}
+
+static int
+cutbytes (v, line, ops)
+ SHELL_VAR *v;
+ char *line;
+ struct cutop *ops;
+{
+ arrayind_t ind;
+ char *buf, *bmap;
+ size_t llen;
+ int i, b, n, s, e;
+
+ llen = strlen (line);
+ buf = xmalloc (llen + 1);
+ bmap = xmalloc (llen + 1);
+ memset (bmap, 0, llen);
+
+ for (n = 0; n < ops->npos; n++)
+ {
+ s = ops->poslist[n].startpos; /* no translation needed yet */
+ e = ops->poslist[n].endpos;
+ if (e == NORANGE)
+ e = s;
+ else if (e == EOL || e >= llen)
+ e = llen - 1;
+ /* even if a column is specified multiple times, it will only be printed
+ once */
+ for (i = s; i <= e; i++)
+ bmap[i] = 1;
+ }
+
+ b = 0;
+ for (i = 0; i < llen; i++)
+ if (bmap[i])
+ buf[b++] = line[i];
+ buf[b] = 0;
+
+ if (v)
+ {
+ ind = 0;
+ bind_array_element (v, ind, buf, 0);
+ ind++;
+ }
+ else
+ printf ("%s\n", buf);
+
+ free (buf);
+ free (bmap);
+
+ return ind;
+}
+
+static int
+cutchars (v, line, ops)
+ SHELL_VAR *v;
+ char *line;
+ struct cutop *ops;
+{
+ arrayind_t ind;
+ char *buf, *bmap;
+ wchar_t *wbuf, *wb2;
+ size_t llen, wlen;
+ int i, b, n, s, e;
+
+ if (MB_CUR_MAX == 1)
+ return (cutbytes (v, line, ops));
+ if (locale_utf8locale && utf8_mbsmbchar (line) == 0)
+ return (cutbytes (v, line, ops));
+
+ llen = strlen (line);
+ wbuf = (wchar_t *)xmalloc ((llen + 1) * sizeof (wchar_t));
+
+ wlen = mbstowcs (wbuf, line, llen);
+ if (MB_INVALIDCH (wlen))
+ {
+ free (wbuf);
+ return (cutbytes (v, line, ops));
+ }
+
+ bmap = xmalloc (llen + 1);
+ memset (bmap, 0, llen);
+
+ for (n = 0; n < ops->npos; n++)
+ {
+ s = ops->poslist[n].startpos; /* no translation needed yet */
+ e = ops->poslist[n].endpos;
+ if (e == NORANGE)
+ e = s;
+ else if (e == EOL || e >= wlen)
+ e = wlen - 1;
+ /* even if a column is specified multiple times, it will only be printed
+ once */
+ for (i = s; i <= e; i++)
+ bmap[i] = 1;
+ }
+
+ wb2 = (wchar_t *)xmalloc ((wlen + 1) * sizeof (wchar_t));
+ b = 0;
+ for (i = 0; i < wlen; i++)
+ if (bmap[i])
+ wb2[b++] = wbuf[i];
+ wb2[b] = 0;
+
+ free (wbuf);
+
+ buf = bmap;
+ n = wcstombs (buf, wb2, llen);
+
+ if (v)
+ {
+ ind = 0;
+ bind_array_element (v, ind, buf, 0);
+ ind++;
+ }
+ else
+ printf ("%s\n", buf);
+
+ free (buf);
+ free (wb2);
+
+ return ind;
+}
+
+/* The basic strategy is to cut the line into fields using strsep, populate
+ an array of fields from 0..nf, then select those fields using the same
+ bitmap approach as cut{bytes,chars} and assign them to the array variable
+ V or print them on stdout. This function obeys SFLAG. */
+static int
+cutfields (v, line, ops)
+ SHELL_VAR *v;
+ char *line;
+ struct cutop *ops;
+{
+ arrayind_t ind;
+ char *buf, *bmap, *field, **fields, delim[2];
+ size_t llen, fsize;
+ int i, b, n, s, e, nf;
+
+ ind = 0;
+
+ delim[0] = ops->delim;
+ delim[1] = '\0';
+
+ fields = 0;
+ nf = 0;
+ fsize = 0;
+
+ field = buf = line;
+ do
+ {
+ field = strsep (&buf, delim); /* destructive */
+ if (nf == fsize)
+ {
+ fsize += 8;
+ fields = xrealloc (fields, fsize * sizeof (char *));
+ }
+ fields[nf] = field;
+ if (field)
+ nf++;
+ }
+ while (field);
+
+ if (nf == 1)
+ {
+ free (fields);
+ if (ops->flags & SFLAG)
+ return ind;
+ if (v)
+ {
+ bind_array_element (v, ind, line, 0);
+ ind++;
+ }
+ else
+ printf ("%s\n", line);
+ return ind;
+ }
+
+ bmap = xmalloc (nf + 1);
+ memset (bmap, 0, nf);
+
+ for (n = 0; n < ops->npos; n++)
+ {
+ s = ops->poslist[n].startpos; /* no translation needed yet */
+ e = ops->poslist[n].endpos;
+ if (e == NORANGE)
+ e = s;
+ else if (e == EOL || e >= nf)
+ e = nf - 1;
+ /* even if a column is specified multiple times, it will only be printed
+ once */
+ for (i = s; i <= e; i++)
+ bmap[i] = 1;
+ }
+
+ for (i = 1, b = 0; b < nf; b++)
+ {
+ if (bmap[b] == 0)
+ continue;
+ if (v)
+ {
+ bind_array_element (v, ind, fields[b], 0);
+ ind++;
+ }
+ else
+ {
+ if (i == 0)
+ putchar (ops->delim);
+ printf ("%s", fields[b]);
+ }
+ i = 0;
+ }
+ if (v == 0)
+ putchar ('\n');
+
+ return nf;
+}
+
+static int
+cutline (v, line, ops)
+ SHELL_VAR *v;
+ char *line;
+ struct cutop *ops;
+{
+ int rval;
+
+ if (ops->flags & BFLAG)
+ rval = cutbytes (v, line, ops);
+ else if (ops->flags & CFLAG)
+ rval = cutchars (v, line, ops);
+ else
+ rval = cutfields (v, line, ops);
+
+ return (rval >= 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
+static int
+cutfile (v, list, ops)
+ SHELL_VAR *v;
+ WORD_LIST *list;
+ struct cutop *ops;
+{
+ int fd, unbuffered_read;
+ char *line, *b;
+ size_t llen;
+ WORD_LIST *l;
+ ssize_t n;
+
+ line = 0;
+ llen = 0;
+
+ l = list;
+ do
+ {
+ /* for each file */
+ if (l == 0 || (l->word->word[0] == '-' && l->word->word[1] == '\0'))
+ fd = 0;
+ else
+ fd = open (l->word->word, O_RDONLY);
+ if (fd < 0)
+ {
+ file_error (l->word->word);
+ return (EXECUTION_FAILURE);
+ }
+
+#ifndef __CYGWIN__
+ unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
+#else
+ unbuffered_read = 1;
+#endif
+
+ while ((n = zgetline (fd, &line, &llen, '\n', unbuffered_read)) != -1)
+ cutline (v, line, ops); /* can modify line */
+ if (fd > 0)
+ close (fd);
+
+ if (l)
+ l = l->next;
+ }
+ while (l);
+
+ free (line);
+ return EXECUTION_SUCCESS;
+}
+
+#define OPTSET(x) ((cutflags & (x)) ? 1 : 0)
+
+static int
+cut_internal (which, list)
+ int which; /* not used yet */
+ WORD_LIST *list;
+{
+ int opt, rval, cutflags, delim, npos;
+ char *array_name, *cutstring, *list_arg;
+ SHELL_VAR *v;
+ struct cutop op;
+ struct cutpos *poslist;
+
+ v = 0;
+ rval = EXECUTION_SUCCESS;
+
+ cutflags = 0;
+ array_name = 0;
+ list_arg = 0;
+ delim = '\t';
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "a:b:c:d:f:sn")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ array_name = list_optarg;
+ break;
+ case 'b':
+ cutflags |= BFLAG;
+ list_arg = list_optarg;
+ break;
+ case 'c':
+ cutflags |= CFLAG;
+ list_arg = list_optarg;
+ break;
+ case 'd':
+ cutflags |= DFLAG;
+ delim = list_optarg[0];
+ if (delim == 0 || list_optarg[1])
+ {
+ builtin_error ("delimiter must be a single non-null character");
+ return (EX_USAGE);
+ }
+ break;
+ case 'f':
+ cutflags |= FFLAG;
+ list_arg = list_optarg;
+ break;
+ case 'n':
+ break;
+ case 's':
+ cutflags |= SFLAG;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (array_name && (legal_identifier (array_name) == 0))
+ {
+ sh_invalidid (array_name);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (list == 0 && which == 0)
+ {
+ builtin_error ("string argument required");
+ return (EX_USAGE);
+ }
+
+ /* options are mutually exclusive and one is required */
+ if ((OPTSET (BFLAG) + OPTSET (CFLAG) + OPTSET (FFLAG)) != 1)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if ((npos = getlist (list_arg, &poslist)) < 0)
+ {
+ free (poslist);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (array_name)
+ {
+ v = find_or_make_array_variable (array_name, 1);
+ if (v == 0 || readonly_p (v) || noassign_p (v))
+ {
+ if (v && readonly_p (v))
+ err_readonly (array_name);
+ return (EXECUTION_FAILURE);
+ }
+ else if (array_p (v) == 0)
+ {
+ builtin_error ("%s: not an indexed array", array_name);
+ return (EXECUTION_FAILURE);
+ }
+ if (invisible_p (v))
+ VUNSETATTR (v, att_invisible);
+ array_flush (array_cell (v));
+ }
+
+ op.flags = cutflags;
+ op.delim = delim;
+ op.npos = npos;
+ op.poslist = poslist;
+
+ /* we implement cut as a builtin with a cutfile() function that opens each
+ filename in LIST as a filename (or `-' for stdin) and runs cutline on
+ every line in the file. */
+ if (which == 0)
+ {
+ cutstring = list->word->word;
+ if (cutstring == 0 || *cutstring == 0)
+ {
+ free (poslist);
+ return (EXECUTION_SUCCESS);
+ }
+ rval = cutline (v, cutstring, &op);
+ }
+ else
+ rval = cutfile (v, list, &op);
+
+ return (rval);
+}
+
+int
+lcut_builtin (list)
+ WORD_LIST *list;
+{
+ return (cut_internal (0, list));
+}
+
+int
+cut_builtin (list)
+ WORD_LIST *list;
+{
+ return (cut_internal (1, list));
+}
+
+char *lcut_doc[] = {
+ "Extract selected fields from a string.",
+ "",
+ "Select portions of LINE (as specified by LIST) and assign them to",
+ "elements of the indexed array ARRAY starting at index 0, or write",
+ "them to the standard output if -a is not specified.",
+ "",
+ "Items specified by LIST are either column positions or fields delimited",
+ "by a special character, and are described more completely in cut(1).",
+ "",
+ "Columns correspond to bytes (-b), characters (-c), or fields (-f). The",
+ "field delimiter is specified by -d (default TAB). Column numbering",
+ "starts at 1.",
+ (char *)NULL
+};
+
+struct builtin lcut_struct = {
+ "lcut", /* builtin name */
+ lcut_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ lcut_doc, /* array of long documentation strings. */
+ "lcut [-a ARRAY] [-b LIST] [-c LIST] [-f LIST] [-d CHAR] [-sn] line", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
+
+char *cut_doc[] = {
+ "Extract selected fields from each line of a file.",
+ "",
+ "Select portions of each line (as specified by LIST) from each FILE",
+ "and write them to the standard output. cut reads from the standard",
+ "input if no FILE arguments are specified or if a FILE argument is a",
+ "single hyphen.",
+ "",
+ "Items specified by LIST are either column positions or fields delimited",
+ "by a special character, and are described more completely in cut(1).",
+ "",
+ "Columns correspond to bytes (-b), characters (-c), or fields (-f). The",
+ "field delimiter is specified by -d (default TAB). Column numbering",
+ "starts at 1.",
+ (char *)NULL
+};
+
+struct builtin cut_struct = {
+ "cut", /* builtin name */
+ cut_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ cut_doc, /* array of long documentation strings. */
+ "cut [-a ARRAY] [-b LIST] [-c LIST] [-f LIST] [-d CHAR] [-sn] [file ...]", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/fdflags.c b/examples/loadables/fdflags.c
index f3094666..fbe52304 100644
--- a/examples/loadables/fdflags.c
+++ b/examples/loadables/fdflags.c
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
- Copyright (C) 2017 Free Software Foundation, Inc.
+ Copyright (C) 2017,2018,2019 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -32,6 +32,10 @@
#include "loadables.h"
+#ifndef FD_CLOEXEC
+# define FD_CLOEXEC 1
+#endif
+
static const struct
{
const char *name;
@@ -40,37 +44,69 @@ static const struct
{
#ifdef O_APPEND
{ "append", O_APPEND },
+#else
+# define O_APPEND 0
#endif
#ifdef O_ASYNC
{ "async", O_ASYNC },
+#else
+# define O_ASYNC 0
#endif
#ifdef O_SYNC
{ "sync", O_SYNC },
+#else
+# define O_SYNC 0
#endif
#ifdef O_NONBLOCK
{ "nonblock", O_NONBLOCK },
+#else
+# define O_NONBLOCK 0
#endif
#ifdef O_FSYNC
{ "fsync", O_FSYNC },
+#else
+# define O_FSYNC 0
#endif
#ifdef O_DSYNC
{ "dsync", O_DSYNC },
+#else
+# define O_DSYNC 0
#endif
#ifdef O_RSYNC
{ "rsync", O_RSYNC },
+#else
+# define O_RSYNC 0
#endif
#ifdef O_ALT_IO
{ "altio", O_ALT_IO },
+#else
+# define O_ALT_IO 0
#endif
#ifdef O_DIRECT
{ "direct", O_DIRECT },
+#else
+# define O_DIRECT 0
#endif
#ifdef O_NOATIME
{ "noatime", O_NOATIME },
+#else
+# define O_NOATIME 0
#endif
#ifdef O_NOSIGPIPE
{ "nosigpipe", O_NOSIGPIPE },
+#else
+# define O_NOSIGPIPE 0
+#endif
+
+#ifndef O_CLOEXEC
+# define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_FSYNC|O_DSYNC|\
+ O_RSYNC|O_ALT_IO|O_DIRECT|O_NOATIME|O_NOSIGPIPE)
+
+/* An unsed bit in the file status flags word we can use to pass around the
+ state of close-on-exec. */
+# define O_CLOEXEC ((~ALLFLAGS) ^ ((~ALLFLAGS) & ((~ALLFLAGS) - 1)))
#endif
+
#ifdef O_CLOEXEC
{ "cloexec", O_CLOEXEC },
#endif
@@ -199,10 +235,12 @@ setone(int fd, char *v, int verbose)
parseflags(v, &pos, &neg);
cloexec = -1;
+
if ((pos & O_CLOEXEC) && (f & O_CLOEXEC) == 0)
cloexec = FD_CLOEXEC;
if ((neg & O_CLOEXEC) && (f & O_CLOEXEC))
cloexec = 0;
+
if (cloexec != -1 && fcntl(fd, F_SETFD, cloexec) == -1)
builtin_error("can't set status for fd %d: %s", fd, strerror(errno));
diff --git a/examples/loadables/finfo.c b/examples/loadables/finfo.c
index 4273aa59..8c278c35 100644
--- a/examples/loadables/finfo.c
+++ b/examples/loadables/finfo.c
@@ -28,6 +28,12 @@
#endif
#include <sys/types.h>
+#ifdef MAJOR_IN_MKDEV
+# include <sys/mkdev.h>
+#endif
+#ifdef MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+#endif
#include "posixstat.h"
#include <stdio.h>
#include <pwd.h>
@@ -334,13 +340,13 @@ int flags;
else
printf("%ld\n", st->st_ctime);
} else if (flags & OPT_DEV)
- printf("%d\n", st->st_dev);
+ printf("%lu\n", (unsigned long)st->st_dev);
else if (flags & OPT_INO)
printf("%lu\n", (unsigned long)st->st_ino);
else if (flags & OPT_FID)
- printf("%d:%lu\n", st->st_dev, (unsigned long)st->st_ino);
+ printf("%lu:%lu\n", (unsigned long)st->st_dev, (unsigned long)st->st_ino);
else if (flags & OPT_NLINK)
- printf("%d\n", st->st_nlink);
+ printf("%lu\n", (unsigned long)st->st_nlink);
else if (flags & OPT_LNKNAM) {
#ifdef S_ISLNK
b = xmalloc(4096);
diff --git a/examples/loadables/ln.c b/examples/loadables/ln.c
index 93764a35..874e9db8 100644
--- a/examples/loadables/ln.c
+++ b/examples/loadables/ln.c
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
- Copyright (C) 1999-2009 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -42,7 +42,7 @@
extern int errno;
#endif
-typedef int unix_link_syscall_t __P((const char *, const char *));
+typedef int unix_link_syscall_t PARAMS((const char *, const char *));
#define LN_SYMLINK 0x01
#define LN_UNLINK 0x02
diff --git a/examples/loadables/mkdir.c b/examples/loadables/mkdir.c
index b3811199..d5d39551 100644
--- a/examples/loadables/mkdir.c
+++ b/examples/loadables/mkdir.c
@@ -93,7 +93,7 @@ mkdir_builtin (list)
return (EXECUTION_FAILURE);
}
}
- else if (mode)
+ else /* symbolic mode */
{
/* initial bits are a=rwx; the mode argument modifies them */
omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
diff --git a/examples/loadables/mkfifo.c b/examples/loadables/mkfifo.c
new file mode 100644
index 00000000..2bc4e98a
--- /dev/null
+++ b/examples/loadables/mkfifo.c
@@ -0,0 +1,146 @@
+/* mkfifo - make FIFOs */
+
+/* See Makefile for compilation details. */
+
+/*
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash.
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#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"
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
+
+extern int parse_symbolic_mode ();
+
+static int original_umask;
+
+int
+mkfifo_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, mflag, omode, rval, nmode, basemode;
+ char *mode;
+ WORD_LIST *l;
+
+ mflag = 0;
+ mode = (char *)NULL;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt(list, "m:")) != -1)
+ switch (opt)
+ {
+ case 'm':
+ mflag = 1;
+ mode = list_optarg;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage();
+ return (EX_USAGE);
+ }
+ list = loptend;
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ basemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ if (mode == NULL)
+ omode = basemode;
+ else if (ISOCTAL (*mode)) /* octal number */
+ {
+ omode = read_octal (mode);
+ if (omode < 0)
+ {
+ builtin_error ("invalid file mode: %s", mode);
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else /* symbolic mode */
+ {
+ /* initial bits are a=rwx; the mode argument modifies them */
+ omode = parse_symbolic_mode (mode, basemode);
+ if (omode < 0)
+ {
+ builtin_error ("invalid file mode: %s", mode);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ /* Make the new mode */
+ original_umask = umask (0);
+ umask (original_umask);
+
+ nmode = basemode & ~original_umask;
+ /* Adjust new mode based on mode argument */
+ nmode &= omode;
+
+ for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
+ {
+ if (mkfifo (l->word->word, nmode) < 0)
+ {
+ builtin_error ("cannot create FIFO `%s': %s", l->word->word, strerror (errno));
+ rval = EXECUTION_FAILURE;
+ }
+ }
+ return rval;
+}
+
+
+char *mkfifo_doc[] = {
+ "Create FIFOs (named pipes).",
+ "",
+ "Make FIFOs. Create the FIFOs named as arguments, in",
+ "the order specified, using mode a=rw as modified by the current",
+ "umask (see `help umask'). The -m option causes the file permission",
+ "bits of the final FIFO 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=rw\". mkfifo returns 0 if the FIFOs are",
+ "umask, plus write and search permissions for the owner. mkdir",
+ "created successfully, and non-zero if an error occurs.",
+ (char *)NULL
+};
+
+struct builtin mkfifo_struct = {
+ "mkfifo",
+ mkfifo_builtin,
+ BUILTIN_ENABLED,
+ mkfifo_doc,
+ "mkfifo [-m mode] fifo_name [fifo_name ...]",
+ 0
+};
diff --git a/examples/loadables/mktemp.c b/examples/loadables/mktemp.c
new file mode 100644
index 00000000..1f7c9ad3
--- /dev/null
+++ b/examples/loadables/mktemp.c
@@ -0,0 +1,212 @@
+/* mktemp - create temporary file or directory */
+
+/*
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash.
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "bashansi.h"
+
+#include "loadables.h"
+
+#define DEFAULT_PREFIX "shtmp"
+
+int
+mktemp_builtin (list)
+ WORD_LIST *list;
+{
+ WORD_LIST *l;
+ int rval, opt, fd, mflags, base_mflags;
+ int dflag, qflag, tflag, uflag, onetime;
+ char *prefix, *varname, *filename, *template;
+ SHELL_VAR *v;
+
+ dflag = qflag = uflag = tflag = onetime = 0;
+ prefix = varname = 0;
+ rval = EXECUTION_SUCCESS;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "dqut:v:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ prefix = list_optarg;
+ break;
+ case 'u':
+ uflag = 1;
+ break;
+ case 'v':
+ varname = list_optarg;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (varname) /* check for validity, not readonly */
+ {
+ if (legal_identifier (varname) == 0)
+ {
+ if (qflag == 0)
+ sh_invalidid (varname);
+ return (EXECUTION_FAILURE);
+ }
+ v = find_variable (varname);
+ if (v && readonly_p (v))
+ {
+ if (qflag == 0)
+ sh_readonly (varname);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ onetime = (list == 0); /* once through the loop, $TMPDIR/prefix.XXXXXX */
+
+ if (prefix == 0)
+ prefix = DEFAULT_PREFIX;
+ base_mflags = MT_USETMPDIR|MT_USERANDOM; /* USERANDOM not strictly needed */
+
+ while (list || onetime)
+ {
+ mflags = base_mflags;
+ onetime = 0;
+#if defined (USE_MKTEMP) && defined (USE_MKSTEMP)
+ if (list)
+ {
+ template = list->word->word;
+ mflags |= MT_TEMPLATE;
+ }
+#else
+ /* This is sub-optimal. */
+ if (list)
+ {
+ /* Treat the basename as a prefix */
+ template = strrchr (list->word->word, '/');
+ if (template)
+ template++;
+ else
+ template = list->word->word;
+ }
+#endif
+ else
+ template = prefix;
+
+ if (dflag)
+ {
+ filename = sh_mktmpdir (template, mflags);
+ if (filename == 0)
+ {
+ if (qflag == 0)
+ builtin_error ("%s: cannot create directory", template);
+ rval = EXECUTION_FAILURE;
+ }
+ else
+ {
+ if (uflag)
+ rmdir (filename);
+ printf ("%s\n", filename);
+ }
+ }
+ else /* filename */
+ {
+ fd = sh_mktmpfd (template, mflags, &filename);
+ if (fd < 0)
+ {
+ if (qflag == 0)
+ builtin_error ("%s: cannot create file", template);
+ rval = EXECUTION_FAILURE;
+ }
+ else
+ {
+ close (fd);
+ if (uflag)
+ unlink (filename);
+ printf ("%s\n", filename);
+ }
+ }
+
+ /* Assign variable if requested */
+ if (filename && varname)
+ {
+ v = builtin_bind_variable (varname, filename, 0);
+ if (v == 0 || readonly_p (v) || noassign_p (v))
+ {
+ builtin_error ("%s: cannot set variable", varname);
+ rval = EXECUTION_FAILURE;
+ }
+ }
+
+ FREE (filename);
+
+ if (list)
+ list = list->next;
+ }
+
+ return (rval);
+}
+
+char *mktemp_doc[] = {
+ "Make unique temporary file name",
+ "",
+ "Take each supplied filename template and overwrite a portion of it",
+ "to create a filename, which is unique and may be used by the calling",
+ "script. TEMPLATE is a string ending in some number of 'X's. If",
+ "TEMPLATE is not supplied, shtmp.XXXXXX is used and $TMPDIR is used as",
+ "the name of the containing directory. Files are created u+rw; directories",
+ "are created u+rwx.",
+ "",
+ "Options, if supplied, have the following meanings:",
+ "",
+ " -d Create a directory instead of a file",
+ " -q Do not print error messages about file creation failure",
+ " -t PREFIX Use PREFIX as the directory in which to create files",
+ " -u Do not create anything; simply print a name",
+ " -v VAR Store the generated name into shell variable VAR",
+ "",
+ "Any PREFIX supplied with -t is ignored if TEMPLATE is supplied.",
+ "",
+ "The return status is true if the file or directory was created successfully;",
+ "false if an error occurs or VAR is invalid or readonly.",
+
+ (char *)NULL
+};
+
+struct builtin mktemp_struct = {
+ "mktemp", /* builtin name */
+ mktemp_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ mktemp_doc, /* array of long documentation strings. */
+ "mktemp [-d] [-q] [-t prefix] [-u] [-v varname] [template] ...",
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/push.c b/examples/loadables/push.c
index 9bcd5c32..b27455b4 100644
--- a/examples/loadables/push.c
+++ b/examples/loadables/push.c
@@ -4,7 +4,7 @@
*/
/*
- Copyright (C) 1999-2009 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -35,7 +35,7 @@
extern int errno;
#endif
-extern int dollar_dollar_pid;
+extern pid_t dollar_dollar_pid;
extern int last_command_exit_value;
int
@@ -92,7 +92,7 @@ push_builtin (list)
else
{
stop_pipeline (0, (COMMAND *)NULL);
- xstatus = wait_for (pid);
+ xstatus = wait_for (pid, 0);
return (xstatus);
}
}
diff --git a/examples/loadables/realpath.c b/examples/loadables/realpath.c
index 9892ddb8..0974ac41 100644
--- a/examples/loadables/realpath.c
+++ b/examples/loadables/realpath.c
@@ -130,7 +130,7 @@ 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",
+ "validity of each PATHNAME. The -v option produces verbose output. The",
"exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
(char *)NULL
};
diff --git a/examples/loadables/rm.c b/examples/loadables/rm.c
index adfbffdc..0af5493c 100644
--- a/examples/loadables/rm.c
+++ b/examples/loadables/rm.c
@@ -145,8 +145,12 @@ rm_builtin (list)
if (list == 0)
{
- builtin_usage ();
- return (EXECUTION_FAILURE);
+ if (force == 0)
+ {
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ return (EXECUTION_SUCCESS);
}
for (l = list; l; l = l->next)
diff --git a/examples/loadables/seq.c b/examples/loadables/seq.c
index d8f3e0a0..e5624079 100644
--- a/examples/loadables/seq.c
+++ b/examples/loadables/seq.c
@@ -1,5 +1,5 @@
/* seq - print sequence of numbers to standard output.
- Copyright (C) 2018 Free Software Foundation, Inc.
+ Copyright (C) 2018-2020 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,8 +49,8 @@ typedef double floatmax_t;
# define FLOATMAX_FMT "%g"
# define FLOATMAX_WFMT "%0.f"
#endif
-static floatmax_t getfloatmax __P((const char *));
-static char *genformat __P((floatmax_t, floatmax_t, floatmax_t));
+static floatmax_t getfloatmax PARAMS((const char *));
+static char *genformat PARAMS((floatmax_t, floatmax_t, floatmax_t));
#define MAX(a, b) (((a) < (b))? (b) : (a))
@@ -238,7 +238,7 @@ print_fltseq (fmt, first, last, incr)
floatmax_t next;
const char *s;
- n = 0; /* interation counter */
+ n = 0; /* iteration counter */
s = "";
for (next = first; incr >= 0 ? (next <= last) : (next >= last); next = first + n * incr)
{
diff --git a/examples/loadables/setpgid.c b/examples/loadables/setpgid.c
index 7da58f13..e56fd51e 100644
--- a/examples/loadables/setpgid.c
+++ b/examples/loadables/setpgid.c
@@ -105,7 +105,7 @@ const char *setpgid_doc[] = {
"invoke the setpgid(2) system call",
"",
"Arguments:",
- " pid : numeric process identifer, >= 0",
+ " pid : numeric process identifier, >= 0",
" pgrpid: numeric process group identifier, >=0",
"See the setpgid(2) manual page.",
(const char *)NULL
diff --git a/examples/loadables/sleep.c b/examples/loadables/sleep.c
index 92b1a8fa..fc2203d4 100644
--- a/examples/loadables/sleep.c
+++ b/examples/loadables/sleep.c
@@ -5,7 +5,7 @@
*/
/*
- Copyright (C) 1999-2009 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -53,6 +53,9 @@ sleep_builtin (list)
WORD_LIST *list;
{
long sec, usec;
+ char *ep;
+ int r, mul;
+ time_t t;
if (list == 0) {
builtin_usage();
@@ -68,8 +71,12 @@ WORD_LIST *list;
return (EX_USAGE);
}
- if (uconvert(list->word->word, &sec, &usec)) {
+ r = uconvert(list->word->word, &sec, &usec, &ep);
+ /* Maybe postprocess conversion failures here based on EP */
+
+ if (r) {
fsleep(sec, usec);
+ QUIT;
return(EXECUTION_SUCCESS);
}
diff --git a/examples/loadables/strftime.c b/examples/loadables/strftime.c
index 2de09e34..f4e194e6 100644
--- a/examples/loadables/strftime.c
+++ b/examples/loadables/strftime.c
@@ -34,6 +34,7 @@
#include "builtins.h"
#include "shell.h"
#include "common.h"
+#include "bashgetopt.h"
int
strftime_builtin (list)
@@ -46,15 +47,16 @@ strftime_builtin (list)
int n;
intmax_t i;
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
+
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
- if (no_options (list))
- return (EX_USAGE);
-
format = list->word->word;
if (format == 0 || *format == 0)
{
@@ -86,7 +88,7 @@ strftime_builtin (list)
/* Now try to figure out how big the buffer should really be. strftime(3)
will return the number of bytes placed in the buffer unless it's greater
than MAXSIZE, in which case it returns 0. */
- for (n = 1; n < 4; n++)
+ for (n = 1; n <= 8; n++)
{
tbuf = xrealloc (tbuf, tbsize * n);
tsize = strftime (tbuf, tbsize * n, format, t);
@@ -94,7 +96,8 @@ strftime_builtin (list)
break;
}
- printf ("%s\n", tbuf);
+ if (tsize)
+ printf ("%s\n", tbuf);
free (tbuf);
return (EXECUTION_SUCCESS);
diff --git a/examples/loadables/tee.c b/examples/loadables/tee.c
index 819d83ae..283f23f1 100644
--- a/examples/loadables/tee.c
+++ b/examples/loadables/tee.c
@@ -164,7 +164,7 @@ char *tee_doc[] = {
"Duplicate standard output.",
"",
"Copy standard input to standard output, making a copy in each",
- "filename argument. If the `-a' option is gived, the specified",
+ "filename argument. If the `-a' option is given, the specified",
"files are appended to, otherwise they are overwritten. If the",
"`-i' option is supplied, tee ignores interrupts.",
(char *)NULL
diff --git a/examples/startup-files/Bash_aliases b/examples/startup-files/Bash_aliases
index bb9c01e4..2abb93ee 100644
--- a/examples/startup-files/Bash_aliases
+++ b/examples/startup-files/Bash_aliases
@@ -17,7 +17,7 @@ alias pu="pushd"
alias po="popd"
#
-# Csh compatability:
+# Csh compatibility:
#
alias unsetenv=unset
function setenv () {