summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2018-05-22 16:51:07 -0400
committerChet Ramey <chet.ramey@case.edu>2018-05-22 16:51:07 -0400
commit9a51695bed07d37086c352372ac69d0a30039a6b (patch)
tree4d0f57cba0dd1ec7a75aae56e18cfe9997d0b7a7 /examples
parent7de27456f6494f5f9c11ea1c19024d0024f31112 (diff)
downloadbash-5.0-alpha.tar.gz
bash-5.0-alpha releasebash-5.0-alpha
Diffstat (limited to 'examples')
-rw-r--r--examples/INDEX.html464
-rw-r--r--examples/INDEX.txt112
-rw-r--r--examples/bash-completion/README7
-rw-r--r--examples/bash-completion/bash-completion-2.5.tar.xzbin0 -> 276732 bytes
-rw-r--r--examples/functions/arrayops.bash146
-rw-r--r--examples/functions/autoload2
-rw-r--r--examples/functions/autoload.v4556
-rw-r--r--examples/functions/autoload.v4.t184
-rw-r--r--examples/loadables/Makefile.in16
-rw-r--r--examples/loadables/README15
-rw-r--r--examples/loadables/cat.c2
-rw-r--r--examples/loadables/fdflags.c336
-rw-r--r--examples/loadables/head.c1
-rw-r--r--examples/loadables/id.c1
-rw-r--r--examples/loadables/ln.c1
-rw-r--r--examples/loadables/mkdir.c1
-rw-r--r--examples/loadables/necho.c2
-rw-r--r--examples/loadables/pathchk.c3
-rw-r--r--examples/loadables/print.c1
-rw-r--r--examples/loadables/printenv.c1
-rw-r--r--examples/loadables/push.c1
-rw-r--r--examples/loadables/realpath.c6
-rw-r--r--examples/loadables/rm.c177
-rw-r--r--examples/loadables/stat.c430
-rw-r--r--examples/loadables/tee.c1
-rw-r--r--examples/loadables/template.c1
-rw-r--r--examples/loadables/tty.c1
-rw-r--r--examples/loadables/uname.c1
-rw-r--r--examples/loadables/whoami.c1
29 files changed, 1923 insertions, 547 deletions
diff --git a/examples/INDEX.html b/examples/INDEX.html
index bd06b256..bcca1f9e 100644
--- a/examples/INDEX.html
+++ b/examples/INDEX.html
@@ -44,44 +44,28 @@
<td>ksh</td>
</tr>
<tr>
+ <td>./functions/autoload.v3</td>
+ <td>An updated ksh-compatible 'autoload'.</td>
+ <td>ksh</td>
+ </tr>
+ <tr>
<td>./functions/basename</td>
<td>A replacement for basename(1).</td>
<td>basename</td>
</tr>
<tr>
- <td>./functions/basename2</td>
- <td>Fast basename(1) and dirname(1) functions for BASH/SH.</td>
- <td>basename, dirname</td>
- </tr>
- <tr>
- <td>./functions/coproc.bash</td>
- <td>Start, control, and end coprocesses.</td>
- </tr>
- <tr>
- <td>./functions/coshell.bash</td>
- <td>Control shell coprocesses (see coprocess.bash).</td>
- </tr>
- <tr>
- <td>./functions/coshell.README</td>
- <td>README for coshell and coproc.</td>
- </tr>
- <tr>
<td>./functions/csh-compat</td>
<td>A C-shell compatibility package.</td>
<td>csh</td>
</tr>
<tr>
- <td>./functions/dirfuncs</td>
- <td>Directory manipulation functions from the book 'The Korn Shell'.</td>
- </tr>
- <tr>
<td>./functions/dirname</td>
<td>A replacement for dirname(1).</td>
<td>dirname</td>
</tr>
<tr>
- <td>./functions/emptydir</td>
- <td>Find out if a directory is empty.</td>
+ <td>./functions/dirstack</td>
+ <td>Directory stack functions.</td>
</tr>
<tr>
<td>./functions/exitstat</td>
@@ -101,18 +85,6 @@
<td>stty.bash</td>
</tr>
<tr>
- <td>./functions/func</td>
- <td>Print out definitions for functions named by arguments.</td>
- </tr>
- <tr>
- <td>./functions/gethtml</td>
- <td>Get a web page from a remote server (wget(1) in bash!).</td>
- </tr>
- <tr>
- <td>./functions/getoptx.bash</td>
- <td>getopt function that parses long-named options.</td>
- </tr>
- <tr>
<td>./functions/inetaddr</td>
<td>Internet address conversion (inet2hex & hex2inet).</td>
</tr>
@@ -122,10 +94,6 @@
<td>inpath</td>
</tr>
<tr>
- <td>./functions/isnum.bash</td>
- <td>Test user input on numeric or character value.</td>
- </tr>
- <tr>
<td>./functions/isnum2</td>
<td>Test user input on numeric values, with floating point.</td>
</tr>
@@ -134,18 +102,6 @@
<td>Test user input for valid IP Addresses.</td>
</tr>
<tr>
- <td>./functions/jdate.bash</td>
- <td>Julian date conversion.</td>
- </tr>
- <tr>
- <td>./functions/jj.bash</td>
- <td>Look for running jobs.</td>
- </tr>
- <tr>
- <td>./functions/keep</td>
- <td>Try to keep some programs in the foreground and running.</td>
- </tr>
- <tr>
<td>./functions/ksh-cd</td>
<td>ksh-like 'cd': cd [-LP] [dir [change]].</td>
<td>ksh</td>
@@ -165,47 +121,14 @@
<td>Replace the 'login' and 'newgrp' builtins in old Bourne shells.</td>
</tr>
<tr>
- <td>./functions/lowercase</td>
- <td>Rename files to lower case.</td>
- <td>rename lower</td>
- </tr>
- <tr>
- <td>./functions/manpage</td>
- <td>Find and print a manual page.</td>
- <td>fman</td>
- </tr>
- <tr>
- <td>./functions/mhfold</td>
- <td>Print MH folders, useful only because folders(1) doesn't print mod date/times.</td>
- </tr>
- <tr>
<td>./functions/notify.bash</td>
<td>Notify when jobs change status.</td>
</tr>
<tr>
- <td>./functions/pathfuncs</td>
- <td>Path related functions (no_path, add_path, pre-path, del_path).</td>
- <td>path</td>
- </tr>
- <tr>
<td>./functions/README</td>
<td>README</td>
</tr>
<tr>
- <td>./functions/recurse</td>
- <td>Recursive directory traverser.</td>
- </tr>
- <tr>
- <td>./functions/repeat2</td>
- <td>A clone of C shell builtin 'repeat'.</td>
- <td>repeat, csh</td>
- </tr>
- <tr>
- <td>./functions/repeat3</td>
- <td>A clone of C shell builtin 'repeat'.</td>
- <td>repeat, csh</td>
- </tr>
- <tr>
<td>./functions/seq</td>
<td>Generate a sequence from m to n, m defaults to 1.</td>
</tr>
@@ -238,10 +161,6 @@
<td>ksh</td>
</tr>
<tr>
- <td>./functions/term</td>
- <td>A shell function to set the terminal type interactively or not.</td>
- </tr>
- <tr>
<td>./functions/whatis</td>
<td>An implementation of the 10th Edition Unix sh builtin 'whatis(1)' command.</td>
</tr>
@@ -254,17 +173,6 @@
<td>An emulation of 'which(1)' as it appears in FreeBSD.</td>
</tr>
<tr>
- <td>./functions/xalias.bash</td>
- <td>Convert csh alias commands to bash functions.</td>
- <td>csh, aliasconv</td>
- </tr>
- <tr>
- <td>./functions/xfind.bash</td>
- <td>A 'find(1)' clone.</td>
- </tr>
- <tr>
- </tr>
- <tr>
<td>./loadables/</td>
<td>Example loadable replacements</td>
</tr>
@@ -279,25 +187,17 @@
<td>cat, readline pager</td>
</tr>
<tr>
- <td>./loadables/cut.c</td>
- <td>cut(1) replacement.</td>
- </tr>
- <tr>
<td>./loadables/dirname.c</td>
<td>Return directory portion of pathname.</td>
<td>dirname</td>
</tr>
<tr>
- <td>./loadables/finfo.c</td>
- <td>Print file info.</td>
+ <td>./loadables/fdflags.c</td>
+ <td>Display or modify file descriptor flags</td>
</tr>
<tr>
- <td>./loadables/getconf.c</td>
- <td>POSIX.2 getconf utility.</td>
- </tr>
- <tr>
- <td>./loadables/getconf.h</td>
- <td>Replacement definitions for ones the system doesn't provide.</td>
+ <td>./loadables/finfo.c</td>
+ <td>Print file info.</td>
</tr>
<tr>
<td>./loadables/head.c</td>
@@ -324,10 +224,18 @@
<td>Simple makefile for the sample loadable builtins.</td>
</tr>
<tr>
+ <td>./loadables/Makefile.inc.in</td>
+ <td>Sample makefile to use for loadable builtin development.</td>
+ </tr>
+ <tr>
<td>./loadables/mkdir.c</td>
<td>Make directories.</td>
</tr>
<tr>
+ <td>./loadables/mypid.c</td>
+ <td>Demonstrate how a loadable builtin can create and delete shell variables.</td>
+ </tr>
+ <tr>
<td>./loadables/necho.c</td>
<td>echo without options or argument interpretation.</td>
</tr>
@@ -356,14 +264,26 @@
<td>Canonicalize pathnames, resolving symlinks.</td>
</tr>
<tr>
+ <td>./loadables/rm.c</td>
+ <td>Remove file.</td>
+ </tr>
+ <tr>
<td>./loadables/rmdir.c</td>
<td>Remove directory.</td>
</tr>
<tr>
+ <td>./loadables/setpgid.c</td>
+ <td>Set a child process's process group.
+ </tr>
+ <tr>
<td>./loadables/sleep.c</td>
<td>sleep for fractions of a second.</td>
</tr>
<tr>
+ <td>./loadables/stat.c</td>
+ <td>Load an associative array with stat information about a file.</td>
+ </tr>
+ <tr>
<td>./loadables/strftime.c</td>
<td>Loadable builtin interface to strftime(3).</td>
</tr>
@@ -431,221 +351,12 @@
<td>README</td>
</tr>
<tr>
- <td>./misc/suncmd.termcap</td>
- <td>SunView TERMCAP string.</td>
- </tr>
- <tr>
- </tr>
- <tr>
- <td>./scripts.noah</td>
- <td>Noah Friedman's collection of scripts (updated to bash v2 syntax by Chet Ramey)</td>
- </tr>
- <tr>
- <td>./scripts.noah/aref.bash</td>
- <td>Pseudo-arrays and substring indexing examples.</td>
- </tr>
- <tr>
- <td>./scripts.noah/bash.sub.bash</td>
- <td>Library functions used by require.bash.</td>
- </tr>
- <tr>
- <td>./scripts.noah/bash_version.bash</td>
- <td>A function to slice up $BASH_VERSION.</td>
- </tr>
- <tr>
- <td>./scripts.noah/meta.bash</td>
- <td>Enable and disable eight-bit readline input.</td>
- </tr>
- <tr>
- <td>./scripts.noah/mktmp.bash</td>
- <td>Make a temporary file with a unique name.</td>
- </tr>
- <tr>
- <td>./scripts.noah/number.bash</td>
- <td>A fun hack to translate numerals into English.</td>
- </tr>
- <tr>
- <td>./scripts.noah/PERMISSION</td>
- <td>Permissions to use the scripts in this directory.</td>
- </tr>
- <tr>
- <td>./scripts.noah/prompt.bash</td>
- <td>A way to set PS1 to some predefined strings.</td>
- </tr>
- <tr>
- <td>./scripts.noah/README</td>
- <td>README</td>
- </tr>
- <tr>
- <td>./scripts.noah/remap_keys.bash</td>
- <td>A front end to 'bind' to redo readline bindings.</td>
- </tr>
- <tr>
- <td>./scripts.noah/require.bash</td>
- <td>Lisp-like require/provide library functions for bash.</td>
- </tr>
- <tr>
- <td>./scripts.noah/send_mail.bash</td>
- <td>Replacement SMTP client written in bash.</td>
- </tr>
- <tr>
- <td>./scripts.noah/shcat.bash</td>
- <td>Bash replacement for 'cat(1)'.</td>
- <td>cat</td>
- </tr>
- <tr>
- <td>./scripts.noah/source.bash</td>
- <td>Replacement for source that uses current directory.</td>
- </tr>
- <tr>
- <td>./scripts.noah/string.bash</td>
- <td>The string(3) functions at the shell level.</td>
- </tr>
- <tr>
- <td>./scripts.noah/stty.bash</td>
- <td>Front-end to stty(1) that changes readline bindings too.</td>
- <td>fstty</td>
- </tr>
- <tr>
- <td>./scripts.noah/y_or_n_p.bash</td>
- <td>Prompt for a yes/no/quit answer.</td>
- <td>ask</td>
- </tr>
- <tr>
- </tr>
- <tr>
- <td>./scripts.v2</td>
- <td>John DuBois' ksh script collection (converted to bash v2 syntax by Chet Ramey).</td>
- </tr>
- <tr>
- <td>./scripts.v2/arc2tarz</td>
- <td>Convert an "arc" archive to a compressed tar archive.</td>
- </tr>
- <tr>
- <td>./scripts.v2/bashrand</td>
- <td>Random number generator with upper and lower bounds and optional seed.</td>
- <td>random</td>
- </tr>
- <tr>
- <td>./scripts.v2/cal2day.bash</td>
- <td>Convert a day number to a name.</td>
- </tr>
- <tr>
- <td>./scripts.v2/cdhist.bash</td>
- <td>cd replacement with a directory stack added.</td>
- </tr>
- <tr>
- <td>./scripts.v2/corename</td>
- <td>Tell what produced a core file.</td>
- </tr>
- <tr>
- <td>./scripts.v2/fman</td>
- <td>Fast man(1) replacement.</td>
- <td>manpage</td>
- </tr>
- <tr>
- <td>./scripts.v2/frcp</td>
- <td>Copy files using ftp(1) but with rcp-type command line syntax.</td>
- </tr>
- <tr>
- <td>./scripts.v2/lowercase</td>
- <td>Change filenames to lower case.</td>
- <td>rename lower</td>
- </tr>
- <tr>
- <td>./scripts.v2/ncp</td>
- <td>A nicer front end for cp(1) (has -i, etc.).</td>
- </tr>
- <tr>
- <td>./scripts.v2/newext</td>
- <td>Change the extension of a group of files.</td>
- <td>rename</td>
- </tr>
- <tr>
- <td>./scripts.v2/nmv</td>
- <td>A nicer front end for mv(1) (has -i, etc.).</td>
- <td>rename</td>
- </tr>
- <tr>
- <td>./scripts.v2/pages</td>
- <td>Print specified pages from files.</td>
- </tr>
- <tr>
- <td>./scripts.v2/PERMISSION</td>
- <td>Permissions to use the scripts in this directory.</td>
- </tr>
- <tr>
- <td>./scripts.v2/pf</td>
- <td>A pager front end that handles compressed files.</td>
- </tr>
- <tr>
- <td>./scripts.v2/pmtop</td>
- <td>Poor man's 'top(1)' for SunOS 4.x and BSD/OS.</td>
- </tr>
- <tr>
- <td>./scripts.v2/README</td>
- <td>README</td>
- </tr>
- <tr>
- <td>./scripts.v2/ren</td>
- <td>Rename files by changing parts of filenames that match a pattern.</td>
- <td>rename</td>
- </tr>
- <tr>
- <td>./scripts.v2/rename</td>
- <td>Change the names of files that match a pattern.</td>
- <td>rename</td>
- </tr>
- <tr>
- <td>./scripts.v2/repeat</td>
- <td>Execute a command multiple times.</td>
- <td>repeat</td>
- </tr>
- <tr>
- <td>./scripts.v2/shprof</td>
- <td>Line profiler for bash scripts.</td>
- </tr>
- <tr>
- <td>./scripts.v2/untar</td>
- <td>Unarchive a (possibly compressed) tarfile into a directory.</td>
- </tr>
- <tr>
- <td>./scripts.v2/uudec</td>
- <td>Carefully uudecode(1) multiple files.</td>
- </tr>
- <tr>
- <td>./scripts.v2/uuenc</td>
- <td>uuencode(1) multiple files.</td>
- </tr>
- <tr>
- <td>./scripts.v2/vtree</td>
- <td>Print a visual display of a directory tree.</td>
- <td>tree</td>
- </tr>
- <tr>
- <td>./scripts.v2/where</td>
- <td>Show where commands that match a pattern are.</td>
- </tr>
- <tr>
</tr>
<tr>
<td>./scripts</td>
<td>Example scripts</td>
</tr>
<tr>
- <td>./scripts/adventure.sh</td>
- <td>Text adventure game in bash!</td>
- </tr>
- <tr>
- <td>./scripts/bcsh.sh</td>
- <td>Bourne shell cshell-emulator.</td>
- <td>csh</td>
- </tr>
- <tr>
- <td>./scripts/bash-hexdump.sh</td>
- <td>hexdump(1) in bash</td>
- <td>hexdump -C, hd</td>
- <tr>
<td>./scripts/cat.sh</td>
<td>Readline-based pager.</td>
<td>cat, readline pager</td>
@@ -655,65 +366,15 @@
<td>Center - center a group of lines.</td>
</tr>
<tr>
- <td>./scripts/dd-ex.sh</td>
- <td>Line editor using only /bin/sh, /bin/dd and /bin/rm.</td>
- </tr>
- <tr>
- <td>./scripts/fixfiles.bash</td>
- <td>Recurse a tree and fix files containing various "bad" chars.</td>
- </tr>
- <tr>
- <td>./scripts/hanoi.bash</td>
- <td>The inevitable Towers of Hanoi in bash.</td>
- </tr>
- <tr>
<td>./scripts/inpath</td>
<td>Search $PATH for a file the same name as $1; return TRUE if found.</td>
<td>inpath</td>
</tr>
<tr>
- <td>./scripts/krand.bash</td>
- <td>Produces a random number within integer limits.</td>
- <td>random</td>
- </tr>
- <tr>
- <td>./scripts/line-input.bash</td>
- <td>Line input routine for GNU Bourne-Again Shell plus terminal-control primitives.</td>
- </tr>
- <tr>
- <td>./scripts/nohup.bash</td>
- <td>bash version of 'nohup' command.</td>
- </tr>
- <tr>
- <td>./scripts/precedence</td>
- <td>Test relative precedences for '&&' and '||' operators.</td>
- </tr>
- <tr>
- <td>./scripts/randomcard.bash</td>
- <td>Print a random card from a card deck.</td>
- <td>random</td>
- </tr>
- <tr>
<td>./scripts/README</td>
<td>README</td>
</tr>
<tr>
- <td>./scripts/scrollbar</td>
- <td>Display scrolling text.</td>
- </tr>
- <tr>
- <td>./scripts/scrollbar2</td>
- <td>Display scrolling text.</td>
- </tr>
- <tr>
- <td>./scripts/self-repro</td>
- <td>A self-reproducing script (careful!)</td>
- </tr>
- <tr>
- <td>./scripts/showperm.bash</td>
- <td>Convert ls(1) symbolic permissions into octal mode.</td>
- </tr>
- <tr>
<td>./scripts/shprompt</td>
<td>Display a prompt and get an answer satisfying certain criteria.</td>
<td>ask</td>
@@ -723,37 +384,6 @@
<td>Display a 'spinning wheel' to show progress.</td>
</tr>
<tr>
- <td>./scripts/timeout</td>
- <td>Give rsh(1) a shorter timeout.</td>
- </tr>
- <tr>
- <td>./scripts/timeout2</td>
- <td>Execute a given command with a timeout.</td>
- </tr>
- <tr>
- <td>./scripts/timeout3</td>
- <td>Execute a given command with a timeout.</td>
- </tr>
- <tr>
- <td>./scripts/vtree2</td>
- <td>Display a tree printout of dir in 1k blocks.</td>
- <td>tree</td>
- </tr>
- <tr>
- <td>./scripts/vtree3</td>
- <td>Display a graphical tree printout of dir.</td>
- <td>tree</td>
- </tr>
- <tr>
- <td>./scripts/vtree3a</td>
- <td>Display a graphical tree printout of dir.</td>
- <td>tree</td>
- </tr>
- <tr>
- <td>./scripts/websrv.sh</td>
- <td>A web server in bash!</td>
- </tr>
- <tr>
<td>./scripts/xterm_title</td>
<td>Print the contents of the xterm title bar.</td>
</tr>
@@ -793,36 +423,4 @@
</tr>
<tr>
</tr>
- <tr>
- <td>./startup-files/apple</td>
- <td>Example Start-up files for Mac OS X.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/aliases</td>
- <td>Sample aliases for Mac OS X.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/bash.defaults</td>
- <td>Sample User preferences file.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/environment</td>
- <td>Sample Bourne Again Shell environment file.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/login</td>
- <td>Sample login wrapper.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/logout</td>
- <td>Sample logout wrapper.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/rc</td>
- <td>Sample Bourne Again Shell config file.</td>
- </tr>
- <tr>
- <td>./startup-files/apple/README</td>
- <td>README</td>
- </tr>
</table>
diff --git a/examples/INDEX.txt b/examples/INDEX.txt
index 4b5478ee..b47e2113 100644
--- a/examples/INDEX.txt
+++ b/examples/INDEX.txt
@@ -9,43 +9,25 @@ Path Description X-Ref
./functions/autoload An almost ksh-compatible 'autoload' (no lazy load). ksh
./functions/autoload.v2 An almost ksh-compatible 'autoload' (no lazy load). ksh
./functions/autoload.v3 A more ksh-compatible 'autoload' (with lazy load). ksh
+./functions/autoload.v4 An updated ksh-compatible 'autoload'. ksh
./functions/basename A replacement for basename(1). basename
-./functions/basename2 Fast basename(1) and dirname(1) functions for BASH/SH. basename, dirname
-./functions/coproc.bash Start, control, and end coprocesses.
-./functions/coshell.bash Control shell coprocesses (see coprocess.bash).
-./functions/coshell.README README for coshell and coproc.
./functions/csh-compat A C-shell compatibility package. csh
-./functions/dirfuncs Directory manipulation functions from the book 'The Korn Shell'.
./functions/dirname A replacement for dirname(1). dirname
-./functions/emptydir Find out if a directory is empty.
+./functions/dirstack Directory stack functions.
./functions/exitstat Display the exit status of processes.
./functions/external Like 'command' but FORCES use of external command.
./functions/fact Recursive factorial function.
./functions/fstty Front end to sync TERM changes to both stty(1) and readline 'bind'. stty.bash
-./functions/func Print out definitions for functions named by arguments.
-./functions/gethtml Get a web page from a remote server (wget(1) in bash!).
-./functions/getoptx.bash getopt function that parses long-named options.
./functions/inetaddr Internet address conversion (inet2hex & hex2inet).
./functions/inpath Return zero if the argument is in the path and executable. inpath
-./functions/isnum.bash Test user input on numeric or character value.
./functions/isnum2 Test user input on numeric values, with floating point.
./functions/isvalidip Test user input for valid IP Addresses.
-./functions/jdate.bash Julian date conversion.
-./functions/jj.bash Look for running jobs.
-./functions/keep Try to keep some programs in the foreground and running.
./functions/ksh-cd ksh-like 'cd': cd [-LP] [dir [change]]. ksh
./functions/ksh-compat-test ksh-like arithmetic test replacements. ksh
./functions/kshenv Functions and aliases to provide the beginnings of a ksh environment for bash. ksh
./functions/login Replace the 'login' and 'newgrp' builtins in old Bourne shells.
-./functions/lowercase Rename files to lower case. rename lower
-./functions/manpage Find and print a manual page. fman
-./functions/mhfold Print MH folders, useful only because folders(1) doesn't print mod date/times.
./functions/notify.bash Notify when jobs change status.
-./functions/pathfuncs Path related functions (no_path, add_path, pre-path, del_path). path
./functions/README README
-./functions/recurse Recursive directory traverser.
-./functions/repeat2 A clone of C shell builtin 'repeat'. repeat, csh
-./functions/repeat3 A clone of C shell builtin 'repeat'. repeat, csh
./functions/seq Generate a sequence from m to n, m defaults to 1.
./functions/seq2 Generate a sequence from m to n, m defaults to 1.
./functions/shcat Readline-based pager. cat, readline pager
@@ -53,28 +35,25 @@ Path Description X-Ref
./functions/sort-pos-params Sort the positional parameters.
./functions/substr A function to emulate the ancient ksh builtin. ksh
./functions/substr2 A function to emulate the ancient ksh builtin. ksh
-./functions/term A shell function to set the terminal type interactively or not.
./functions/whatis An implementation of the 10th Edition Unix sh builtin 'whatis(1)' command.
./functions/whence An almost-ksh compatible 'whence(1)' command.
./functions/which An emulation of 'which(1)' as it appears in FreeBSD.
-./functions/xalias.bash Convert csh alias commands to bash functions. csh, aliasconv
-./functions/xfind.bash A 'find(1)' clone.
./loadables/ Example loadable replacements
./loadables/basename.c Return non-directory portion of pathname. basename
./loadables/cat.c cat(1) replacement with no options - the way cat was intended. cat, readline pager
-./loadables/cut.c cut(1) replacement.
./loadables/dirname.c Return directory portion of pathname. dirname
+./loadables/fdflags.c Display or modify file descriptor flags
./loadables/finfo.c Print file info.
-./loadables/getconf.c POSIX.2 getconf utility.
-./loadables/getconf.h Replacement definitions for ones the system doesn't provide.
./loadables/head.c Copy first part of files.
./loadables/hello.c Obligatory "Hello World" / sample loadable.
./loadables/id.c POSIX.2 user identity.
./loadables/ln.c Make links.
./loadables/logname.c Print login name of current user.
./loadables/Makefile.in Simple makefile for the sample loadable builtins.
+./loadables/Makefile.inc.in Sample makefile to use for loadable builtin development.
./loadables/mkdir.c Make directories.
+./loadables/mypid.c Demonstrate how a loadable builtin can create and delete shell variables.
./loadables/necho.c echo without options or argument interpretation.
./loadables/pathchk.c Check pathnames for validity and portability.
./loadables/print.c Loadable ksh-93 style print builtin.
@@ -82,8 +61,11 @@ Path Description X-Ref
./loadables/push.c Anyone remember TOPS-20?
./loadables/README README
./loadables/realpath.c Canonicalize pathnames, resolving symlinks.
+./loadables/rm.c Remove file.
./loadables/rmdir.c Remove directory.
+./loadables/setpgid.c Set a child process's process group.
./loadables/sleep.c sleep for fractions of a second.
+./loadables/stat.c Load an associative array with stat information about a file.
./loadables/strftime.c Loadable builtin interface to strftime(3).
./loadables/sync.c Sync the disks by forcing pending filesystem writes to complete.
./loadables/tee.c Duplicate standard input.
@@ -101,83 +83,13 @@ Path Description X-Ref
./misc/aliasconv.sh Convert csh aliases to bash aliases and functions. csh, xalias
./misc/cshtobash Convert csh aliases, environment variables, and variables to bash equivalents. csh, xalias
./misc/README README
-./misc/suncmd.termcap SunView TERMCAP string.
-
-./scripts.noah Noah Friedman's collection of scripts (updated to bash v2 syntax by Chet Ramey)
-./scripts.noah/aref.bash Pseudo-arrays and substring indexing examples.
-./scripts.noah/bash.sub.bash Library functions used by require.bash.
-./scripts.noah/bash_version.bash A function to slice up $BASH_VERSION.
-./scripts.noah/meta.bash Enable and disable eight-bit readline input.
-./scripts.noah/mktmp.bash Make a temporary file with a unique name.
-./scripts.noah/number.bash A fun hack to translate numerals into English.
-./scripts.noah/PERMISSION Permissions to use the scripts in this directory.
-./scripts.noah/prompt.bash A way to set PS1 to some predefined strings.
-./scripts.noah/README README
-./scripts.noah/remap_keys.bash A front end to 'bind' to redo readline bindings.
-./scripts.noah/require.bash Lisp-like require/provide library functions for bash.
-./scripts.noah/send_mail.bash Replacement SMTP client written in bash.
-./scripts.noah/shcat.bash Bash replacement for 'cat(1)'. cat
-./scripts.noah/source.bash Replacement for source that uses current directory.
-./scripts.noah/string.bash The string(3) functions at the shell level.
-./scripts.noah/stty.bash Front-end to stty(1) that changes readline bindings too. fstty
-./scripts.noah/y_or_n_p.bash Prompt for a yes/no/quit answer. ask
-
-./scripts.v2 John DuBois' ksh script collection (converted to bash v2 syntax by Chet Ramey).
-./scripts.v2/arc2tarz Convert an "arc" archive to a compressed tar archive.
-./scripts.v2/bashrand Random number generator with upper and lower bounds and optional seed. random
-./scripts.v2/cal2day.bash Convert a day number to a name.
-./scripts.v2/cdhist.bash cd replacement with a directory stack added.
-./scripts.v2/corename Tell what produced a core file.
-./scripts.v2/fman Fast man(1) replacement. manpage
-./scripts.v2/frcp Copy files using ftp(1) but with rcp-type command line syntax.
-./scripts.v2/lowercase Change filenames to lower case. rename lower
-./scripts.v2/ncp A nicer front end for cp(1) (has -i, etc.).
-./scripts.v2/newext Change the extension of a group of files. rename
-./scripts.v2/nmv A nicer front end for mv(1) (has -i, etc.). rename
-./scripts.v2/pages Print specified pages from files.
-./scripts.v2/PERMISSION Permissions to use the scripts in this directory.
-./scripts.v2/pf A pager front end that handles compressed files.
-./scripts.v2/pmtop Poor man's 'top(1)' for SunOS 4.x and BSD/OS.
-./scripts.v2/README README
-./scripts.v2/ren Rename files by changing parts of filenames that match a pattern. rename
-./scripts.v2/rename Change the names of files that match a pattern. rename
-./scripts.v2/repeat Execute a command multiple times. repeat
-./scripts.v2/shprof Line profiler for bash scripts.
-./scripts.v2/untar Unarchive a (possibly compressed) tarfile into a directory.
-./scripts.v2/uudec Carefully uudecode(1) multiple files.
-./scripts.v2/uuenc uuencode(1) multiple files.
-./scripts.v2/vtree Print a visual display of a directory tree. tree
-./scripts.v2/where Show where commands that match a pattern are.
./scripts Example scripts
-./scripts/adventure.sh Text adventure game in bash!
-./scripts/bash-hexdump.sh hexdump(1) in bash
-./scripts/bcsh.sh Bourne shell cshell-emulator. csh
./scripts/cat.sh Readline-based pager. cat, readline pager
./scripts/center Center - center a group of lines.
-./scripts/dd-ex.sh Line editor using only /bin/sh, /bin/dd and /bin/rm.
-./scripts/fixfiles.bash Recurse a tree and fix files containing various "bad" chars.
-./scripts/hanoi.bash The inevitable Towers of Hanoi in bash.
./scripts/inpath Search $PATH for a file the same name as $1; return TRUE if found. inpath
-./scripts/krand.bash Produces a random number within integer limits. random
-./scripts/line-input.bash Line input routine for GNU Bourne-Again Shell plus terminal-control primitives.
-./scripts/nohup.bash bash version of 'nohup' command.
-./scripts/precedence Test relative precedences for '&&' and '||' operators.
-./scripts/randomcard.bash Print a random card from a card deck. random
-./scripts/README README
-./scripts/scrollbar Display scrolling text.
-./scripts/scrollbar2 Display scrolling text.
-./scripts/self-repro A self-reproducing script (careful!)
-./scripts/showperm.bash Convert ls(1) symbolic permissions into octal mode.
./scripts/shprompt Display a prompt and get an answer satisfying certain criteria. ask
./scripts/spin.bash Display a 'spinning wheel' to show progress.
-./scripts/timeout Give rsh(1) a shorter timeout.
-./scripts/timeout2 Execute a given command with a timeout.
-./scripts/timeout3 Execute a given command with a timeout.
-./scripts/vtree2 Display a tree printout of dir in 1k blocks. tree
-./scripts/vtree3 Display a graphical tree printout of dir. tree
-./scripts/vtree3a Display a graphical tree printout of dir. tree
-./scripts/websrv.sh A web server in bash!
./scripts/xterm_title Print the contents of the xterm title bar.
./scripts/zprintf Emulate printf (obsolete since it's now a bash builtin).
@@ -189,11 +101,3 @@ Path Description X-Ref
./startup-files/Bashrc.bfox Sample Bourne Again SHell init file (Fox).
./startup-files/README README
-./startup-files/apple Example Start-up files for Mac OS X.
-./startup-files/apple/aliases Sample aliases for Mac OS X.
-./startup-files/apple/bash.defaults Sample User preferences file.
-./startup-files/apple/environment Sample Bourne Again Shell environment file.
-./startup-files/apple/login Sample login wrapper.
-./startup-files/apple/logout Sample logout wrapper.
-./startup-files/apple/rc Sample Bourne Again Shell config file.
-./startup-files/apple/README README
diff --git a/examples/bash-completion/README b/examples/bash-completion/README
new file mode 100644
index 00000000..fb5e7654
--- /dev/null
+++ b/examples/bash-completion/README
@@ -0,0 +1,7 @@
+Master source: https://github.com/scop/bash-completion
+
+This is the latest version of the bash-completion package, which provides
+programmable completion specifications for a large number of commands.
+
+If you are a vendor installing bash or preparing a package containing bash,
+please install the latest version of bash-completion when installing bash.
diff --git a/examples/bash-completion/bash-completion-2.5.tar.xz b/examples/bash-completion/bash-completion-2.5.tar.xz
new file mode 100644
index 00000000..f5b90790
--- /dev/null
+++ b/examples/bash-completion/bash-completion-2.5.tar.xz
Binary files differ
diff --git a/examples/functions/arrayops.bash b/examples/functions/arrayops.bash
new file mode 100644
index 00000000..d34353ae
--- /dev/null
+++ b/examples/functions/arrayops.bash
@@ -0,0 +1,146 @@
+# arrayops.bash --- hide some of the nasty syntax for manipulating bash arrays
+# Author: Noah Friedman <friedman@splode.com>
+# Created: 2016-07-08
+# Public domain
+
+# $Id: arrayops.bash,v 1.3 2016/07/28 15:38:55 friedman Exp $
+
+# Commentary:
+
+# These functions try to tame the syntactic nightmare that is bash array
+# syntax, which makes perl's almost look reasonable.
+#
+# For example the apush function below lets you write:
+#
+# apush arrayvar newval
+#
+# instead of
+#
+# ${arrayvar[${#arrayvar[@]}]}=newval
+#
+# Because seriously, you've got to be kidding me.
+
+# These functions avoid the use of local variables as much as possible
+# (especially wherever modification occurs) because those variable names
+# might shadow the array name passed in. Dynamic scope!
+
+# Code:
+
+#:docstring apush:
+# Usage: apush arrayname val1 {val2 {...}}
+#
+# Appends VAL1 and any remaining arguments to the end of the array
+# ARRAYNAME as new elements.
+#:end docstring:
+apush()
+{
+ eval "$1=(\"\${$1[@]}\" \"\${@:2}\")"
+}
+
+#:docstring apop:
+# Usage: apop arrayname {n}
+#
+# Removes the last element from ARRAYNAME.
+# Optional argument N means remove the last N elements.
+#:end docstring:
+apop()
+{
+ eval "$1=(\"\${$1[@]:0:\${#$1[@]}-${2-1}}\")"
+}
+
+#:docstring aunshift:
+# Usage: aunshift arrayname val1 {val2 {...}}
+#
+# Prepends VAL1 and any remaining arguments to the beginning of the array
+# ARRAYNAME as new elements. The new elements will appear in the same order
+# as given to this function, rather than inserting them one at a time.
+#
+# For example:
+#
+# foo=(a b c)
+# aunshift foo 1 2 3
+# => foo is now (1 2 3 a b c)
+# but
+#
+# foo=(a b c)
+# aunshift foo 1
+# aunshift foo 2
+# aunshift foo 3
+# => foo is now (3 2 1 a b c)
+#
+#:end docstring:
+aunshift()
+{
+ eval "$1=(\"\${@:2}\" \"\${$1[@]}\")"
+}
+
+#:docstring ashift:
+# Usage: ashift arrayname {n}
+#
+# Removes the first element from ARRAYNAME.
+# Optional argument N means remove the first N elements.
+#:end docstring:
+ashift()
+{
+ eval "$1=(\"\${$1[@]: -\${#$1[@]}+${2-1}}\")"
+}
+
+#:docstring aset:
+# Usage: aset arrayname idx newval
+#
+# Assigns ARRAYNAME[IDX]=NEWVAL
+#:end docstring:
+aset()
+{
+ eval "$1[\$2]=${@:3}"
+}
+
+#:docstring aref:
+# Usage: aref arrayname idx {idx2 {...}}
+#
+# Echoes the value of ARRAYNAME at index IDX to stdout.
+# If more than one IDX is specified, each one is echoed.
+#
+# Unfortunately bash functions cannot return arbitrary values in the usual way.
+#:end docstring:
+aref()
+{
+ eval local "v=(\"\${$1[@]}\")"
+ local x
+ for x in ${@:2} ; do echo "${v[$x]}"; done
+}
+
+#:docstring aref:
+# Usage: alen arrayname
+#
+# Echoes the length of the number of elements in ARRAYNAME.
+#
+# It also returns number as a numeric value, but return values are limited
+# by a maximum of 255 so don't rely on this unless you know your arrays are
+# relatively small.
+#:end docstring:
+alen()
+{
+ eval echo "\${#$1[@]}"
+ eval return "\${#$1[@]}"
+}
+
+#:docstring anreverse:
+# Usage: anreverse arrayname
+#
+# Reverse the order of the elements in ARRAYNAME.
+# The array variable is altered by this operation.
+#:end docstring:
+anreverse()
+{
+ eval set $1 "\"\${$1[@]}\""
+ eval unset $1
+ while [ $# -gt 1 ]; do
+ eval "$1=(\"$2\" \"\${$1[@]}\")"
+ set $1 "${@:3}"
+ done
+}
+
+#provide arrayops
+
+# arrayops.bash ends here
diff --git a/examples/functions/autoload b/examples/functions/autoload
index a563a779..cb3a673e 100644
--- a/examples/functions/autoload
+++ b/examples/functions/autoload
@@ -22,7 +22,7 @@
#
# 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
new file mode 100644
index 00000000..a172e612
--- /dev/null
+++ b/examples/functions/autoload.v4
@@ -0,0 +1,556 @@
+## -*- sh -*-
+
+# The psuedo-ksh autoloader.
+
+# How to use:
+# o One function per file.
+# o File and function name match exactly.
+# o File is located in a directory that is in FPATH.
+# o This script (autoload) must be sourced in as early as possible. This
+# implies that any code in this script should NOT rely on any library of local
+# or self-defined functions having already been loaded.
+# o autoload must be called for each function before the function can be used. If
+# autoloads are in directories where there are nothing but autoloads, then
+# 'autoload /path/to/files/*' suffices (but see options -a and -f).
+# o The call must be made in the current environment, not a subshell.
+# o The command line suffices as "current environment". If you have autoload
+# calls in a script, that script must be dotted into the process.
+
+# The first cut of this was by Bill Trost, trost@reed.bitnet.
+# The second cut came from Chet Ramey, chet@ins.CWRU.Edu
+# The third cut came from Mark Kennedy, mtk@ny.ubs.com. 1998/08/25
+# The fourth cut came from Matthew Persico, matthew.persico@gmail.com 2017/August
+
+autoload_calc_shimsize ()
+{
+ echo $((AUTOLOAD_SHIM_OVERHEAD + 3 * ${#1}))
+}
+
+_autoload_split_fpath ()
+{
+ (IFS=':'; set -- ${FPATH}; echo "$@")
+}
+
+_aload()
+{
+ local opt OPTIND
+ local doexport=0
+ local doreload=0
+ local doverbose=0
+ local doevalshim=0
+ local loadthese
+ local optimize=0
+ local loaded=0
+ local exported=0
+ local optimized=0
+ local summary=0
+ local dofpath=0
+ while getopts xrvla:oyf opt; do
+ case $opt in
+ x) doexport=1;;
+ r) doreload=1;;
+ v) doverbose=1;;
+ l) doevalshim=1;;
+ a) loadthese=$(find $OPTARG -maxdepth 1 -type f -printf '%f ');;
+ o) optimize=1;;
+ y) summary=1;;
+ f) loadthese=$(find $(_autoload_split_fpath) -maxdepth 1 -type f -printf '%f ');;
+ *) echo "_aload: usage: _aload [-xrvlyf] [-a dir] [function ...]" >&2; return;;
+ esac
+ done
+
+ shift $(($OPTIND-1))
+
+ [ -z "$loadthese" ] && loadthese="$@"
+
+ local func
+ for func in $loadthese; do
+ local exists_fn
+ exists_fn=$(declare -F $func)
+ if [ -n "$exists_fn" ] && ((doreload==0)) && ((doevalshim==0))
+ then
+ if ((doverbose))
+ then
+ echo "autoload: function '$func' already exists"
+ fi
+ else
+ local andevaled=''
+ local andexported=''
+ local evalstat=0
+ local doshim=1
+ local funcfile
+ funcfile=$(_autoload_resolve $func)
+ if [[ $funcfile ]] ; then
+ ## The file was found for $func. Process it.
+
+ if ((optimize)); then
+ ## For the first function loaded, we will not know
+ ## AUTOLOAD_SHIM_OVERHEAD. We can only calculate it after
+ ## we have loaded one function.
+ if [[ $AUTOLOAD_SHIM_OVERHEAD ]]; then
+ local size=$(wc -c $funcfile| sed 's/ .*//')
+ local shimsize=$(autoload_calc_shimsize $func)
+ if (( size <= shimsize)); then
+ doshim=0
+ andevaled=', optimized'
+ ((optimized+=1))
+ fi
+ fi
+ fi
+
+ if ((doevalshim)); then
+ doshim=0
+ andevaled=', evaled'
+ fi
+
+ ## 'brand' as in branding a cow with a mark. We add a local
+ ## variable to each function we autoload so that we can tell
+ ## later on it is an autoloaded function without having to
+ ## maintain some bash array or hash that cannot be passed to
+ ## and used by subshells.
+ local brandtext
+ brandtext="eval \"\$(type $func | sed -e 1d -e 4ilocal\\ AUTOLOADED=\'$func\')\""
+ if ((doshim)); then
+ ## Don't bother trying to save space by shoving all the
+ ## eval text below onto one unreadable line; new lines will
+ ## be added at your semicolons and any indentation below
+ ## seems to be ignored anyway if you export the function;
+ ## look at its BASH_FUNCTION representation.
+ eval $func '()
+ {
+ local IS_SHIM="$func"
+ local file=$(_autoload_resolve '$func')
+ if [[ $file ]]
+ then
+ . $file
+ '$brandtext'
+ '$func' "$@"
+ return $?
+ else
+ return 1;
+ fi
+ }'
+ else
+ . $funcfile
+ eval "$brandtext"
+ fi
+ evalstat=$?
+ if((evalstat==0))
+ then
+ ((loaded+=1))
+ ((doexport)) && export -f $func && andexported=', exported' && ((exported+=1))
+ ((doverbose)) && echo "$func autoloaded${andexported}${andevaled}"
+ if [[ ! $AUTOLOAD_SHIM_OVERHEAD ]] && ((doshim)); then
+ ## ...we have just loaded the first function shim into
+ ## memory. Let's calc the AUTOLOAD_SHIM_OVERHEAD size
+ ## to use going forward. In theory, we could check
+ ## again here to see if we should optimize and source
+ ## in this function, now that we now the
+ ## AUTOLOAD_SHIM_OVERHEAD. In practice, it's not worth
+ ## duping that code or creating a function to do so for
+ ## one function.
+ AUTOLOAD_SHIM_OVERHEAD=$(type $func | grep -v -E "^$1 is a function" | sed "s/$func//g"| wc -c)
+ export AUTOLOAD_SHIM_OVERHEAD
+ fi
+ else
+ echo "$func failed to load" >&2
+ fi
+ fi
+ fi
+ done
+ ((summary)) && echo "autoload: loaded:$loaded exported:$exported optimized:$optimized overhead:$AUTOLOAD_SHIM_OVERHEAD bytes"
+}
+
+_autoload_dump()
+{
+ local opt OPTIND
+ local opt_p=''
+ local opt_s=''
+ while getopts ps opt
+ do
+ case $opt in
+ p ) opt_p=1;;
+ s ) opt_s=1;;
+ esac
+ done
+
+ shift $(($OPTIND-1))
+
+ local exported=''
+ local executed=''
+ local func
+ for func in $(declare | grep -E 'local\\{0,1} AUTOLOADED' | sed -e "s/.*AUTOLOADED=//" -e 's/\\//g' -e 's/[");]//g' -e "s/'//g")
+ do
+ if [ -n "$opt_p" ]; then echo -n "autoload "; fi
+ if [ -n "$opt_s" ]
+ then
+ exported=$(declare -F | grep -E "${func}$" | sed 's/declare -f\(x\{0,1\}\).*/\1/')
+ [ "$exported" = 'x' ] && exported=' exported' || exported=' not exported'
+ executed=$(type $func | grep 'local IS_SHIM')
+ [ -z "$executed" ] && executed=' executed' || executed=' not executed'
+ fi
+ echo "${func}${exported}${executed}"
+ done
+}
+
+_autoload_resolve()
+{
+ if [[ ! "$FPATH" ]]; then
+ echo "autoload: FPATH not set or null" >&2
+ return
+ fi
+
+ local p # for 'path'. The $() commands in the for loop split the FPATH
+ # string into its constituents so that each one may be processed.
+
+ for p in $( _autoload_split_fpath ); do
+ p=${p:-.}
+ if [ -f $p/$1 ]; then echo $p/$1; return; fi
+ done
+
+ echo "autoload: $1: function source file not found" >&2
+}
+
+_autoload_edit()
+{
+ [ -z "$EDITOR" ] && echo "Error: no EDITOR defined" && return 1
+ local toedit
+ local func
+ for func in "$@"
+ do
+ local file=$(_autoload_resolve $func)
+ if [[ $file ]]
+ then
+ toedit="$toedit $file"
+ else
+ echo "$funcname not found in FPATH funcfile. Skipping."
+ fi
+ done
+
+ [ -z "$toedit" ] && return 1
+
+ local timemarker=$(mktemp)
+
+ $EDITOR $toedit
+
+ local i
+ for i in $toedit
+ do
+ if [ $i -nt $timemarker ]
+ then
+ local f=$(basename $i)
+ echo Reloading $f
+ autoload -r $f
+ fi
+ done
+}
+
+_autoload_page()
+{
+ [ -z "$PAGER" ] && echo "Error: no PAGER defined" && return 1
+ local topage
+ local func
+ for func in "$@"
+ do
+ local file=$(_autoload_resolve $func)
+ if [[ $file ]]
+ then
+ topage="$topage $file"
+ else
+ echo "$funcname not found in FPATH funcfile. Skipping."
+ fi
+ done
+
+ [ -z "$topage" ] && return 1
+
+ $PAGER $topage
+}
+
+_autoload_remove()
+{
+ unset -f "$@"
+}
+
+_autoload_help()
+{
+ cat <<EOH
+NAME
+ autoload
+
+SYNOPSIS
+ autoload [-ps]
+ autoload [-xuremloyv] [function ...]
+ autoload -a directory [-oyv]
+ autoload -f [-oyv]
+ autoload [-h]
+
+ autoreload [function ...]
+
+DESCRIPTION
+
+ An implementation of the 'autoload' functionality built into other
+ shells, of which 'ksh' is the most prominent. It allows for a keeping
+ the process environment small by loading small 'shim' functions into
+ memory that will, on first call, load the full text of the given
+ function and run it. Subsequent calls to the function just run the
+ function.
+
+ 'autoreload' is a synonym for 'autoload -r'. See below.
+
+USAGE
+
+ o Each function to be autoloaded should be defined in a single file,
+ named exactly the same as the function.
+
+ o In order to avoid side effects, do NOT put code other than the
+ function definition in the file. Unless of course you want to do some
+ one-time initialization. But beware that if you reload the function
+ for any reason, you will rerun the initialization code. Make sure
+ your initialization is re-entrant. Or, better yet,
+
+ *** do NOT put code other than the function definition in the file ***
+
+ o These function definition files should be placed in a directory that
+ is in the FPATH environment variable. Subdirectories are NOT scanned.
+
+ o The autoload script should be sourced into the current process as
+ early as possible in process start up. See NOTES below for
+ suggestions.
+
+ o The calls to the autoload function must be made in the current
+ process. If your calls are in their own script, that script must be
+ sourced in. Command line invocations are also sufficient. (But see
+ '-l' below.)
+
+ o The first time the function is called, the shim function that was
+ created by the 'autoload' call is what is executed. This function
+ then goes and finds the appropriate file in FPATH, sources it in and
+ then calls the actual function with any arguments you just passed in
+ to the shim function. Subsequent calls just run the function.
+
+OPTIONS
+
+ -a Autoload (a)ll the functions found in the given directory.
+
+ -f Autoload all the functions found in all the directories on the
+ FPATH.
+
+ -p Print all the autoloaded functions.
+
+ -s Print all the autoloaded functions and add their export status.
+
+ -x Export the specified functions to the environment for use in
+ subshells.
+
+ -u Unset the function, so it can be reloaded.
+
+ -r Reload the shims of the specified functions, even if the functions
+ have been already been executed. This will allow you to modify the
+ functions' source and have the new version executed next time the
+ function is called.
+
+ It would be very easy to modify a function's script, run the
+ function and scratch your head for a long time trying to figure out
+ why your changes are not being executed. That's why we provide the
+ '-e' flag described below for modifications.
+
+ Reloads, of course, only apply in the context of the current session
+ and any future subshell you start from the current session. Existing
+ sessions will need to have the same 'autoload -r' command run in
+ them.
+
+ -e Find the scripts in which the specified functions are defined and
+ start up \$EDITOR on those scripts. Reload the ones that were
+ modified when you exit \$EDITOR. (Note: If you use 'autoload -e foo'
+ to edit function 'foo', and then in your editor you separately load
+ up function 'bar', 'autoload' has no way of knowing that you edited
+ 'bar' and will NOT reload 'bar' for you.)
+
+ Reloads, of course, only apply in the context of the current session
+ and any future subshell you start from the current session. Existing
+ sessions will need to have the same 'autoload -r' command run in
+ them.
+
+ -m Find the scripts in which the specified functions are defined and
+ run \$PAGER on them ('m' is for 'more', because 'p' (page) and 'l'
+ (load) are already used as options in 'autoload').
+
+ -l When autoloading a function, eval the shim immediately in order to
+ load the true function code. See "Using '-l'" in the NOTES below for
+ details.
+
+ -o Optimize. When autoloading, take the time to execute
+
+ 'theCharCount=\$(wc -c \$theFuncFile)'
+
+ for each funcion and
+
+ if \$theCharCount < \$AUTOLOAD_SHIM_OVERHEAD
+
+ don't shim it, just eval directly.
+
+ -y Summar(y). Print the number of loaded, exported and optimized
+ functions.
+
+ -v Turns up the chattiness.
+
+NOTES
+
+ o Calling 'autoload' on a function that already exists (either shimmed
+ or expanded) silently ignores the request to load the shim unless it
+ has been previously removed (-u) or you force the reload (-r).
+
+ o Changing and reloading a function that has been exported does not
+ require it be re-exported; the modifications will appear in
+ subsequent subshells.
+
+ o Using '-1'
+
+ If you are running under set -x and/or set -v, you may see that the
+ shim does not appear to "work"; instead of seeing the shim first and
+ the real code subsequently, you may see the shim evaluated multiple
+ times.
+
+ This may not be an error; review your code. What is most likely
+ happening is that you are calling the function in subshells via
+ 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
+ encounter the shim and replace with the real code before executing.
+
+ Remember, however, that environment modifications that occur in a
+ subshell are NOT propagated back to the calling shell or over to any
+ sibling shells. So, if you call an autoloaded function in a very
+ tight loop of very many subshells, you may want to make an 'autoload
+ -l' call before you start your loop. '-l' will instruct 'autoload' to
+ bypass the shim creation and just source in the function's file
+ directly. For a few calls, the overhead of repeatedly running the
+ shim is not expensive, but in a tight loop, it might be. Caveat
+ Programer.
+
+ o Although the number of functions in the environment does not change
+ by using 'autoload', the amount of memory they take up can be greatly
+ reduced, depending on the size of your functions. If you have a lot
+ of small functions, then it is possible that the shim text will be
+ larger than your actual functions, rendering the memory savings moot.
+
+ 'small' in this case can be determined by calling the function
+ 'autoload_calc_shimsize' with the name of the function to determine
+ its shim size.
+
+ o In order to support the -p and -s options, we need a way to determine
+ if a function 'func' has been autoloaded or if it was loaded
+ diredctly. In order to do that, we modify the function's code by
+ adding the text
+
+ local AUTOLOADED='func';
+
+ to the shim and to the actual function text, just after the opening
+ brace. Then supporting -p and -s is just a matter of grepping through
+ all the function text in memory. Even though grepping through the
+ environment may not be the most efficient way to support this, it is
+ the simplest to implement for -p and -s operations that are not
+ heavily used.
+
+ As a consquence of this (and other reasons), the AUTOLOAD* namespace
+ is reserved for autoloading. Make sure you check any functions that
+ you bring under autoload for use of variables or functions that start
+ with AUTOLOAD and change them.
+
+ o The easiest way to load shims for all functions on the FPATH is to run
+
+ autoload -f -x
+
+ in the profile that gets run for login shells.
+
+ When called in the profile of a login shell where no definitions
+ exist, -f will load all functions it can find on FPATH and -x will
+ export all of those functions to be available in subshells when this
+ is called in a login shell. Using this option will relieve you of the
+ need to call 'autoload' after Every Single Function Definition, nor
+ will you need to call it in subshells.
+
+ The only thing left to do is to load up the autoload function itself
+ and its helper functions. That needs to happen in your profile:
+
+ export FPATH=~/functions # or wherever you stash them
+ if [ -z $(declare -F autoload) ]
+ then
+ . ~/bin/autoload # or wherever you've put it
+ fi
+
+ The 'if' statement is used to make sure we don't reload autoload
+ needlessly. Sourcing in the autoload script loads the 'autoload'
+ function and all of its support functions. Additionally, we export
+ all of these functions so that they are available in subshells; you
+ do not have to re-source the autoload file in '.bashrc'.
+
+ o Even with all of these shenanigans, you will find cases where no
+ 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.
+
+ At the time of this writing, git extentions 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
+ exported shell functions. Ballgame over.
+
+ If you find that you want your functions to be available in such
+ circumstances, convert them back to plain old scripts, make sure they
+ are 'sh' compliant and take the read/parse hit every time they are
+ run.
+
+EOH
+}
+
+autoload()
+{
+ if (( $# == 0 )) ; then _autoload_dump; return; fi
+
+ local opt OPTIND OPTARG
+ local passthru
+ local dumpopt
+ while getopts psuema:yxrvlohf opt
+ do
+ case $opt in
+ p|s) dumpopt="$dumpopt -${opt}";;
+ u) shift $((OPTIND-1)); _autoload_remove "$@"; return;;
+ e) shift $((OPTIND-1)); _autoload_edit "$@"; return;;
+ m) shift $((OPTIND-1)); _autoload_page "$@"; return;;
+ x|r|v|l|y|f|o) passthru="$passthru -$opt";;
+ a) passthru="$passthru -$opt $OPTARG";;
+ h) _autoload_help; return;;
+ *) echo "autoload: usage: autoload [-puUx] [function ...]" >&2; return;;
+ esac
+ done
+
+ shift $(($OPTIND-1))
+ if [ -n "$dumpopt" ]
+ then
+ _autoload_dump $dumpopt
+ else
+ _aload $passthru "$@"
+ fi
+}
+
+autoreload ()
+{
+ autoload -r "$@"
+}
+
+## When we source in autoload, we export (but NOT autoload) the autoload
+## functions so that they are available in subshells and you don't have to
+## source in the autoload file in subshells.
+export -f _aload \
+ _autoload_dump \
+ _autoload_edit \
+ _autoload_help \
+ _autoload_page \
+ _autoload_resolve \
+ _autoload_split_fpath \
+ autoload \
+ autoload_calc_shimsize \
+ autoreload
diff --git a/examples/functions/autoload.v4.t b/examples/functions/autoload.v4.t
new file mode 100644
index 00000000..6d35d141
--- /dev/null
+++ b/examples/functions/autoload.v4.t
@@ -0,0 +1,184 @@
+#!/bin/bash
+
+workdir=$(mktemp -d)
+
+cp autoload $workdir
+
+cd $workdir
+pwd
+
+. ./autoload
+
+funclist='ALTEST_func1 ALTEST_funcexport ALTEST_funcu'
+for funcname in $funclist; do
+ cat <<EOFFUNC > $funcname
+$funcname ()
+{
+echo this is $funcname
+
+}
+EOFFUNC
+
+done
+
+export FPATH=$workdir
+
+autoload ALTEST_func1 ALTEST_funcu
+autoload -x ALTEST_funcexport
+
+ok=0
+failed=0
+
+for funcname in $funclist; do
+
+ testname="$funcname loaded"
+ got=$(type $funcname 2>&1)
+ if [[ $got =~ "$funcname: not found" ]]; then
+ echo "## Failed $testname"
+ ((failed+=1))
+ else
+ echo "ok - $testname"
+ ((ok+=1))
+
+ testname="$funcname is a shim"
+ if [[ ! $got =~ "IS_SHIM" ]]; then
+ echo "## Failed $testname"
+ ((failed+=1))
+ else
+ echo "ok - $testname"
+ ((ok+=1))
+
+ testname="$funcname shim executed"
+ $funcname > /dev/null
+ got=$(type $funcname 2>&1)
+ if [[ $got =~ "IS_SHIM" ]]; then
+ echo "## Failed $testname"
+ ((failed+=1))
+ else
+ echo "ok - $testname"
+ ((ok+=1))
+ fi
+ fi
+ fi
+done
+
+funcname=ALTEST_func1
+testname="$funcname shim reloaded"
+autoload -r $funcname
+got=$(type $funcname 2>&1)
+if [[ ! $got =~ "IS_SHIM" ]]; then
+ echo "## Failed $testname"
+ ((failed+=1))
+else
+ echo "ok - $testname"
+ ((ok+=1))
+fi
+
+funcname=ALTEST_funcu
+testname="$funcname shim unloaded"
+autoload -u $funcname
+got=$(type $funcname 2>&1)
+if [[ ! $got =~ "$funcname: not found" ]]; then
+ echo "## Failed $testname"
+ ((failed+=1))
+else
+ echo "ok - $testname"
+ ((ok+=1))
+fi
+
+testname="autoload -p"
+got=$(autoload -p | grep ALTEST)
+if [[ ! $got =~ "autoload ALTEST_func1" ]] || \
+ [[ ! $got =~ "autoload ALTEST_funcexport" ]] ; then
+echo "## Failed $testname"
+ ((failed+=1))
+else
+ echo "ok - $testname"
+ ((ok+=1))
+fi
+
+testname="autoload -s"
+echo "Executing $testname, could take a long time..."
+got=$(autoload -s | grep ALTEST)
+if [[ ! $got =~ "ALTEST_func1 not exported not executed" ]] || \
+ [[ ! $got =~ "ALTEST_funcexport exported executed" ]] ; then
+ echo "## Failed $testname"
+ echo "## got: $got"
+ ((failed+=1))
+else
+ echo "ok - $testname"
+ ((ok+=1))
+fi
+
+testname="autoload -r -a $FPATH"
+autoload -r -a $FPATH
+localfailed=0
+localok=0
+for funcname in $funclist; do
+ got=$(type $funcname 2>&1)
+ if [[ $got =~ "$funcname: not found" ]]; then
+ echo "## Failed $testname - $funcname"
+ ((localfailed+=1))
+ else
+ ((localok+=1))
+ if [[ ! $got =~ "IS_SHIM" ]]; then
+ ((localfailed+=1))
+ else
+ ((localok+=1))
+ fi
+ fi
+done
+if ((localfailed==0)); then
+ echo "ok - $testname"
+ ((ok+=1))
+else
+ ((failed+=1))
+fi
+
+testname="autoload -u $funclist"
+autoload -u $funclist
+localfailed=0
+localok=0
+for funcname in $funclist; do
+ got=$(type $funcname 2>&1)
+ if [[ ! $got =~ "$funcname: not found" ]]; then
+ echo "## Failed $testname - $funcname"
+ ((localfailed+=1))
+ else
+ ((localok+=1))
+ fi
+done
+if ((localfailed==0)); then
+ echo "ok - $testname"
+ ((ok+=1))
+else
+ ((failed+=1))
+fi
+
+testname="autoload -r -f"
+autoload -r -f
+localfailed=0
+localok=0
+for funcname in $funclist; do
+ got=$(type $funcname 2>&1)
+ if [[ $got =~ "$funcname: not found" ]]; then
+ echo "## Failed $testname - $funcname"
+ ((localfailed+=1))
+ else
+ ((localok+=1))
+ if [[ ! $got =~ "IS_SHIM" ]]; then
+ ((localfailed+=1))
+ else
+ ((localok+=1))
+ fi
+ fi
+done
+if ((localfailed==0)); then
+ echo "ok - $testname"
+ ((ok+=1))
+else
+ ((failed+=1))
+fi
+
+echo $ok passed, $failed failed
+exit $failed
diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in
index ec305cda..0facc0ba 100644
--- a/examples/loadables/Makefile.in
+++ b/examples/loadables/Makefile.in
@@ -103,7 +103,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
ALLPROG = print truefalse sleep finfo logname basename dirname \
tty pathchk tee head mkdir rmdir printenv id whoami \
uname sync push ln unlink realpath strftime mypid setpgid
-OTHERPROG = necho hello cat pushd
+OTHERPROG = necho hello cat pushd stat rm fdflags
all: $(SHOBJ_STATUS)
@@ -142,6 +142,12 @@ finfo: finfo.o
cat: cat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
+rm: rm.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rm.o $(SHOBJ_LIBS)
+
+fdflags: fdflags.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ fdflags.o $(SHOBJ_LIBS)
+
logname: logname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
@@ -202,10 +208,12 @@ strftime: strftime.o
mypid: mypid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mypid.o $(SHOBJ_LIBS)
-
setpgid: setpgid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ setpgid.o $(SHOBJ_LIBS)
+stat: stat.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ stat.o $(SHOBJ_LIBS)
+
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
@@ -236,6 +244,7 @@ installdirs:
install-dev: installdirs
@$(INSTALL_DATA) Makefile.inc $(DESTDIR)$(loadablesdir)/Makefile.inc
+ @$(INSTALL_DATA) $(srcdir)/loadables.h $(DESTDIR)$(loadablesdir)/loadables.h
@( cd $(BUILD_DIR) && ${MAKE} ${MFLAGS} DESTDIR="$(DESTDIR)" install-headers)
install-supported: all installdirs install-dev
@@ -246,7 +255,7 @@ install-supported: all installdirs install-dev
done
uninstall-dev:
- -$(RM) $(DESTDIR)$(loadablesdir)/Makefile.inc
+ -$(RM) $(DESTDIR)$(loadablesdir)/Makefile.inc $(DESTDIR)$(loadablesdir)/loadables.h
-( cd $(BUILD_DIR) && ${MAKE} ${MFLAGS} DESTDIR="$(DESTDIR)" uninstall-headers)
uninstall-supported: uninstall-dev
@@ -283,3 +292,4 @@ mkdir.o: mkdir.c
realpath.o: realpath.c
strftime.o: strftime.c
setpgid.o: setpgid.c
+stat.o: stat.c
diff --git a/examples/loadables/README b/examples/loadables/README
index 2eae9cc6..91febd48 100644
--- a/examples/loadables/README
+++ b/examples/loadables/README
@@ -32,28 +32,37 @@ the canonical example. There is no real `builtin writers' programming
guide'. The file template.c provides a template to use for creating
new loadable builtins.
+The file "Makefile.inc" is created using the same values that configure
+writes into Makefile.in, and is installed in the same directory as the
+rest of the example builtins. It's intended to be a start at something
+that can be modified or included to help you build your own loadables
+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.
finfo.c Print file info.
head.c Copy first part of files.
hello.c Obligatory "Hello World" / sample loadable.
id.c POSIX.2 user identity.
ln.c Make links.
-loadables.h Start at a file loadable builtins can include for shell definitions
+loadables.h File loadable builtins can include for shell definitions.
logname.c Print login name of current user.
Makefile.in Simple makefile for the sample loadable builtins.
mkdir.c Make directories.
-mypid.c Add $MYPID variable, demonstrate use of unload hook function
+mypid.c Add $MYPID variable, demonstrate use of unload hook functio.n
necho.c echo without options or argument interpretation.
pathchk.c Check pathnames for validity and portability.
print.c Loadable ksh-93 style print builtin.
printenv.c Minimal builtin clone of BSD printenv(1).
push.c Anyone remember TOPS-20?
-README README
realpath.c Canonicalize pathnames, resolving symlinks.
+rm.c Remove files and directories.
rmdir.c Remove directory.
+setpgid.c Set a process's pgrp; example of how to wrap a system call.
sleep.c sleep for fractions of a second.
+stat.c populate an associative array with information about a file
strftime.c Loadable builtin interface to strftime(3).
sync.c Sync the disks by forcing pending filesystem writes to complete.
tee.c Duplicate standard input.
diff --git a/examples/loadables/cat.c b/examples/loadables/cat.c
index 1ce2e2dc..be99c4cd 100644
--- a/examples/loadables/cat.c
+++ b/examples/loadables/cat.c
@@ -56,6 +56,7 @@ int fd;
return 0;
}
+int
cat_main (argc, argv)
int argc;
char **argv;
@@ -88,6 +89,7 @@ char **argv;
return (r);
}
+int
cat_builtin(list)
WORD_LIST *list;
{
diff --git a/examples/loadables/fdflags.c b/examples/loadables/fdflags.c
new file mode 100644
index 00000000..f3094666
--- /dev/null
+++ b/examples/loadables/fdflags.c
@@ -0,0 +1,336 @@
+/* Loadable builtin to get and set file descriptor flags. */
+
+/* See Makefile for compilation details. */
+
+/*
+ Copyright (C) 2017 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 <fcntl.h>
+#include <errno.h>
+#include "bashansi.h"
+#include <stdio.h>
+
+#include "loadables.h"
+
+static const struct
+{
+ const char *name;
+ int value;
+} file_flags[] =
+{
+#ifdef O_APPEND
+ { "append", O_APPEND },
+#endif
+#ifdef O_ASYNC
+ { "async", O_ASYNC },
+#endif
+#ifdef O_SYNC
+ { "sync", O_SYNC },
+#endif
+#ifdef O_NONBLOCK
+ { "nonblock", O_NONBLOCK },
+#endif
+#ifdef O_FSYNC
+ { "fsync", O_FSYNC },
+#endif
+#ifdef O_DSYNC
+ { "dsync", O_DSYNC },
+#endif
+#ifdef O_RSYNC
+ { "rsync", O_RSYNC },
+#endif
+#ifdef O_ALT_IO
+ { "altio", O_ALT_IO },
+#endif
+#ifdef O_DIRECT
+ { "direct", O_DIRECT },
+#endif
+#ifdef O_NOATIME
+ { "noatime", O_NOATIME },
+#endif
+#ifdef O_NOSIGPIPE
+ { "nosigpipe", O_NOSIGPIPE },
+#endif
+#ifdef O_CLOEXEC
+ { "cloexec", O_CLOEXEC },
+#endif
+};
+
+#define N_FLAGS (sizeof (file_flags) / sizeof (file_flags[0]))
+
+#ifndef errno
+extern int errno;
+#endif
+
+/* FIX THIS */
+static int
+getallflags ()
+{
+ int i, allflags;
+
+ for (i = allflags = 0; i < N_FLAGS; i++)
+ allflags |= file_flags[i].value;
+ return allflags;
+}
+
+static int
+getflags(int fd, int p)
+{
+ int c, f;
+ int allflags;
+
+ if ((c = fcntl(fd, F_GETFD)) == -1)
+ {
+ if (p)
+ builtin_error("can't get status for fd %d: %s", fd, strerror(errno));
+ return -1;
+ }
+
+ if ((f = fcntl(fd, F_GETFL)) == -1)
+ {
+ if (p)
+ builtin_error("Can't get flags for fd %d: %s", fd, strerror(errno));
+ return -1;
+ }
+
+ if (c)
+ f |= O_CLOEXEC;
+
+ return f & getallflags();
+}
+
+static void
+printone(int fd, int p, int verbose)
+{
+ int f;
+ size_t i;
+
+ if ((f = getflags(fd, p)) == -1)
+ return;
+
+ printf ("%d:", fd);
+
+ for (i = 0; i < N_FLAGS; i++)
+ {
+ if (f & file_flags[i].value)
+ {
+ printf ("%s%s", verbose ? "+" : "", file_flags[i].name);
+ f &= ~file_flags[i].value;
+ }
+ else if (verbose)
+ printf ( "-%s", file_flags[i].name);
+ else
+ continue;
+
+ if (f || (verbose && i != N_FLAGS - 1))
+ putchar (',');
+ }
+ printf ("\n");
+}
+
+static int
+parseflags(char *s, int *p, int *n)
+{
+ int f, *v;
+ size_t i;
+
+ f = 0;
+ *p = *n = 0;
+
+ for (s = strtok(s, ","); s; s = strtok(NULL, ","))
+ {
+ switch (*s)
+ {
+ case '+':
+ v = p;
+ s++;
+ break;
+ case '-':
+ v = n;
+ s++;
+ break;
+ default:
+ v = &f;
+ break;
+ }
+
+ for (i = 0; i < N_FLAGS; i++)
+ if (strcmp(s, file_flags[i].name) == 0)
+ {
+ *v |= file_flags[i].value;
+ break;
+ }
+ if (i == N_FLAGS)
+ builtin_error("invalid flag `%s'", s);
+ }
+
+ return f;
+}
+
+static void
+setone(int fd, char *v, int verbose)
+{
+ int f, n, pos, neg, cloexec;
+
+ f = getflags(fd, 1);
+ if (f == -1)
+ return;
+
+ 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));
+
+ pos &= ~O_CLOEXEC;
+ neg &= ~O_CLOEXEC;
+ f &= ~O_CLOEXEC;
+
+ n = f;
+ n |= pos;
+ n &= ~neg;
+
+ if (n != f && fcntl(fd, F_SETFL, n) == -1)
+ builtin_error("can't set flags for fd %d: %s", fd, strerror(errno));
+}
+
+static int
+getmaxfd ()
+{
+ int maxfd, ignore;
+
+#ifdef F_MAXFD
+ maxfd = fcntl (0, F_MAXFD);
+ if (maxfd > 0)
+ return maxfd;
+#endif
+
+ maxfd = getdtablesize ();
+ if (maxfd <= 0)
+ maxfd = HIGH_FD_MAX;
+ for (maxfd--; maxfd > 0; maxfd--)
+ if (fcntl (maxfd, F_GETFD, &ignore) != -1)
+ break;
+
+ return maxfd;
+}
+
+int
+fdflags_builtin (WORD_LIST *list)
+{
+ int opt, maxfd, i, num, verbose, setflag;
+ char *setspec;
+ WORD_LIST *l;
+ intmax_t inum;
+
+ setflag = verbose = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "s:v")) != -1)
+ {
+ switch (opt)
+ {
+ case 's':
+ setflag = 1;
+ setspec = list_optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ }
+ list = loptend;
+
+ /* Maybe we could provide some default here, but we don't yet. */
+ if (list == 0 && setflag)
+ return (EXECUTION_SUCCESS);
+
+ if (list == 0)
+ {
+ maxfd = getmaxfd ();
+ if (maxfd < 0)
+ {
+ builtin_error ("can't get max fd: %s", strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+ for (i = 0; i < maxfd; i++)
+ printone (i, 0, verbose);
+ return (EXECUTION_SUCCESS);
+ }
+
+ opt = EXECUTION_SUCCESS;
+ for (l = list; l; l = l->next)
+ {
+ if (legal_number (l->word->word, &inum) == 0 || inum < 0)
+ {
+ builtin_error ("%s: invalid file descriptor", l->word->word);
+ opt = EXECUTION_FAILURE;
+ continue;
+ }
+ num = inum; /* truncate to int */
+ if (setflag)
+ setone (num, setspec, verbose);
+ else
+ printone (num, 1, verbose);
+ }
+
+ return (opt);
+}
+
+char *fdflags_doc[] =
+{
+ "Display and modify file descriptor flags.",
+ "",
+ "Display or, if the -s option is supplied, set flags for each file",
+ "descriptor supplied as an argument. If the -v option is supplied,",
+ "the display is verbose, including each settable option name in the",
+ "form of a string such as that accepted by the -s option.",
+ "",
+ "The -s option accepts a string with a list of flag names, each preceded",
+ "by a `+' (set) or `-' (unset). Those changes are applied to each file",
+ "descriptor supplied as an argument.",
+ "",
+ "If no file descriptor arguments are supplied, the displayed information",
+ "consists of the status of flags for each of the shell's open files.",
+ (char *)NULL
+};
+
+/* The standard structure describing a builtin command. bash keeps an array
+ of these structures. The flags must include BUILTIN_ENABLED so the
+ builtin can be used. */
+struct builtin fdflags_struct = {
+ "fdflags", /* builtin name */
+ fdflags_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ fdflags_doc, /* array of long documentation strings. */
+ "fdflags [-v] [-s flags_string] [fd ...]", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/head.c b/examples/loadables/head.c
index 748bb83e..1edca6c5 100644
--- a/examples/loadables/head.c
+++ b/examples/loadables/head.c
@@ -117,6 +117,7 @@ head_builtin (list)
return (EX_USAGE);
}
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/id.c b/examples/loadables/id.c
index 87733494..f857b547 100644
--- a/examples/loadables/id.c
+++ b/examples/loadables/id.c
@@ -91,6 +91,7 @@ id_builtin (list)
case 'n': id_flags |= ID_USENAME; break;
case 'r': id_flags |= ID_USEREAL; break;
case 'u': id_flags |= ID_USERONLY; break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/ln.c b/examples/loadables/ln.c
index a853bc99..93764a35 100644
--- a/examples/loadables/ln.c
+++ b/examples/loadables/ln.c
@@ -76,6 +76,7 @@ ln_builtin (list)
case 'n':
flags |= LN_NOFOLLOW;
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/mkdir.c b/examples/loadables/mkdir.c
index 39ae07f9..767ad9eb 100644
--- a/examples/loadables/mkdir.c
+++ b/examples/loadables/mkdir.c
@@ -68,6 +68,7 @@ mkdir_builtin (list)
case 'm':
mode = list_optarg;
break;
+ CASE_HELPOPT;
default:
builtin_usage();
return (EX_USAGE);
diff --git a/examples/loadables/necho.c b/examples/loadables/necho.c
index ee65f184..dd2092b0 100644
--- a/examples/loadables/necho.c
+++ b/examples/loadables/necho.c
@@ -38,7 +38,7 @@ WORD_LIST *list;
char *necho_doc[] = {
"Display arguments.",
"",
- "Print the arguments to the standard ouput separated",
+ "Print the arguments to the standard output separated",
"by space characters and terminated with a newline.",
(char *)NULL
};
diff --git a/examples/loadables/pathchk.c b/examples/loadables/pathchk.c
index 85e8a04c..c1151db4 100644
--- a/examples/loadables/pathchk.c
+++ b/examples/loadables/pathchk.c
@@ -112,6 +112,7 @@ pathchk_builtin (list)
case 'p':
pflag = 1;
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
@@ -135,7 +136,7 @@ char *pathchk_doc[] = {
"Check pathnames for validity.",
"",
"Check each pathname argument for validity (i.e., it may be used to",
- "create or access a file without casuing syntax errors) and portability",
+ "create or access a file without causing 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
diff --git a/examples/loadables/print.c b/examples/loadables/print.c
index e17597b3..0120dbf4 100644
--- a/examples/loadables/print.c
+++ b/examples/loadables/print.c
@@ -122,6 +122,7 @@ print_builtin (list)
case 'f':
pfmt = list_optarg;
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/printenv.c b/examples/loadables/printenv.c
index 8d3a05df..8c7f7201 100644
--- a/examples/loadables/printenv.c
+++ b/examples/loadables/printenv.c
@@ -46,6 +46,7 @@ printenv_builtin (list)
{
switch (opt)
{
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/push.c b/examples/loadables/push.c
index b0760733..9bcd5c32 100644
--- a/examples/loadables/push.c
+++ b/examples/loadables/push.c
@@ -51,6 +51,7 @@ push_builtin (list)
{
switch (opt)
{
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/realpath.c b/examples/loadables/realpath.c
index b19b87fb..9892ddb8 100644
--- a/examples/loadables/realpath.c
+++ b/examples/loadables/realpath.c
@@ -86,15 +86,19 @@ WORD_LIST *list;
case 'v':
vflag = 1;
break;
+ CASE_HELPOPT;
default:
builtin_usage();
+ return (EX_USAGE);
}
}
list = loptend;
- if (list == 0)
+ if (list == 0) {
builtin_usage();
+ return (EX_USAGE);
+ }
for (es = EXECUTION_SUCCESS; list; list = list->next) {
p = list->word->word;
diff --git a/examples/loadables/rm.c b/examples/loadables/rm.c
new file mode 100644
index 00000000..adfbffdc
--- /dev/null
+++ b/examples/loadables/rm.c
@@ -0,0 +1,177 @@
+/* rm - remove files and directories with -r */
+
+/* See Makefile for compilation details. */
+
+/*
+ Copyright (C) 2016 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 <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include "builtins.h"
+#include "shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+static int rm_file(const char *fname);
+
+static int force, recursive;
+
+static int
+_remove_directory(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *dp;
+ size_t dirlen;
+ int err;
+
+ dirlen = strlen (dirname);
+ err = 0;
+
+ if ((dir = opendir(dirname)))
+ {
+ while ((dp = readdir(dir)))
+ {
+#ifdef __GNUC__
+ char fname[dirlen + 1 + strlen (dp->d_name) + 1];
+#else
+ char *fname;
+ int fnsize;
+#endif
+
+ if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
+ continue;
+
+#ifdef __GNUC__
+ snprintf(fname, sizeof (fname), "%s/%s", dirname, dp->d_name);
+#else
+ fnsize = dirlen + 1 + strlen (dp->d_name) + 1;
+ fname = xmalloc (fnsize);
+ snprintf(fname, fnsize, "%s/%s", dirname, dp->d_name);
+#endif
+
+ if (rm_file (fname) && force == 0)
+ err = 1;
+#ifndef __GNUC__
+ free (fname);
+#endif
+ }
+
+ closedir(dir);
+
+ if (err == 0 && rmdir (dirname) && force == 0)
+ err = 1;
+ }
+ else if (force == 0)
+ err = 1;
+
+ if (err)
+ builtin_error ("%s: %s", dirname, strerror (errno));
+
+ return err;
+}
+
+static int
+rm_file(const char *fname)
+{
+ if (unlink (fname) == 0)
+ return 0;
+
+ /* If FNAME is a directory glibc returns EISDIR but correct POSIX value
+ would be EPERM. If we get that error and FNAME is a directory and -r
+ was supplied, recursively remove the directory and its contents */
+ if ((errno == EISDIR || errno == EPERM) && recursive && file_isdir (fname))
+ return _remove_directory(fname);
+ else if (force)
+ return 0;
+
+ builtin_error ("%s: %s", fname, strerror (errno));
+ return 1;
+}
+
+int
+rm_builtin (list)
+ WORD_LIST *list;
+{
+ const char *name;
+ WORD_LIST *l;
+ int rval, opt;
+
+ recursive = force = 0;
+ rval = EXECUTION_SUCCESS;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "Rrfi")) != -1)
+ {
+ switch (opt)
+ {
+ case 'R':
+ case 'r':
+ recursive = 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'i':
+ return (EX_DISKFALLBACK);
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+
+ for (l = list; l; l = l->next)
+ {
+ if (rm_file(l->word->word) && force == 0)
+ rval = EXECUTION_FAILURE;
+ }
+
+ return rval;
+}
+
+char *rm_doc[] = {
+ "Remove files.",
+ "",
+ "rm removes the files specified as arguments.",
+ (char *)NULL
+};
+
+/* The standard structure describing a builtin command. bash keeps an array
+ of these structures. */
+struct builtin rm_struct = {
+ "rm", /* builtin name */
+ rm_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ rm_doc, /* array of long documentation strings. */
+ "rm [-rf] file ...", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/stat.c b/examples/loadables/stat.c
new file mode 100644
index 00000000..52b9580f
--- /dev/null
+++ b/examples/loadables/stat.c
@@ -0,0 +1,430 @@
+/* stat - load up an associative array with stat information about a file */
+
+/* See Makefile for compilation details. */
+
+/*
+ Copyright (C) 2016 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 <sys/types.h>
+#include "posixstat.h"
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include "posixtime.h"
+
+#include "bashansi.h"
+#include "shell.h"
+#include "builtins.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#ifndef errno
+extern int errno;
+#endif
+
+#define ST_NAME 0
+#define ST_DEV 1
+#define ST_INO 2
+#define ST_MODE 3
+#define ST_NLINK 4
+#define ST_UID 5
+#define ST_GID 6
+#define ST_RDEV 7
+#define ST_SIZE 8
+#define ST_ATIME 9
+#define ST_MTIME 10
+#define ST_CTIME 11
+#define ST_BLKSIZE 12
+#define ST_BLOCKS 13
+#define ST_CHASELINK 14
+#define ST_PERMS 15
+
+#define ST_END 16
+
+static char *arraysubs[] =
+ {
+ "name", "device", "inode", "type", "nlink", "uid", "gid", "rdev",
+ "size", "atime", "mtime", "ctime", "blksize", "blocks", "link", "perms",
+ 0
+ };
+
+static int
+getstat (fname, flags, sp)
+ const char *fname;
+ int flags;
+ struct stat *sp;
+{
+ intmax_t lfd;
+ int fd, r;
+
+ if (strncmp (fname, "/dev/fd/", 8) == 0)
+ {
+ if ((legal_number(fname + 8, &lfd) == 0) || (int)lfd != lfd)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ fd = lfd;
+ r = fstat(fd, sp);
+ }
+#ifdef HAVE_LSTAT
+ else if (flags & 1)
+ r = lstat(fname, sp);
+#endif
+ else
+ r = stat(fname, sp);
+
+ return r;
+}
+
+static char *
+statlink (fname, sp)
+ char *fname;
+ struct stat *sp;
+{
+#if defined (HAVE_READLINK)
+ char linkbuf[PATH_MAX];
+ int n;
+
+ if (fname && S_ISLNK (sp->st_mode) && (n = readlink (fname, linkbuf, PATH_MAX)) > 0)
+ {
+ linkbuf[n] = '\0';
+ return (savestring (linkbuf));
+ }
+ else
+#endif
+ return (savestring (fname));
+}
+
+static char *
+octalperms (m)
+ int m;
+{
+ int operms;
+ char *ret;
+
+ operms = 0;
+
+ if (m & S_IRUSR)
+ operms |= 0400;
+ if (m & S_IWUSR)
+ operms |= 0200;
+ if (m & S_IXUSR)
+ operms |= 0100;
+
+ if (m & S_IRGRP)
+ operms |= 0040;
+ if (m & S_IWGRP)
+ operms |= 0020;
+ if (m & S_IXGRP)
+ operms |= 0010;
+
+ if (m & S_IROTH)
+ operms |= 0004;
+ if (m & S_IWOTH)
+ operms |= 0002;
+ if (m & S_IXOTH)
+ operms |= 0001;
+
+ if (m & S_ISUID)
+ operms |= 04000;
+ if (m & S_ISGID)
+ operms |= 02000;
+ if (m & S_ISVTX)
+ operms |= 01000;
+
+ ret = (char *)xmalloc (16);
+ snprintf (ret, 16, "%04o", operms);
+ return ret;
+}
+
+static char *
+statperms (m)
+ int m;
+{
+ char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
+ int i;
+ char *ret;
+
+ 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';
+
+ ret = (char *)xmalloc (32);
+ snprintf (ret, 32, "u=%s,g=%s,o=%s", ubits, gbits, obits);
+ return ret;
+}
+
+static char *
+statmode(mode)
+ int mode;
+{
+ char *modestr, *m;
+
+ modestr = m = (char *)xmalloc (8);
+ if (S_ISBLK (mode))
+ *m++ = 'b';
+ if (S_ISCHR (mode))
+ *m++ = 'c';
+ if (S_ISDIR (mode))
+ *m++ = 'd';
+ if (S_ISREG(mode))
+ *m++ = '-';
+ if (S_ISFIFO(mode))
+ *m++ = 'p';
+ if (S_ISLNK(mode))
+ *m++ = 'l';
+ if (S_ISSOCK(mode))
+ *m++ = 's';
+
+#ifdef S_ISDOOR
+ if (S_ISDOOR (mode))
+ *m++ = 'D';
+#endif
+#ifdef S_ISWHT
+ if (S_ISWHT(mode))
+ *m++ = 'W';
+#endif
+#ifdef S_ISNWK
+ if (S_ISNWK(mode))
+ *m++ = 'n';
+#endif
+#ifdef S_ISMPC
+ if (S_ISMPC (mode))
+ *m++ = 'm';
+#endif
+
+ *m = '\0';
+ return (modestr);
+}
+
+static char *
+stattime (t)
+ time_t t;
+{
+ char *tbuf, *ret;
+ size_t tlen;
+
+ tbuf = ctime (&t);
+ tlen = strlen (tbuf);
+ ret = savestring (tbuf);
+ ret[tlen-1] = '\0';
+ return ret;
+}
+
+static char *
+statval (which, fname, flags, sp)
+ int which;
+ char *fname;
+ int flags;
+ struct stat *sp;
+{
+ int temp;
+
+ switch (which)
+ {
+ case ST_NAME:
+ return savestring (fname);
+ case ST_DEV:
+ return itos (sp->st_dev);
+ case ST_INO:
+ return itos (sp->st_ino);
+ case ST_MODE:
+ return (statmode (sp->st_mode));
+ case ST_NLINK:
+ return itos (sp->st_nlink);
+ case ST_UID:
+ return itos (sp->st_uid);
+ case ST_GID:
+ return itos (sp->st_gid);
+ case ST_RDEV:
+ return itos (sp->st_rdev);
+ case ST_SIZE:
+ return itos (sp->st_size);
+ case ST_ATIME:
+ return ((flags & 2) ? stattime (sp->st_atime) : itos (sp->st_atime));
+ case ST_MTIME:
+ return ((flags & 2) ? stattime (sp->st_mtime) : itos (sp->st_mtime));
+ case ST_CTIME:
+ return ((flags & 2) ? stattime (sp->st_ctime) : itos (sp->st_ctime));
+ case ST_BLKSIZE:
+ return itos (sp->st_blksize);
+ case ST_BLOCKS:
+ return itos (sp->st_blocks);
+ case ST_CHASELINK:
+ return (statlink (fname, sp));
+ case ST_PERMS:
+ temp = sp->st_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID);
+ return (flags & 2) ? statperms (temp) : octalperms (temp);
+ default:
+ return savestring ("42");
+ }
+}
+
+static int
+loadstat (vname, var, fname, flags, sp)
+ char *vname;
+ SHELL_VAR *var;
+ char *fname;
+ int flags;
+ struct stat *sp;
+{
+ int i;
+ char *key, *value;
+ SHELL_VAR *v;
+
+ for (i = 0; arraysubs[i]; i++)
+ {
+ key = savestring (arraysubs[i]);
+ value = statval (i, fname, flags, sp);
+ v = bind_assoc_variable (var, vname, key, value, ASS_FORCE);
+ }
+ return 0;
+}
+
+int
+stat_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, flags;
+ char *aname, *fname;
+ struct stat st;
+ SHELL_VAR *v;
+
+ aname = "STAT";
+ flags = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "A:Ll")) != -1)
+ {
+ switch (opt)
+ {
+ case 'A':
+ aname = list_optarg;
+ break;
+ case 'L':
+ flags |= 1; /* operate on links rather than resolving them */
+ break;
+ case 'l':
+ flags |= 2;
+ break;
+ CASE_HELPOPT;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ fname = list->word->word;
+
+ if (getstat (fname, flags, &st) < 0)
+ {
+ builtin_error ("%s: cannot stat: %s", fname, strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+
+ unbind_variable (aname);
+ v = make_new_assoc_variable (aname);
+ if (v == 0)
+ {
+ builtin_error ("%s: cannot create variable", aname);
+ return (EXECUTION_FAILURE);
+ }
+ if (loadstat (aname, v, fname, flags, &st) < 0)
+ {
+ builtin_error ("%s: cannot assign file status information", aname);
+ unbind_variable (aname);
+ return (EXECUTION_FAILURE);
+ }
+
+ return (EXECUTION_SUCCESS);
+}
+
+/* An array of strings forming the `long' documentation for a builtin xxx,
+ which is printed by `help xxx'. It must end with a NULL. By convention,
+ the first line is a short description. */
+char *stat_doc[] = {
+ "Load an associative array with file status information.",
+ "",
+ "Take a filename and load the status information returned by a",
+ "stat(2) call on that file into the associative array specified",
+ "by the -A option. The default array name is STAT. If the -L",
+ "option is supplied, stat does not resolve symbolic links and",
+ "reports information about the link itself. The -l option results",
+ "in longer-form listings for some of the fields. The exit status is 0",
+ "unless the stat fails or assigning the array is unsuccessful.",
+ (char *)NULL
+};
+
+/* The standard structure describing a builtin command. bash keeps an array
+ of these structures. The flags must include BUILTIN_ENABLED so the
+ builtin can be used. */
+struct builtin stat_struct = {
+ "stat", /* builtin name */
+ stat_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ stat_doc, /* array of long documentation strings. */
+ "stat [-lL] [-A aname] file", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/tee.c b/examples/loadables/tee.c
index 9462cda0..819d83ae 100644
--- a/examples/loadables/tee.c
+++ b/examples/loadables/tee.c
@@ -84,6 +84,7 @@ tee_builtin (list)
case 'i':
nointr = 1;
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/template.c b/examples/loadables/template.c
index 8cfd571d..094b80ce 100644
--- a/examples/loadables/template.c
+++ b/examples/loadables/template.c
@@ -31,6 +31,7 @@ template_builtin (list)
{
switch (opt)
{
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/tty.c b/examples/loadables/tty.c
index 1adc5b59..febf518b 100644
--- a/examples/loadables/tty.c
+++ b/examples/loadables/tty.c
@@ -46,6 +46,7 @@ tty_builtin (list)
case 's':
sflag = 1;
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/uname.c b/examples/loadables/uname.c
index 339ec3dd..106a1c8d 100644
--- a/examples/loadables/uname.c
+++ b/examples/loadables/uname.c
@@ -95,6 +95,7 @@ uname_builtin (list)
case 'v':
uname_flags |= FLAG_VERSION;
break;
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
diff --git a/examples/loadables/whoami.c b/examples/loadables/whoami.c
index 5aa73828..3e7e36e4 100644
--- a/examples/loadables/whoami.c
+++ b/examples/loadables/whoami.c
@@ -39,6 +39,7 @@ whoami_builtin (list)
{
switch (opt)
{
+ CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);