Adding upstream version 5.2.37.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
parent
cf91100bce
commit
fa1b3d3922
1435 changed files with 757174 additions and 0 deletions
426
examples/INDEX.html
Normal file
426
examples/INDEX.html
Normal file
|
@ -0,0 +1,426 @@
|
|||
<table border=1>
|
||||
<tr>
|
||||
<th>Path</th>
|
||||
<th>Description</th>
|
||||
<th>X-Ref</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./obashdb</td>
|
||||
<td>Deprecated sample implementation of a bash debugger</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./complete</td>
|
||||
<td>Shell completion code</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions</td>
|
||||
<td>Example functions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/array-stuff</td>
|
||||
<td>Various array functions (ashift, array_sort, reverse).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/array-to-string</td>
|
||||
<td>Convert an array to a string.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/autoload</td>
|
||||
<td>An almost ksh-compatible 'autoload' (no lazy load).</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/autoload.v2</td>
|
||||
<td>An almost ksh-compatible 'autoload' (no lazy load).</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/autoload.v3</td>
|
||||
<td>A more ksh-compatible 'autoload' (with lazy load).</td>
|
||||
<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/csh-compat</td>
|
||||
<td>A C-shell compatibility package.</td>
|
||||
<td>csh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/dirname</td>
|
||||
<td>A replacement for dirname(1).</td>
|
||||
<td>dirname</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/dirstack</td>
|
||||
<td>Directory stack functions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/exitstat</td>
|
||||
<td>Display the exit status of processes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/external</td>
|
||||
<td>Like 'command' but FORCES use of external command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/fact</td>
|
||||
<td>Recursive factorial function.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/fstty</td>
|
||||
<td>Front end to sync TERM changes to both stty(1) and readline 'bind'.</td>
|
||||
<td>stty.bash</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/inetaddr</td>
|
||||
<td>Internet address conversion (inet2hex & hex2inet).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/inpath</td>
|
||||
<td>Return zero if the argument is in the path and executable.</td>
|
||||
<td>inpath</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/isnum2</td>
|
||||
<td>Test user input on numeric values, with floating point.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/isvalidip</td>
|
||||
<td>Test user input for valid IP Addresses.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/ksh-cd</td>
|
||||
<td>ksh-like 'cd': cd [-LP] [dir [change]].</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/ksh-compat-test</td>
|
||||
<td>ksh-like arithmetic test replacements.</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/kshenv</td>
|
||||
<td>Functions and aliases to provide the beginnings of a ksh environment for bash.</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/login</td>
|
||||
<td>Replace the 'login' and 'newgrp' builtins in old Bourne shells.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/notify.bash</td>
|
||||
<td>Notify when jobs change status.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/README</td>
|
||||
<td>README</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/seq</td>
|
||||
<td>Generate a sequence from m to n, m defaults to 1.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/seq2</td>
|
||||
<td>Generate a sequence from m to n, m defaults to 1.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/shcat</td>
|
||||
<td>Readline-based pager.</td>
|
||||
<td>cat, readline pager</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/shcat2</td>
|
||||
<td>Readline-based pagers.</td>
|
||||
<td>cat, readline pager</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/sort-pos-params</td>
|
||||
<td>Sort the positional parameters.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/substr</td>
|
||||
<td>A function to emulate the ancient ksh builtin.</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/substr2</td>
|
||||
<td>A function to emulate the ancient ksh builtin.</td>
|
||||
<td>ksh</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/whatis</td>
|
||||
<td>An implementation of the 10th Edition Unix sh builtin 'whatis(1)' command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/whence</td>
|
||||
<td>An almost-ksh compatible 'whence(1)' command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./functions/which</td>
|
||||
<td>An emulation of 'which(1)' as it appears in FreeBSD.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/</td>
|
||||
<td>Example loadable replacements</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/basename.c</td>
|
||||
<td>Return non-directory portion of pathname.</td>
|
||||
<td>basename</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/cat.c</td>
|
||||
<td>cat(1) replacement with no options - the way cat was intended.</td>
|
||||
<td>cat, readline pager</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/dirname.c</td>
|
||||
<td>Return directory portion of pathname.</td>
|
||||
<td>dirname</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/fdflags.c</td>
|
||||
<td>Display or modify file descriptor flags</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/finfo.c</td>
|
||||
<td>Print file info.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/head.c</td>
|
||||
<td>Copy first part of files.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/hello.c</td>
|
||||
<td>Obligatory "Hello World" / sample loadable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/id.c</td>
|
||||
<td>POSIX.2 user identity.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/ln.c</td>
|
||||
<td>Make links.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/logname.c</td>
|
||||
<td>Print login name of current user.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/Makefile.in</td>
|
||||
<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>
|
||||
<tr>
|
||||
<td>./loadables/pathchk.c</td>
|
||||
<td>Check pathnames for validity and portability.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/print.c</td>
|
||||
<td>Loadable ksh-93 style print builtin.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/printenv.c</td>
|
||||
<td>Minimal builtin clone of BSD printenv(1).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/push.c</td>
|
||||
<td>Anyone remember TOPS-20?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/README</td>
|
||||
<td>README</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/realpath.c</td>
|
||||
<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>
|
||||
<tr>
|
||||
<td>./loadables/sync.c</td>
|
||||
<td>Sync the disks by forcing pending filesystem writes to complete.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/tee.c</td>
|
||||
<td>Duplicate standard input.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/template.c</td>
|
||||
<td>Example template for loadable builtin.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/truefalse.c</td>
|
||||
<td>True and false builtins.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/tty.c</td>
|
||||
<td>Return terminal name.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/uname.c</td>
|
||||
<td>Print system information.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/unlink.c</td>
|
||||
<td>Remove a directory entry.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/whoami.c</td>
|
||||
<td>Print out username of current user.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./loadables/perl/</td>
|
||||
<td>Illustrate how to build a Perl interpreter into bash.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./misc</td>
|
||||
<td>Miscellaneous</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./misc/aliasconv.bash</td>
|
||||
<td>Convert csh aliases to bash aliases and functions.</td>
|
||||
<td>csh, xalias</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./misc/aliasconv.sh</td>
|
||||
<td>Convert csh aliases to bash aliases and functions.</td>
|
||||
<td>csh, xalias</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./misc/cshtobash</td>
|
||||
<td>Convert csh aliases, environment variables, and variables to bash equivalents.</td>
|
||||
<td>csh, xalias</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./misc/README</td>
|
||||
<td>README</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts</td>
|
||||
<td>Example scripts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts/cat.sh</td>
|
||||
<td>Readline-based pager.</td>
|
||||
<td>cat, readline pager</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts/center</td>
|
||||
<td>Center - center a group of lines.</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/README</td>
|
||||
<td>README</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts/shprompt</td>
|
||||
<td>Display a prompt and get an answer satisfying certain criteria.</td>
|
||||
<td>ask</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts/spin.bash</td>
|
||||
<td>Display a 'spinning wheel' to show progress.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts/xterm_title</td>
|
||||
<td>Print the contents of the xterm title bar.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./scripts/zprintf</td>
|
||||
<td>Emulate printf (obsolete since it's now a bash builtin).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files</td>
|
||||
<td>Example Start-up files.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files/Bash_aliases</td>
|
||||
<td>Some useful aliases (Fox).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files/Bash_profile</td>
|
||||
<td>Sample startup file for bash login shells (Fox).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files/bash-profile</td>
|
||||
<td>Sample startup file for bash login shells (Ramey).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files/bashrc</td>
|
||||
<td>Sample Bourne Again SHell init file (Ramey).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files/Bashrc.bfox</td>
|
||||
<td>Sample Bourne Again SHell init file (Fox).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>./startup-files/README</td>
|
||||
<td>README</td>
|
||||
</tr>
|
||||
<tr>
|
||||
</tr>
|
||||
</table>
|
103
examples/INDEX.txt
Normal file
103
examples/INDEX.txt
Normal file
|
@ -0,0 +1,103 @@
|
|||
Path Description X-Ref
|
||||
./obashdb Deprecated sample implementation of a bash debugger
|
||||
|
||||
./complete Shell completion code
|
||||
|
||||
./functions Example functions
|
||||
./functions/array-stuff Various array functions (ashift, array_sort, reverse).
|
||||
./functions/array-to-string Convert an array to a string.
|
||||
./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/csh-compat A C-shell compatibility package. csh
|
||||
./functions/dirname A replacement for dirname(1). dirname
|
||||
./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/inetaddr Internet address conversion (inet2hex & hex2inet).
|
||||
./functions/inpath Return zero if the argument is in the path and executable. inpath
|
||||
./functions/isnum2 Test user input on numeric values, with floating point.
|
||||
./functions/isvalidip Test user input for valid IP Addresses.
|
||||
./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/notify.bash Notify when jobs change status.
|
||||
./functions/README README
|
||||
./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
|
||||
./functions/shcat2 Readline-based pagers. cat, readline pager
|
||||
./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/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.
|
||||
|
||||
./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/dirname.c Return directory portion of pathname. dirname
|
||||
./loadables/fdflags.c Display or modify file descriptor flags
|
||||
./loadables/finfo.c Print file info.
|
||||
./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.
|
||||
./loadables/printenv.c Minimal builtin clone of BSD printenv(1).
|
||||
./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.
|
||||
./loadables/template.c Example template for loadable builtin.
|
||||
./loadables/truefalse.c True and false builtins.
|
||||
./loadables/tty.c Return terminal name.
|
||||
./loadables/uname.c Print system information.
|
||||
./loadables/unlink.c Remove a directory entry.
|
||||
./loadables/whoami.c Print out username of current user.
|
||||
|
||||
./loadables/perl/ Illustrate how to build a Perl interpreter into bash.
|
||||
|
||||
./misc Miscellaneous
|
||||
./misc/aliasconv.bash Convert csh aliases to bash aliases and functions. csh, xalias
|
||||
./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
|
||||
|
||||
./scripts Example scripts
|
||||
./scripts/cat.sh Readline-based pager. cat, readline pager
|
||||
./scripts/center Center - center a group of lines.
|
||||
./scripts/inpath Search $PATH for a file the same name as $1; return TRUE if found. inpath
|
||||
./scripts/shprompt Display a prompt and get an answer satisfying certain criteria. ask
|
||||
./scripts/spin.bash Display a 'spinning wheel' to show progress.
|
||||
./scripts/xterm_title Print the contents of the xterm title bar.
|
||||
./scripts/zprintf Emulate printf (obsolete since it's now a bash builtin).
|
||||
|
||||
./startup-files Example Start-up files.
|
||||
./startup-files/Bash_aliases Some useful aliases (Fox).
|
||||
./startup-files/Bash_profile Sample startup file for bash login shells (Fox).
|
||||
./startup-files/bash-profile Sample startup file for bash login shells (Ramey).
|
||||
./startup-files/bashrc Sample Bourne Again SHell init file (Ramey).
|
||||
./startup-files/Bashrc.bfox Sample Bourne Again SHell init file (Fox).
|
||||
./startup-files/README README
|
||||
|
7
examples/bash-completion/README
Normal file
7
examples/bash-completion/README
Normal file
|
@ -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.
|
BIN
examples/bash-completion/bash-completion-2.5.tar.xz
Normal file
BIN
examples/bash-completion/bash-completion-2.5.tar.xz
Normal file
Binary file not shown.
9401
examples/complete/bash_completion
Normal file
9401
examples/complete/bash_completion
Normal file
File diff suppressed because it is too large
Load diff
BIN
examples/complete/bashcc-1.0.1.tar.gz
Normal file
BIN
examples/complete/bashcc-1.0.1.tar.gz
Normal file
Binary file not shown.
76
examples/complete/cdfunc
Normal file
76
examples/complete/cdfunc
Normal file
|
@ -0,0 +1,76 @@
|
|||
# cdfunc - example completion function for cd
|
||||
#
|
||||
# based on the cd completion function from the bash_completion package
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2011 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
_comp_cd()
|
||||
{
|
||||
local IFS=$' \t\n' # normalize IFS
|
||||
local cur _skipdot _cdpath
|
||||
local i j k
|
||||
|
||||
# Tilde expansion, with side effect of expanding tilde to full pathname
|
||||
case "$2" in
|
||||
\~*) eval cur="$2" ;;
|
||||
*) cur=$2 ;;
|
||||
esac
|
||||
|
||||
# no cdpath or absolute pathname -- straight directory completion
|
||||
if [[ -z "${CDPATH:-}" ]] || [[ "$cur" == @(./*|../*|/*) ]]; then
|
||||
# compgen prints paths one per line; could also use while loop
|
||||
IFS=$'\n'
|
||||
COMPREPLY=( $(compgen -d -- "$cur") )
|
||||
IFS=$' \t\n'
|
||||
# CDPATH+directories in the current directory if not in CDPATH
|
||||
else
|
||||
IFS=$'\n'
|
||||
_skipdot=false
|
||||
# preprocess CDPATH to convert null directory names to .
|
||||
_cdpath=${CDPATH/#:/.:}
|
||||
_cdpath=${_cdpath//::/:.:}
|
||||
_cdpath=${_cdpath/%:/:.}
|
||||
for i in ${_cdpath//:/$'\n'}; do
|
||||
if [[ $i -ef . ]]; then _skipdot=true; fi
|
||||
k="${#COMPREPLY[@]}"
|
||||
for j in $( compgen -d -- "$i/$cur" ); do
|
||||
COMPREPLY[k++]=${j#$i/} # cut off directory
|
||||
done
|
||||
done
|
||||
$_skipdot || COMPREPLY+=( $(compgen -d -- "$cur") )
|
||||
IFS=$' \t\n'
|
||||
fi
|
||||
|
||||
# variable names if appropriate shell option set and no completions
|
||||
if shopt -q cdable_vars && [[ ${#COMPREPLY[@]} -eq 0 ]]; then
|
||||
COMPREPLY=( $(compgen -v -- "$cur") )
|
||||
fi
|
||||
|
||||
# append slash to passed directory name that is the only completion.
|
||||
# readline will not do this if we complete from CDPATH
|
||||
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
|
||||
i=${COMPREPLY[0]} # shorthand
|
||||
if [[ "$cur" == "$i" ]] && [[ "$i" != "*/" ]]; then
|
||||
COMPREPLY[0]+=/
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -o filenames -o nospace -o bashdefault -F _comp_cd cd
|
512
examples/complete/complete-examples
Normal file
512
examples/complete/complete-examples
Normal file
|
@ -0,0 +1,512 @@
|
|||
#
|
||||
# Completion examples
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2002 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# This encapsulates the default bash completion code
|
||||
# call with the word to be completed as $1
|
||||
#
|
||||
# Since programmable completion does not use the bash default completions
|
||||
# or the readline default of filename completion when the compspec does
|
||||
# not generate any matches, this may be used as a `last resort' in a
|
||||
# completion function to mimic the default bash completion behavior.
|
||||
#
|
||||
_bash_def_completion ()
|
||||
{
|
||||
local h t
|
||||
COMPREPLY=()
|
||||
|
||||
# command substitution
|
||||
if [[ "$1" == \$\(* ]]; then
|
||||
t=${1#??}
|
||||
COMPREPLY=( $(compgen -c -P '$(' $t) )
|
||||
fi
|
||||
# variables with a leading `${'
|
||||
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == \$\{* ]]; then
|
||||
t=${1#??}
|
||||
COMPREPLY=( $(compgen -v -P '${' -S '}' $t) )
|
||||
fi
|
||||
# variables with a leading `$'
|
||||
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == \$* ]]; then
|
||||
t=${1#?}
|
||||
COMPREPLY=( $(compgen -v -P '$' $t ) )
|
||||
fi
|
||||
# username expansion
|
||||
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == ~* ]] && [[ "$1" != */* ]]; then
|
||||
t=${1#?}
|
||||
COMPREPLY=( $( compgen -u -P '~' $t ) )
|
||||
fi
|
||||
# hostname
|
||||
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == *@* ]]; then
|
||||
h=${1%%@*}
|
||||
t=${1#*@}
|
||||
COMPREPLY=( $( compgen -A hostname -P "${h}@" $t ) )
|
||||
fi
|
||||
# glob pattern
|
||||
if [ ${#COMPREPLY[@]} -eq 0 ]; then
|
||||
# sh-style glob pattern
|
||||
if [[ $1 == *[*?[]* ]]; then
|
||||
COMPREPLY=( $( compgen -G "$1" ) )
|
||||
# ksh-style extended glob pattern - must be complete
|
||||
elif shopt -q extglob && [[ $1 == *[?*+\!@]\(*\)* ]]; then
|
||||
COMPREPLY=( $( compgen -G "$1" ) )
|
||||
fi
|
||||
fi
|
||||
|
||||
# final default is filename completion
|
||||
if [ ${#COMPREPLY[@]} -eq 0 ]; then
|
||||
COMPREPLY=( $(compgen -f "$1" ) )
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Return 1 if $1 appears to contain a redirection operator. Handles backslash
|
||||
# quoting (barely).
|
||||
#
|
||||
_redir_op()
|
||||
{
|
||||
case "$1" in
|
||||
*\\'[\<\>]'*) return 1;;
|
||||
*[\<\>]*) return 0;;
|
||||
*) return 1;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
# _redir_test tests the current word ($1) and the previous word ($2) for
|
||||
# redirection operators and does filename completion on the current word
|
||||
# if either one contains a redirection operator
|
||||
_redir_test()
|
||||
{
|
||||
if _redir_op "$1" ; then
|
||||
COMPREPLY=( $( compgen -f "$1" ) )
|
||||
return 0
|
||||
elif _redir_op "$2" ; then
|
||||
COMPREPLY=( $( compgen -f "$1" ) )
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# optional, but without this you can't use extended glob patterns
|
||||
shopt -s extglob
|
||||
|
||||
#
|
||||
# Easy ones for the shell builtins
|
||||
#
|
||||
# nothing for: alias, break, continue, dirs, echo, eval, exit, getopts,
|
||||
# let, logout, popd, printf, pwd, return, shift, suspend, test, times,
|
||||
# umask
|
||||
#
|
||||
|
||||
complete -f -- . source
|
||||
complete -A enabled builtin
|
||||
complete -d cd
|
||||
|
||||
# this isn't exactly right yet -- needs to skip shell functions and
|
||||
# do $PATH lookup (or do compgen -c and filter out matches that also
|
||||
# appear in compgen -A function)
|
||||
complete -c command
|
||||
|
||||
# could add -S '=', but that currently screws up because readline appends
|
||||
# a space unconditionally
|
||||
|
||||
complete -v export local readonly
|
||||
complete -A helptopic help # currently same as builtins
|
||||
|
||||
complete -d pushd
|
||||
|
||||
complete -A shopt shopt
|
||||
|
||||
complete -c type
|
||||
|
||||
complete -a unalias
|
||||
complete -v unset
|
||||
|
||||
#
|
||||
# Job control builtins: fg, bg, disown, kill, wait
|
||||
# kill not done yet
|
||||
#
|
||||
|
||||
complete -A stopped -P '%' bg
|
||||
complete -j -P '%' fg jobs disown
|
||||
|
||||
# this is not quite right at this point
|
||||
|
||||
_wait_func ()
|
||||
{
|
||||
local cur
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
|
||||
case "$cur" in
|
||||
%*) COMPREPLY=( $(compgen -A running -P '%' ${cur#?} ) ) ;;
|
||||
[0-9]*) COMPREPLY=( $(jobs -p | grep ^${cur}) ) ;;
|
||||
*) COMPREPLY=( $(compgen -A running -P '%') $(jobs -p) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
complete -F _wait_func wait
|
||||
|
||||
#
|
||||
# more complicated things, several as yet unimplemented
|
||||
#
|
||||
|
||||
#complete -F _bind_func bind
|
||||
|
||||
_declare_func()
|
||||
{
|
||||
local cur prev nflag opts
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
COMPREPLY=()
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-a -f -F -i -p -r -t -x)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $cur == '+' ]]; then
|
||||
COMPREPLY=(+i +t +x)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $prev == '-p' ]]; then
|
||||
COMPREPLY=( $(compgen -v $cur) )
|
||||
return 0;
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
complete -F _declare_func declare typeset
|
||||
|
||||
_enable_func()
|
||||
{
|
||||
local cur prev nflag opts
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
COMPREPLY=()
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-a -d -f -n -p -s)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $prev == '-f' ]]; then
|
||||
COMPREPLY=( $( compgen -f $cur ) )
|
||||
return 0;
|
||||
fi
|
||||
for opts in "${COMP_WORDS[@]}" ; do
|
||||
if [[ $opts == -*n* ]]; then nflag=1; fi
|
||||
done
|
||||
|
||||
if [ -z "$nflag" ] ; then
|
||||
COMPREPLY=( $( compgen -A enabled $cur ) )
|
||||
else
|
||||
COMPREPLY=( $( compgen -A disabled $cur ) )
|
||||
fi
|
||||
return 0;
|
||||
}
|
||||
complete -F _enable_func enable
|
||||
|
||||
_exec_func()
|
||||
{
|
||||
local cur prev
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-a -c -l)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $prev != -*a* ]]; then
|
||||
COMPREPLY=( $( compgen -c $cur ) )
|
||||
return 0
|
||||
fi
|
||||
return 1;
|
||||
}
|
||||
complete -F _exec_func exec
|
||||
|
||||
_fc_func()
|
||||
{
|
||||
local cur prev
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-e -n -l -r -s)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $prev == -*e ]]; then
|
||||
COMPREPLY=( $(compgen -c $cur) )
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
complete -F _fc_func fc
|
||||
|
||||
_hash_func()
|
||||
{
|
||||
local cur prev
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-p -r -t)
|
||||
return 0;
|
||||
fi
|
||||
|
||||
if [[ $prev == '-p' ]]; then
|
||||
COMPREPLY=( $( compgen -f $cur ) )
|
||||
return 0;
|
||||
fi
|
||||
COMPREPLY=( $( compgen -c $cur ) )
|
||||
return 0
|
||||
}
|
||||
complete -F _hash_func hash
|
||||
|
||||
_history_func()
|
||||
{
|
||||
local cur prev
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
COMPREPLY=()
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-a -c -d -n -r -w -p -s)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $prev == -[anrw] ]]; then
|
||||
COMPREPLY=( $( compgen -f $cur ) )
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
complete -F _history_func history
|
||||
|
||||
#complete -F _read_func read
|
||||
|
||||
_set_func ()
|
||||
{
|
||||
local cur prev
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
COMPREPLY=()
|
||||
|
||||
_redir_test "$cur" "$prev" && return 0;
|
||||
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-a -b -e -f -k -m -n -o -p -t -u -v -x -B -C -H -P --)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $cur == '+' ]]; then
|
||||
COMPREPLY=(+a +b +e +f +k +m +n +o +p +t +u +v +x +B +C +H +P)
|
||||
return 0;
|
||||
fi
|
||||
if [[ $prev == [+-]o ]]; then
|
||||
COMPREPLY=( $(compgen -A setopt $cur) )
|
||||
return 0;
|
||||
fi
|
||||
return 1;
|
||||
}
|
||||
complete -F _set_func set
|
||||
|
||||
_trap_func ()
|
||||
{
|
||||
local cur
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
|
||||
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
|
||||
COMPREPLY=(-l -p)
|
||||
return 0;
|
||||
fi
|
||||
COMPREPLY=( $( compgen -A signal ${cur}) )
|
||||
return 0
|
||||
}
|
||||
complete -F _trap_func trap
|
||||
|
||||
#
|
||||
# meta-completion (completion for complete/compgen)
|
||||
#
|
||||
_complete_meta_func()
|
||||
{
|
||||
local cur prev cmd
|
||||
COMPREPLY=()
|
||||
|
||||
cmd=$1
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
_redir_test "$cur" "$prev" && return 0;
|
||||
|
||||
if (( $COMP_CWORD <= 1 )) || [[ "$cur" == '-' ]]; then
|
||||
case "$cmd" in
|
||||
complete) COMPREPLY=(-a -b -c -d -e -f -j -k -s -v -u -r -p -A -G -W -P -S -X -F -C);;
|
||||
compgen) COMPREPLY=(-a -b -c -d -e -f -j -k -s -v -u -A -G -W -P -S -X -F -C);;
|
||||
esac
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $prev == -A ]]; then
|
||||
COMPREPLY=(alias arrayvar binding builtin command directory \
|
||||
disabled enabled export file 'function' helptopic hostname job keyword \
|
||||
running service setopt shopt signal stopped variable)
|
||||
return 0
|
||||
elif [[ $prev == -F ]]; then
|
||||
COMPREPLY=( $( compgen -A function $cur ) )
|
||||
elif [[ $prev == -C ]]; then
|
||||
COMPREPLY=( $( compgen -c $cur ) )
|
||||
else
|
||||
COMPREPLY=( $( compgen -c $cur ) )
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
complete -F _complete_meta_func complete compgen
|
||||
|
||||
#
|
||||
# some completions for shell reserved words
|
||||
#
|
||||
#complete -c -k time do if then else elif '{'
|
||||
|
||||
#
|
||||
# external commands
|
||||
#
|
||||
|
||||
complete -e printenv
|
||||
|
||||
complete -c nohup exec nice eval trace truss strace sotruss gdb
|
||||
|
||||
_make_targets ()
|
||||
{
|
||||
local mdef makef gcmd cur prev i
|
||||
|
||||
COMPREPLY=()
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
# if prev argument is -f, return possible filename completions.
|
||||
# we could be a little smarter here and return matches against
|
||||
# `makefile Makefile *.mk', whatever exists
|
||||
case "$prev" in
|
||||
-*f) COMPREPLY=( $(compgen -f $cur ) ); return 0;;
|
||||
esac
|
||||
|
||||
# if we want an option, return the possible posix options
|
||||
case "$cur" in
|
||||
-) COMPREPLY=(-e -f -i -k -n -p -q -r -S -s -t); return 0;;
|
||||
esac
|
||||
|
||||
# make reads `makefile' before `Makefile'
|
||||
# GNU make reads `GNUmakefile' before all other makefiles, but we
|
||||
# check that we're completing `gmake' before checking for it
|
||||
if [ -f GNUmakefile ] && [ ${COMP_WORDS[0]} == gmake ]; then
|
||||
mdef=GNUmakefile
|
||||
elif [ -f makefile ]; then
|
||||
mdef=makefile
|
||||
elif [ -f Makefile ]; then
|
||||
mdef=Makefile
|
||||
else
|
||||
mdef=*.mk # local convention
|
||||
fi
|
||||
|
||||
# before we scan for targets, see if a makefile name was specified
|
||||
# with -f
|
||||
for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
|
||||
if [[ ${COMP_WORDS[i]} == -*f ]]; then
|
||||
eval makef=${COMP_WORDS[i+1]} # eval for tilde expansion
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
[ -z "$makef" ] && makef=$mdef
|
||||
|
||||
# if we have a partial word to complete, restrict completions to
|
||||
# matches of that word
|
||||
if [ -n "$2" ]; then gcmd='grep "^$2"' ; else gcmd=cat ; fi
|
||||
|
||||
# if we don't want to use *.mk, we can take out the cat and use
|
||||
# test -f $makef and input redirection
|
||||
COMPREPLY=( $(cat $makef 2>/dev/null | awk 'BEGIN {FS=":"} /^[^.# ][^=]*:/ {print $1}' | tr -s ' ' '\012' | sort -u | eval $gcmd ) )
|
||||
}
|
||||
complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake
|
||||
|
||||
_umount_func ()
|
||||
{
|
||||
COMPREPLY=( $(mount | awk '{print $1}') )
|
||||
}
|
||||
complete -F _umount_func umount
|
||||
|
||||
_configure_func ()
|
||||
{
|
||||
case "$2" in
|
||||
-*) ;;
|
||||
*) return ;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
\~*) eval cmd=$1 ;;
|
||||
*) cmd="$1" ;;
|
||||
esac
|
||||
|
||||
COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) )
|
||||
}
|
||||
complete -F _configure_func configure
|
||||
|
||||
complete -W '"${GROUPS[@]}"' newgrp
|
||||
|
||||
complete -f chown ln more cat
|
||||
complete -d mkdir rmdir
|
||||
complete -f strip
|
||||
|
||||
complete -f -X '*.gz' gzip
|
||||
complete -f -X '*.bz2' bzip2
|
||||
complete -f -X '*.Z' compress
|
||||
complete -f -X '!*.+(gz|tgz|Gz)' gunzip gzcat zcat zmore
|
||||
complete -f -X '!*.Z' uncompress zmore zcat
|
||||
complete -f -X '!*.bz2' bunzip2 bzcat
|
||||
complete -f -X '!*.zip' unzip
|
||||
complete -f -X '!*.+(gif|jpg|jpeg|GIF|JPG|JPEG|bmp)' xv
|
||||
|
||||
complete -f -X '!*.pl' perl perl5
|
||||
|
||||
complete -A hostname rsh telnet rlogin ftp ping xping host traceroute nslookup
|
||||
complete -A hostname rxterm rxterm3 rxvt2
|
||||
|
||||
complete -u su
|
||||
complete -g newgrp groupdel groupmod
|
||||
|
||||
complete -f -X '!*.+(ps|PS)' gs gv ghostview psselect pswrap
|
||||
complete -f -X '!*.+(dvi|DVI)' dvips xdvi dviselect dvitype catdvi
|
||||
complete -f -X '!*.+(pdf|PDF)' acroread4
|
||||
complete -f -X '!*.texi*' makeinfo texi2dvi texi2html
|
||||
complete -f -X '!*.+(tex|TEX)' tex latex slitex
|
||||
|
||||
complete -f -X '!*.+(mp3|MP3)' mpg123
|
||||
complete -f -X '!*.+(htm|html)' links w3m lynx
|
||||
|
||||
#
|
||||
# other possibilities, left as exercises
|
||||
#
|
||||
#complete -F _find_func find
|
||||
#complete -F _man_func man
|
||||
#complete -F _stty_func stty
|
122
examples/functions/array-stuff
Normal file
122
examples/functions/array-stuff
Normal file
|
@ -0,0 +1,122 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1999 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# usage: reverse arrayname
|
||||
reverse()
|
||||
{
|
||||
local -a R
|
||||
local -i i
|
||||
local rlen temp
|
||||
|
||||
# make r a copy of the array whose name is passed as an arg
|
||||
eval R=\( \"\$\{$1\[@\]\}\" \)
|
||||
|
||||
# reverse R
|
||||
rlen=${#R[@]}
|
||||
|
||||
for ((i=0; i < rlen/2; i++ ))
|
||||
do
|
||||
temp=${R[i]}
|
||||
R[i]=${R[rlen-i-1]}
|
||||
R[rlen-i-1]=$temp
|
||||
done
|
||||
|
||||
# and assign R back to array whose name is passed as an arg
|
||||
eval $1=\( \"\$\{R\[@\]\}\" \)
|
||||
}
|
||||
|
||||
A=(1 2 3 4 5 6 7)
|
||||
echo "${A[@]}"
|
||||
reverse A
|
||||
echo "${A[@]}"
|
||||
reverse A
|
||||
echo "${A[@]}"
|
||||
|
||||
# unset last element of A
|
||||
alen=${#A[@]}
|
||||
unset A[$alen-1]
|
||||
echo "${A[@]}"
|
||||
|
||||
# ashift -- like shift, but for arrays
|
||||
|
||||
ashift()
|
||||
{
|
||||
local -a R
|
||||
local n
|
||||
|
||||
case $# in
|
||||
1) n=1 ;;
|
||||
2) n=$2 ;;
|
||||
*) echo "$FUNCNAME: usage: $FUNCNAME array [count]" >&2
|
||||
exit 2;;
|
||||
esac
|
||||
|
||||
# make r a copy of the array whose name is passed as an arg
|
||||
eval R=\( \"\$\{$1\[@\]\}\" \)
|
||||
|
||||
# shift R
|
||||
R=( "${R[@]:$n}" )
|
||||
|
||||
# and assign R back to array whose name is passed as an arg
|
||||
eval $1=\( \"\$\{R\[@\]\}\" \)
|
||||
}
|
||||
|
||||
ashift A 2
|
||||
echo "${A[@]}"
|
||||
|
||||
ashift A
|
||||
echo "${A[@]}"
|
||||
|
||||
ashift A 7
|
||||
echo "${A[@]}"
|
||||
|
||||
# Sort the members of the array whose name is passed as the first non-option
|
||||
# arg. If -u is the first arg, remove duplicate array members.
|
||||
array_sort()
|
||||
{
|
||||
local -a R
|
||||
local u
|
||||
|
||||
case "$1" in
|
||||
-u) u=-u ; shift ;;
|
||||
esac
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "array_sort: argument expected" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# make r a copy of the array whose name is passed as an arg
|
||||
eval R=\( \"\$\{$1\[@\]\}\" \)
|
||||
|
||||
# sort R
|
||||
R=( $( printf "%s\n" "${A[@]}" | sort $u) )
|
||||
|
||||
# and assign R back to array whose name is passed as an arg
|
||||
eval $1=\( \"\$\{R\[@\]\}\" \)
|
||||
return 0
|
||||
}
|
||||
|
||||
A=(3 1 4 1 5 9 2 6 5 3 2)
|
||||
array_sort A
|
||||
echo "${A[@]}"
|
||||
|
||||
A=(3 1 4 1 5 9 2 6 5 3 2)
|
||||
array_sort -u A
|
||||
echo "${A[@]}"
|
15
examples/functions/array-to-string
Normal file
15
examples/functions/array-to-string
Normal file
|
@ -0,0 +1,15 @@
|
|||
#! /bin/bash
|
||||
|
||||
# Format: array_to_string vname_of_array vname_of_string separator
|
||||
array_to_string()
|
||||
{
|
||||
(( ($# < 2) || ($# > 3) )) && {
|
||||
"$FUNCNAME: usage: $FUNCNAME arrayname stringname [separator]"
|
||||
return 2
|
||||
}
|
||||
|
||||
local array=$1 string=$2
|
||||
((3==$#)) && [[ $3 = ? ]] && local IFS="${3}${IFS}"
|
||||
eval $string="\"\${$array[*]}\""
|
||||
return 0
|
||||
}
|
146
examples/functions/arrayops.bash
Normal file
146
examples/functions/arrayops.bash
Normal file
|
@ -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
|
111
examples/functions/autoload
Normal file
111
examples/functions/autoload
Normal file
|
@ -0,0 +1,111 @@
|
|||
#
|
||||
# An almost ksh-compatible `autoload'. A function declared as `autoload' will
|
||||
# be read in from a file the same name as the function found by searching the
|
||||
# $FPATH (which works the same as $PATH), then that definition will be run.
|
||||
#
|
||||
# To do this without source support, we define a dummy function that, when
|
||||
# executed, will load the file (thereby re-defining the function), then
|
||||
# execute that newly-redefined function with the original arguments.
|
||||
#
|
||||
# It's not identical to ksh because ksh apparently does lazy evaluation
|
||||
# and looks for the file to load from only when the function is referenced.
|
||||
# This one requires that the file exist when the function is declared as
|
||||
# `autoload'.
|
||||
#
|
||||
# usage: autoload func [func...]
|
||||
#
|
||||
# The first cut of this was by Bill Trost, trost@reed.bitnet
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@ins.CWRU.Edu
|
||||
|
||||
#
|
||||
# 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
|
||||
# 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.
|
||||
#
|
||||
|
||||
aload()
|
||||
{
|
||||
eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }'
|
||||
}
|
||||
|
||||
#
|
||||
# Search $FPATH for a file the same name as the function given as $1, and
|
||||
# autoload the function from that file. There is no default $FPATH.
|
||||
#
|
||||
|
||||
autoload()
|
||||
{
|
||||
#
|
||||
# Save the list of functions; we're going to blow away the arguments
|
||||
# in a second. If any of the names contain white space, TFB.
|
||||
#
|
||||
|
||||
local args="$*"
|
||||
|
||||
#
|
||||
# This should, I think, list the functions marked as autoload and not
|
||||
# yet defined, but we don't have enough information to do that here.
|
||||
#
|
||||
if [ $# -eq 0 ] ; then
|
||||
echo "usage: autoload function [function...]" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# If there is no $FPATH, there is no work to be done
|
||||
#
|
||||
|
||||
if [ -z "$FPATH" ] ; then
|
||||
echo autoload: FPATH not set or null >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# This treats FPATH exactly like PATH: a null field anywhere in the
|
||||
# FPATH is treated the same as the current directory.
|
||||
#
|
||||
# The path splitting command is taken from Kernighan and Pike
|
||||
#
|
||||
|
||||
# fp=$(echo $FPATH | sed 's/^:/.:/
|
||||
# s/::/:.:/g
|
||||
# s/:$/:./
|
||||
# s/:/ /g')
|
||||
|
||||
# replaced with builtin mechanisms 2001 Oct 10
|
||||
|
||||
fp=${FPATH/#:/.:}
|
||||
fp=${fp//::/:.:}
|
||||
fp=${fp/%:/:.}
|
||||
fp=${fp//:/ }
|
||||
|
||||
for FUNC in $args ; do
|
||||
#
|
||||
# We're blowing away the arguments to autoload here...
|
||||
# We have to; there are no arrays (well, there are, but
|
||||
# this doesn't use them yet).
|
||||
#
|
||||
set -- $fp
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
if [ -f $1/$FUNC ] ; then
|
||||
break # found it!
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if [ $# -eq 0 ] ; then
|
||||
echo "$FUNC: autoload function not found" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# echo auto-loading $FUNC from $1/$FUNC
|
||||
aload $FUNC $1/$FUNC
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
192
examples/functions/autoload.v2
Normal file
192
examples/functions/autoload.v2
Normal file
|
@ -0,0 +1,192 @@
|
|||
#
|
||||
# An almost ksh-compatible `autoload'. A function declared as `autoload' will
|
||||
# be read in from a file the same name as the function found by searching the
|
||||
# $FPATH (which works the same as $PATH), then that definition will be run.
|
||||
#
|
||||
# To do this without source support, we define a dummy function that, when
|
||||
# executed, will load the file (thereby re-defining the function), then
|
||||
# execute that newly-redefined function with the original arguments.
|
||||
#
|
||||
# It's not identical to ksh because ksh apparently does lazy evaluation
|
||||
# and looks for the file to load from only when the function is referenced.
|
||||
# This one requires that the file exist when the function is declared as
|
||||
# `autoload'.
|
||||
#
|
||||
# usage: autoload [-pu] [func ...]
|
||||
#
|
||||
# options:
|
||||
# -p print in a format that can be reused as input
|
||||
# -u unset each function and remove it from the autoload list
|
||||
#
|
||||
# The first cut of this was by Bill Trost, trost@reed.edu
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@ins.CWRU.Edu
|
||||
|
||||
unset _AUTOLOADS
|
||||
_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
|
||||
# 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.
|
||||
#
|
||||
|
||||
_aload()
|
||||
{
|
||||
eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }'
|
||||
_autoload_addlist "$1"
|
||||
}
|
||||
|
||||
_autoload_addlist()
|
||||
{
|
||||
local i=0
|
||||
|
||||
while (( i < $_aindex )); do
|
||||
case "${_AUTOLOADS[i]}" in
|
||||
"$1") return 1 ;;
|
||||
esac
|
||||
(( i += 1 ))
|
||||
done
|
||||
_AUTOLOADS[_aindex]="$1"
|
||||
(( _aindex += 1 ))
|
||||
return 0
|
||||
}
|
||||
|
||||
_autoload_dump()
|
||||
{
|
||||
local func
|
||||
|
||||
for func in ${_AUTOLOADS[@]}; do
|
||||
[ -n "$1" ] && echo -n "autoload "
|
||||
echo "$func"
|
||||
done
|
||||
}
|
||||
|
||||
# Remove $1 from the list of autoloaded functions
|
||||
_autoload_remove_one()
|
||||
{
|
||||
local i=0 nnl=0
|
||||
local -a nlist
|
||||
|
||||
while (( i < _aindex )); do
|
||||
case "${_AUTOLOADS[i]}" in
|
||||
"$1") ;;
|
||||
*) nlist[nnl]="${_AUTOLOADS[i]}" ; (( nnl += 1 ));;
|
||||
esac
|
||||
(( i += 1 ))
|
||||
done
|
||||
unset _AUTOLOADS _aindex
|
||||
eval _AUTOLOADS=( ${nlist[@]} )
|
||||
_aindex=$nnl
|
||||
}
|
||||
|
||||
# Remove all function arguments from the list of autoloaded functions
|
||||
_autoload_remove()
|
||||
{
|
||||
local func i es=0
|
||||
|
||||
# first unset the autoloaded functions
|
||||
for func; do
|
||||
i=0
|
||||
while (( i < _aindex )); do
|
||||
case "${_AUTOLOADS[i]}" in
|
||||
"$func") unset -f $func ; break ;;
|
||||
esac
|
||||
(( i += 1 ))
|
||||
done
|
||||
if (( i == _aindex )); then
|
||||
echo "autoload: $func: not an autoloaded function" >&2
|
||||
es=1
|
||||
fi
|
||||
done
|
||||
|
||||
# then rebuild the list of autoloaded functions
|
||||
for func ; do
|
||||
_autoload_remove_one "$func"
|
||||
done
|
||||
|
||||
return $es
|
||||
}
|
||||
|
||||
#
|
||||
# Search $FPATH for a file the same name as the function given as $1, and
|
||||
# autoload the function from that file. There is no default $FPATH.
|
||||
#
|
||||
|
||||
autoload()
|
||||
{
|
||||
local -a fp
|
||||
local _autoload_unset nfp i
|
||||
|
||||
if (( $# == 0 )) ; then
|
||||
_autoload_dump
|
||||
return 0
|
||||
fi
|
||||
|
||||
OPTIND=1
|
||||
while getopts pu opt
|
||||
do
|
||||
case "$opt" in
|
||||
p) _autoload_dump printable; return 0;;
|
||||
u) _autoload_unset=y ;;
|
||||
*) echo "autoload: usage: autoload [-pu] [function ...]" >&2
|
||||
return 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
if [ -n "$_autoload_unset" ]; then
|
||||
_autoload_remove "$@"
|
||||
return $?
|
||||
fi
|
||||
|
||||
#
|
||||
# If there is no $FPATH, there is no work to be done
|
||||
#
|
||||
|
||||
if [ -z "$FPATH" ] ; then
|
||||
echo "autoload: FPATH not set or null" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#
|
||||
# This treats FPATH exactly like PATH: a null field anywhere in the
|
||||
# FPATH is treated the same as the current directory.
|
||||
#
|
||||
# This turns $FPATH into an array, substituting `.' for `'
|
||||
#
|
||||
eval fp=( $(
|
||||
IFS=':'
|
||||
set -- ${FPATH}
|
||||
for p in "$@" ; do echo -n "${p:-.} "; done
|
||||
)
|
||||
)
|
||||
|
||||
nfp=${#fp[@]}
|
||||
|
||||
for FUNC ; do
|
||||
i=0;
|
||||
while (( i < nfp )) ; do
|
||||
if [ -f ${fp[i]}/$FUNC ] ; then
|
||||
break # found it!
|
||||
fi
|
||||
(( i += 1 ))
|
||||
done
|
||||
|
||||
if (( i == nfp )) ; then
|
||||
echo "autoload: $FUNC: autoload function not found" >&2
|
||||
es=1
|
||||
continue
|
||||
fi
|
||||
|
||||
# echo auto-loading $FUNC from ${fp[i]}/$FUNC
|
||||
_aload $FUNC ${fp[i]}/$FUNC
|
||||
es=0
|
||||
done
|
||||
|
||||
return $es
|
||||
}
|
125
examples/functions/autoload.v3
Normal file
125
examples/functions/autoload.v3
Normal file
|
@ -0,0 +1,125 @@
|
|||
#From: Mark Kennedy <mark.t.kennedy@gmail.com> (<mtk@ny.ubs.com>)
|
||||
#Message-ID: <35E2B899.63A02DF5@ny.ubs.com>
|
||||
#Date: Tue, 25 Aug 1998 09:14:01 -0400
|
||||
#To: chet@nike.ins.cwru.edu
|
||||
#Subject: a newer version of the ksh-style 'autoload'
|
||||
|
||||
#enclosed you'll find 'autoload.v3', a version of the autoloader
|
||||
#that emulates the ksh semantics of delaying the resolution (and loading) of the function
|
||||
#until its first use. i took the liberty of simplifying the code a bit although it still uses the
|
||||
#same functional breakdown. i recently went through the exercise of converting
|
||||
#my ksh-based environment to bash (a very, very pleasant experience)
|
||||
#and this popped out.
|
||||
|
||||
# the psuedo-ksh autoloader.
|
||||
|
||||
# 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
|
||||
|
||||
unset _AUTOLOADS
|
||||
|
||||
_aload()
|
||||
{
|
||||
local func
|
||||
for func; do
|
||||
eval $func '()
|
||||
{
|
||||
local f=$(_autoload_resolve '$func')
|
||||
if [[ $f ]]; then
|
||||
. $f
|
||||
'$func' "$@"
|
||||
return $?
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}'
|
||||
_autoload_addlist $func
|
||||
done
|
||||
}
|
||||
|
||||
_autoload_addlist()
|
||||
{
|
||||
local func
|
||||
|
||||
for func in ${_AUTOLOADS[@]}; do
|
||||
[[ $func = "$1" ]] && return
|
||||
done
|
||||
|
||||
_AUTOLOADS[${#_AUTOLOADS[@]}]=$1
|
||||
}
|
||||
|
||||
_autoload_dump()
|
||||
{
|
||||
local func
|
||||
|
||||
for func in ${_AUTOLOADS[@]}; do
|
||||
[[ $1 ]] && echo -n "autoload "
|
||||
echo $func
|
||||
done
|
||||
}
|
||||
|
||||
_autoload_remove_one()
|
||||
{
|
||||
local func
|
||||
local -a NEW_AUTOLOADS
|
||||
|
||||
for func in ${_AUTOLOADS[@]}; do
|
||||
[[ $func != "$1" ]] && NEW_AUTOLOADS[${#NEW_AUTOLOADS[@]}]=$func
|
||||
done
|
||||
|
||||
_AUTOLOADS=( ${NEW_AUTOLOADS[@]} )
|
||||
}
|
||||
|
||||
_autoload_remove()
|
||||
{
|
||||
local victim func
|
||||
|
||||
for victim; do
|
||||
for func in ${_AUTOLOADS[@]}; do
|
||||
[[ $victim = "$func" ]] && unset -f $func && continue 2
|
||||
done
|
||||
echo "autoload: $func: not an autoloaded function" >&2
|
||||
done
|
||||
|
||||
for func; do
|
||||
_autoload_remove_one $func
|
||||
done
|
||||
}
|
||||
|
||||
_autoload_resolve()
|
||||
{
|
||||
if [[ ! "$FPATH" ]]; then
|
||||
echo "autoload: FPATH not set or null" >&2
|
||||
return
|
||||
fi
|
||||
|
||||
local p
|
||||
|
||||
for p in $( (IFS=':'; set -- ${FPATH}; echo "$@") ); do
|
||||
p=${p:-.}
|
||||
if [ -f $p/$1 ]; then echo $p/$1; return; fi
|
||||
done
|
||||
|
||||
echo "autoload: $1: function source file not found" >&2
|
||||
}
|
||||
|
||||
autoload()
|
||||
{
|
||||
if (( $# == 0 )) ; then _autoload_dump; return; fi
|
||||
|
||||
local opt OPTIND
|
||||
|
||||
while getopts pu opt
|
||||
do
|
||||
case $opt in
|
||||
p) _autoload_dump printable; return;;
|
||||
u) shift $((OPTIND-1)); _autoload_remove "$@"; return;;
|
||||
*) echo "autoload: usage: autoload [-pu] [function ...]" >&2; return;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(($OPTIND-1))
|
||||
|
||||
_aload "$@"
|
||||
}
|
556
examples/functions/autoload.v4
Normal file
556
examples/functions/autoload.v4
Normal file
|
@ -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 function 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 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
|
||||
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
|
||||
Programmer.
|
||||
|
||||
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 consequence 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 extensions.
|
||||
|
||||
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
|
||||
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
|
184
examples/functions/autoload.v4.t
Normal file
184
examples/functions/autoload.v4.t
Normal file
|
@ -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
|
23
examples/functions/basename
Normal file
23
examples/functions/basename
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Date: Fri, 11 Oct 91 11:22:36 edt
|
||||
# From: friedman@gnu.ai.mit.edu
|
||||
# To: bfox@gnu.ai.mit.edu
|
||||
|
||||
# A replacement for basename(1). Not all the systems I use have this
|
||||
# program. Usage: basename [path] {extension}
|
||||
function basename ()
|
||||
{
|
||||
local path="$1"
|
||||
local suffix="$2"
|
||||
local tpath="${path%/}"
|
||||
|
||||
# Strip trailing '/' characters from path (unusual that this should
|
||||
# ever occur, but basename(1) seems to deal with it.)
|
||||
while [ "${tpath}" != "${path}" ]; do
|
||||
tpath="${path}"
|
||||
path="${tpath%/}"
|
||||
done
|
||||
|
||||
path="${path##*/}" # Strip off pathname
|
||||
echo ${path%${suffix}} # Also strip off extension, if any.
|
||||
}
|
||||
|
48
examples/functions/csh-compat
Normal file
48
examples/functions/csh-compat
Normal file
|
@ -0,0 +1,48 @@
|
|||
# C-shell compatibility package.
|
||||
# setenv VAR VALUE
|
||||
function setenv ()
|
||||
{
|
||||
export $1="$2"
|
||||
}
|
||||
|
||||
function unsetenv ()
|
||||
{
|
||||
unset $1
|
||||
}
|
||||
|
||||
# Can't write foreach yet. Need pattern matching, and a few extras.
|
||||
function foreach () {
|
||||
echo 'Can'\''t do `foreach'\'' yet. Type "help for".'
|
||||
}
|
||||
|
||||
# Make this work like csh's. Special case "term" and "path".
|
||||
#set () {
|
||||
#}
|
||||
|
||||
chdir ()
|
||||
{
|
||||
builtin cd "$@"
|
||||
}
|
||||
|
||||
# alias - convert csh alias commands to bash functions
|
||||
# from Mohit Aron <aron@cs.rice.edu>
|
||||
# posted to usenet as <4i5p17$bnu@larry.rice.edu>
|
||||
function alias ()
|
||||
{
|
||||
if [ "x$2" = "x" ]
|
||||
then
|
||||
declare -f $1
|
||||
else
|
||||
case $2 in
|
||||
*[#\!]*)
|
||||
comm=$(echo $2 | sed 's/\\!\*/\"$\@\"/g
|
||||
s/\\!:\([1-9]\)/\"$\1\"/g
|
||||
s/#/\\#/g')
|
||||
;;
|
||||
*)
|
||||
comm="$2 \"\$@\"" ;;
|
||||
esac
|
||||
|
||||
eval function $1 \(\) "{" command "$comm" "; }"
|
||||
fi
|
||||
}
|
21
examples/functions/dirname
Normal file
21
examples/functions/dirname
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Date: Fri, 11 Oct 91 11:22:36 edt
|
||||
# From: friedman@gnu.ai.mit.edu
|
||||
# To: bfox@gnu.ai.mit.edu
|
||||
|
||||
# A replacement for dirname(1). This one appears less often on some
|
||||
# systems I use than basename(1), and I really depend on it for some
|
||||
# things. Usage: dirname [path]
|
||||
function dirname ()
|
||||
{
|
||||
local dir="$1"
|
||||
local tdir="${dir%/}"
|
||||
|
||||
# Strip trailing '/' characters from dir (unusual that this should
|
||||
# ever occur, but dirname(1) seems to deal with it.)
|
||||
while [ "${tdir}" != "${dir}" ]; do
|
||||
tdir="${dir}"
|
||||
dir="${tdir%/}"
|
||||
done
|
||||
|
||||
echo "${dir%/*}"
|
||||
}
|
160
examples/functions/dirstack
Normal file
160
examples/functions/dirstack
Normal file
|
@ -0,0 +1,160 @@
|
|||
#!/bin/bash
|
||||
# @(#) dirstack
|
||||
|
||||
###
|
||||
# Another implementation of the directory manipulation functions
|
||||
# published in the Bolsky & Korn book : "The new Korn shell" :
|
||||
# cd, to change current directory
|
||||
# d, to display the stack content
|
||||
# Eric Sanchis (eric.sanchis@iut-rodez.fr), 2012
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
shopt -s expand_aliases
|
||||
shopt -s extglob
|
||||
shopt -s cdable_vars
|
||||
|
||||
alias integer='declare -i'
|
||||
|
||||
integer MAX=32
|
||||
integer INDMAX=MAX-1
|
||||
integer INDTOP=0
|
||||
|
||||
unalias cd 2>/dev/null
|
||||
alias cd=cdir
|
||||
|
||||
unset tab
|
||||
tab[INDTOP]="$(pwd)"
|
||||
|
||||
|
||||
function cdir
|
||||
{
|
||||
local -i ind
|
||||
local dir
|
||||
|
||||
dir="${1:-$HOME}"
|
||||
case "$dir" in
|
||||
- ) # cd - => equivalent to : cd -1
|
||||
ind=INDTOP-1
|
||||
cd_by_number $ind
|
||||
;;
|
||||
-+([[:digit:]]) ) # cd -n
|
||||
ind=$INDTOP-${dir#-}
|
||||
cd_by_number $ind
|
||||
;;
|
||||
*) # cd ~ or cd dir_name
|
||||
cd_by_name "$dir"
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
function cd_by_number
|
||||
{
|
||||
local -i k=$1
|
||||
local -i j
|
||||
local dirtmp
|
||||
|
||||
if (( k < 0 ))
|
||||
then
|
||||
echo Impossible to change directory >&2
|
||||
return 1
|
||||
else
|
||||
dirtmp="${tab[k]}"
|
||||
j=k+1
|
||||
while (( j <= INDTOP ))
|
||||
do
|
||||
tab[j-1]="${tab[j]}"
|
||||
j=j+1
|
||||
done
|
||||
tab[INDTOP]="$dirtmp"
|
||||
\cd "${tab[INDTOP]}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function cd_by_name
|
||||
{
|
||||
local -i i
|
||||
local rep
|
||||
|
||||
rep=$( \cd "$1" &>/dev/null && pwd)
|
||||
if [[ -z "$rep" ]]
|
||||
then
|
||||
echo cd : "$1" unknown >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
i=$INDTOP
|
||||
while (( i >= 0 ))
|
||||
do
|
||||
if [[ "${tab[i]}" == "$rep" ]]
|
||||
then break
|
||||
fi
|
||||
i=i-1
|
||||
done
|
||||
|
||||
if (( i == INDTOP ))
|
||||
then # cd -0 => we do nothing !
|
||||
return 0
|
||||
elif (( i == -1 ))
|
||||
then # the directory isn't in the stack
|
||||
if (( INDTOP == INDMAX ))
|
||||
then # the stack is FULL
|
||||
# the oldest directory is removed
|
||||
local -i m
|
||||
|
||||
m=1
|
||||
while (( m <= INDMAX ))
|
||||
do
|
||||
tab[m-1]="${tab[m]}"
|
||||
m=m+1
|
||||
done
|
||||
else # the new directory is added to the top of the stack
|
||||
INDTOP=INDTOP+1
|
||||
fi
|
||||
tab[INDTOP]="$rep"
|
||||
\cd "${tab[INDTOP]}"
|
||||
return 0
|
||||
|
||||
else # the directory is already in the stack
|
||||
# $i gives its index
|
||||
cd_by_number $i
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function d # display the directory stack
|
||||
{
|
||||
local -i i
|
||||
local rep
|
||||
|
||||
i=0
|
||||
while (( $i <= $INDTOP ))
|
||||
do
|
||||
rep="${tab[INDTOP-i]#$HOME/}"
|
||||
case "$rep" in
|
||||
$HOME) rep="~" ;;
|
||||
/* ) : ;;
|
||||
* ) rep="~/$rep"
|
||||
esac
|
||||
|
||||
echo "$i ) $rep"
|
||||
i=i+1
|
||||
done
|
||||
}
|
||||
|
||||
|
22
examples/functions/exitstat
Normal file
22
examples/functions/exitstat
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Contributed by Noah Friedman and Roland McGrath.
|
||||
|
||||
# To be run by the PROMPT_COMMAND variable, so that one can see what
|
||||
# the exit status of processes are.
|
||||
|
||||
function check_exit_status ()
|
||||
{
|
||||
local status="$?"
|
||||
local signal=""
|
||||
|
||||
if [ ${status} -ne 0 ] && [ ${status} != 128 ]; then
|
||||
# If process exited by a signal, determine name of signal.
|
||||
if [ ${status} -gt 128 ]; then
|
||||
signal="$(builtin kill -l $((${status} - 128)) 2>/dev/null)"
|
||||
if [ "$signal" ]; then signal="($signal)"; fi
|
||||
fi
|
||||
echo "[Exit ${status} ${signal}]" 1>&2
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
PROMPT_COMMAND=check_exit_status
|
50
examples/functions/external
Normal file
50
examples/functions/external
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Contributed by Noah Friedman.
|
||||
|
||||
# To avoid using a function in bash, you can use the `builtin' or
|
||||
# `command' builtins, but neither guarantees that you use an external
|
||||
# program instead of a bash builtin if there's a builtin by that name. So
|
||||
# this function can be used like `command' except that it guarantees the
|
||||
# program is external by first disabling any builtin by that name. After
|
||||
# the command is done executing, the state of the builtin is restored.
|
||||
function external ()
|
||||
{
|
||||
local state=""
|
||||
local exit_status
|
||||
|
||||
if builtin_p "$1"; then
|
||||
state="builtin"
|
||||
enable -n "$1"
|
||||
fi
|
||||
|
||||
command "$@"
|
||||
exit_status=$?
|
||||
|
||||
if [ "$state" = "builtin" ]; then
|
||||
enable "$1"
|
||||
fi
|
||||
|
||||
return ${exit_status}
|
||||
}
|
||||
|
||||
# What is does is tell you if a particular keyword is currently enabled as
|
||||
# a shell builtin. It does NOT tell you if invoking that keyword will
|
||||
# necessarily run the builtin. For that, do something like
|
||||
#
|
||||
# test "$(builtin type -type [keyword])" = "builtin"
|
||||
#
|
||||
# Note also, that disabling a builtin with "enable -n" will make builtin_p
|
||||
# return false, since the builtin is no longer available.
|
||||
function builtin_p ()
|
||||
{
|
||||
local word
|
||||
|
||||
set $(builtin type -all -type "$1")
|
||||
|
||||
for word in "$@" ; do
|
||||
if [ "${word}" = "builtin" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
13
examples/functions/fact
Normal file
13
examples/functions/fact
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Who said shells can't use recursion? Here is a factorial function.
|
||||
# You call it with a number as an argument, and it returns the factorial
|
||||
# of that number.
|
||||
|
||||
fact ()
|
||||
{
|
||||
local num=$1;
|
||||
if [ "$num" = 1 ] ; then
|
||||
echo 1
|
||||
return ;
|
||||
fi;
|
||||
echo $(( $num * $(fact $(( $num - 1 )) ) ))
|
||||
}
|
77
examples/functions/fstty
Normal file
77
examples/functions/fstty
Normal file
|
@ -0,0 +1,77 @@
|
|||
#
|
||||
# A function that works as a front end for both stty and the `bind'
|
||||
# builtin, so the tty driver and readline see the same changes
|
||||
#
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2011 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# Convert between the stty ^H control character form and the readline \C-H
|
||||
# form
|
||||
#
|
||||
cvt()
|
||||
{
|
||||
echo "$@" | cat -v | sed 's/\^/\\C-/'
|
||||
}
|
||||
|
||||
#
|
||||
# stty front-end. Parses the argument list and creates two command strings,
|
||||
# one for stty, another for bind.
|
||||
#
|
||||
fstty()
|
||||
{
|
||||
local cmd="" bargs=""
|
||||
local e
|
||||
|
||||
while [ $# -gt 0 ]
|
||||
do
|
||||
case "$1" in
|
||||
-a) cmd="$cmd everything"
|
||||
;;
|
||||
erase) shift;
|
||||
e=$(cvt "$1")
|
||||
cmd="$cmd erase $1"
|
||||
bargs="$bargs '\"$e\": backward-delete-char'"
|
||||
;;
|
||||
kill) shift
|
||||
e=$(cvt "$1")
|
||||
cmd="$cmd kill $1"
|
||||
bargs="$bargs '\"$e\": unix-line-discard'"
|
||||
;;
|
||||
werase) shift;
|
||||
e=$(cvt "$1")
|
||||
cmd="$cmd erase $1"
|
||||
bargs="$bargs '\"$e\": backward-kill-word'"
|
||||
;;
|
||||
lnext) shift;
|
||||
e=$(cvt "$1")
|
||||
cmd="$cmd erase $1"
|
||||
bargs="$bargs '\"$e\": quoted-insert'"
|
||||
;;
|
||||
*) cmd="$cmd $1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
command stty $cmd
|
||||
if [ -n "$bargs" ]; then
|
||||
builtin bind $bargs
|
||||
fi
|
||||
}
|
43
examples/functions/func
Normal file
43
examples/functions/func
Normal file
|
@ -0,0 +1,43 @@
|
|||
#
|
||||
# func -- print out definitions for functions named by arguments
|
||||
#
|
||||
# usage: func name [name ...]
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1991 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
func()
|
||||
{
|
||||
local status=0
|
||||
|
||||
if [ $# -eq 0 ] ; then
|
||||
echo "usage: func name [name...]" 1>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
for f
|
||||
do
|
||||
if [ "$(builtin type -type $f)" != "function" ] ; then
|
||||
echo "func: $f: not a function" 1>&2
|
||||
status=1 # one failed
|
||||
continue
|
||||
fi
|
||||
builtin type $f | sed 1d
|
||||
done
|
||||
return $status
|
||||
}
|
79
examples/functions/inetaddr
Normal file
79
examples/functions/inetaddr
Normal file
|
@ -0,0 +1,79 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2002 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# inet2hex - Internet address conversion, dotted-decimal to hex
|
||||
#
|
||||
inet2hex ()
|
||||
{
|
||||
local IFS
|
||||
|
||||
IFS=.
|
||||
set -- $1
|
||||
|
||||
if (( $# != 4 )); then
|
||||
echo "inet2hex: incorrect input format: $1" >&2
|
||||
echo "inet2hex: usage: inet2hex XX.XX.XX.XX" >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
printf "0x%02x%02x%02x%02x\n" $1 $2 $3 $4
|
||||
}
|
||||
|
||||
#
|
||||
# hex2inet - Internet address conversion, hex to dotted-decimal
|
||||
#
|
||||
hex2inet ()
|
||||
{
|
||||
local x1 x2 x3 x4
|
||||
local rev
|
||||
|
||||
OPTIND=1
|
||||
while getopts "r" o
|
||||
do
|
||||
case "$o" in
|
||||
r) rev=true;;
|
||||
*) echo "hex2inet: usage: hex2inet [-r] [0x]XXXXXXXX" >&2 ; exit 2;;
|
||||
esac
|
||||
done
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
case "$1" in
|
||||
0x*) h=${1#??} ;;
|
||||
*) h=$1 ;;
|
||||
esac
|
||||
|
||||
if (( ${#h} != 8 )); then
|
||||
echo "hex2inet: $h not in inet format" >&2
|
||||
echo "hex2inet: usage: hex2inet [0x]XXXXXXXX" >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
x1=$(( 0x${h:0:2} ))
|
||||
x2=$(( 0x${h:2:2} ))
|
||||
x3=$(( 0x${h:4:2} ))
|
||||
x4=$(( 0x${h:6:2} ))
|
||||
|
||||
if [ -z "$rev" ] ; then
|
||||
printf "%d.%d.%d.%d\n" $x1 $x2 $x3 $x4
|
||||
else
|
||||
printf "%d.%d.%d.%d\n" $x4 $x3 $x2 $x1
|
||||
fi
|
||||
return 0
|
||||
}
|
14
examples/functions/inpath
Normal file
14
examples/functions/inpath
Normal file
|
@ -0,0 +1,14 @@
|
|||
inpath()
|
||||
{
|
||||
local PROG
|
||||
path=$(echo $PATH | sed 's/^:/.:/
|
||||
s/::/:.:/g
|
||||
s/:$/:./
|
||||
s/:/ /g')
|
||||
|
||||
for x in $path
|
||||
do
|
||||
[ -x $x/$1 ] && { PROG=$x/$1; break; }
|
||||
done
|
||||
[ -n "$PROG" ]
|
||||
}
|
41
examples/functions/isnum2
Normal file
41
examples/functions/isnum2
Normal file
|
@ -0,0 +1,41 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1998 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
isnum2()
|
||||
{
|
||||
case "$1" in
|
||||
[-+] | '') return 1;; # empty or bare `-' or `+'
|
||||
[-+]*[!0-9]*) return 1;; # non-digit with leading sign
|
||||
[-+]*) return 0;; # OK
|
||||
*[!0-9]*) return 1;; # non-digit
|
||||
*) return 0;; # OK
|
||||
esac
|
||||
}
|
||||
|
||||
# this one handles floating point
|
||||
isnum3()
|
||||
{
|
||||
case "$1" in
|
||||
'') return 1;; # empty
|
||||
*[!0-9.+-]*) return 1;; # non-digit, +, -, or .
|
||||
*?[-+]*) return 1;; # sign as second or later char
|
||||
*.*.*) return 1;; # multiple decimal points
|
||||
*) return 0;; # OK
|
||||
esac
|
||||
}
|
14
examples/functions/isvalidip
Normal file
14
examples/functions/isvalidip
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Thanks to Chris F. A. Johnson <c.f.a.johnson@rogers.com> for this one
|
||||
is_validip()
|
||||
{
|
||||
case "$*" in
|
||||
""|*[!0-9.]*|*[!0-9]) return 1 ;;
|
||||
esac
|
||||
|
||||
local IFS=.
|
||||
set -- $*
|
||||
|
||||
[ $# -eq 4 ] &&
|
||||
[ ${1:-666} -le 255 ] && [ ${2:-666} -le 255 ] &&
|
||||
[ ${3:-666} -le 255 ] && [ ${4:-666} -le 254 ]
|
||||
}
|
54
examples/functions/ksh-cd
Normal file
54
examples/functions/ksh-cd
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2001 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# ksh-like `cd': cd [-LP] [dir [change]]
|
||||
#
|
||||
cd()
|
||||
{
|
||||
OPTIND=1
|
||||
while getopts "LP" opt
|
||||
do
|
||||
case $opt in
|
||||
L|P) CDOPTS="$CDOPTS -$opt" ;;
|
||||
*) echo "$FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
|
||||
return 2;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
case $# in
|
||||
0) builtin cd $CDOPTS "$HOME" ;;
|
||||
1) builtin cd $CDOPTS "$@" ;;
|
||||
2) old="$1" new="$2"
|
||||
case "$PWD" in
|
||||
*$old*) ;;
|
||||
*) echo "${0##*/}: $FUNCNAME: bad substitution" >&2 ; return 1 ;;
|
||||
esac
|
||||
|
||||
dir=${PWD//$old/$new}
|
||||
|
||||
builtin cd $CDOPTS "$dir" && echo "$PWD"
|
||||
|
||||
;;
|
||||
*) echo "${0##*/}: $FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
|
||||
return 2 ;;
|
||||
esac
|
||||
}
|
58
examples/functions/ksh-compat-test
Normal file
58
examples/functions/ksh-compat-test
Normal file
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1999 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# replacements for test/[ that do arithmetic expansion on the operands to
|
||||
# the arithmetic operators, like ksh.
|
||||
#
|
||||
function test()
|
||||
{
|
||||
local -i n1 n3
|
||||
case "$#" in
|
||||
3) case "$2" in
|
||||
-lt|-gt|-eq|-ne|-le|-ge) n1=$(( $1 ))
|
||||
n3=$(( $3 ))
|
||||
builtin test "$n1" $2 "$n3"
|
||||
return $?;;
|
||||
*) builtin test "$@" ;;
|
||||
esac;;
|
||||
*) builtin test "$@" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
function [()
|
||||
{
|
||||
local -i n1 n3
|
||||
case "$#" in
|
||||
4) case "$2" in
|
||||
-lt|-gt|-eq|-ne|-le|-ge) n1=$(( $1 ))
|
||||
n3=$(( $3 ))
|
||||
builtin [ "$n1" $2 "$n3" ]
|
||||
return $?;;
|
||||
*) builtin [ "$@" ;;
|
||||
esac;;
|
||||
*) builtin [ "$@" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
q=7
|
||||
|
||||
[ q -lt 10 ]
|
||||
echo $?
|
||||
[ $q -lt 10 ]
|
||||
echo $?
|
246
examples/functions/kshenv
Normal file
246
examples/functions/kshenv
Normal file
|
@ -0,0 +1,246 @@
|
|||
#
|
||||
# .kshenv -- functions and aliases to provide the beginnings of a ksh
|
||||
# environment for bash.
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@ins.CWRU.Edu
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2002 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# These are definitions for the ksh compiled-in `exported aliases'. There
|
||||
# are others, but we already have substitutes for them: "history", "type",
|
||||
# and "hash".
|
||||
#
|
||||
alias r="fc -s"
|
||||
alias functions="typeset -f"
|
||||
alias integer="typeset -i"
|
||||
alias nohup="nohup "
|
||||
alias command="command "
|
||||
alias stop="kill -s STOP"
|
||||
alias redirect="command exec"
|
||||
alias hist="fc"
|
||||
|
||||
#
|
||||
# An almost-ksh compatible `whence' command. This is as hairy as it is
|
||||
# because of the desire to exactly mimic ksh (whose behavior was determined
|
||||
# empirically).
|
||||
#
|
||||
# This depends somewhat on knowing the format of the output of the bash
|
||||
# `builtin type' command.
|
||||
#
|
||||
|
||||
whence()
|
||||
{
|
||||
local vflag pflag fflag defarg c
|
||||
local path
|
||||
|
||||
vflag= aflag= pflag= fflag=
|
||||
path=
|
||||
if [ "$#" = "0" ] ; then
|
||||
echo "whence: usage: whence [-afpv] name..." >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
OPTIND=1
|
||||
while getopts "avfp" c
|
||||
do
|
||||
case "$c" in
|
||||
a) defarg=-a ;;
|
||||
f) fflag=1 ;; # no-op
|
||||
p) pflag=1 ;;
|
||||
v) vflag=1 ;;
|
||||
?) echo "whence: $1: unknown option" >&2
|
||||
echo "whence: usage: whence [-afpv] name..." >&2
|
||||
return 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
if [ "$#" = "0" ] ; then
|
||||
echo "whence: usage: whence [-afpv] name..." >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
for cmd
|
||||
do
|
||||
if [ "$vflag" ] ; then
|
||||
if [ -z "$defarg" ]; then
|
||||
builtin type $cmd | sed 1q
|
||||
else
|
||||
if builtin type $defarg -t $cmd | grep 'function$' >/dev/null 2>&1; then
|
||||
# HAIRY awk script to suppress
|
||||
# printing of function body -- could
|
||||
# do it with sed, but I don't have
|
||||
# that kind of time
|
||||
builtin type $defarg $cmd | awk '
|
||||
BEGIN {printit = 1;}
|
||||
$1 == "'$cmd'" && $2 == "()" {printit=0; next; }
|
||||
/^}$/ { if (printit == 0) printit=1 ; else print $0; next ; }
|
||||
/.*/ { if (printit) print $0; }'
|
||||
else
|
||||
builtin type $defarg $cmd
|
||||
fi
|
||||
fi
|
||||
else
|
||||
path=$(builtin type $defarg -p $cmd)
|
||||
if [ "$path" ] ; then
|
||||
echo $path
|
||||
else
|
||||
case "$cmd" in
|
||||
/*) echo "" ;;
|
||||
*) case "$(builtin type -t $cmd)" in
|
||||
"") echo "" ;;
|
||||
*) echo "$cmd" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# For real ksh homeboy fanatics, redefine the `type' builtin with a ksh
|
||||
# version.
|
||||
#
|
||||
#type()
|
||||
#{
|
||||
# whence -v "$*"
|
||||
#}
|
||||
|
||||
#
|
||||
# ksh-like `cd': cd [-LP] [dir [change]]
|
||||
#
|
||||
cd()
|
||||
{
|
||||
OPTIND=1
|
||||
while getopts "LP" opt
|
||||
do
|
||||
case $opt in
|
||||
L|P) CDOPTS="$CDOPTS -$opt" ;;
|
||||
*) echo "$FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
|
||||
return 2;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
case $# in
|
||||
0) builtin cd $CDOPTS "$HOME" ;;
|
||||
1) builtin cd $CDOPTS "$@" ;;
|
||||
2) old="$1" new="$2"
|
||||
case "$PWD" in
|
||||
*$old*) ;;
|
||||
*) echo "${0##*/}: $FUNCNAME: bad substitution" >&2 ; return 1 ;;
|
||||
esac
|
||||
|
||||
dir=${PWD//$old/$new}
|
||||
|
||||
builtin cd $CDOPTS "$dir" && echo "$PWD"
|
||||
|
||||
;;
|
||||
*) echo "${0##*/}: $FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
|
||||
return 2 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
#
|
||||
# ksh print emulation
|
||||
#
|
||||
# print [-Rnprsu[n]] [-f format] [arg ...]
|
||||
#
|
||||
# - end of options
|
||||
# -R BSD-style -- only accept -n, no escapes
|
||||
# -n do not add trailing newline
|
||||
# -p no-op (no coprocesses)
|
||||
# -r no escapes
|
||||
# -s print to the history file
|
||||
# -u n redirect output to fd n
|
||||
# -f format printf "$format" "$@"
|
||||
#
|
||||
|
||||
print()
|
||||
{
|
||||
local eflag=-e
|
||||
local nflag= fflag= c
|
||||
local fd=1
|
||||
|
||||
OPTIND=1
|
||||
while getopts "fRnprsu:" c
|
||||
do
|
||||
case $c in
|
||||
R) eflag= ;;
|
||||
r) eflag= ;;
|
||||
n) nflag=-n ;;
|
||||
s) sflag=y ;;
|
||||
f) fflag=y ;;
|
||||
u) fd=$OPTARG ;;
|
||||
p) ;;
|
||||
esac
|
||||
done
|
||||
shift $(( $OPTIND - 1 ))
|
||||
|
||||
if [ -n "$fflag" ]; then
|
||||
builtin printf "$@" >&$fd
|
||||
return
|
||||
fi
|
||||
|
||||
case "$sflag" in
|
||||
y) builtin history -s "$*" ;;
|
||||
*) builtin echo $eflag $nflag "$@" >&$fd
|
||||
esac
|
||||
}
|
||||
|
||||
# substring function
|
||||
# this function should be equivalent to the substring built-in which was
|
||||
# eliminated after the 06/29/84 version
|
||||
substring ()
|
||||
{
|
||||
local lpat flag str #local variables
|
||||
set -f
|
||||
case $1 in
|
||||
-l|-L)
|
||||
flag=$1
|
||||
lpat=$2
|
||||
shift 2
|
||||
;;
|
||||
esac
|
||||
# test for too few or too many arguments
|
||||
if [ x"$1" = x ] || [ $# -gt 2 ]; then
|
||||
print -u2 'substring: bad argument count'
|
||||
return 1
|
||||
fi
|
||||
str=$1
|
||||
if [ x"$flag" = x-l ]; then #substring -l lpat
|
||||
str=${str#$lpat}
|
||||
elif [ x"$flag" = x-L ]; then
|
||||
str=${str##$lpat} #substring -L lpat
|
||||
fi
|
||||
|
||||
if [ x"$2" != x ]; then
|
||||
echo ${str%$2}
|
||||
else
|
||||
echo $str
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
11
examples/functions/login
Normal file
11
examples/functions/login
Normal file
|
@ -0,0 +1,11 @@
|
|||
# replace the `login' and `newgrp' builtins in old bourne shells
|
||||
|
||||
login()
|
||||
{
|
||||
exec login "$@"
|
||||
}
|
||||
|
||||
newgrp()
|
||||
{
|
||||
exec newgrp "$@"
|
||||
}
|
77
examples/functions/notify.bash
Normal file
77
examples/functions/notify.bash
Normal file
|
@ -0,0 +1,77 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1992 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
trap _notify CHLD
|
||||
NOTIFY_ALL=false
|
||||
unset NOTIFY_LIST
|
||||
unalias false
|
||||
|
||||
false()
|
||||
{
|
||||
return 1
|
||||
}
|
||||
|
||||
_notify ()
|
||||
{
|
||||
local i j
|
||||
local newlist=
|
||||
|
||||
if $NOTIFY_ALL
|
||||
then
|
||||
return # let bash take care of this itself
|
||||
elif [ -z "$NOTIFY_LIST" ]; then
|
||||
return
|
||||
else
|
||||
set -- $NOTIFY_LIST
|
||||
for i in "$@"
|
||||
do
|
||||
j=$(jobs -n %$i)
|
||||
if [ -n "$j" ]; then
|
||||
echo "$j"
|
||||
jobs -n %$i >/dev/null
|
||||
else
|
||||
newlist="newlist $i"
|
||||
fi
|
||||
done
|
||||
NOTIFY_LIST="$newlist"
|
||||
fi
|
||||
}
|
||||
|
||||
notify ()
|
||||
{
|
||||
local i j
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
NOTIFY_ALL=:
|
||||
set -b
|
||||
return
|
||||
else
|
||||
for i in "$@"
|
||||
do
|
||||
# turn a valid job spec into a job number
|
||||
j=$(jobs $i)
|
||||
case "$j" in
|
||||
[*) j=${j%%]*}
|
||||
j=${j#[}
|
||||
NOTIFY_LIST="$NOTIFY_LIST $j"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
48
examples/functions/seq
Normal file
48
examples/functions/seq
Normal file
|
@ -0,0 +1,48 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1995 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# Generate a sequence from m to n, m defaults to 1.
|
||||
|
||||
seq ()
|
||||
{
|
||||
declare -i lo hi i # makes local
|
||||
local _SEQ
|
||||
|
||||
case $# in
|
||||
1) seq 1 "$1" ; return $? ;;
|
||||
2) lo=$1 hi=$2
|
||||
i=$lo _SEQ=""
|
||||
while let "i <= hi"; do
|
||||
_SEQ="${_SEQ}$i "
|
||||
let i+=1
|
||||
done
|
||||
echo "${_SEQ# }"
|
||||
return 0 ;;
|
||||
*) echo seq: usage: seq [low] high 1>&2 ; return 2 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# like the APL `iota' function (or at least how I remember it :-)
|
||||
iota()
|
||||
{
|
||||
case $# in
|
||||
1) seq 1 "$1"; return $?;;
|
||||
*) echo "iota: usage: iota high" 1>&2; return 2;;
|
||||
esac
|
||||
}
|
56
examples/functions/seq2
Normal file
56
examples/functions/seq2
Normal file
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1998 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# Generate a sequence from m to n, m defaults to 1.
|
||||
|
||||
seq ()
|
||||
{
|
||||
declare -i lo hi i # makes local
|
||||
local _SEQ INIT COMPARE STEP
|
||||
|
||||
case "$1" in
|
||||
-r) INIT='i=$hi _SEQ=""' COMPARE='let "i >= $lo"' STEP='let i-=1' ; shift ;;
|
||||
*) INIT='i=$lo _SEQ=""' COMPARE='let "i <= $hi"' STEP='let i+=1' ;;
|
||||
esac
|
||||
|
||||
case $# in
|
||||
1) lo=1 hi="$1" ;;
|
||||
2) lo=$1 hi=$2 ;;
|
||||
*) echo seq: usage: seq [-r] [low] high 1>&2 ; return 2 ;;
|
||||
esac
|
||||
|
||||
# equivalent to the as-yet-unimplemented
|
||||
# for (( "$INIT" ; "$COMPARE" ; "$STEP" )); do _SEQ="${_SEQ}$i "; done
|
||||
eval "$INIT"
|
||||
while eval "$COMPARE"; do
|
||||
_SEQ="${_SEQ}$i "
|
||||
eval "$STEP"
|
||||
done
|
||||
echo "${_SEQ# }"
|
||||
return 0
|
||||
}
|
||||
|
||||
# like the APL `iota' function (or at least how I remember it :-)
|
||||
iota()
|
||||
{
|
||||
case $# in
|
||||
1) seq 1 "$1"; return $?;;
|
||||
*) echo "iota: usage: iota high" 1>&2; return 2;;
|
||||
esac
|
||||
}
|
7
examples/functions/shcat
Normal file
7
examples/functions/shcat
Normal file
|
@ -0,0 +1,7 @@
|
|||
shcat()
|
||||
{
|
||||
while IFS= read -r line
|
||||
do
|
||||
echo "$line"
|
||||
done
|
||||
}
|
19
examples/functions/shcat2
Normal file
19
examples/functions/shcat2
Normal file
|
@ -0,0 +1,19 @@
|
|||
shcat()
|
||||
{
|
||||
while read -r
|
||||
do
|
||||
echo "$REPLY"
|
||||
done
|
||||
}
|
||||
|
||||
shcat2()
|
||||
{
|
||||
while [ $# -ge 1 ]; do
|
||||
case "$1" in
|
||||
-) shcat ;;
|
||||
*) shcat < "$1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
exit 0
|
||||
}
|
69
examples/functions/sort-pos-params
Normal file
69
examples/functions/sort-pos-params
Normal file
|
@ -0,0 +1,69 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2001 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# 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()
|
||||
{
|
||||
local -a R
|
||||
local u
|
||||
|
||||
case "$1" in
|
||||
-u) u=-u ; shift ;;
|
||||
esac
|
||||
|
||||
# if you want the case of no positional parameters to return success,
|
||||
# remove the error message and return 0
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "$FUNCNAME: argument expected" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# make R a copy of the positional parameters
|
||||
R=( "${@}" )
|
||||
|
||||
# sort R.
|
||||
R=( $( printf "%s\n" "${R[@]}" | sort $u) )
|
||||
|
||||
printf "%s\n" "${R[@]}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# will print everything on separate lines
|
||||
set -- 3 1 4 1 5 9 2 6 5 3 2
|
||||
sort_posparams "$@"
|
||||
|
||||
# sets without preserving quoted parameters
|
||||
set -- $( sort_posparams "$@" )
|
||||
echo "$@"
|
||||
echo $#
|
||||
|
||||
# sets preserving quoted parameters, beware pos params with embedded newlines
|
||||
set -- 'a b' 'a c' 'x z'
|
||||
|
||||
oifs=$IFS
|
||||
IFS=$'\n'
|
||||
set -- $( sort_posparams "$@" )
|
||||
IFS="$oifs"
|
||||
|
||||
echo "$@"
|
||||
echo $#
|
||||
|
||||
sort_posparams
|
97
examples/functions/substr
Normal file
97
examples/functions/substr
Normal file
|
@ -0,0 +1,97 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2002 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# substr -- a function to emulate the ancient ksh builtin
|
||||
#
|
||||
|
||||
#
|
||||
# -l == shortest from left
|
||||
# -L == longest from left
|
||||
# -r == shortest from right (the default)
|
||||
# -R == longest from right
|
||||
|
||||
substr()
|
||||
{
|
||||
local flag pat str
|
||||
local usage="usage: substr -lLrR pat string or substr string pat"
|
||||
|
||||
case "$1" in
|
||||
-l | -L | -r | -R)
|
||||
flag="$1"
|
||||
pat="$2"
|
||||
shift 2
|
||||
;;
|
||||
-*)
|
||||
echo "substr: unknown option: $1"
|
||||
echo "$usage"
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
flag="-r"
|
||||
pat="$2"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$#" -eq 0 ] || [ "$#" -gt 2 ] ; then
|
||||
echo "substr: bad argument count"
|
||||
return 2
|
||||
fi
|
||||
|
||||
str="$1"
|
||||
|
||||
#
|
||||
# We don't want -f, but we don't want to turn it back on if
|
||||
# we didn't have it already
|
||||
#
|
||||
case "$-" in
|
||||
"*f*")
|
||||
;;
|
||||
*)
|
||||
fng=1
|
||||
set -f
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$flag" in
|
||||
-l)
|
||||
str="${str#$pat}" # substr -l pat string
|
||||
;;
|
||||
-L)
|
||||
str="${str##$pat}" # substr -L pat string
|
||||
;;
|
||||
-r)
|
||||
str="${str%$pat}" # substr -r pat string
|
||||
;;
|
||||
-R)
|
||||
str="${str%%$pat}" # substr -R pat string
|
||||
;;
|
||||
*)
|
||||
str="${str%$2}" # substr string pat
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$str"
|
||||
|
||||
#
|
||||
# If we had file name generation when we started, re-enable it
|
||||
#
|
||||
if [ "$fng" = "1" ] ; then
|
||||
set +f
|
||||
fi
|
||||
}
|
99
examples/functions/substr2
Normal file
99
examples/functions/substr2
Normal file
|
@ -0,0 +1,99 @@
|
|||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 2002 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# substr -- a function to emulate the ancient ksh builtin
|
||||
#
|
||||
|
||||
# -l == remove shortest from left
|
||||
# -L == remove longest from left
|
||||
# -r == remove shortest from right (the default)
|
||||
# -R == remove longest from right
|
||||
|
||||
substr()
|
||||
{
|
||||
local flag pat str
|
||||
local usage="usage: substr -lLrR pat string or substr string pat"
|
||||
local options="l:L:r:R:"
|
||||
|
||||
OPTIND=1
|
||||
while getopts "$options" c
|
||||
do
|
||||
case "$c" in
|
||||
l | L | r | R)
|
||||
flag="-$c"
|
||||
pat="$OPTARG"
|
||||
;;
|
||||
'?')
|
||||
echo "$usage"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$OPTIND" -gt 1 ] ; then
|
||||
shift $(( $OPTIND -1 ))
|
||||
fi
|
||||
|
||||
if [ "$#" -eq 0 ] || [ "$#" -gt 2 ] ; then
|
||||
echo "substr: bad argument count"
|
||||
return 2
|
||||
fi
|
||||
|
||||
str="$1"
|
||||
|
||||
#
|
||||
# We don't want -f, but we don't want to turn it back on if
|
||||
# we didn't have it already
|
||||
#
|
||||
case "$-" in
|
||||
"*f*")
|
||||
;;
|
||||
*)
|
||||
fng=1
|
||||
set -f
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$flag" in
|
||||
-l)
|
||||
str="${str#$pat}" # substr -l pat string
|
||||
;;
|
||||
-L)
|
||||
str="${str##$pat}" # substr -L pat string
|
||||
;;
|
||||
-r)
|
||||
str="${str%$pat}" # substr -r pat string
|
||||
;;
|
||||
-R)
|
||||
str="${str%%$pat}" # substr -R pat string
|
||||
;;
|
||||
*)
|
||||
str="${str%$2}" # substr string pat
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$str"
|
||||
|
||||
#
|
||||
# If we had file name generation when we started, re-enable it
|
||||
#
|
||||
if [ "$fng" = "1" ] ; then
|
||||
set +f
|
||||
fi
|
||||
}
|
71
examples/functions/whatis
Normal file
71
examples/functions/whatis
Normal file
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
# whatis -- and implementation of the 10th Edition Unix sh builtin `whatis'
|
||||
# command.
|
||||
#
|
||||
# usage: whatis arg [...]
|
||||
#
|
||||
# For each argument, whatis prints the associated value as a parameter,
|
||||
# builtin, function, alias, or executable file as appropriate. In each
|
||||
# case, the value is printed in a form which would yield the same value
|
||||
# if typed as input to the shell itself.
|
||||
#
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1994 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
whatis()
|
||||
{
|
||||
local wusage='usage: whatis arg [arg...]'
|
||||
local fail=0
|
||||
|
||||
if [ $# -eq 0 ] ; then
|
||||
echo "$wusage"
|
||||
return 1
|
||||
fi
|
||||
|
||||
for arg
|
||||
do
|
||||
case $(builtin type -type $arg 2>/dev/null) in
|
||||
"alias")
|
||||
builtin alias "$arg"
|
||||
;;
|
||||
"function")
|
||||
builtin type "$arg" | sed 1d
|
||||
;;
|
||||
"builtin")
|
||||
echo builtin "$arg"
|
||||
;;
|
||||
"file")
|
||||
builtin type -path "$arg"
|
||||
;;
|
||||
*)
|
||||
# OK, we could have a variable, or we could have nada
|
||||
if [ "$(eval echo \${$arg+set})" = "set" ] ; then
|
||||
# It is a variable, and it is set
|
||||
echo -n "$arg="
|
||||
eval echo '\"'\$$arg'\"'
|
||||
else
|
||||
echo whatis: $arg: not found
|
||||
fail=1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return $fail
|
||||
}
|
78
examples/functions/whence
Normal file
78
examples/functions/whence
Normal file
|
@ -0,0 +1,78 @@
|
|||
#
|
||||
# An almost-ksh compatible `whence' command. This is as hairy as it is
|
||||
# because of the desire to exactly mimic ksh.
|
||||
#
|
||||
# This depends somewhat on knowing the format of the output of the bash
|
||||
# `builtin type' command.
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@ins.CWRU.Edu
|
||||
#
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1994 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
whence()
|
||||
{
|
||||
local vflag= path=
|
||||
|
||||
if [ "$#" = "0" ] ; then
|
||||
echo "whence: argument expected"
|
||||
return 1
|
||||
fi
|
||||
case "$1" in
|
||||
-v) vflag=1
|
||||
shift 1
|
||||
;;
|
||||
-*) echo "whence: bad option: $1"
|
||||
return 1
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
if [ "$#" = "0" ] ; then
|
||||
echo "whence: bad argument count"
|
||||
return 1
|
||||
fi
|
||||
|
||||
for cmd
|
||||
do
|
||||
if [ "$vflag" ] ; then
|
||||
echo $(builtin type $cmd | sed 1q)
|
||||
else
|
||||
path=$(builtin type -path $cmd)
|
||||
if [ "$path" ] ; then
|
||||
echo $path
|
||||
else
|
||||
case "$cmd" in
|
||||
/*) if [ -x "$cmd" ]; then
|
||||
echo "$cmd"
|
||||
fi
|
||||
;;
|
||||
*) case "$(builtin type -type $cmd)" in
|
||||
"") ;;
|
||||
*) echo "$cmd"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
62
examples/functions/which
Normal file
62
examples/functions/which
Normal file
|
@ -0,0 +1,62 @@
|
|||
#
|
||||
# which - emulation of `which' as it appears in FreeBSD
|
||||
#
|
||||
# usage: which [-as] command [command...]
|
||||
#
|
||||
#
|
||||
# Chet Ramey <chet.ramey@case.edu>
|
||||
#
|
||||
# Copyright 1999 Chester Ramey
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# TThis program 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 this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
which()
|
||||
{
|
||||
local aflag sflag ES a opt
|
||||
|
||||
OPTIND=1
|
||||
while builtin getopts as opt ; do
|
||||
case "$opt" in
|
||||
a) aflag=-a ;;
|
||||
s) sflag=1 ;;
|
||||
?) echo "which: usage: which [-as] command [command ...]" >&2
|
||||
exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
(( $OPTIND > 1 )) && shift $(( $OPTIND - 1 ))
|
||||
|
||||
# without command arguments, exit with status 1
|
||||
ES=1
|
||||
|
||||
# exit status is 0 if all commands are found, 1 if any are not found
|
||||
for command; do
|
||||
# if $command is a function, make sure we add -a so type
|
||||
# will look in $PATH after finding the function
|
||||
a=$aflag
|
||||
case "$(builtin type -t $command)" in
|
||||
"function") a=-a;;
|
||||
esac
|
||||
|
||||
if [ -n "$sflag" ]; then
|
||||
builtin type -p $a $command >/dev/null 2>&1
|
||||
else
|
||||
builtin type -p $a $command
|
||||
fi
|
||||
ES=$?
|
||||
done
|
||||
|
||||
return $ES
|
||||
}
|
335
examples/loadables/Makefile.in
Normal file
335
examples/loadables/Makefile.in
Normal file
|
@ -0,0 +1,335 @@
|
|||
#
|
||||
# Simple makefile for the sample loadable builtins
|
||||
#
|
||||
# Copyright (C) 1996-2022 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
PACKAGE = @PACKAGE_NAME@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
loadablesdir = @loadablesdir@
|
||||
headersdir = @headersdir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
# Support an alternate destination root directory for package building
|
||||
DESTDIR =
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALLMODE= -m 0755
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
host_os = @host_os@
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
STYLE_CFLAGS = @STYLE_CFLAGS@
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
SUPPORT_SRC = $(topdir)/support/
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(STYLE_CFLAGS)
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ @LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
|
||||
-I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
|
||||
-I$(BUILD_DIR)/builtins $(INTL_INC)
|
||||
|
||||
.c.o:
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
|
||||
ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \
|
||||
tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \
|
||||
uname sync push ln unlink realpath strftime mypid setpgid seq rm \
|
||||
accept csv dsv cut stat getconf
|
||||
OTHERPROG = necho hello cat pushd asort
|
||||
|
||||
all: $(SHOBJ_STATUS)
|
||||
|
||||
supported: $(ALLPROG)
|
||||
others: $(OTHERPROG)
|
||||
|
||||
unsupported:
|
||||
@echo "Your system (${host_os}) is not supported by the"
|
||||
@echo "${topdir}/support/shobj-conf script."
|
||||
@echo "If your operating system provides facilities for dynamic"
|
||||
@echo "loading of shared objects using the dlopen(3) interface,"
|
||||
@echo "please update the script and re-run configure."
|
||||
@echo "Please send the changes you made to bash-maintainers@gnu.org"
|
||||
@echo "for inclusion in future bash releases."
|
||||
|
||||
everything: supported others
|
||||
|
||||
print: print.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
|
||||
|
||||
necho: necho.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
|
||||
|
||||
hello: hello.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
finfo: finfo.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
seq: seq.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ seq.o $(SHOBJ_LIBS)
|
||||
|
||||
logname: logname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
|
||||
|
||||
basename: basename.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
|
||||
|
||||
dirname: dirname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
|
||||
|
||||
tty: tty.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
|
||||
|
||||
pathchk: pathchk.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
|
||||
|
||||
tee: tee.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
|
||||
|
||||
mkdir: mkdir.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
printenv: printenv.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
|
||||
|
||||
getconf: getconf.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
|
||||
|
||||
id: id.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
|
||||
|
||||
whoami: whoami.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
|
||||
|
||||
uname: uname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
|
||||
|
||||
sync: sync.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
|
||||
|
||||
push: push.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
|
||||
|
||||
ln: ln.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
|
||||
|
||||
unlink: unlink.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
dsv: dsv.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dsv.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)
|
||||
|
||||
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)
|
||||
|
||||
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.
|
||||
#
|
||||
pushd.c: ${topdir}/builtins/pushd.def
|
||||
$(RM) $@
|
||||
${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
|
||||
|
||||
pushd.o: pushd.c
|
||||
$(RM) $@
|
||||
$(SHOBJ_CC) -Wno-format-security -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
pushd: pushd.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALLPROG) $(OTHERPROG) *.o
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
mostlyclean: clean
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
$(RM) Makefile Makefile.inc Makefile.sample pushd.c
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
installdirs:
|
||||
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(loadablesdir)
|
||||
|
||||
install-dev: installdirs
|
||||
@$(INSTALL_DATA) Makefile.inc $(DESTDIR)$(loadablesdir)/Makefile.inc
|
||||
@$(INSTALL_DATA) Makefile.sample $(DESTDIR)$(loadablesdir)/Makefile.sample
|
||||
@$(INSTALL_DATA) $(srcdir)/loadables.h $(DESTDIR)$(loadablesdir)/loadables.h
|
||||
@( cd $(BUILD_DIR) && ${MAKE} ${MFLAGS} DESTDIR="$(DESTDIR)" install-headers)
|
||||
|
||||
install-supported: all installdirs install-dev
|
||||
@echo installing example loadable builtins in $(DESTDIR)${loadablesdir}
|
||||
@for prog in ${ALLPROG}; do \
|
||||
echo $$prog ; \
|
||||
$(INSTALL_PROGRAM) $(INSTALLMODE) $$prog $(DESTDIR)$(loadablesdir)/$$prog ;\
|
||||
done
|
||||
|
||||
uninstall-dev:
|
||||
-$(RM) $(DESTDIR)$(loadablesdir)/Makefile.inc $(DESTDIR)$(loadablesdir)/Makefile.sample
|
||||
-$(RM) $(DESTDIR)$(loadablesdir)/loadables.h
|
||||
-( cd $(BUILD_DIR) && ${MAKE} ${MFLAGS} DESTDIR="$(DESTDIR)" uninstall-headers)
|
||||
|
||||
uninstall-supported: uninstall-dev
|
||||
-( cd $(DESTDIR)${loadablesdir} && $(RM) ${ALLPROG} )
|
||||
|
||||
install-unsupported:
|
||||
uninstall-unsupported:
|
||||
|
||||
install: install-$(SHOBJ_STATUS)
|
||||
uninstall: uninstall-$(SHOBJ_STATUS)
|
||||
|
||||
print.o: print.c
|
||||
truefalse.o: truefalse.c
|
||||
accept.o: accept.c
|
||||
sleep.o: sleep.c
|
||||
finfo.o: finfo.c
|
||||
getconf.o: getconf.c getconf.h
|
||||
logname.o: logname.c
|
||||
basename.o: basename.c
|
||||
dirname.o: dirname.c
|
||||
tty.o: tty.c
|
||||
pathchk.o: pathchk.c
|
||||
tee.o: tee.c
|
||||
head.o: head.c
|
||||
rmdir.o: rmdir.c
|
||||
necho.o: necho.c
|
||||
hello.o: hello.c
|
||||
cat.o: cat.c
|
||||
csv.o: csv.c
|
||||
dsv.o: dsv.c
|
||||
cut.o: cut.c
|
||||
printenv.o: printenv.c
|
||||
id.o: id.c
|
||||
whoami.o: whoami.c
|
||||
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
|
101
examples/loadables/Makefile.inc.in
Normal file
101
examples/loadables/Makefile.inc.in
Normal file
|
@ -0,0 +1,101 @@
|
|||
#
|
||||
# Sample makefile for bash loadable builtin development
|
||||
#
|
||||
# Copyright (C) 2015-2022 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
PACKAGE = @PACKAGE_NAME@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
loadablesdir = @loadablesdir@
|
||||
headersdir = @headersdir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
# Support an alternate destination root directory for package building
|
||||
DESTDIR =
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALLMODE= -m 0755
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
host_os = @host_os@
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
SUPPORT_SRC = $(topdir)/support/
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ @LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
INC = -I$(headersdir) -I$(headersdir)/include -I$(headersdir)/builtins
|
||||
|
||||
.c.o:
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
|
44
examples/loadables/Makefile.sample.in
Normal file
44
examples/loadables/Makefile.sample.in
Normal file
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Sample makefile for bash loadable builtin development
|
||||
#
|
||||
# Copyright (C) 2022 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# these should match the ones in Makefile.in (for the make install target)
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @libdir@
|
||||
|
||||
# ${loadablesdir} is where the example loadable builtins and data files
|
||||
# are installed (make install target in Makefile.in)
|
||||
|
||||
loadablesdir = @loadablesdir@
|
||||
DESTDIR =
|
||||
|
||||
# include Makefile.inc for all boilerplate definitions
|
||||
|
||||
include $(DESTDIR)$(loadablesdir)/Makefile.inc
|
||||
|
||||
# here, `example' is the name of the shared object
|
||||
# replace `example' with the appropriate filename
|
||||
|
||||
all: example
|
||||
|
||||
example: example.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ example.o $(SHOBJ_LIBS)
|
||||
|
||||
example.o: example.c
|
82
examples/loadables/README
Normal file
82
examples/loadables/README
Normal file
|
@ -0,0 +1,82 @@
|
|||
Some examples of ready-to-dynamic-load builtins. Most of the
|
||||
examples given are reimplementations of standard commands whose
|
||||
execution time is dominated by process startup time. Some
|
||||
exceptions are sleep, which allows you to sleep for fractions
|
||||
of a second, finfo, which provides access to the rest of the
|
||||
elements of the `stat' structure that `test' doesn't let you
|
||||
see, csv, which allows you to manipulate data from comma-separated
|
||||
values files, fdflags, which lets you change the flags associated
|
||||
with one of the shell's file descriptors, and pushd/popd/dirs, which
|
||||
allows you to compile them out of the shell.
|
||||
|
||||
All of the new builtins in ksh93 that bash didn't already have
|
||||
are included here, as is the ksh `print' builtin.
|
||||
|
||||
The configure script in the top-level source directory uses the
|
||||
support/shobj-conf script to set the right values in the Makefile,
|
||||
so you should not need to change the Makefile. If your system
|
||||
is not supported by support/shobj-conf, and it has the necessary
|
||||
facilities for building shared objects and support for the
|
||||
dlopen/dlsyn/dlclose/dlerror family of functions, please make
|
||||
the necessary changes to support/shobj-conf and send the changes
|
||||
to bash-maintainers@gnu.org.
|
||||
|
||||
Loadable builtins are loaded into a running shell with
|
||||
|
||||
enable -f filename builtin-name
|
||||
|
||||
enable uses a simple reference-counting scheme to avoid unloading a
|
||||
shared object that implements more than one loadable builtin before
|
||||
all loadable builtins implemented in the object are removed.
|
||||
|
||||
Many of the details needed by builtin writers are found in hello.c,
|
||||
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.
|
||||
csv.c Process a line of csv data and store it in an indexed array.
|
||||
cut.c Cut out selected portions of each line of a file.
|
||||
dirname.c Return directory portion of pathname.
|
||||
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.
|
||||
id.c POSIX.2 user identity.
|
||||
ln.c Make links.
|
||||
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.
|
||||
Makefile.inc.in Sample makefile to use for loadable builtin development.
|
||||
mkdir.c Make directories.
|
||||
mkfifo.c Create named pipes.
|
||||
mktemp.c Make unique temporary file name.
|
||||
mypid.c Add $MYPID variable, demonstrate use of unload hook function.
|
||||
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?
|
||||
realpath.c Canonicalize pathnames, resolving symlinks.
|
||||
rm.c Remove files and directories.
|
||||
rmdir.c Remove directory.
|
||||
seq.c Print a sequence of decimal or floating point numbers.
|
||||
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.
|
||||
template.c Example template for loadable builtin.
|
||||
truefalse.c True and false builtins.
|
||||
tty.c Return terminal name.
|
||||
uname.c Print system information.
|
||||
unlink.c Remove a directory entry.
|
||||
whoami.c Print out username of current user.
|
245
examples/loadables/accept.c
Normal file
245
examples/loadables/accept.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* 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 <limits.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;
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
intmax_t iport;
|
||||
int opt;
|
||||
char *tmoutarg, *fdvar, *rhostvar, *rhost, *bindaddr;
|
||||
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 = bindaddr = (char *)NULL;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "b:r:t:v:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'b':
|
||||
bindaddr = list_optarg;
|
||||
break;
|
||||
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 = bindaddr ? inet_addr (bindaddr) : htonl(INADDR_ANY);
|
||||
|
||||
if (server.sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
builtin_error ("invalid address: %s", strerror (errno));
|
||||
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 (bind (servsock, (struct sockaddr *)&server, sizeof (server)) < 0)
|
||||
{
|
||||
builtin_error ("socket bind failure: %s", strerror (errno));
|
||||
close (servsock);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
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); /* XXX */
|
||||
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:",
|
||||
" -b address use ADDRESS as the IP address to listen on; the",
|
||||
" default is INADDR_ANY",
|
||||
" -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 [-b address] [-t timeout] [-v varname] [-r addrvar ] port", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
279
examples/loadables/asort.c
Normal file
279
examples/loadables/asort.c
Normal file
|
@ -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
|
||||
};
|
131
examples/loadables/basename.c
Normal file
131
examples/loadables/basename.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/* basename - return nondirectory portion of pathname */
|
||||
|
||||
/* 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"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
basename_builtin (list)
|
||||
WORD_LIST *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);
|
||||
}
|
||||
|
||||
string = list->word->word;
|
||||
suffix = (char *)NULL;
|
||||
if (list->next)
|
||||
{
|
||||
list = list->next;
|
||||
suffix = list->word->word;
|
||||
}
|
||||
|
||||
if (list->next)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
slen = strlen (string);
|
||||
|
||||
/* Strip trailing slashes */
|
||||
while (slen > 0 && string[slen - 1] == '/')
|
||||
slen--;
|
||||
|
||||
/* (2) If string consists entirely of slash characters, string shall be
|
||||
set to a single slash character. In this case, skip steps (3)
|
||||
through (5). */
|
||||
if (slen == 0)
|
||||
{
|
||||
fputs ("/\n", stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* (3) If there are any trailing slash characters in string, they
|
||||
shall be removed. */
|
||||
string[slen] = '\0';
|
||||
|
||||
/* (4) If there are any slash characters remaining in string, the prefix
|
||||
of string up to an including the last slash character in string
|
||||
shall be removed. */
|
||||
while (--slen >= 0)
|
||||
if (string[slen] == '/')
|
||||
break;
|
||||
|
||||
fn = string + slen + 1;
|
||||
|
||||
/* (5) If the suffix operand is present, is not identical to the
|
||||
characters remaining in string, and is identical to a suffix
|
||||
of the characters remaining in string, the suffix suffix
|
||||
shall be removed from string. Otherwise, string shall not be
|
||||
modified by this step. */
|
||||
if (suffix)
|
||||
{
|
||||
sufflen = strlen (suffix);
|
||||
slen = strlen (fn);
|
||||
if (sufflen < slen)
|
||||
{
|
||||
off = slen - sufflen;
|
||||
if (strcmp (fn + off, suffix) == 0)
|
||||
fn[off] = '\0';
|
||||
}
|
||||
}
|
||||
printf ("%s\n", fn);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *basename_doc[] = {
|
||||
"Return non-directory portion of pathname.",
|
||||
"",
|
||||
"The STRING is converted to a filename corresponding to the last",
|
||||
"pathname component in STRING. If the suffix string SUFFIX is",
|
||||
"supplied, it is removed.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin basename_struct = {
|
||||
"basename", /* builtin name */
|
||||
basename_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
basename_doc, /* array of long documentation strings. */
|
||||
"basename string [suffix]", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
138
examples/loadables/cat.c
Normal file
138
examples/loadables/cat.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* cat replacement
|
||||
*
|
||||
* no options - the way cat was intended
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009,2022 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 <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char *strerror ();
|
||||
extern char **make_builtin_argv ();
|
||||
|
||||
static int
|
||||
fcopy(fd, fn)
|
||||
int fd;
|
||||
char *fn;
|
||||
{
|
||||
char buf[4096], *s;
|
||||
int n, w, e;
|
||||
|
||||
while (n = read(fd, buf, sizeof (buf))) {
|
||||
if (n < 0) {
|
||||
e = errno;
|
||||
write(2, "cat: read error: ", 18);
|
||||
write(2, fn, strlen(fn));
|
||||
write(2, ": ", 2);
|
||||
s = strerror(e);
|
||||
write(2, s, strlen(s));
|
||||
write(2, "\n", 1);
|
||||
return 1;
|
||||
}
|
||||
QUIT;
|
||||
w = write(1, buf, n);
|
||||
if (w != n) {
|
||||
e = errno;
|
||||
write(2, "cat: write error: ", 18);
|
||||
s = strerror(e);
|
||||
write(2, s, strlen(s));
|
||||
write(2, "\n", 1);
|
||||
return 1;
|
||||
}
|
||||
QUIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cat_main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i, fd, r;
|
||||
char *s;
|
||||
|
||||
if (argc == 1)
|
||||
return (fcopy(0, "standard input"));
|
||||
|
||||
for (i = r = 1; i < argc; i++) {
|
||||
QUIT;
|
||||
if (argv[i][0] == '-' && argv[i][1] == '\0')
|
||||
fd = 0;
|
||||
else {
|
||||
fd = open(argv[i], O_RDONLY, 0666);
|
||||
if (fd < 0) {
|
||||
s = strerror(errno);
|
||||
write(2, "cat: cannot open ", 17);
|
||||
write(2, argv[i], strlen(argv[i]));
|
||||
write(2, ": ", 2);
|
||||
write(2, s, strlen(s));
|
||||
write(2, "\n", 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r = fcopy(fd, argv[i]);
|
||||
if (fd != 0)
|
||||
close(fd);
|
||||
}
|
||||
QUIT;
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
cat_builtin(list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char **v;
|
||||
int c, r;
|
||||
|
||||
v = make_builtin_argv(list, &c);
|
||||
QUIT;
|
||||
r = cat_main(c, v);
|
||||
free(v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *cat_doc[] = {
|
||||
"Display files.",
|
||||
"",
|
||||
"Read each FILE and display it on the standard output. If any",
|
||||
"FILE is `-' or if no FILE argument is given, the standard input",
|
||||
"is read.",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin cat_struct = {
|
||||
"cat",
|
||||
cat_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
cat_doc,
|
||||
"cat [-] [file ...]",
|
||||
0
|
||||
};
|
206
examples/loadables/csv.c
Normal file
206
examples/loadables/csv.c
Normal file
|
@ -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, dstring)
|
||||
SHELL_VAR *csv;
|
||||
char *line, *dstring;
|
||||
{
|
||||
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 == *dstring)
|
||||
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, dstring);
|
||||
}
|
||||
|
||||
delim = *field;
|
||||
*field = '\0';
|
||||
|
||||
bind_array_element (csv, ind, buf, 0);
|
||||
ind++;
|
||||
|
||||
*field = delim;
|
||||
|
||||
if (delim == *dstring)
|
||||
prev = field + 1;
|
||||
}
|
||||
while (delim == *dstring);
|
||||
|
||||
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 */
|
||||
};
|
631
examples/loadables/cut.c
Normal file
631
examples/loadables/cut.c
Normal file
|
@ -0,0 +1,631 @@
|
|||
/* 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 (<ok, "-");
|
||||
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)
|
||||
{
|
||||
QUIT;
|
||||
if (line[n] == '\n')
|
||||
line[n] = '\0'; /* cutline expects no newline terminator */
|
||||
cutline (v, line, ops); /* can modify line */
|
||||
}
|
||||
if (fd > 0)
|
||||
close (fd);
|
||||
|
||||
QUIT;
|
||||
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 */
|
||||
};
|
119
examples/loadables/dirname.c
Normal file
119
examples/loadables/dirname.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* dirname - return directory portion of pathname */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
dirname_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int slen;
|
||||
char *string;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
if (list == 0 || list->next)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
string = list->word->word;
|
||||
slen = strlen (string);
|
||||
|
||||
/* Strip trailing slashes */
|
||||
while (slen > 0 && string[slen - 1] == '/')
|
||||
slen--;
|
||||
|
||||
/* (2) If string consists entirely of slash characters, string shall be
|
||||
set to a single slash character. In this case, skip steps (3)
|
||||
through (8). */
|
||||
if (slen == 0)
|
||||
{
|
||||
fputs ("/\n", stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* (3) If there are any trailing slash characters in string, they
|
||||
shall be removed. */
|
||||
string[slen] = '\0';
|
||||
|
||||
/* (4) If there are no slash characters remaining in string, string
|
||||
shall be set to a single period character. In this case, skip
|
||||
steps (5) through (8).
|
||||
|
||||
(5) If there are any trailing nonslash characters in string,
|
||||
they shall be removed. */
|
||||
|
||||
while (--slen >= 0)
|
||||
if (string[slen] == '/')
|
||||
break;
|
||||
|
||||
if (slen < 0)
|
||||
{
|
||||
fputs (".\n", stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* (7) If there are any trailing slash characters in string, they
|
||||
shall be removed. */
|
||||
while (--slen >= 0)
|
||||
if (string[slen] != '/')
|
||||
break;
|
||||
string[++slen] = '\0';
|
||||
|
||||
/* (8) If the remaining string is empty, string shall be set to a single
|
||||
slash character. */
|
||||
printf ("%s\n", (slen == 0) ? "/" : string);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *dirname_doc[] = {
|
||||
"Display directory portion of pathname.",
|
||||
"",
|
||||
"The STRING is converted to the name of the directory containing",
|
||||
"the filename corresponding to the last pathname component in STRING.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin dirname_struct = {
|
||||
"dirname", /* builtin name */
|
||||
dirname_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
dirname_doc, /* array of long documentation strings. */
|
||||
"dirname string", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
300
examples/loadables/dsv.c
Normal file
300
examples/loadables/dsv.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
/* dsv - process a line of delimiter-separated data and populate an indexed
|
||||
array with the fields */
|
||||
|
||||
/*
|
||||
Copyright (C) 2022 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 DSV_ARRAY_DEFAULT "DSV"
|
||||
|
||||
#define NQUOTE 0
|
||||
#define DQUOTE 1
|
||||
#define SQUOTE 2
|
||||
|
||||
#define F_SHELLQUOTE 0x01
|
||||
#define F_GREEDY 0x02
|
||||
#define F_PRESERVE 0x04
|
||||
|
||||
/* Split LINE into delimiter-separated fields, storing each field into a
|
||||
separate element of array variable DSV, starting at index 0. The format
|
||||
of LINE is delimiter-separated values. By default, this splits lines of
|
||||
CSV data as described in RFC 4180. If *DSTRING is any other value than
|
||||
',', this uses that character as a field delimiter. Pass F_SHELLQUOTE in
|
||||
FLAGS to understand shell-like double-quoting and backslash-escaping in
|
||||
double quotes instead of the "" CSV behavior, and shell-like single quotes.
|
||||
Pass F_GREEDY in FLAGS to consume multiple leading and trailing instances
|
||||
of *DSTRING and consecutive instances of *DSTRING in LINE without creating
|
||||
null fields. If you want to preserve the quote characters in the generated
|
||||
fields, pass F_PRESERVE; by default, this removes them. */
|
||||
static int
|
||||
dsvsplit (dsv, line, dstring, flags)
|
||||
SHELL_VAR *dsv;
|
||||
char *line, *dstring;
|
||||
int flags;
|
||||
{
|
||||
arrayind_t ind;
|
||||
char *field, *prev, *buf, *xbuf;
|
||||
int delim, qstate;
|
||||
int b, rval;
|
||||
|
||||
xbuf = 0;
|
||||
ind = 0;
|
||||
field = prev = line;
|
||||
|
||||
/* If we want a greedy split, consume leading instances of *DSTRING */
|
||||
if (flags & F_GREEDY)
|
||||
{
|
||||
while (*prev == *dstring)
|
||||
prev++;
|
||||
field = prev;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (*prev == '"')
|
||||
{
|
||||
if (xbuf == 0)
|
||||
xbuf = xmalloc (strlen (prev) + 1);
|
||||
buf = xbuf;
|
||||
b = 0;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *prev;
|
||||
qstate = DQUOTE;
|
||||
for (field = ++prev; *field; field++)
|
||||
{
|
||||
if (qstate == DQUOTE && *field == '"' && field[1] == '"' && (flags & F_SHELLQUOTE) == 0)
|
||||
buf[b++] = *field++; /* skip double quote */
|
||||
else if (qstate == DQUOTE && (flags & F_SHELLQUOTE) && *field == '\\' && strchr (slashify_in_quotes, field[1]) != 0)
|
||||
buf[b++] = *++field; /* backslash quoted double quote */
|
||||
else if (qstate == DQUOTE && *field == '"')
|
||||
{
|
||||
qstate = NQUOTE;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *field;
|
||||
}
|
||||
else if (qstate == NQUOTE && *field == *dstring)
|
||||
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 if ((flags & F_SHELLQUOTE) && *prev == '\'')
|
||||
{
|
||||
if (xbuf == 0)
|
||||
xbuf = xmalloc (strlen (prev) + 1);
|
||||
buf = xbuf;
|
||||
b = 0;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *prev;
|
||||
qstate = SQUOTE;
|
||||
for (field = ++prev; *field; field++)
|
||||
{
|
||||
if (qstate == SQUOTE && *field == '\'')
|
||||
{
|
||||
qstate = NQUOTE;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *field;
|
||||
}
|
||||
else if (qstate == NQUOTE && *field == *dstring)
|
||||
break;
|
||||
else
|
||||
/* This copies any text between a closing single quote and the
|
||||
delimiter. If you want to change that, make sure to do the
|
||||
copy only if qstate == SQUOTE. */
|
||||
buf[b++] = *field;
|
||||
}
|
||||
buf[b] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = prev;
|
||||
field = prev + strcspn (prev, dstring);
|
||||
}
|
||||
|
||||
delim = *field;
|
||||
*field = '\0';
|
||||
|
||||
if ((flags & F_GREEDY) == 0 || buf[0])
|
||||
{
|
||||
bind_array_element (dsv, ind, buf, 0);
|
||||
ind++;
|
||||
}
|
||||
|
||||
*field = delim;
|
||||
|
||||
if (delim == *dstring)
|
||||
prev = field + 1;
|
||||
}
|
||||
while (delim == *dstring);
|
||||
|
||||
if (xbuf)
|
||||
free (xbuf);
|
||||
|
||||
return (rval = ind); /* number of fields */
|
||||
}
|
||||
|
||||
int
|
||||
dsv_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, rval, flags;
|
||||
char *array_name, *dsvstring, *delims;
|
||||
SHELL_VAR *v;
|
||||
|
||||
array_name = 0;
|
||||
rval = EXECUTION_SUCCESS;
|
||||
|
||||
delims = ",";
|
||||
flags = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "a:d:Sgp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
array_name = list_optarg;
|
||||
break;
|
||||
case 'd':
|
||||
delims = list_optarg;
|
||||
break;
|
||||
case 'S':
|
||||
flags |= F_SHELLQUOTE;
|
||||
break;
|
||||
case 'g':
|
||||
flags |= F_GREEDY;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= F_PRESERVE;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (array_name == 0)
|
||||
array_name = DSV_ARRAY_DEFAULT;
|
||||
|
||||
if (legal_identifier (array_name) == 0)
|
||||
{
|
||||
sh_invalidid (array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_error ("dsv 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));
|
||||
|
||||
dsvstring = list->word->word;
|
||||
|
||||
if (dsvstring == 0 || *dsvstring == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
opt = dsvsplit (v, dsvstring, delims, flags);
|
||||
/* 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
|
||||
dsv_builtin_load (name)
|
||||
char *name;
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Called when builtin is disabled. */
|
||||
void
|
||||
dsv_builtin_unload (name)
|
||||
char *name;
|
||||
{
|
||||
}
|
||||
|
||||
char *dsv_doc[] = {
|
||||
"Read delimiter-separated fields from STRING.",
|
||||
"",
|
||||
"Parse STRING, a line of delimiter-separated values, into individual",
|
||||
"fields, and store them into the indexed array ARRAYNAME starting at",
|
||||
"index 0. The parsing understands and skips over double-quoted strings. ",
|
||||
"If ARRAYNAME is not supplied, \"DSV\" is the default array name.",
|
||||
"If the delimiter is a comma, the default, this parses comma-",
|
||||
"separated values as specified in RFC 4180.",
|
||||
"",
|
||||
"The -d option specifies the delimiter. The delimiter is the first",
|
||||
"character of the DELIMS argument. Specifying a DELIMS argument that",
|
||||
"contains more than one character is not supported and will produce",
|
||||
"unexpected results. The -S option enables shell-like quoting: double-",
|
||||
"quoted strings can contain backslashes preceding special characters,",
|
||||
"and the backslash will be removed; and single-quoted strings are",
|
||||
"processed as the shell would process them. The -g option enables a",
|
||||
"greedy split: sequences of the delimiter are skipped at the beginning",
|
||||
"and end of STRING, and consecutive instances of the delimiter in STRING",
|
||||
"do not generate empty fields. If the -p option is supplied, dsv leaves",
|
||||
"quote characters as part of the generated field; otherwise they are",
|
||||
"removed.",
|
||||
"",
|
||||
"The return value is 0 unless an invalid option is supplied or the ARRAYNAME",
|
||||
"argument is invalid or readonly.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin dsv_struct = {
|
||||
"dsv", /* builtin name */
|
||||
dsv_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
dsv_doc, /* array of long documentation strings. */
|
||||
"dsv [-a ARRAYNAME] [-d DELIMS] [-Sgp] string", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
374
examples/loadables/fdflags.c
Normal file
374
examples/loadables/fdflags.c
Normal file
|
@ -0,0 +1,374 @@
|
|||
/* Loadable builtin to get and set file descriptor flags. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2017-2022 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"
|
||||
|
||||
#ifndef FD_CLOEXEC
|
||||
# define FD_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *name;
|
||||
int value;
|
||||
} file_flags[] =
|
||||
{
|
||||
#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 unused 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
|
||||
};
|
||||
|
||||
#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 */
|
||||
};
|
629
examples/loadables/finfo.c
Normal file
629
examples/loadables/finfo.c
Normal file
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* finfo - print file info
|
||||
*
|
||||
* Chet Ramey
|
||||
* chet@po.cwru.edu
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#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>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include "posixtime.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "common.h"
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char **make_builtin_argv ();
|
||||
|
||||
static void perms();
|
||||
static int printst();
|
||||
static int printsome();
|
||||
static void printmode();
|
||||
static int printfinfo();
|
||||
static int finfo_main();
|
||||
|
||||
extern int sh_optind;
|
||||
extern char *sh_optarg;
|
||||
extern char *this_command_name;
|
||||
|
||||
static char *prog;
|
||||
static int pmask;
|
||||
|
||||
#define OPT_UID 0x00001
|
||||
#define OPT_GID 0x00002
|
||||
#define OPT_DEV 0x00004
|
||||
#define OPT_INO 0x00008
|
||||
#define OPT_PERM 0x00010
|
||||
#define OPT_LNKNAM 0x00020
|
||||
#define OPT_FID 0x00040
|
||||
#define OPT_NLINK 0x00080
|
||||
#define OPT_RDEV 0x00100
|
||||
#define OPT_SIZE 0x00200
|
||||
#define OPT_ATIME 0x00400
|
||||
#define OPT_MTIME 0x00800
|
||||
#define OPT_CTIME 0x01000
|
||||
#define OPT_BLKSIZE 0x02000
|
||||
#define OPT_BLKS 0x04000
|
||||
#define OPT_FTYPE 0x08000
|
||||
#define OPT_PMASK 0x10000
|
||||
#define OPT_OPERM 0x20000
|
||||
|
||||
#define OPT_ASCII 0x1000000
|
||||
|
||||
#define OPTIONS "acdgiflmnopsuACGMP:U"
|
||||
|
||||
static int
|
||||
octal(s)
|
||||
char *s;
|
||||
{
|
||||
int r;
|
||||
|
||||
r = *s - '0';
|
||||
while (*++s >= '0' && *s <= '7')
|
||||
r = (r * 8) + (*s - '0');
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
finfo_main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
int mode, flags, opt;
|
||||
|
||||
sh_optind = 0; /* XXX */
|
||||
prog = base_pathname(argv[0]);
|
||||
if (argc == 1) {
|
||||
builtin_usage();
|
||||
return(1);
|
||||
}
|
||||
flags = 0;
|
||||
while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) {
|
||||
switch(opt) {
|
||||
case 'a': flags |= OPT_ATIME; break;
|
||||
case 'A': flags |= OPT_ATIME|OPT_ASCII; break;
|
||||
case 'c': flags |= OPT_CTIME; break;
|
||||
case 'C': flags |= OPT_CTIME|OPT_ASCII; break;
|
||||
case 'd': flags |= OPT_DEV; break;
|
||||
case 'i': flags |= OPT_INO; break;
|
||||
case 'f': flags |= OPT_FID; break;
|
||||
case 'g': flags |= OPT_GID; break;
|
||||
case 'G': flags |= OPT_GID|OPT_ASCII; break;
|
||||
case 'l': flags |= OPT_LNKNAM; break;
|
||||
case 'm': flags |= OPT_MTIME; break;
|
||||
case 'M': flags |= OPT_MTIME|OPT_ASCII; break;
|
||||
case 'n': flags |= OPT_NLINK; break;
|
||||
case 'o': flags |= OPT_OPERM; break;
|
||||
case 'p': flags |= OPT_PERM; break;
|
||||
case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break;
|
||||
case 's': flags |= OPT_SIZE; break;
|
||||
case 'u': flags |= OPT_UID; break;
|
||||
case 'U': flags |= OPT_UID|OPT_ASCII; break;
|
||||
default: builtin_usage (); return(1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= sh_optind;
|
||||
argv += sh_optind;
|
||||
|
||||
if (argc == 0) {
|
||||
builtin_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]);
|
||||
|
||||
return(opt);
|
||||
}
|
||||
|
||||
static struct stat *
|
||||
getstat(f)
|
||||
char *f;
|
||||
{
|
||||
static struct stat st;
|
||||
int fd, r;
|
||||
intmax_t lfd;
|
||||
|
||||
if (strncmp(f, "/dev/fd/", 8) == 0) {
|
||||
if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) {
|
||||
builtin_error("%s: invalid fd", f + 8);
|
||||
return ((struct stat *)0);
|
||||
}
|
||||
fd = lfd;
|
||||
r = fstat(fd, &st);
|
||||
} else
|
||||
#ifdef HAVE_LSTAT
|
||||
r = lstat(f, &st);
|
||||
#else
|
||||
r = stat(f, &st);
|
||||
#endif
|
||||
if (r < 0) {
|
||||
builtin_error("%s: cannot stat: %s", f, strerror(errno));
|
||||
return ((struct stat *)0);
|
||||
}
|
||||
return (&st);
|
||||
}
|
||||
|
||||
static int
|
||||
printfinfo(f)
|
||||
char *f;
|
||||
{
|
||||
struct stat *st;
|
||||
|
||||
st = getstat(f);
|
||||
return (st ? printst(st) : 1);
|
||||
}
|
||||
|
||||
static int
|
||||
getperm(m)
|
||||
int m;
|
||||
{
|
||||
return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID));
|
||||
}
|
||||
|
||||
static void
|
||||
perms(m)
|
||||
int m;
|
||||
{
|
||||
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
if (m & S_IRUSR)
|
||||
ubits[i++] = 'r';
|
||||
if (m & S_IWUSR)
|
||||
ubits[i++] = 'w';
|
||||
if (m & S_IXUSR)
|
||||
ubits[i++] = 'x';
|
||||
ubits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if (m & S_IRGRP)
|
||||
gbits[i++] = 'r';
|
||||
if (m & S_IWGRP)
|
||||
gbits[i++] = 'w';
|
||||
if (m & S_IXGRP)
|
||||
gbits[i++] = 'x';
|
||||
gbits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if (m & S_IROTH)
|
||||
obits[i++] = 'r';
|
||||
if (m & S_IWOTH)
|
||||
obits[i++] = 'w';
|
||||
if (m & S_IXOTH)
|
||||
obits[i++] = 'x';
|
||||
obits[i] = '\0';
|
||||
|
||||
if (m & S_ISUID)
|
||||
ubits[2] = (m & S_IXUSR) ? 's' : 'S';
|
||||
if (m & S_ISGID)
|
||||
gbits[2] = (m & S_IXGRP) ? 's' : 'S';
|
||||
if (m & S_ISVTX)
|
||||
obits[2] = (m & S_IXOTH) ? 't' : 'T';
|
||||
|
||||
printf ("u=%s,g=%s,o=%s", ubits, gbits, obits);
|
||||
}
|
||||
|
||||
static void
|
||||
printmode(mode)
|
||||
int mode;
|
||||
{
|
||||
if (S_ISBLK(mode))
|
||||
printf("S_IFBLK ");
|
||||
if (S_ISCHR(mode))
|
||||
printf("S_IFCHR ");
|
||||
if (S_ISDIR(mode))
|
||||
printf("S_IFDIR ");
|
||||
if (S_ISREG(mode))
|
||||
printf("S_IFREG ");
|
||||
if (S_ISFIFO(mode))
|
||||
printf("S_IFIFO ");
|
||||
if (S_ISLNK(mode))
|
||||
printf("S_IFLNK ");
|
||||
if (S_ISSOCK(mode))
|
||||
printf("S_IFSOCK ");
|
||||
#ifdef S_ISWHT
|
||||
if (S_ISWHT(mode))
|
||||
printf("S_ISWHT ");
|
||||
#endif
|
||||
perms(getperm(mode));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
printst(st)
|
||||
struct stat *st;
|
||||
{
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
char *owner;
|
||||
int ma, mi, d;
|
||||
|
||||
ma = major (st->st_rdev);
|
||||
mi = minor (st->st_rdev);
|
||||
#if defined (makedev)
|
||||
d = makedev (ma, mi);
|
||||
#else
|
||||
d = st->st_rdev & 0xFF;
|
||||
#endif
|
||||
printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi);
|
||||
|
||||
printf("Inode: %d\n", (int) st->st_ino);
|
||||
printf("Mode: (%o) ", (int) st->st_mode);
|
||||
printmode((int) st->st_mode);
|
||||
printf("Link count: %d\n", (int) st->st_nlink);
|
||||
pw = getpwuid(st->st_uid);
|
||||
owner = pw ? pw->pw_name : "unknown";
|
||||
printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner);
|
||||
gr = getgrgid(st->st_gid);
|
||||
owner = gr ? gr->gr_name : "unknown";
|
||||
printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner);
|
||||
printf("Device type: %d\n", (int) st->st_rdev);
|
||||
printf("File size: %ld\n", (long) st->st_size);
|
||||
printf("File last access time: %s", ctime (&st->st_atime));
|
||||
printf("File last modify time: %s", ctime (&st->st_mtime));
|
||||
printf("File last status change time: %s", ctime (&st->st_ctime));
|
||||
fflush(stdout);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
printsome(f, flags)
|
||||
char *f;
|
||||
int flags;
|
||||
{
|
||||
struct stat *st;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
int p;
|
||||
char *b;
|
||||
|
||||
st = getstat(f);
|
||||
if (st == NULL)
|
||||
return (1);
|
||||
|
||||
/* Print requested info */
|
||||
if (flags & OPT_ATIME) {
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s", ctime(&st->st_atime));
|
||||
else
|
||||
printf("%ld\n", st->st_atime);
|
||||
} else if (flags & OPT_MTIME) {
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s", ctime(&st->st_mtime));
|
||||
else
|
||||
printf("%ld\n", st->st_mtime);
|
||||
} else if (flags & OPT_CTIME) {
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s", ctime(&st->st_ctime));
|
||||
else
|
||||
printf("%ld\n", st->st_ctime);
|
||||
} else if (flags & OPT_DEV)
|
||||
printf("%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("%lu:%lu\n", (unsigned long)st->st_dev, (unsigned long)st->st_ino);
|
||||
else if (flags & OPT_NLINK)
|
||||
printf("%lu\n", (unsigned long)st->st_nlink);
|
||||
else if (flags & OPT_LNKNAM) {
|
||||
#ifdef S_ISLNK
|
||||
b = xmalloc(4096);
|
||||
p = readlink(f, b, 4096);
|
||||
if (p >= 0 && p < 4096)
|
||||
b[p] = '\0';
|
||||
else {
|
||||
p = errno;
|
||||
strcpy(b, prog);
|
||||
strcat(b, ": ");
|
||||
strcat(b, strerror(p));
|
||||
}
|
||||
printf("%s\n", b);
|
||||
free(b);
|
||||
#else
|
||||
printf("%s\n", f);
|
||||
#endif
|
||||
} else if (flags & OPT_PERM) {
|
||||
perms(st->st_mode);
|
||||
printf("\n");
|
||||
} else if (flags & OPT_OPERM)
|
||||
printf("%o\n", getperm(st->st_mode));
|
||||
else if (flags & OPT_PMASK)
|
||||
printf("%o\n", getperm(st->st_mode) & pmask);
|
||||
else if (flags & OPT_UID) {
|
||||
pw = getpwuid(st->st_uid);
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s\n", pw ? pw->pw_name : "unknown");
|
||||
else
|
||||
printf("%d\n", st->st_uid);
|
||||
} else if (flags & OPT_GID) {
|
||||
gr = getgrgid(st->st_gid);
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s\n", gr ? gr->gr_name : "unknown");
|
||||
else
|
||||
printf("%d\n", st->st_gid);
|
||||
} else if (flags & OPT_SIZE)
|
||||
printf("%ld\n", (long) st->st_size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifndef NOBUILTIN
|
||||
int
|
||||
finfo_builtin(list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int c, r;
|
||||
char **v;
|
||||
WORD_LIST *l;
|
||||
|
||||
v = make_builtin_argv (list, &c);
|
||||
r = finfo_main (c, v);
|
||||
free (v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *finfo_doc[] = {
|
||||
"Display information about file attributes.",
|
||||
"",
|
||||
"Display information about each FILE. Only single operators should",
|
||||
"be supplied. If no options are supplied, a summary of the info",
|
||||
"available about each FILE is printed. If FILE is of the form",
|
||||
"/dev/fd/XX, file descriptor XX is described. Operators, if supplied,",
|
||||
"have the following meanings:",
|
||||
"",
|
||||
" -a last file access time",
|
||||
" -A last file access time in ctime format",
|
||||
" -c last file status change time",
|
||||
" -C last file status change time in ctime format",
|
||||
" -m last file modification time",
|
||||
" -M last file modification time in ctime format",
|
||||
" -d device",
|
||||
" -i inode",
|
||||
" -f composite file identifier (device:inode)",
|
||||
" -g gid of owner",
|
||||
" -G group name of owner",
|
||||
" -l name of file pointed to by symlink",
|
||||
" -n link count",
|
||||
" -o permissions in octal",
|
||||
" -p permissions in ascii",
|
||||
" -P mask permissions ANDed with MASK (like with umask)",
|
||||
" -s file size in bytes",
|
||||
" -u uid of owner",
|
||||
" -U user name of owner",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin finfo_struct = {
|
||||
"finfo",
|
||||
finfo_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
finfo_doc,
|
||||
"finfo [-acdgiflmnopsuACGMPU] file [file...]",
|
||||
0
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NOBUILTIN
|
||||
#if defined (PREFER_STDARG)
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# if defined (PREFER_VARARGS)
|
||||
# include <varargs.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
char *this_command_name;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
this_command_name = argv[0];
|
||||
exit(finfo_main(argc, argv));
|
||||
}
|
||||
|
||||
void
|
||||
builtin_usage()
|
||||
{
|
||||
fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, prog, OPTIONS);
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
char *
|
||||
strerror(e)
|
||||
int e;
|
||||
{
|
||||
static char ebuf[40];
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
|
||||
if (e < 0 || e > sys_nerr) {
|
||||
sprintf(ebuf,"Unknown error code %d", e);
|
||||
return (&ebuf[0]);
|
||||
}
|
||||
return (sys_errlist[e]);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
xmalloc(s)
|
||||
size_t s;
|
||||
{
|
||||
char *ret;
|
||||
extern char *malloc();
|
||||
|
||||
ret = malloc(s);
|
||||
if (ret)
|
||||
return (ret);
|
||||
fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *
|
||||
base_pathname(p)
|
||||
char *p;
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (t = strrchr(p, '/'))
|
||||
return(++t);
|
||||
return(p);
|
||||
}
|
||||
|
||||
int
|
||||
legal_number (string, result)
|
||||
char *string;
|
||||
long *result;
|
||||
{
|
||||
int sign;
|
||||
long value;
|
||||
|
||||
sign = 1;
|
||||
value = 0;
|
||||
|
||||
if (result)
|
||||
*result = 0;
|
||||
|
||||
/* Skip leading whitespace characters. */
|
||||
while (whitespace (*string))
|
||||
string++;
|
||||
|
||||
if (!*string)
|
||||
return (0);
|
||||
|
||||
/* We allow leading `-' or `+'. */
|
||||
if (*string == '-' || *string == '+')
|
||||
{
|
||||
if (!digit (string[1]))
|
||||
return (0);
|
||||
|
||||
if (*string == '-')
|
||||
sign = -1;
|
||||
|
||||
string++;
|
||||
}
|
||||
|
||||
while (digit (*string))
|
||||
{
|
||||
if (result)
|
||||
value = (value * 10) + digit_value (*string);
|
||||
string++;
|
||||
}
|
||||
|
||||
/* Skip trailing whitespace, if any. */
|
||||
while (whitespace (*string))
|
||||
string++;
|
||||
|
||||
/* Error if not at end of string. */
|
||||
if (*string)
|
||||
return (0);
|
||||
|
||||
if (result)
|
||||
*result = value * sign;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int sh_optind;
|
||||
char *sh_optarg;
|
||||
int sh_opterr;
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
int
|
||||
sh_getopt(c, v, o)
|
||||
int c;
|
||||
char **v, *o;
|
||||
{
|
||||
int r;
|
||||
|
||||
r = getopt(c, v, o);
|
||||
sh_optind = optind;
|
||||
sh_optarg = optarg;
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined (USE_VARARGS)
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
builtin_error (const char *format, ...)
|
||||
#else
|
||||
builtin_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
#if defined (PREFER_STDARG)
|
||||
va_start (args, format);
|
||||
#else
|
||||
va_start (args);
|
||||
#endif
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
#else
|
||||
void
|
||||
builtin_error (format, arg1, arg2, arg3, arg4, arg5)
|
||||
char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
|
||||
{
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
#endif /* !USE_VARARGS */
|
||||
|
||||
#endif
|
1163
examples/loadables/getconf.c
Normal file
1163
examples/loadables/getconf.c
Normal file
File diff suppressed because it is too large
Load diff
136
examples/loadables/getconf.h
Normal file
136
examples/loadables/getconf.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
Copyright (C) 2021 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/>.
|
||||
*/
|
||||
/* getconf.h -- replacement definitions for ones the system doesn't provide
|
||||
and don't appear in <typemax.h> */
|
||||
|
||||
#ifndef _GETCONF_H
|
||||
#define _GETCONF_H
|
||||
|
||||
/* Some systems do not define these; use POSIX.2 minimum recommended values. */
|
||||
#ifndef _POSIX2_COLL_WEIGHTS_MAX
|
||||
# define _POSIX2_COLL_WEIGHTS_MAX 2
|
||||
#endif
|
||||
|
||||
/* If we're on a posix system, but the system doesn't define the necessary
|
||||
constants, use posix.1 minimum values. */
|
||||
#if defined (_POSIX_VERSION)
|
||||
|
||||
#ifndef _POSIX_ARG_MAX
|
||||
# define _POSIX_ARG_MAX 4096
|
||||
#endif
|
||||
#ifndef _POSIX_CHILD_MAX
|
||||
# define _POSIX_CHILD_MAX 6
|
||||
#endif
|
||||
#ifndef _POSIX_LINK_MAX
|
||||
# define _POSIX_LINK_MAX 8
|
||||
#endif
|
||||
#ifndef _POSIX_MAX_CANON
|
||||
# define _POSIX_MAX_CANON 255
|
||||
#endif
|
||||
#ifndef _POSIX_MAX_INPUT
|
||||
# define _POSIX_MAX_INPUT 255
|
||||
#endif
|
||||
#ifndef _POSIX_NAME_MAX
|
||||
# define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
#ifndef _POSIX_NGROUPS_MAX
|
||||
# define _POSIX_NGROUPS_MAX 0
|
||||
#endif
|
||||
#ifndef _POSIX_OPEN_MAX
|
||||
# define _POSIX_OPEN_MAX 16
|
||||
#endif
|
||||
#ifndef _POSIX_PATH_MAX
|
||||
# define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
#ifndef _POSIX_PIPE_BUF
|
||||
# define _POSIX_PIPE_BUF 512
|
||||
#endif
|
||||
#ifndef _POSIX_SSIZE_MAX
|
||||
# define _POSIX_SSIZE_MAX 32767
|
||||
#endif
|
||||
#ifndef _POSIX_STREAM_MAX
|
||||
# define _POSIX_STREAM_MAX 8
|
||||
#endif
|
||||
#ifndef _POSIX_TZNAME_MAX
|
||||
# define _POSIX_TZNAME_MAX 3
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX2_BC_BASE_MAX
|
||||
# define _POSIX2_BC_BASE_MAX 99
|
||||
#endif
|
||||
#ifndef _POSIX2_BC_DIM_MAX
|
||||
# define _POSIX2_BC_DIM_MAX 2048
|
||||
#endif
|
||||
#ifndef _POSIX2_BC_SCALE_MAX
|
||||
# define _POSIX2_BC_SCALE_MAX 99
|
||||
#endif
|
||||
#ifndef _POSIX2_BC_STRING_MAX
|
||||
# define _POSIX2_BC_STRING_MAX 1000
|
||||
#endif
|
||||
#ifndef _POSIX2_EQUIV_CLASS_MAX
|
||||
# define _POSIX2_EQUIV_CLASS_MAX 2
|
||||
#endif
|
||||
#ifndef _POSIX2_EXPR_NEST_MAX
|
||||
# define _POSIX2_EXPR_NEST_MAX 32
|
||||
#endif
|
||||
#ifndef _POSIX2_LINE_MAX
|
||||
# define _POSIX2_LINE_MAX 2048
|
||||
#endif
|
||||
#ifndef _POSIX2_RE_DUP_MAX
|
||||
# define _POSIX2_RE_DUP_MAX 255
|
||||
#endif
|
||||
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
/* ANSI/ISO C, POSIX.1-200x, XPG 4.2, and C language type limits.
|
||||
Defined only if the system include files and <typemax.h> don't. */
|
||||
|
||||
#ifndef CHAR_MAX
|
||||
# define CHAR_MAX 127
|
||||
#endif
|
||||
#ifndef CHAR_MIN
|
||||
# define CHAR_MIN -128
|
||||
#endif
|
||||
#ifndef SCHAR_MAX
|
||||
# define SCHAR_MAX 127
|
||||
#endif
|
||||
#ifndef SCHAR_MIN
|
||||
# define SCHAR_MIN -128
|
||||
#endif
|
||||
|
||||
#ifndef INT_BIT
|
||||
# define INT_BIT (sizeof (int) * CHAR_BIT)
|
||||
#endif
|
||||
|
||||
#ifndef LONG_BIT
|
||||
# define LONG_BIT (sizeof (long int) * CHAR_BIT)
|
||||
#endif
|
||||
|
||||
#ifndef WORD_BIT
|
||||
# define WORD_BIT (sizeof (int) * CHAR_BIT)
|
||||
#endif
|
||||
|
||||
#if !defined (PRIdMAX)
|
||||
# if HAVE_LONG_LONG
|
||||
# define PRIdMAX "lld"
|
||||
# else
|
||||
# define PRIdMAX "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _GETCONF_H */
|
170
examples/loadables/head.c
Normal file
170
examples/loadables/head.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/* head - copy first part of files. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "filecntl.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static void
|
||||
munge_list (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *l, *nl;
|
||||
WORD_DESC *wd;
|
||||
char *arg;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
arg = l->word->word;
|
||||
if (arg[0] != '-' || arg[1] == '-' || (DIGIT(arg[1]) == 0))
|
||||
return;
|
||||
/* We have -[0-9]* */
|
||||
wd = make_bare_word (arg+1);
|
||||
nl = make_word_list (wd, l->next);
|
||||
l->word->word[1] = 'n';
|
||||
l->word->word[2] = '\0';
|
||||
l->next = nl;
|
||||
l = nl; /* skip over new argument */
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
file_head (fp, cnt)
|
||||
FILE *fp;
|
||||
int cnt;
|
||||
{
|
||||
int ch;
|
||||
|
||||
while (cnt--)
|
||||
{
|
||||
while ((ch = getc (fp)) != EOF)
|
||||
{
|
||||
QUIT;
|
||||
if (putchar (ch) == EOF)
|
||||
{
|
||||
builtin_error ("write error: %s", strerror (errno));
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
QUIT;
|
||||
if (ch == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
head_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int nline, opt, rval;
|
||||
WORD_LIST *l;
|
||||
FILE *fp;
|
||||
|
||||
char *t;
|
||||
|
||||
munge_list (list); /* change -num into -n num */
|
||||
|
||||
reset_internal_getopt ();
|
||||
nline = 10;
|
||||
while ((opt = internal_getopt (list, "n:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
nline = atoi (list_optarg);
|
||||
if (nline <= 0)
|
||||
{
|
||||
builtin_error ("bad line count: %s", list_optarg);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
return (file_head (stdin, nline));
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, opt = 1, l = list; l; l = l->next)
|
||||
{
|
||||
fp = fopen (l->word->word, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
builtin_error ("%s: %s", l->word->word, strerror (errno));
|
||||
continue;
|
||||
}
|
||||
if (list->next) /* more than one file */
|
||||
{
|
||||
printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word);
|
||||
opt = 0;
|
||||
}
|
||||
QUIT;
|
||||
rval = file_head (fp, nline);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
char *head_doc[] = {
|
||||
"Display lines from beginning of file.",
|
||||
"",
|
||||
"Copy the first N lines from the input files to the standard output.",
|
||||
"N is supplied as an argument to the `-n' option. If N is not given,",
|
||||
"the first ten lines are copied.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin head_struct = {
|
||||
"head", /* builtin name */
|
||||
head_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
head_doc, /* array of long documentation strings. */
|
||||
"head [-n num] [file ...]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
96
examples/loadables/hello.c
Normal file
96
examples/loadables/hello.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* Sample builtin to be dynamically loaded with enable -f and create a new
|
||||
builtin. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "loadables.h"
|
||||
|
||||
/* A builtin `xxx' is normally implemented with an `xxx_builtin' function.
|
||||
If you're converting a command that uses the normal Unix argc/argv
|
||||
calling convention, use argv = make_builtin_argv (list, &argc) and call
|
||||
the original `main' something like `xxx_main'. Look at cat.c for an
|
||||
example.
|
||||
|
||||
Builtins should use internal_getopt to parse options. It is the same as
|
||||
getopt(3), but it takes a WORD_LIST *. Look at print.c for an example
|
||||
of its use.
|
||||
|
||||
If the builtin takes no options, call no_options(list) before doing
|
||||
anything else. If it returns a non-zero value, your builtin should
|
||||
immediately return EX_USAGE. Look at logname.c for an example.
|
||||
|
||||
A builtin command returns EXECUTION_SUCCESS for success and
|
||||
EXECUTION_FAILURE to indicate failure. */
|
||||
int
|
||||
hello_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
printf("hello world\n");
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
hello_builtin_load (s)
|
||||
char *s;
|
||||
{
|
||||
printf ("hello builtin loaded\n");
|
||||
fflush (stdout);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
hello_builtin_unload (s)
|
||||
char *s;
|
||||
{
|
||||
printf ("hello builtin unloaded\n");
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
/* 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 *hello_doc[] = {
|
||||
"Sample builtin.",
|
||||
"",
|
||||
"this is the long doc for the sample hello builtin",
|
||||
(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 hello_struct = {
|
||||
"hello", /* builtin name */
|
||||
hello_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
hello_doc, /* array of long documentation strings. */
|
||||
"hello", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
329
examples/loadables/id.c
Normal file
329
examples/loadables/id.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* id - POSIX.2 user identity
|
||||
*
|
||||
* (INCOMPLETE -- supplementary groups for other users not yet done)
|
||||
*
|
||||
* usage: id [-Ggu] [-nr] [user]
|
||||
*
|
||||
* The default output format looks something like:
|
||||
* uid=xxx(chet) gid=xx groups=aa(aname), bb(bname), cc(cname)
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "bashtypes.h"
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include "bashansi.h"
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#else
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_GETPW_DECLS)
|
||||
extern struct passwd *getpwuid ();
|
||||
#endif
|
||||
extern struct group *getgrgid ();
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "stdc.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#define ID_ALLGROUPS 0x001 /* -G */
|
||||
#define ID_GIDONLY 0x002 /* -g */
|
||||
#define ID_USENAME 0x004 /* -n */
|
||||
#define ID_USEREAL 0x008 /* -r */
|
||||
#define ID_USERONLY 0x010 /* -u */
|
||||
|
||||
#define ID_FLAGSET(s) ((id_flags & (s)) != 0)
|
||||
|
||||
static int id_flags;
|
||||
|
||||
static uid_t ruid, euid;
|
||||
static gid_t rgid, egid;
|
||||
|
||||
static char *id_user;
|
||||
|
||||
static int inituser ();
|
||||
|
||||
static int id_pruser ();
|
||||
static int id_prgrp ();
|
||||
static int id_prgroups ();
|
||||
static int id_prall ();
|
||||
|
||||
int
|
||||
id_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt;
|
||||
char *user;
|
||||
|
||||
id_flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "Ggnru")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'G': id_flags |= ID_ALLGROUPS; break;
|
||||
case 'g': id_flags |= ID_GIDONLY; break;
|
||||
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);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
user = list ? list->word->word : (char *)NULL;
|
||||
|
||||
/* Check for some invalid option combinations */
|
||||
opt = ID_FLAGSET (ID_ALLGROUPS) + ID_FLAGSET (ID_GIDONLY) + ID_FLAGSET (ID_USERONLY);
|
||||
if (opt > 1 || (opt == 0 && ((id_flags & (ID_USEREAL|ID_USENAME)) != 0)))
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (list && list->next)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (inituser (user) < 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
opt = 0;
|
||||
if (id_flags & ID_USERONLY)
|
||||
opt += id_pruser ((id_flags & ID_USEREAL) ? ruid : euid);
|
||||
else if (id_flags & ID_GIDONLY)
|
||||
opt += id_prgrp ((id_flags & ID_USEREAL) ? rgid : egid);
|
||||
else if (id_flags & ID_ALLGROUPS)
|
||||
opt += id_prgroups (user);
|
||||
else
|
||||
opt += id_prall (user);
|
||||
putchar ('\n');
|
||||
fflush (stdout);
|
||||
|
||||
return (opt == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
static int
|
||||
inituser (uname)
|
||||
char *uname;
|
||||
{
|
||||
struct passwd *pwd;
|
||||
|
||||
if (uname)
|
||||
{
|
||||
pwd = getpwnam (uname);
|
||||
if (pwd == 0)
|
||||
{
|
||||
builtin_error ("%s: no such user", uname);
|
||||
return -1;
|
||||
}
|
||||
ruid = euid = pwd->pw_uid;
|
||||
rgid = egid = pwd->pw_gid;
|
||||
}
|
||||
else
|
||||
{
|
||||
ruid = current_user.uid;
|
||||
euid = current_user.euid;
|
||||
rgid = current_user.gid;
|
||||
egid = current_user.egid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print the name or value of user ID UID. */
|
||||
static int
|
||||
id_pruser (uid)
|
||||
int uid;
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
int r;
|
||||
|
||||
r = 0;
|
||||
if (id_flags & ID_USENAME)
|
||||
{
|
||||
pwd = getpwuid (uid);
|
||||
if (pwd == NULL)
|
||||
r = 1;
|
||||
}
|
||||
if (pwd)
|
||||
printf ("%s", pwd->pw_name);
|
||||
else
|
||||
printf ("%u", (unsigned) uid);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Print the name or value of group ID GID. */
|
||||
|
||||
static int
|
||||
id_prgrp (gid)
|
||||
int gid;
|
||||
{
|
||||
struct group *grp = NULL;
|
||||
int r;
|
||||
|
||||
r = 0;
|
||||
if (id_flags & ID_USENAME)
|
||||
{
|
||||
grp = getgrgid (gid);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (grp)
|
||||
printf ("%s", grp->gr_name);
|
||||
else
|
||||
printf ("%u", (unsigned) gid);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
id_prgroups (uname)
|
||||
char *uname;
|
||||
{
|
||||
int *glist, ng, i, r;
|
||||
|
||||
r = 0;
|
||||
id_prgrp (rgid);
|
||||
if (egid != rgid)
|
||||
{
|
||||
putchar (' ');
|
||||
id_prgrp (egid);
|
||||
}
|
||||
|
||||
if (uname)
|
||||
{
|
||||
builtin_error ("supplementary groups for other users not yet implemented");
|
||||
glist = (int *)NULL;
|
||||
ng = 0;
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
glist = get_group_array (&ng);
|
||||
|
||||
for (i = 0; i < ng; i++)
|
||||
if (glist[i] != rgid && glist[i] != egid)
|
||||
{
|
||||
putchar (' ');
|
||||
id_prgrp (glist[i]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
id_prall (uname)
|
||||
char *uname;
|
||||
{
|
||||
int r, i, ng, *glist;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
|
||||
r = 0;
|
||||
printf ("uid=%u", (unsigned) ruid);
|
||||
pwd = getpwuid (ruid);
|
||||
if (pwd == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", pwd->pw_name);
|
||||
|
||||
printf (" gid=%u", (unsigned) rgid);
|
||||
grp = getgrgid (rgid);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
|
||||
if (euid != ruid)
|
||||
{
|
||||
printf (" euid=%u", (unsigned) euid);
|
||||
pwd = getpwuid (euid);
|
||||
if (pwd == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", pwd->pw_name);
|
||||
}
|
||||
|
||||
if (egid != rgid)
|
||||
{
|
||||
printf (" egid=%u", (unsigned) egid);
|
||||
grp = getgrgid (egid);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
}
|
||||
|
||||
if (uname)
|
||||
{
|
||||
builtin_error ("supplementary groups for other users not yet implemented");
|
||||
glist = (int *)NULL;
|
||||
ng = 0;
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
glist = get_group_array (&ng);
|
||||
|
||||
if (ng > 0)
|
||||
printf (" groups=");
|
||||
for (i = 0; i < ng; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
printf (", ");
|
||||
printf ("%u", (unsigned) glist[i]);
|
||||
grp = getgrgid (glist[i]);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *id_doc[] = {
|
||||
"Display information about user."
|
||||
"",
|
||||
"Return information about user identity",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin id_struct = {
|
||||
"id",
|
||||
id_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
id_doc,
|
||||
"id [user]\n\tid -G [-n] [user]\n\tid -g [-nr] [user]\n\tid -u [-nr] [user]",
|
||||
0
|
||||
};
|
236
examples/loadables/ln.c
Normal file
236
examples/loadables/ln.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
/* ln - make links */
|
||||
|
||||
/* 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"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
typedef int unix_link_syscall_t PARAMS((const char *, const char *));
|
||||
|
||||
#define LN_SYMLINK 0x01
|
||||
#define LN_UNLINK 0x02
|
||||
#define LN_NOFOLLOW 0x04
|
||||
|
||||
static unix_link_syscall_t *linkfn;
|
||||
static int dolink ();
|
||||
|
||||
int
|
||||
ln_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int rval, opt, flags;
|
||||
WORD_LIST *l;
|
||||
char *sdir;
|
||||
struct stat sb;
|
||||
|
||||
flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
flags |= LN_UNLINK;
|
||||
break;
|
||||
case 's':
|
||||
flags |= LN_SYMLINK;
|
||||
break;
|
||||
case 'h':
|
||||
case 'n':
|
||||
flags |= LN_NOFOLLOW;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
linkfn = (flags & LN_SYMLINK) ? symlink : link;
|
||||
|
||||
if (list->next == 0) /* ln target, equivalent to ln target . */
|
||||
return (dolink (list->word->word, ".", flags));
|
||||
|
||||
if (list->next->next == 0) /* ln target source */
|
||||
return (dolink (list->word->word, list->next->word->word, flags));
|
||||
|
||||
/* ln target1 target2 ... directory */
|
||||
|
||||
/* find last argument: target directory, and make sure it's an existing
|
||||
directory. */
|
||||
for (l = list; l->next; l = l->next)
|
||||
;
|
||||
sdir = l->word->word;
|
||||
|
||||
if (stat(sdir, &sb) < 0)
|
||||
{
|
||||
builtin_error ("%s", sdir);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (S_ISDIR (sb.st_mode) == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
for (rval = EXECUTION_SUCCESS; list != l; list = list->next)
|
||||
rval += dolink (list->word->word, sdir, flags);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static char *
|
||||
mkdirpath (dir, file)
|
||||
char *dir, *file;
|
||||
{
|
||||
int dlen, flen;
|
||||
char *ret;
|
||||
|
||||
dlen = strlen (dir);
|
||||
flen = strlen (file);
|
||||
|
||||
ret = xmalloc (2 + dlen + flen);
|
||||
|
||||
strcpy (ret, dir);
|
||||
if (ret[dlen - 1] != '/')
|
||||
ret[dlen++] = '/';
|
||||
strcpy (ret + dlen, file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined (HAVE_LSTAT)
|
||||
# define LSTAT lstat
|
||||
# define LSTAT_OR_STAT_IF(c, f, b) ((c) ? lstat((f), (b)) : stat((f), (b)))
|
||||
#else
|
||||
# define LSTAT stat
|
||||
# define LSTAT_OR_STAT_IF(c, f, b) (stat((f), (b)))
|
||||
#endif
|
||||
|
||||
static int
|
||||
dolink (src, dst, flags)
|
||||
char *src, *dst;
|
||||
int flags;
|
||||
{
|
||||
struct stat ssb, dsb;
|
||||
int exists;
|
||||
char *dst_path, *p;
|
||||
|
||||
/* If we're not doing symlinks, the source must exist and not be a
|
||||
directory. */
|
||||
if ((flags & LN_SYMLINK) == 0)
|
||||
{
|
||||
if (stat (src, &ssb) != 0)
|
||||
{
|
||||
builtin_error ("%s: %s", src, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (S_ISDIR (ssb.st_mode))
|
||||
{
|
||||
errno = EISDIR;
|
||||
builtin_error ("%s: %s", src, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the destination is a directory, create the final filename by appending
|
||||
the basename of the source to the destination. */
|
||||
dst_path = 0;
|
||||
if ((LSTAT_OR_STAT_IF((flags & LN_NOFOLLOW), dst, &dsb) == 0) && S_ISDIR (dsb.st_mode))
|
||||
{
|
||||
if ((p = strrchr (src, '/')) == 0)
|
||||
p = src;
|
||||
else
|
||||
p++;
|
||||
|
||||
dst_path = mkdirpath (dst, p);
|
||||
dst = dst_path;
|
||||
}
|
||||
|
||||
exists = LSTAT (dst, &dsb) == 0;
|
||||
|
||||
/* If -f was specified, and the destination exists, unlink it. */
|
||||
if ((flags & LN_UNLINK) && exists && unlink (dst) != 0)
|
||||
{
|
||||
builtin_error ("%s: cannot unlink: %s", dst, strerror (errno));
|
||||
FREE (dst_path);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Perform the link. */
|
||||
if ((*linkfn) (src, dst) != 0)
|
||||
{
|
||||
builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno));
|
||||
FREE (dst_path);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
FREE (dst_path);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *ln_doc[] = {
|
||||
"Link files.",
|
||||
"",
|
||||
"Create a new directory entry with the same modes as the original",
|
||||
"file. The -f option means to unlink any existing file, permitting",
|
||||
"the link to occur. The -s option means to create a symbolic link.",
|
||||
"By default, ln makes hard links. Specifying -n or its synonym -h",
|
||||
"causes ln to not resolve symlinks in the target file or directory.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin ln_struct = {
|
||||
"ln", /* builtin name */
|
||||
ln_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
ln_doc, /* array of long documentation strings. */
|
||||
"ln [-fhns] file1 [file2] OR ln [-fhns] file ... directory", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
34
examples/loadables/loadables.h
Normal file
34
examples/loadables/loadables.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* loadables.h -- Include files needed by all loadable builtins */
|
||||
|
||||
/* Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LOADABLES_H_
|
||||
#define __LOADABLES_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#endif
|
74
examples/loadables/logname.c
Normal file
74
examples/loadables/logname.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* logname - print login name of current user */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
logname_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *np;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
|
||||
np = getlogin ();
|
||||
if (np == 0)
|
||||
{
|
||||
builtin_error ("cannot find username: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
printf ("%s\n", np);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *logname_doc[] = {
|
||||
"Display user login name.",
|
||||
"",
|
||||
"Write the current user's login name to the standard output",
|
||||
"and exit. logname ignores the LOGNAME and USER variables.",
|
||||
"logname ignores any non-option arguments.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin logname_struct = {
|
||||
"logname",
|
||||
logname_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
logname_doc,
|
||||
"logname",
|
||||
0
|
||||
};
|
||||
|
245
examples/loadables/mkdir.c
Normal file
245
examples/loadables/mkdir.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* mkdir - make directories */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 make_path ();
|
||||
|
||||
static int original_umask;
|
||||
|
||||
int
|
||||
mkdir_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, pflag, mflag, omode, rval, nmode, parent_mode;
|
||||
char *mode;
|
||||
WORD_LIST *l;
|
||||
|
||||
reset_internal_getopt ();
|
||||
pflag = mflag = 0;
|
||||
mode = (char *)NULL;
|
||||
while ((opt = internal_getopt(list, "m:p")) != -1)
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
if (mode == NULL)
|
||||
omode = S_IRWXU | S_IRWXG | S_IRWXO; /* a=rwx */
|
||||
else if (ISOCTAL (*mode)) /* octal number */
|
||||
{
|
||||
omode = read_octal (mode);
|
||||
if (omode < 0)
|
||||
{
|
||||
builtin_error ("invalid file mode: %s", mode);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else /* symbolic mode */
|
||||
{
|
||||
/* initial bits are a=rwx; the mode argument modifies them */
|
||||
omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (omode < 0)
|
||||
{
|
||||
builtin_error ("invalid file mode: %s", mode);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the new mode */
|
||||
original_umask = umask (0);
|
||||
umask (original_umask);
|
||||
|
||||
nmode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask;
|
||||
parent_mode = nmode | (S_IWUSR|S_IXUSR); /* u+wx */
|
||||
|
||||
/* Adjust new mode based on mode argument */
|
||||
nmode &= omode;
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
||||
{
|
||||
if (pflag && make_path (l->word->word, mflag, nmode, parent_mode))
|
||||
{
|
||||
rval = EXECUTION_FAILURE;
|
||||
continue;
|
||||
}
|
||||
else if (pflag == 0 && mkdir (l->word->word, nmode) < 0)
|
||||
{
|
||||
builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Make all the directories leading up to PATH, then create PATH. Note that
|
||||
this changes the process's umask; make sure that all paths leading to a
|
||||
return reset it to ORIGINAL_UMASK */
|
||||
static int
|
||||
make_path (path, user_mode, nmode, parent_mode)
|
||||
char *path;
|
||||
int user_mode;
|
||||
int nmode, parent_mode;
|
||||
{
|
||||
int oumask;
|
||||
struct stat sb;
|
||||
char *p, *npath;
|
||||
|
||||
if (stat (path, &sb) == 0)
|
||||
{
|
||||
if (S_ISDIR (sb.st_mode) == 0)
|
||||
{
|
||||
builtin_error ("`%s': file exists but is not a directory", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (user_mode && chmod (path, nmode))
|
||||
{
|
||||
builtin_error ("%s: %s", path, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
oumask = umask (0);
|
||||
npath = savestring (path); /* So we can write to it. */
|
||||
|
||||
/* Check whether or not we need to do anything with intermediate dirs. */
|
||||
|
||||
/* Skip leading slashes. */
|
||||
p = npath;
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
while (p = strchr (p, '/'))
|
||||
{
|
||||
*p = '\0';
|
||||
if (stat (npath, &sb) != 0)
|
||||
{
|
||||
if (mkdir (npath, 0))
|
||||
{
|
||||
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
if (chmod (npath, parent_mode) != 0)
|
||||
{
|
||||
builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno));
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (S_ISDIR (sb.st_mode) == 0)
|
||||
{
|
||||
builtin_error ("`%s': file exists but is not a directory", npath);
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*p++ = '/'; /* restore slash */
|
||||
while (*p == '/')
|
||||
p++;
|
||||
}
|
||||
|
||||
/* Create the final directory component. */
|
||||
if (stat (npath, &sb) && mkdir (npath, nmode))
|
||||
{
|
||||
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *mkdir_doc[] = {
|
||||
"Create directories.",
|
||||
"",
|
||||
"Make directories. Create the directories named as arguments, in",
|
||||
"the order specified, using mode rwxrwxrwx as modified by the current",
|
||||
"umask (see `help umask'). The -m option causes the file permission",
|
||||
"bits of the final directory to be MODE. The MODE argument may be",
|
||||
"an octal number or a symbolic mode like that used by chmod(1). If",
|
||||
"a symbolic mode is used, the operations are interpreted relative to",
|
||||
"an initial mode of \"a=rwx\". The -p option causes any required",
|
||||
"intermediate directories in PATH to be created. The directories",
|
||||
"are created with permission bits of rwxrwxrwx as modified by the current",
|
||||
"umask, plus write and search permissions for the owner. mkdir",
|
||||
"returns 0 if the directories are created successfully, and non-zero",
|
||||
"if an error occurs.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin mkdir_struct = {
|
||||
"mkdir",
|
||||
mkdir_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
mkdir_doc,
|
||||
"mkdir [-p] [-m mode] directory [directory ...]",
|
||||
0
|
||||
};
|
146
examples/loadables/mkfifo.c
Normal file
146
examples/loadables/mkfifo.c
Normal file
|
@ -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
|
||||
};
|
212
examples/loadables/mktemp.c
Normal file
212
examples/loadables/mktemp.c
Normal file
|
@ -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 */
|
||||
};
|
89
examples/loadables/mypid.c
Normal file
89
examples/loadables/mypid.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* This module should be dynamically loaded with enable -f
|
||||
* which would create a new builtin named mypid. You'll need
|
||||
* the source code for GNU bash to recompile this module.
|
||||
*
|
||||
* Then, from within bash, enable -f ./mypid enable_mypid, where ./mypid
|
||||
* is the binary obtained from running make. Hereafter, `${MYPID}'
|
||||
* is a shell builtin variable.
|
||||
*
|
||||
* This defines an unload hook function that is called when the builtin is
|
||||
* deleted with enable -d that will unbind the MYPID variable so future
|
||||
* references to it do not attempt to access memory that is no longer part
|
||||
* of this process's address space.
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
|
||||
#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
|
||||
do \
|
||||
{ SHELL_VAR *v = bind_variable (var, (val), 0); \
|
||||
if (v) \
|
||||
{ \
|
||||
v->dynamic_value = gfunc; \
|
||||
v->assign_func = afunc; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static SHELL_VAR *
|
||||
assign_mypid (
|
||||
SHELL_VAR *self,
|
||||
char *value,
|
||||
arrayind_t unused,
|
||||
char *key )
|
||||
{
|
||||
return (self);
|
||||
}
|
||||
|
||||
static SHELL_VAR *
|
||||
get_mypid (SHELL_VAR *var)
|
||||
{
|
||||
int rv;
|
||||
char *p;
|
||||
|
||||
rv = getpid();
|
||||
p = itos (rv);
|
||||
|
||||
FREE (value_cell (var));
|
||||
|
||||
VSETATTR (var, att_integer);
|
||||
var_setvalue (var, p);
|
||||
return (var);
|
||||
}
|
||||
|
||||
int
|
||||
enable_mypid_builtin(WORD_LIST *list)
|
||||
{
|
||||
INIT_DYNAMIC_VAR ("MYPID", (char *)NULL, get_mypid, assign_mypid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
enable_mypid_builtin_unload (char *s)
|
||||
{
|
||||
unbind_variable ("MYPID");
|
||||
}
|
||||
|
||||
char const *enable_mypid_doc[] = {
|
||||
"Enable $MYPID.",
|
||||
"",
|
||||
"Enables use of the ${MYPID} dynamic variable. ",
|
||||
"It will yield the current pid of a subshell.",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin enable_mypid_struct = {
|
||||
"enable_mypid",
|
||||
enable_mypid_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
(char**)(void*)enable_mypid_doc,
|
||||
"enable_mypid N",
|
||||
0
|
||||
};
|
54
examples/loadables/necho.c
Normal file
54
examples/loadables/necho.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* necho - echo without options or argument interpretation */
|
||||
|
||||
/* Sample builtin to be dynamically loaded with enable -f and replace an
|
||||
existing builtin. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
|
||||
int
|
||||
necho_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
print_word_list (list, " ");
|
||||
printf("\n");
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *necho_doc[] = {
|
||||
"Display arguments.",
|
||||
"",
|
||||
"Print the arguments to the standard output separated",
|
||||
"by space characters and terminated with a newline.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin necho_struct = {
|
||||
"echo",
|
||||
necho_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
necho_doc,
|
||||
"echo [args]",
|
||||
0
|
||||
};
|
||||
|
381
examples/loadables/pathchk.c
Normal file
381
examples/loadables/pathchk.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/* pathchk - check pathnames for validity and portability */
|
||||
|
||||
/* Usage: pathchk [-p] path ...
|
||||
|
||||
For each PATH, print a message if any of these conditions are false:
|
||||
* all existing leading directories in PATH have search (execute) permission
|
||||
* strlen (PATH) <= PATH_MAX
|
||||
* strlen (each_directory_in_PATH) <= NAME_MAX
|
||||
|
||||
Exit status:
|
||||
0 All PATH names passed all of the tests.
|
||||
1 An error occurred.
|
||||
|
||||
Options:
|
||||
-p Instead of performing length checks on the
|
||||
underlying filesystem, test the length of the
|
||||
pathname and its components against the POSIX.1
|
||||
minimum limits for portability, _POSIX_NAME_MAX
|
||||
and _POSIX_PATH_MAX in 2.9.2. Also check that
|
||||
the pathname contains no character not in the
|
||||
portable filename character set. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <sys/types.h>
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "stdc.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if !defined (_POSIX_PATH_MAX)
|
||||
# define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
#if !defined (_POSIX_NAME_MAX)
|
||||
# define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
|
||||
/* How do we get PATH_MAX? */
|
||||
#if defined (_POSIX_VERSION) && !defined (PATH_MAX)
|
||||
# define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
|
||||
#endif
|
||||
|
||||
/* How do we get NAME_MAX? */
|
||||
#if defined (_POSIX_VERSION) && !defined (NAME_MAX)
|
||||
# define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX)
|
||||
#endif
|
||||
|
||||
#if !defined (PATH_MAX_FOR)
|
||||
# define PATH_MAX_FOR(p) PATH_MAX
|
||||
#endif
|
||||
|
||||
#if !defined (NAME_MAX_FOR)
|
||||
# define NAME_MAX_FOR(p) NAME_MAX
|
||||
#endif
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
static int validate_path ();
|
||||
|
||||
int
|
||||
pathchk_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int retval, pflag, opt;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "p")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
for (retval = 0; list; list = list->next)
|
||||
retval |= validate_path (list->word->word, pflag);
|
||||
|
||||
return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *pathchk_doc[] = {
|
||||
"Check pathnames for validity.",
|
||||
"",
|
||||
"Check each pathname argument for validity (i.e., it may be used to",
|
||||
"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
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin pathchk_struct = {
|
||||
"pathchk", /* builtin name */
|
||||
pathchk_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
pathchk_doc, /* array of long documentation strings. */
|
||||
"pathchk [-p] pathname ...", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
||||
|
||||
/* The remainder of this file is stolen shamelessly from `pathchk.c' in
|
||||
the sh-utils-1.12 distribution, by
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu>
|
||||
and Jim Meyering <meyering@cs.utexas.edu> */
|
||||
|
||||
/* Each element is nonzero if the corresponding ASCII character is
|
||||
in the POSIX portable character set, and zero if it is not.
|
||||
In addition, the entry for `/' is nonzero to simplify checking. */
|
||||
static char const portable_chars[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* If PATH contains only portable characters, return 1, else 0. */
|
||||
|
||||
static int
|
||||
portable_chars_only (path)
|
||||
const char *path;
|
||||
{
|
||||
const char *p;
|
||||
|
||||
for (p = path; *p; ++p)
|
||||
if (portable_chars[(const unsigned char) *p] == 0)
|
||||
{
|
||||
builtin_error ("path `%s' contains nonportable character `%c'", path, *p);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* On some systems, stat can return EINTR. */
|
||||
|
||||
#ifndef EINTR
|
||||
# define SAFE_STAT(name, buf) stat (name, buf)
|
||||
#else
|
||||
# define SAFE_STAT(name, buf) safe_stat (name, buf)
|
||||
static inline int
|
||||
safe_stat (name, buf)
|
||||
const char *name;
|
||||
struct stat *buf;
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
ret = stat (name, buf);
|
||||
while (ret < 0 && errno == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if PATH is a usable leading directory, 0 if not,
|
||||
2 if it doesn't exist. */
|
||||
|
||||
static int
|
||||
dir_ok (path)
|
||||
const char *path;
|
||||
{
|
||||
struct stat stats;
|
||||
|
||||
if (SAFE_STAT (path, &stats))
|
||||
return 2;
|
||||
|
||||
if (!S_ISDIR (stats.st_mode))
|
||||
{
|
||||
builtin_error ("`%s' is not a directory", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use access to test for search permission because
|
||||
testing permission bits of st_mode can lose with new
|
||||
access control mechanisms. Of course, access loses if you're
|
||||
running setuid. */
|
||||
if (access (path, X_OK) != 0)
|
||||
{
|
||||
if (errno == EACCES)
|
||||
builtin_error ("directory `%s' is not searchable", path);
|
||||
else
|
||||
builtin_error ("%s: %s", path, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
xstrdup (s)
|
||||
char *s;
|
||||
{
|
||||
return (savestring (s));
|
||||
}
|
||||
|
||||
/* Make sure that
|
||||
strlen (PATH) <= PATH_MAX
|
||||
&& strlen (each-existing-directory-in-PATH) <= NAME_MAX
|
||||
|
||||
If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
|
||||
_POSIX_NAME_MAX instead, and make sure that PATH contains no
|
||||
characters not in the POSIX portable filename character set, which
|
||||
consists of A-Z, a-z, 0-9, ., _, -.
|
||||
|
||||
Make sure that all leading directories along PATH that exist have
|
||||
`x' permission.
|
||||
|
||||
Return 0 if all of these tests are successful, 1 if any fail. */
|
||||
|
||||
static int
|
||||
validate_path (path, portability)
|
||||
char *path;
|
||||
int portability;
|
||||
{
|
||||
int path_max;
|
||||
int last_elem; /* Nonzero if checking last element of path. */
|
||||
int exists; /* 2 if the path element exists. */
|
||||
char *slash;
|
||||
char *parent; /* Last existing leading directory so far. */
|
||||
|
||||
if (portability && !portable_chars_only (path))
|
||||
return 1;
|
||||
|
||||
if (*path == '\0')
|
||||
return 0;
|
||||
|
||||
#ifdef lint
|
||||
/* Suppress `used before initialized' warning. */
|
||||
exists = 0;
|
||||
#endif
|
||||
|
||||
/* Figure out the parent of the first element in PATH. */
|
||||
parent = xstrdup (*path == '/' ? "/" : ".");
|
||||
|
||||
slash = path;
|
||||
last_elem = 0;
|
||||
while (1)
|
||||
{
|
||||
int name_max;
|
||||
int length; /* Length of partial path being checked. */
|
||||
char *start; /* Start of path element being checked. */
|
||||
|
||||
/* Find the end of this element of the path.
|
||||
Then chop off the rest of the path after this element. */
|
||||
while (*slash == '/')
|
||||
slash++;
|
||||
start = slash;
|
||||
slash = strchr (slash, '/');
|
||||
if (slash != NULL)
|
||||
*slash = '\0';
|
||||
else
|
||||
{
|
||||
last_elem = 1;
|
||||
slash = strchr (start, '\0');
|
||||
}
|
||||
|
||||
if (!last_elem)
|
||||
{
|
||||
exists = dir_ok (path);
|
||||
if (exists == 0)
|
||||
{
|
||||
free (parent);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
length = slash - start;
|
||||
/* Since we know that `parent' is a directory, it's ok to call
|
||||
pathconf with it as the argument. (If `parent' isn't a directory
|
||||
or doesn't exist, the behavior of pathconf is undefined.)
|
||||
But if `parent' is a directory and is on a remote file system,
|
||||
it's likely that pathconf can't give us a reasonable value
|
||||
and will return -1. (NFS and tempfs are not POSIX . . .)
|
||||
In that case, we have no choice but to assume the pessimal
|
||||
POSIX minimums. */
|
||||
name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
|
||||
if (name_max < 0)
|
||||
name_max = _POSIX_NAME_MAX;
|
||||
if (length > name_max)
|
||||
{
|
||||
builtin_error ("name `%s' has length %d; exceeds limit of %d",
|
||||
start, length, name_max);
|
||||
free (parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (last_elem)
|
||||
break;
|
||||
|
||||
if (exists == 1)
|
||||
{
|
||||
free (parent);
|
||||
parent = xstrdup (path);
|
||||
}
|
||||
|
||||
*slash++ = '/';
|
||||
}
|
||||
|
||||
/* `parent' is now the last existing leading directory in the whole path,
|
||||
so it's ok to call pathconf with it as the argument. */
|
||||
path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
|
||||
if (path_max < 0)
|
||||
path_max = _POSIX_PATH_MAX;
|
||||
free (parent);
|
||||
if (strlen (path) > path_max)
|
||||
{
|
||||
builtin_error ("path `%s' has length %lu; exceeds limit of %d",
|
||||
path, (unsigned long)strlen (path), path_max);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
99
examples/loadables/perl/Makefile.in
Normal file
99
examples/loadables/perl/Makefile.in
Normal file
|
@ -0,0 +1,99 @@
|
|||
#
|
||||
# Makefile for builtin perl interpreter
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1998 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
PERL5 = perl5
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
# Values used for compiling the perl files
|
||||
PERL_LDOPTS = `${PERL5} -MExtUtils::Embed -e ldopts`
|
||||
PERL_CFLAGS = ${CCFLAGS} `${PERL5} -MExtUtils::Embed -e ccopts`
|
||||
|
||||
SRC = bperl.c iperl.c perlxsi.c
|
||||
OBJ = bperl.o iperl.o perlxsi.o
|
||||
|
||||
BUILTIN = bperl5
|
||||
|
||||
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
|
||||
-I$(topdir)/include -I$(BUILD_DIR) -I$(BUILD_DIR)/lib \
|
||||
-I$(BUILD_DIR)/builtins
|
||||
|
||||
|
||||
${BUILTIN}: ${OBJ}
|
||||
${RM} $@
|
||||
${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o $@ ${OBJ} ${PERL_LDOPTS} ${SHOBJ_LIBS}
|
||||
|
||||
bperl.o: bperl.c
|
||||
${RM} $@
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ ${srcdir}/bperl.c
|
||||
|
||||
iperl.o: iperl.c
|
||||
${RM} $@
|
||||
$(SHOBJ_CC) ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ ${srcdir}/iperl.c
|
||||
|
||||
perlxsi.c:
|
||||
${PERL5} -MExtUtils::Embed -e xsinit -- -o $@
|
||||
|
||||
perlxsi.o: perlxsi.c
|
||||
${RM} $@
|
||||
${SHOBJ_CC} ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ perlxsi.c
|
||||
|
||||
clean mostlyclean:
|
||||
${RM} ${OBJ}
|
||||
${RM} ${BUILTIN}
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
${RM} perlxsi.c
|
6
examples/loadables/perl/README
Normal file
6
examples/loadables/perl/README
Normal file
|
@ -0,0 +1,6 @@
|
|||
This illustrates how to build a perl interpreter into bash. It's not
|
||||
especially useful; more a proof of concept (it provides none of the
|
||||
bash internals to the perl interpreter, for example).
|
||||
|
||||
This *may* require adding "-rpath /path/to/perl/CORE" and -lperl options
|
||||
when compiling bash itself.
|
53
examples/loadables/perl/bperl.c
Normal file
53
examples/loadables/perl/bperl.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* perl builtin
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char **make_builtin_argv (WORD_LIST *, int *);
|
||||
extern char **export_env;
|
||||
|
||||
extern void perl_close(void);
|
||||
extern int perl_main(int, char **, char **);
|
||||
|
||||
int
|
||||
bperl_builtin(WORD_LIST *list)
|
||||
{
|
||||
char **v;
|
||||
int c, r;
|
||||
|
||||
v = make_builtin_argv(list, &c);
|
||||
r = perl_main(c, v, export_env);
|
||||
free(v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
bperl_builtin_unload (char *s)
|
||||
{
|
||||
perl_close();
|
||||
}
|
||||
|
||||
char *bperl_doc[] = {
|
||||
"An interface to a perl5 interpreter.",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin bperl_struct = {
|
||||
"bperl",
|
||||
bperl_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
bperl_doc,
|
||||
"bperl [perl options] [file ...]",
|
||||
0
|
||||
};
|
38
examples/loadables/perl/iperl.c
Normal file
38
examples/loadables/perl/iperl.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <EXTERN.h> /* from the Perl distribution */
|
||||
#include <perl.h> /* from the Perl distribution */
|
||||
|
||||
#define iperl my_perl /* I guess the name `my_perl' is required */
|
||||
|
||||
extern void xs_init (pTHX);
|
||||
|
||||
static PerlInterpreter *iperl; /*** The Perl interpreter ***/
|
||||
|
||||
static int first = 1;
|
||||
|
||||
void
|
||||
perl_close (void)
|
||||
{
|
||||
PERL_SYS_TERM();
|
||||
}
|
||||
|
||||
int
|
||||
perl_main(int argc, char **argv, char **env)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (first) {
|
||||
first = 0;
|
||||
PERL_SYS_INIT3(&argc, &argv, &env);
|
||||
}
|
||||
iperl = perl_alloc();
|
||||
perl_construct(iperl);
|
||||
perl_parse(iperl, xs_init, argc, argv, (char **)NULL);
|
||||
r = perl_run(iperl);
|
||||
|
||||
PerlIO_flush(PerlIO_stdout());
|
||||
PerlIO_flush(PerlIO_stderr());
|
||||
|
||||
perl_destruct(iperl);
|
||||
perl_free(iperl);
|
||||
return (r);
|
||||
}
|
193
examples/loadables/print.c
Normal file
193
examples/loadables/print.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* print -- loadable ksh-93 style print builtin
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "stdc.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "builtext.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int print_builtin ();
|
||||
static int printargs ();
|
||||
|
||||
static FILE *ofp;
|
||||
|
||||
extern char *this_command_name;
|
||||
|
||||
static char *print_doc[] = {
|
||||
"Display arguments.",
|
||||
"",
|
||||
"Output the arguments. The -f option means to use the argument as a",
|
||||
"format string as would be supplied to printf(1). The rest of the",
|
||||
"options are as in ksh.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin print_struct = {
|
||||
"print",
|
||||
print_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
print_doc,
|
||||
"print [-Rnprs] [-u unit] [-f format] [arguments]",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
#ifndef ISOPTION
|
||||
#define ISOPTION(s, c) (s[0] == '-' && s[2] == '\0' && s[1] == c)
|
||||
#endif
|
||||
|
||||
int
|
||||
print_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int c, r, nflag, raw, ofd, sflag;
|
||||
intmax_t lfd;
|
||||
char **v, *pfmt, *arg;
|
||||
WORD_LIST *l;
|
||||
|
||||
nflag = raw = sflag = 0;
|
||||
ofd = 1;
|
||||
pfmt = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((c = internal_getopt (list, "Rnprsu:f:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'R':
|
||||
raw = 2;
|
||||
loptend = lcurrent;
|
||||
if (loptend && ISOPTION (loptend->word->word, 'n'))
|
||||
{
|
||||
loptend = loptend->next;
|
||||
nflag = 1;
|
||||
}
|
||||
goto opt_end;
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
case 'p':
|
||||
break; /* NOP */
|
||||
case 'u':
|
||||
if (all_digits (list_optarg) && legal_number (list_optarg, &lfd) && lfd == (int)lfd)
|
||||
ofd = lfd;
|
||||
else
|
||||
{
|
||||
for (l = list; l->next && l->next != lcurrent; l = l->next);
|
||||
lcurrent = loptend = l;
|
||||
goto opt_end;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
pfmt = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
opt_end:
|
||||
list = loptend;
|
||||
|
||||
ofp = (ofd == 1) ? stdout : fdopen (dup (ofd), "w");
|
||||
|
||||
if (pfmt)
|
||||
{
|
||||
WORD_DESC *w;
|
||||
WORD_LIST *nlist;
|
||||
|
||||
w = make_word (pfmt);
|
||||
nlist = make_word_list (w, list);
|
||||
r = printf_builtin (nlist);
|
||||
nlist->next = (WORD_LIST *)NULL;
|
||||
dispose_words (nlist);
|
||||
return (r);
|
||||
}
|
||||
|
||||
if (raw)
|
||||
{
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
fprintf (ofp, "%s", l->word->word);
|
||||
if (l->next)
|
||||
fprintf (ofp, " ");
|
||||
}
|
||||
if (nflag == 0)
|
||||
fprintf (ofp, "\n");
|
||||
fflush (ofp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
r = printargs (list, ofp);
|
||||
if (r && nflag == 0)
|
||||
fprintf (ofp, "\n");
|
||||
if (ofd != 1)
|
||||
fclose (ofp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
printargs (list, ofp)
|
||||
WORD_LIST *list;
|
||||
FILE *ofp;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
char *ostr;
|
||||
int sawc;
|
||||
|
||||
for (sawc = 0, l = list; l; l = l->next)
|
||||
{
|
||||
ostr = ansicstr (l->word->word, strlen (l->word->word), 0, &sawc, (int *)0);
|
||||
if (ostr)
|
||||
fprintf (ofp, "%s", ostr);
|
||||
free (ostr);
|
||||
if (sawc)
|
||||
return (0);
|
||||
if (l->next)
|
||||
fprintf (ofp, " ");
|
||||
}
|
||||
return (1);
|
||||
}
|
94
examples/loadables/printenv.c
Normal file
94
examples/loadables/printenv.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* printenv -- minimal builtin clone of BSD printenv(1).
|
||||
*
|
||||
* usage: printenv [varname]
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
extern char **export_env;
|
||||
|
||||
int
|
||||
printenv_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char **envp;
|
||||
int opt;
|
||||
SHELL_VAR *var;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* printenv */
|
||||
if (list == 0)
|
||||
{
|
||||
maybe_make_export_env (); /* this allows minimal code */
|
||||
for (envp = export_env; *envp; envp++)
|
||||
printf ("%s\n", *envp);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* printenv varname */
|
||||
var = find_variable (list->word->word);
|
||||
if (var == 0 || (exported_p (var) == 0))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (function_p (var))
|
||||
print_var_function (var);
|
||||
else
|
||||
print_var_value (var, 0);
|
||||
|
||||
printf("\n");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *printenv_doc[] = {
|
||||
"Display environment.",
|
||||
"",
|
||||
"Print names and values of environment variables",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin printenv_struct = {
|
||||
"printenv",
|
||||
printenv_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
printenv_doc,
|
||||
"printenv [varname]",
|
||||
0
|
||||
};
|
117
examples/loadables/push.c
Normal file
117
examples/loadables/push.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* push - anyone remember TOPS-20?
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
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 <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "jobs.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern pid_t dollar_dollar_pid;
|
||||
extern int last_command_exit_value;
|
||||
|
||||
int
|
||||
push_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
pid_t pid;
|
||||
int xstatus, opt;
|
||||
|
||||
xstatus = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
pid = make_child (savestring ("push"), 0);
|
||||
if (pid == -1)
|
||||
{
|
||||
builtin_error ("cannot fork: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* Shell variable adjustments: $SHLVL, $$, $PPID, $! */
|
||||
adjust_shell_level (1);
|
||||
dollar_dollar_pid = getpid ();
|
||||
set_ppid ();
|
||||
|
||||
/* Clean up job control stuff. */
|
||||
stop_making_children ();
|
||||
cleanup_the_pipeline ();
|
||||
delete_all_jobs (0);
|
||||
|
||||
last_asynchronous_pid = NO_PID;
|
||||
|
||||
/* Make sure the job control code has the right values for
|
||||
the shell's process group and tty process group, and that
|
||||
the signals are set correctly for job control. */
|
||||
initialize_job_control (0);
|
||||
initialize_job_signals ();
|
||||
|
||||
/* And read commands until exit. */
|
||||
reader_loop ();
|
||||
exit_shell (last_command_exit_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
stop_pipeline (0, (COMMAND *)NULL);
|
||||
xstatus = wait_for (pid, 0);
|
||||
return (xstatus);
|
||||
}
|
||||
}
|
||||
|
||||
char *push_doc[] = {
|
||||
"Create child shell.",
|
||||
"",
|
||||
"Create a child that is an exact duplicate of the running shell",
|
||||
"and wait for it to exit. The $SHLVL, $!, $$, and $PPID variables",
|
||||
"are adjusted in the child. The return value is the exit status",
|
||||
"of the child.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin push_struct = {
|
||||
"push",
|
||||
push_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
push_doc,
|
||||
"push",
|
||||
0
|
||||
};
|
207
examples/loadables/realpath.c
Normal file
207
examples/loadables/realpath.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* realpath -- canonicalize pathnames, resolving symlinks
|
||||
*
|
||||
* usage: realpath [-cqsv] [-a name] pathname [pathname...]
|
||||
*
|
||||
* options: -a name assign each canonicalized pathname to indexed array
|
||||
* variable NAME
|
||||
* -c check whether or not each resolved path exists
|
||||
* -q no output, exit status determines whether path is valid
|
||||
* -s strip . and .. from the pathname only, no symlink resolution
|
||||
* -v produce verbose output
|
||||
*
|
||||
*
|
||||
* exit status: 0 if all pathnames resolved
|
||||
* 1 if any of the pathname arguments could not be resolved
|
||||
*
|
||||
*
|
||||
* Bash loadable builtin version
|
||||
*
|
||||
* Chet Ramey
|
||||
* chet@po.cwru.edu
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009,2021,2022 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "bashansi.h"
|
||||
#include <maxpath.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char *sh_realpath();
|
||||
|
||||
int
|
||||
realpath_builtin(WORD_LIST *list)
|
||||
{
|
||||
int opt, cflag, vflag, qflag, sflag, aflag, es;
|
||||
char *r, realbuf[PATH_MAX], *p, *newpath;
|
||||
struct stat sb;
|
||||
#if defined (ARRAY_VARS)
|
||||
arrayind_t ind;
|
||||
char *aname;
|
||||
SHELL_VAR *v;
|
||||
#endif
|
||||
|
||||
if (list == 0) {
|
||||
builtin_usage();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
vflag = cflag = qflag = aflag = sflag = 0;
|
||||
#if defined (ARRAY_VARS)
|
||||
aname = NULL;
|
||||
v = NULL;
|
||||
ind = 0;
|
||||
#endif
|
||||
reset_internal_getopt();
|
||||
while ((opt = internal_getopt (list, "a:cqsv")) != -1) {
|
||||
switch (opt) {
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
aname = list_optarg;
|
||||
break;
|
||||
#endif
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (list == 0) {
|
||||
builtin_usage();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (aflag && legal_identifier (aname) == 0) {
|
||||
sh_invalidid(aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (aname && builtin_unbind_variable (aname) == -2)
|
||||
return (EXECUTION_FAILURE);
|
||||
if (aname) {
|
||||
v = find_or_make_array_variable (aname, 1);
|
||||
if (v == 0 || readonly_p (v) || noassign_p (v)) {
|
||||
if (v && readonly_p (v))
|
||||
err_readonly (aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
} else if (array_p (v) == 0) {
|
||||
builtin_error ("%s: not an indexed array", aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (invisible_p (v))
|
||||
VUNSETATTR (v, att_invisible);
|
||||
array_flush (array_cell (v));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (es = EXECUTION_SUCCESS; list; list = list->next) {
|
||||
p = list->word->word;
|
||||
if (sflag) {
|
||||
/* sh_canonpath doesn't convert to absolute pathnames */
|
||||
newpath = make_absolute(p, get_string_value("PWD"));
|
||||
r = sh_canonpath(newpath, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
free(newpath);
|
||||
} else
|
||||
r = sh_realpath(p, realbuf);
|
||||
if (r == 0) {
|
||||
es = EXECUTION_FAILURE;
|
||||
if (qflag == 0)
|
||||
builtin_error("%s: cannot resolve: %s", p, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (cflag && (stat(r, &sb) < 0)) {
|
||||
es = EXECUTION_FAILURE;
|
||||
if (qflag == 0)
|
||||
builtin_error("%s: %s", p, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (aflag) {
|
||||
bind_array_element (v, ind, r, 0);
|
||||
ind++;
|
||||
}
|
||||
if (qflag == 0) {
|
||||
if (vflag)
|
||||
printf ("%s -> ", p);
|
||||
printf("%s\n", r);
|
||||
}
|
||||
if (sflag)
|
||||
free (r);
|
||||
}
|
||||
return es;
|
||||
}
|
||||
|
||||
char *realpath_doc[] = {
|
||||
"Display pathname in canonical form.",
|
||||
"",
|
||||
"Display the canonicalized version of each PATHNAME argument, resolving",
|
||||
"symbolic links.",
|
||||
"The -a option stores each canonicalized PATHNAME argument into the indexed",
|
||||
"array VARNAME.",
|
||||
"The -c option checks whether or not each resolved name exists.",
|
||||
"The -q option produces no output; the exit status determines the",
|
||||
"validity of each PATHNAME, but any array assignment is still performed.",
|
||||
"If the -s option is supplied, canonicalize . and .. pathname components",
|
||||
"without resolving symbolic links.",
|
||||
"The -v option produces verbose output.",
|
||||
"The exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin realpath_struct = {
|
||||
"realpath", /* builtin name */
|
||||
realpath_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
realpath_doc, /* array of long documentation strings */
|
||||
"realpath [-a varname] [-cqsv] pathname [pathname...]", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
185
examples/loadables/rm.c
Normal file
185
examples/loadables/rm.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/* 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
|
||||
|
||||
QUIT;
|
||||
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
|
||||
QUIT;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
QUIT;
|
||||
/* 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)
|
||||
{
|
||||
if (force == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
QUIT;
|
||||
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 */
|
||||
};
|
72
examples/loadables/rmdir.c
Normal file
72
examples/loadables/rmdir.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* rmdir - remove directory */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
rmdir_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int rval;
|
||||
WORD_LIST *l;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
||||
if (rmdir (l->word->word) < 0)
|
||||
{
|
||||
builtin_error ("%s: %s", l->word->word, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
char *rmdir_doc[] = {
|
||||
"Remove directory.",
|
||||
"",
|
||||
"rmdir removes the directory entry specified by each argument,",
|
||||
"provided the directory is empty.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin rmdir_struct = {
|
||||
"rmdir", /* builtin name */
|
||||
rmdir_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
rmdir_doc, /* array of long documentation strings. */
|
||||
"rmdir directory ...", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
502
examples/loadables/seq.c
Normal file
502
examples/loadables/seq.c
Normal file
|
@ -0,0 +1,502 @@
|
|||
/* seq - print sequence of numbers to standard output.
|
||||
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
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written as bash builtin by Chet Ramey. Portions from seq.c by Ulrich Drepper. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "loadables.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined (PRI_MACROS_BROKEN)
|
||||
# undef PRIdMAX
|
||||
#endif
|
||||
|
||||
#if !defined (PRIdMAX)
|
||||
# if HAVE_LONG_LONG
|
||||
# define PRIdMAX "lld"
|
||||
# else
|
||||
# define PRIdMAX "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
|
||||
typedef long double floatmax_t;
|
||||
# define FLOATMAX_CONV "L"
|
||||
# define strtofltmax strtold
|
||||
# define FLOATMAX_FMT "%Lg"
|
||||
# define FLOATMAX_WFMT "%0.Lf"
|
||||
# define USE_LONG_DOUBLE
|
||||
#else
|
||||
typedef double floatmax_t;
|
||||
# define FLOATMAX_CONV ""
|
||||
# define strtofltmax strtod
|
||||
# define FLOATMAX_FMT "%g"
|
||||
# define FLOATMAX_WFMT "%0.f"
|
||||
#endif
|
||||
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))
|
||||
|
||||
static int conversion_error = 0;
|
||||
|
||||
/* If true print all number with equal width. */
|
||||
static int equal_width;
|
||||
|
||||
/* The string used to separate two numbers. */
|
||||
static char const *separator;
|
||||
|
||||
/* The string output after all numbers have been output. */
|
||||
static char const terminator[] = "\n";
|
||||
|
||||
static char decimal_point;
|
||||
|
||||
/* Pretty much the same as the version in builtins/printf.def */
|
||||
static floatmax_t
|
||||
getfloatmax (arg)
|
||||
const char *arg;
|
||||
{
|
||||
floatmax_t ret;
|
||||
char *ep;
|
||||
|
||||
errno = 0;
|
||||
ret = strtofltmax (arg, &ep);
|
||||
|
||||
if (*ep)
|
||||
{
|
||||
sh_invalidnum ((char *)arg);
|
||||
conversion_error = 1;
|
||||
}
|
||||
else if (errno == ERANGE)
|
||||
{
|
||||
builtin_error ("warning: %s: %s", arg, strerror(ERANGE));
|
||||
conversion_error = 1;
|
||||
}
|
||||
|
||||
if (ret == -0.0)
|
||||
ret = 0.0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* If FORMAT is a valid printf format for a double argument, return
|
||||
its long double equivalent, allocated from dynamic storage. This
|
||||
was written by Ulrich Drepper, taken from coreutils:seq.c */
|
||||
static char *
|
||||
long_double_format (char const *fmt)
|
||||
{
|
||||
size_t i;
|
||||
size_t length_modifier_offset;
|
||||
int has_L;
|
||||
|
||||
for (i = 0; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1)
|
||||
{
|
||||
if (!fmt[i])
|
||||
{
|
||||
builtin_error ("format %s has no %% directive", fmt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
i += strspn (fmt + i, "-+#0 '"); /* zero or more flags */
|
||||
i += strspn (fmt + i, "0123456789"); /* optional minimum field width */
|
||||
if (fmt[i] == '.') /* optional precision */
|
||||
{
|
||||
i++;
|
||||
i += strspn (fmt + i, "0123456789");
|
||||
}
|
||||
|
||||
length_modifier_offset = i; /* optional length modifier */
|
||||
/* we could ignore an 'l' length modifier here */
|
||||
has_L = (fmt[i] == 'L');
|
||||
i += has_L;
|
||||
switch (fmt[i])
|
||||
{
|
||||
case '\0':
|
||||
builtin_error ("format %s ends in %%", fmt);
|
||||
return 0;
|
||||
case 'A':
|
||||
case 'a':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
break;
|
||||
default:
|
||||
builtin_error ("format %s has unknown `%%%c' directive", fmt, fmt[i]);
|
||||
return 0;
|
||||
}
|
||||
for (i++; ; i += (fmt[i] == '%') + 1)
|
||||
if (fmt[i] == '%' && fmt[i + 1] != '%')
|
||||
{
|
||||
builtin_error ("format %s has too many %% directives", fmt);
|
||||
return 0;
|
||||
}
|
||||
else if (fmt[i] == 0)
|
||||
{
|
||||
size_t format_size = i + 1;
|
||||
char *ldfmt = xmalloc (format_size + 1);
|
||||
memcpy (ldfmt, fmt, length_modifier_offset);
|
||||
#ifdef USE_LONG_DOUBLE
|
||||
ldfmt[length_modifier_offset] = 'L';
|
||||
strcpy (ldfmt + length_modifier_offset + 1,
|
||||
fmt + length_modifier_offset + has_L);
|
||||
#else
|
||||
strcpy (ldfmt + length_modifier_offset, fmt + length_modifier_offset);
|
||||
#endif
|
||||
return ldfmt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of digits following the decimal point in NUMBUF */
|
||||
static int
|
||||
getprec (numbuf)
|
||||
const char *numbuf;
|
||||
{
|
||||
int p;
|
||||
char *dp;
|
||||
|
||||
if (dp = strchr (numbuf, decimal_point))
|
||||
dp++; /* skip over decimal point */
|
||||
for (p = 0; dp && *dp && ISDIGIT (*dp); dp++)
|
||||
p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Return the default format given FIRST, INCR, and LAST. */
|
||||
static char *
|
||||
genformat (first, incr, last)
|
||||
floatmax_t first, incr, last;
|
||||
{
|
||||
static char buf[6 + 2 * INT_STRLEN_BOUND (int)];
|
||||
int wfirst, wlast, width;
|
||||
int iprec, fprec, lprec, prec;
|
||||
|
||||
if (equal_width == 0)
|
||||
return (FLOATMAX_FMT);
|
||||
|
||||
/* OK, we have to figure out the largest number of decimal places. This is
|
||||
a little more expensive than using the original strings. */
|
||||
snprintf (buf, sizeof (buf), FLOATMAX_FMT, incr);
|
||||
iprec = getprec (buf);
|
||||
|
||||
wfirst = snprintf (buf, sizeof (buf), FLOATMAX_FMT, first);
|
||||
fprec = getprec (buf);
|
||||
|
||||
prec = MAX (fprec, iprec);
|
||||
|
||||
wlast = snprintf (buf, sizeof (buf), FLOATMAX_FMT, last);
|
||||
lprec = getprec (buf);
|
||||
|
||||
/* increase first width by any increased precision in increment */
|
||||
wfirst += (prec - fprec);
|
||||
|
||||
/* adjust last width to use precision from first/incr */
|
||||
wlast += (prec - lprec);
|
||||
|
||||
if (lprec && prec == 0)
|
||||
wlast--; /* no decimal point */
|
||||
if (lprec == 0 && prec)
|
||||
wlast++; /* include decimal point */
|
||||
if (fprec == 0 && prec)
|
||||
wfirst++; /* include decimal point */
|
||||
|
||||
width = MAX (wfirst, wlast);
|
||||
if (width)
|
||||
sprintf (buf, "%%0%d.%d%sf", width, prec, FLOATMAX_CONV);
|
||||
else
|
||||
sprintf (buf, "%%.%d%sf", prec, FLOATMAX_CONV);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
print_fltseq (fmt, first, last, incr)
|
||||
const char *fmt;
|
||||
floatmax_t first, last, incr;
|
||||
{
|
||||
int n;
|
||||
floatmax_t next;
|
||||
const char *s;
|
||||
|
||||
n = 0; /* iteration counter */
|
||||
s = "";
|
||||
for (next = first; incr >= 0 ? (next <= last) : (next >= last); next = first + n * incr)
|
||||
{
|
||||
QUIT;
|
||||
if (*s && fputs (s, stdout) == EOF)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
if (printf (fmt, next) < 0)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
s = separator;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 0 && fputs (terminator, stdout) == EOF)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* must be <= INT_STRLEN_BOUND(intmax_t) */
|
||||
int
|
||||
width_needed (num)
|
||||
intmax_t num;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = num < 0; /* sign */
|
||||
if (ret)
|
||||
num = -num;
|
||||
do
|
||||
ret++;
|
||||
while (num /= 10);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
print_intseq (ifirst, ilast, iincr)
|
||||
intmax_t ifirst, ilast, iincr;
|
||||
{
|
||||
char intwfmt[6 + INT_STRLEN_BOUND(int) + sizeof (PRIdMAX)];
|
||||
const char *s;
|
||||
intmax_t i, next;
|
||||
|
||||
/* compute integer format string */
|
||||
if (equal_width) /* -w supplied */
|
||||
{
|
||||
int wfirst, wlast, width;
|
||||
|
||||
wfirst = width_needed (ifirst);
|
||||
wlast = width_needed (ilast);
|
||||
width = MAX(wfirst, wlast);
|
||||
|
||||
/* The leading %s is for the separator */
|
||||
snprintf (intwfmt, sizeof (intwfmt), "%%s%%0%u" PRIdMAX, width);
|
||||
}
|
||||
|
||||
/* We could use braces.c:mkseq here but that allocates lots of memory */
|
||||
s = "";
|
||||
for (i = ifirst; (ifirst <= ilast) ? (i <= ilast) : (i >= ilast); i = next)
|
||||
{
|
||||
QUIT;
|
||||
/* The leading %s is for the separator */
|
||||
if (printf (equal_width ? intwfmt : "%s%" PRIdMAX, s, i) < 0)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
s = separator;
|
||||
next = i + iincr;
|
||||
}
|
||||
|
||||
if (fputs (terminator, stdout) == EOF)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
int
|
||||
seq_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
floatmax_t first, last, incr;
|
||||
intmax_t ifirst, ilast, iincr;
|
||||
WORD_LIST *l;
|
||||
int opt, nargs, intseq, freefmt;
|
||||
char *first_str, *incr_str, *last_str;
|
||||
char const *fmtstr; /* The printf(3) format used for output. */
|
||||
|
||||
equal_width = 0;
|
||||
separator = "\n";
|
||||
fmtstr = NULL;
|
||||
|
||||
first = 1.0;
|
||||
last = 0.0;
|
||||
incr = 0.0; /* set later */
|
||||
ifirst = ilast = iincr = 0;
|
||||
first_str = incr_str = last_str = 0;
|
||||
|
||||
intseq = freefmt = 0;
|
||||
opt = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while (opt != -1)
|
||||
{
|
||||
l = lcurrent ? lcurrent : list;
|
||||
if (l && l->word && l->word->word && l->word->word[0] == '-' &&
|
||||
(l->word->word[1] == '.' || DIGIT (l->word->word[1])))
|
||||
{
|
||||
loptend = l;
|
||||
break; /* negative number */
|
||||
}
|
||||
if ((opt = internal_getopt (list, "f:s:w")) == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
fmtstr = list_optarg;
|
||||
break;
|
||||
case 's':
|
||||
separator = list_optarg;
|
||||
break;
|
||||
case 'w':
|
||||
equal_width = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
for (nargs = 1, l = list; l->next; l = l->next)
|
||||
nargs++;
|
||||
if (nargs > 3)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* LAST */
|
||||
conversion_error = 0;
|
||||
last = getfloatmax (last_str = l->word->word);
|
||||
if (conversion_error)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
/* FIRST LAST */
|
||||
if (nargs > 1)
|
||||
{
|
||||
conversion_error = 0;
|
||||
first = getfloatmax (first_str = list->word->word);
|
||||
if (conversion_error)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* FIRST INCR LAST */
|
||||
if (nargs > 2)
|
||||
{
|
||||
conversion_error = 0;
|
||||
incr = getfloatmax (incr_str = list->next->word->word);
|
||||
if (conversion_error)
|
||||
return (EXECUTION_FAILURE);
|
||||
if (incr == 0.0)
|
||||
{
|
||||
builtin_error ("zero %screment", (first < last) ? "in" : "de");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanitize arguments */
|
||||
if (incr == 0.0)
|
||||
incr = (first <= last) ? 1.0 : -1.0;
|
||||
if ((incr < 0.0 && first < last) || (incr > 0 && first > last))
|
||||
{
|
||||
builtin_error ("incorrect %screment", (first < last) ? "in" : "de");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* validate format here */
|
||||
if (fmtstr)
|
||||
{
|
||||
fmtstr = long_double_format (fmtstr);
|
||||
freefmt = 1;
|
||||
if (fmtstr == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (fmtstr != NULL && equal_width)
|
||||
{
|
||||
builtin_warning ("-w ignored when the format string is specified");
|
||||
equal_width = 0;
|
||||
}
|
||||
|
||||
/* Placeholder for later additional conditions */
|
||||
if (last_str && all_digits (last_str) &&
|
||||
(first_str == 0 || all_digits (first_str)) &&
|
||||
(incr_str == 0 || all_digits (incr_str)) &&
|
||||
fmtstr == NULL)
|
||||
intseq = 1;
|
||||
|
||||
if (intseq)
|
||||
{
|
||||
ifirst = (intmax_t)first; /* truncation */
|
||||
ilast = (intmax_t)last;
|
||||
iincr = (intmax_t)incr;
|
||||
|
||||
return (print_intseq (ifirst, ilast, iincr));
|
||||
}
|
||||
|
||||
decimal_point = locale_decpoint ();
|
||||
if (fmtstr == NULL)
|
||||
fmtstr = genformat (first, incr, last);
|
||||
|
||||
print_fltseq (fmtstr, first, last, incr);
|
||||
|
||||
if (freefmt)
|
||||
free ((void *)fmtstr);
|
||||
return sh_chkwrite (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Taken largely from GNU seq. */
|
||||
char *seq_doc[] = {
|
||||
"Print numbers from FIRST to LAST, in steps of INCREMENT.",
|
||||
"",
|
||||
"-f FORMAT use printf style floating-point FORMAT",
|
||||
"-s STRING use STRING to separate numbers (default: \\n)",
|
||||
"-w equalize width by padding with leading zeroes",
|
||||
"",
|
||||
"If FIRST or INCREMENT is omitted, it defaults to 1. However, an",
|
||||
"omitted INCREMENT defaults to -1 when LAST is smaller than FIRST.",
|
||||
"The sequence of numbers ends when the sum of the current number and",
|
||||
"INCREMENT would become greater than LAST.",
|
||||
"FIRST, INCREMENT, and LAST are interpreted as floating point values.",
|
||||
"",
|
||||
"FORMAT must be suitable for printing one argument of type 'double';",
|
||||
"it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point",
|
||||
"decimal numbers with maximum precision PREC, and to %g otherwise.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin seq_struct = {
|
||||
"seq",
|
||||
seq_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
seq_doc,
|
||||
"seq [-f format] [-s separator] [-w] [FIRST [INCR]] LAST",
|
||||
0
|
||||
};
|
121
examples/loadables/setpgid.c
Normal file
121
examples/loadables/setpgid.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* setpgid.c: bash loadable wrapper for setpgid system call
|
||||
|
||||
An example of how to wrap a system call with a loadable builtin.
|
||||
|
||||
Originally contributed by Jason Vas Dias <jason.vas.dias@gmail.com>
|
||||
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixtime.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (_POSIX_VERSION)
|
||||
# define setpgid(pid, pgrp) setpgrp (pid, pgrp)
|
||||
#endif
|
||||
|
||||
int
|
||||
setpgid_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register WORD_LIST *wl;
|
||||
intmax_t pid_arg, pgid_arg;
|
||||
pid_t pid, pgid;
|
||||
char *pidstr, *pgidstr;
|
||||
|
||||
wl = list;
|
||||
pid = pgid = 0;
|
||||
|
||||
if (wl == 0 || wl->next == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
pidstr = wl->word ? wl->word->word : 0;
|
||||
pgidstr = wl->next->word ? wl->next->word->word : 0;
|
||||
|
||||
if (pidstr == 0 || pgidstr == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (legal_number (pidstr, &pid_arg) == 0)
|
||||
{
|
||||
builtin_error ("%s: pid argument must be numeric", pidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (pid_arg < 0)
|
||||
{
|
||||
builtin_error("%s: negative pid values not allowed", pidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
pid = pid_arg;
|
||||
|
||||
if (legal_number (pgidstr, &pgid_arg) == 0)
|
||||
{
|
||||
builtin_error ("%s: pgrp argument must be numeric", pgidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (pgid_arg < 0)
|
||||
{
|
||||
builtin_error ("%s: negative pgrp values not allowed", pgidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
pgid = pgid_arg;
|
||||
|
||||
errno = 0;
|
||||
if (setpgid(pid, pgid) < 0)
|
||||
{
|
||||
builtin_error("setpgid failed: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
const char *setpgid_doc[] = {
|
||||
"invoke the setpgid(2) system call",
|
||||
"",
|
||||
"Arguments:",
|
||||
" pid : numeric process identifier, >= 0",
|
||||
" pgrpid: numeric process group identifier, >=0",
|
||||
"See the setpgid(2) manual page.",
|
||||
(const char *)NULL
|
||||
};
|
||||
|
||||
struct builtin setpgid_struct = {
|
||||
"setpgid",
|
||||
setpgid_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
(char **)setpgid_doc,
|
||||
"setpgid pid pgrpid",
|
||||
0
|
||||
};
|
179
examples/loadables/sleep.c
Normal file
179
examples/loadables/sleep.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* sleep -- sleep for fractions of a second
|
||||
*
|
||||
* usage: sleep seconds[.fraction]
|
||||
*
|
||||
* as an extension, we support the GNU time interval format (2m20s)
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2021 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"
|
||||
|
||||
#if defined (TIME_WITH_SYS_TIME)
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# if defined (HAVE_SYS_TIME_H)
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "loadables.h"
|
||||
|
||||
#define S_SEC 1
|
||||
#define S_MIN (60*S_SEC)
|
||||
#define S_HOUR (60*S_MIN)
|
||||
#define S_DAY (24*S_HOUR)
|
||||
|
||||
static int
|
||||
parse_gnutimefmt (char *string, long *sp, long *up)
|
||||
{
|
||||
int c, r;
|
||||
char *s, *ep;
|
||||
long tsec, tusec, accumsec, accumusec, t;
|
||||
int mult;
|
||||
|
||||
tsec = tusec = 0;
|
||||
accumsec = accumusec = 0;
|
||||
mult = 1;
|
||||
|
||||
for (s = string; s && *s; s++) {
|
||||
r = uconvert(s, &accumsec, &accumusec, &ep);
|
||||
if (r == 0 && *ep == 0)
|
||||
return r;
|
||||
c = *ep;
|
||||
mult = 1;
|
||||
switch (c) {
|
||||
case '\0':
|
||||
case 's':
|
||||
mult = S_SEC;
|
||||
break;
|
||||
case 'm':
|
||||
mult = S_MIN;
|
||||
break;
|
||||
case 'h':
|
||||
mult = S_HOUR;
|
||||
break;
|
||||
case 'd':
|
||||
mult = S_DAY;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* multiply the accumulated value by the multiplier */
|
||||
t = accumusec * mult;
|
||||
accumsec = accumsec * mult + (t / 1000000);
|
||||
accumusec = t % 1000000;
|
||||
|
||||
/* add to running total */
|
||||
tsec += accumsec;
|
||||
tusec += accumusec;
|
||||
if (tusec >= 1000000) {
|
||||
tsec++;
|
||||
tusec -= 1000000;
|
||||
}
|
||||
|
||||
/* reset and continue */
|
||||
accumsec = accumusec = 0;
|
||||
mult = 1;
|
||||
if (c == 0)
|
||||
break;
|
||||
s = ep;
|
||||
}
|
||||
|
||||
if (sp)
|
||||
*sp = tsec;
|
||||
if (up)
|
||||
*up = tusec;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
sleep_builtin (WORD_LIST *list)
|
||||
{
|
||||
long sec, usec;
|
||||
char *ep;
|
||||
int r, mul;
|
||||
time_t t;
|
||||
|
||||
if (list == 0) {
|
||||
builtin_usage();
|
||||
return(EX_USAGE);
|
||||
}
|
||||
|
||||
/* Skip over `--' */
|
||||
if (list->word && ISOPTION (list->word->word, '-'))
|
||||
list = list->next;
|
||||
|
||||
if (*list->word->word == '-' || list->next) {
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
r = uconvert(list->word->word, &sec, &usec, &ep);
|
||||
/*
|
||||
* Maybe postprocess conversion failures here based on EP
|
||||
*
|
||||
* A heuristic: if the conversion failed, but the argument appears to
|
||||
* contain a GNU-like interval specifier (e.g. "1m30s"), try to parse
|
||||
* it. If we can't, return the right exit code to tell
|
||||
* execute_builtin to try and execute a disk command instead.
|
||||
*/
|
||||
if (r == 0 && (strchr ("dhms", *ep) || strpbrk (list->word->word, "dhms")))
|
||||
r = parse_gnutimefmt (list->word->word, &sec, &usec);
|
||||
|
||||
if (r) {
|
||||
fsleep(sec, usec);
|
||||
QUIT;
|
||||
return(EXECUTION_SUCCESS);
|
||||
}
|
||||
builtin_error("%s: bad sleep interval", list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
static char *sleep_doc[] = {
|
||||
"Suspend execution for specified period.",
|
||||
""
|
||||
"sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.",
|
||||
"As an extension, sleep accepts GNU-style time intervals (e.g., 2m30s).",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin sleep_struct = {
|
||||
"sleep",
|
||||
sleep_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
sleep_doc,
|
||||
"sleep seconds[.fraction]",
|
||||
0
|
||||
};
|
464
examples/loadables/stat.c
Normal file
464
examples/loadables/stat.c
Normal file
|
@ -0,0 +1,464 @@
|
|||
/* stat - load up an associative array with stat information about a file */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2016,2022 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
|
||||
};
|
||||
|
||||
#define DEFTIMEFMT "%a %b %e %k:%M:%S %Z %Y"
|
||||
#ifndef TIMELEN_MAX
|
||||
# define TIMELEN_MAX 128
|
||||
#endif
|
||||
|
||||
static char *stattime (time_t, const char *);
|
||||
|
||||
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, timefmt)
|
||||
time_t t;
|
||||
const char *timefmt;
|
||||
{
|
||||
char *tbuf, *ret;
|
||||
const char *fmt;
|
||||
size_t tlen;
|
||||
struct tm *tm;
|
||||
|
||||
fmt = timefmt ? timefmt : DEFTIMEFMT;
|
||||
tm = localtime (&t);
|
||||
|
||||
ret = xmalloc (TIMELEN_MAX);
|
||||
|
||||
tlen = strftime (ret, TIMELEN_MAX, fmt, tm);
|
||||
if (tlen == 0)
|
||||
tlen = strftime (ret, TIMELEN_MAX, DEFTIMEFMT, tm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
statval (which, fname, flags, fmt, sp)
|
||||
int which;
|
||||
char *fname;
|
||||
int flags;
|
||||
char *fmt;
|
||||
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, fmt) : itos (sp->st_atime));
|
||||
case ST_MTIME:
|
||||
return ((flags & 2) ? stattime (sp->st_mtime, fmt) : itos (sp->st_mtime));
|
||||
case ST_CTIME:
|
||||
return ((flags & 2) ? stattime (sp->st_ctime, fmt) : 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, fmt, sp)
|
||||
char *vname;
|
||||
SHELL_VAR *var;
|
||||
char *fname;
|
||||
int flags;
|
||||
char *fmt;
|
||||
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, fmt, 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, *timefmt;
|
||||
struct stat st;
|
||||
SHELL_VAR *v;
|
||||
|
||||
aname = "STAT";
|
||||
flags = 0;
|
||||
timefmt = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "A:F: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 'F':
|
||||
timefmt = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
if (legal_identifier (aname) == 0)
|
||||
{
|
||||
sh_invalidid (aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
unbind_variable (aname);
|
||||
#endif
|
||||
fname = list->word->word;
|
||||
|
||||
if (getstat (fname, flags, &st) < 0)
|
||||
{
|
||||
builtin_error ("%s: cannot stat: %s", fname, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
v = find_or_make_array_variable (aname, 3);
|
||||
if (v == 0)
|
||||
{
|
||||
builtin_error ("%s: cannot create variable", aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (loadstat (aname, v, fname, flags, timefmt, &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. When -l is used,",
|
||||
"the -F option supplies a format string passed to strftime(3) to",
|
||||
"display the file time information.",
|
||||
"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 */
|
||||
};
|
128
examples/loadables/strftime.c
Normal file
128
examples/loadables/strftime.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/* strftime - loadable builtin interface to strftime(3) */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "bashtypes.h"
|
||||
#include "posixtime.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
strftime_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *format, *tbuf;
|
||||
size_t tbsize, tsize;
|
||||
time_t secs;
|
||||
struct tm *t;
|
||||
int n;
|
||||
intmax_t i;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
format = list->word->word;
|
||||
if (format == 0 || *format == 0)
|
||||
{
|
||||
printf ("\n");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
|
||||
if (list && list->word->word)
|
||||
{
|
||||
n = legal_number (list->word->word, &i);
|
||||
if (n == 0 || i < 0 || i != (time_t)i)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
secs = i;
|
||||
}
|
||||
else
|
||||
secs = NOW;
|
||||
|
||||
t = localtime (&secs);
|
||||
|
||||
tbsize = strlen (format) * 4;
|
||||
tbuf = 0;
|
||||
|
||||
/* 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 <= 8; n++)
|
||||
{
|
||||
tbuf = xrealloc (tbuf, tbsize * n);
|
||||
tsize = strftime (tbuf, tbsize * n, format, t);
|
||||
if (tsize)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tsize)
|
||||
printf ("%s\n", tbuf);
|
||||
free (tbuf);
|
||||
|
||||
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. */
|
||||
char *strftime_doc[] = {
|
||||
"Display formatted time.",
|
||||
"",
|
||||
"Converts date and time format to a string and displays it on the",
|
||||
"standard output. If the optional second argument is supplied, it",
|
||||
"is used as the number of seconds since the epoch to use in the",
|
||||
"conversion, otherwise the current time is used.",
|
||||
(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 strftime_struct = {
|
||||
"strftime", /* builtin name */
|
||||
strftime_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
strftime_doc, /* array of long documentation strings. */
|
||||
"strftime format [seconds]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
53
examples/loadables/sync.c
Normal file
53
examples/loadables/sync.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* sync - sync the disks by forcing pending filesystem writes to complete */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
sync_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
sync();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *sync_doc[] = {
|
||||
"Sync disks.",
|
||||
""
|
||||
"Force completion of pending disk writes",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin sync_struct = {
|
||||
"sync", /* builtin name */
|
||||
sync_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
sync_doc, /* array of long documentation strings. */
|
||||
"sync", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
183
examples/loadables/tee.c
Normal file
183
examples/loadables/tee.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* tee - duplicate standard input */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2021 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 "filecntl.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
typedef struct flist {
|
||||
struct flist *next;
|
||||
int fd;
|
||||
char *fname;
|
||||
} FLIST;
|
||||
|
||||
static FLIST *tee_flist;
|
||||
|
||||
#define TEE_BUFSIZE 8192
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
int
|
||||
tee_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, append, nointr, rval, fd, fflags;
|
||||
int n, nr, nw;
|
||||
FLIST *fl;
|
||||
char *buf, *bp;
|
||||
|
||||
char *t;
|
||||
|
||||
reset_internal_getopt ();
|
||||
append = nointr = 0;
|
||||
tee_flist = (FLIST *)NULL;
|
||||
while ((opt = internal_getopt (list, "ai")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
append = 1;
|
||||
break;
|
||||
case 'i':
|
||||
nointr = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (nointr == 0)
|
||||
interrupt_immediately++;
|
||||
|
||||
buf = xmalloc (TEE_BUFSIZE);
|
||||
|
||||
/* Initialize output file list. */
|
||||
fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
|
||||
tee_flist->fd = 1;
|
||||
tee_flist->fname = "stdout";
|
||||
tee_flist->next = (FLIST *)NULL;
|
||||
|
||||
/* Add file arguments to list of output files. */
|
||||
fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
|
||||
for (rval = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
fd = open (list->word->word, fflags, 0666);
|
||||
if (fd < 0)
|
||||
{
|
||||
builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fl->next = (FLIST *)xmalloc (sizeof(FLIST));
|
||||
fl->next->fd = fd;
|
||||
fl->next->fname = list->word->word;
|
||||
fl = fl->next;
|
||||
fl->next = (FLIST *)NULL;
|
||||
}
|
||||
QUIT;
|
||||
}
|
||||
|
||||
while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
|
||||
for (fl = tee_flist; fl; fl = fl->next)
|
||||
{
|
||||
n = nr;
|
||||
bp = buf;
|
||||
do
|
||||
{
|
||||
if ((nw = write (fl->fd, bp, n)) == -1)
|
||||
{
|
||||
builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
break;
|
||||
}
|
||||
bp += nw;
|
||||
QUIT;
|
||||
}
|
||||
while (n -= nw);
|
||||
}
|
||||
if (nr < 0)
|
||||
builtin_error ("read error: %s", strerror (errno));
|
||||
|
||||
/* Deallocate resources -- this is a builtin command. */
|
||||
tee_flist = tee_flist->next; /* skip bogus close of stdout */
|
||||
while (tee_flist)
|
||||
{
|
||||
fl = tee_flist;
|
||||
if (close (fl->fd) < 0)
|
||||
{
|
||||
builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
tee_flist = tee_flist->next;
|
||||
free (fl);
|
||||
}
|
||||
|
||||
QUIT;
|
||||
return (rval);
|
||||
}
|
||||
|
||||
char *tee_doc[] = {
|
||||
"Duplicate standard output.",
|
||||
"",
|
||||
"Copy standard input to standard output, making a copy in each",
|
||||
"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
|
||||
};
|
||||
|
||||
struct builtin tee_struct = {
|
||||
"tee", /* builtin name */
|
||||
tee_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
tee_doc, /* array of long documentation strings. */
|
||||
"tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
75
examples/loadables/template.c
Normal file
75
examples/loadables/template.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* template - example template for loadable builtin */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "loadables.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
int
|
||||
template_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, rval;
|
||||
|
||||
rval = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/* Called when `template' is enabled and loaded from the shared object. If this
|
||||
function returns 0, the load fails. */
|
||||
int
|
||||
template_builtin_load (name)
|
||||
char *name;
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Called when `template' is disabled. */
|
||||
void
|
||||
template_builtin_unload (name)
|
||||
char *name;
|
||||
{
|
||||
}
|
||||
|
||||
char *template_doc[] = {
|
||||
"Short description.",
|
||||
""
|
||||
"Longer description of builtin and usage.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin template_struct = {
|
||||
"template", /* builtin name */
|
||||
template_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
template_doc, /* array of long documentation strings. */
|
||||
"template", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
72
examples/loadables/truefalse.c
Normal file
72
examples/loadables/truefalse.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* true and false builtins */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "common.h"
|
||||
|
||||
int
|
||||
true_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
false_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
static char *true_doc[] = {
|
||||
"Exit successfully.",
|
||||
"",
|
||||
"Return a successful result.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
static char *false_doc[] = {
|
||||
"Exit unsuccessfully.",
|
||||
"",
|
||||
"Return an unsuccessful result.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin true_struct = {
|
||||
"true",
|
||||
true_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
true_doc,
|
||||
"true",
|
||||
0
|
||||
};
|
||||
|
||||
struct builtin false_struct = {
|
||||
"false",
|
||||
false_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
false_doc,
|
||||
"false",
|
||||
0
|
||||
};
|
83
examples/loadables/tty.c
Normal file
83
examples/loadables/tty.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* tty - return terminal name */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2021 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 "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
extern char *ttyname ();
|
||||
|
||||
int
|
||||
tty_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, sflag;
|
||||
char *t;
|
||||
|
||||
reset_internal_getopt ();
|
||||
sflag = 0;
|
||||
while ((opt = internal_getopt (list, "s")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
t = ttyname (0);
|
||||
QUIT;
|
||||
if (sflag == 0)
|
||||
puts (t ? t : "not a tty");
|
||||
return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
char *tty_doc[] = {
|
||||
"Display terminal name.",
|
||||
"",
|
||||
"tty writes the name of the terminal that is opened for standard",
|
||||
"input to standard output. If the `-s' option is supplied, nothing",
|
||||
"is written; the exit status determines whether or not the standard",
|
||||
"input is connected to a tty.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin tty_struct = {
|
||||
"tty", /* builtin name */
|
||||
tty_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
tty_doc, /* array of long documentation strings. */
|
||||
"tty [-s]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
162
examples/loadables/uname.c
Normal file
162
examples/loadables/uname.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* uname - print system information
|
||||
*
|
||||
* usage: uname [-amnrsv]
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNAME)
|
||||
# include <sys/utsname.h>
|
||||
#else
|
||||
struct utsname {
|
||||
char sysname[32];
|
||||
char nodename[32];
|
||||
char release[32];
|
||||
char version[32];
|
||||
char machine[32];
|
||||
};
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#define FLAG_SYSNAME 0x01 /* -s */
|
||||
#define FLAG_NODENAME 0x02 /* -n */
|
||||
#define FLAG_RELEASE 0x04 /* -r */
|
||||
#define FLAG_VERSION 0x08 /* -v */
|
||||
#define FLAG_MACHINE 0x10 /* -m, -p */
|
||||
|
||||
#define FLAG_ALL 0x1f
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static void uprint();
|
||||
|
||||
static int uname_flags;
|
||||
|
||||
int
|
||||
uname_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, r;
|
||||
struct utsname uninfo;
|
||||
|
||||
uname_flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "amnprsv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
uname_flags |= FLAG_ALL;
|
||||
break;
|
||||
case 'm':
|
||||
case 'p':
|
||||
uname_flags |= FLAG_MACHINE;
|
||||
break;
|
||||
case 'n':
|
||||
uname_flags |= FLAG_NODENAME;
|
||||
break;
|
||||
case 'r':
|
||||
uname_flags |= FLAG_RELEASE;
|
||||
break;
|
||||
case 's':
|
||||
uname_flags |= FLAG_SYSNAME;
|
||||
break;
|
||||
case 'v':
|
||||
uname_flags |= FLAG_VERSION;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (uname_flags == 0)
|
||||
uname_flags = FLAG_SYSNAME;
|
||||
|
||||
/* Only ancient systems will not have uname(2). */
|
||||
#ifdef HAVE_UNAME
|
||||
if (uname (&uninfo) < 0)
|
||||
{
|
||||
builtin_error ("cannot get system name: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#else
|
||||
builtin_error ("cannot get system information: uname(2) not available");
|
||||
return (EXECUTION_FAILURE);
|
||||
#endif
|
||||
|
||||
uprint (FLAG_SYSNAME, uninfo.sysname);
|
||||
uprint (FLAG_NODENAME, uninfo.nodename);
|
||||
uprint (FLAG_RELEASE, uninfo.release);
|
||||
uprint (FLAG_VERSION, uninfo.version);
|
||||
uprint (FLAG_MACHINE, uninfo.machine);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
uprint (flag, info)
|
||||
int flag;
|
||||
char *info;
|
||||
{
|
||||
if (uname_flags & flag)
|
||||
{
|
||||
uname_flags &= ~flag;
|
||||
printf ("%s%c", info, uname_flags ? ' ' : '\n');
|
||||
}
|
||||
}
|
||||
|
||||
char *uname_doc[] = {
|
||||
"Display system information.",
|
||||
"",
|
||||
"Display information about the system hardware and OS.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin uname_struct = {
|
||||
"uname",
|
||||
uname_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
uname_doc,
|
||||
"uname [-amnrsv]",
|
||||
0
|
||||
};
|
74
examples/loadables/unlink.c
Normal file
74
examples/loadables/unlink.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* unlink - remove a directory entry */
|
||||
|
||||
/* Should only be used to remove directories by a superuser prepared to let
|
||||
fsck clean up the file system. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
unlink_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (unlink (list->word->word) != 0)
|
||||
{
|
||||
builtin_error ("%s: cannot unlink: %s", list->word->word, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *unlink_doc[] = {
|
||||
"Remove a directory entry.",
|
||||
"",
|
||||
"Forcibly remove a directory entry, even if it's a directory.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin unlink_struct = {
|
||||
"unlink", /* builtin name */
|
||||
unlink_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
unlink_doc, /* array of long documentation strings. */
|
||||
"unlink name", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
75
examples/loadables/whoami.c
Normal file
75
examples/loadables/whoami.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* whoami - print out username of current user
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
int
|
||||
whoami_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
if (list)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (current_user.user_name == 0)
|
||||
get_current_user_info ();
|
||||
printf ("%s\n", current_user.user_name);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *whoami_doc[] = {
|
||||
"Print user name",
|
||||
"",
|
||||
"Display name of current user.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin whoami_struct = {
|
||||
"whoami",
|
||||
whoami_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
whoami_doc,
|
||||
"whoami",
|
||||
0
|
||||
};
|
44
examples/misc/aliasconv.bash
Normal file
44
examples/misc/aliasconv.bash
Normal file
|
@ -0,0 +1,44 @@
|
|||
#! /bin/bash
|
||||
#
|
||||
# aliasconv.bash - convert csh aliases to bash aliases and functions
|
||||
#
|
||||
# usage: aliasconv.bash
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@po.cwru.edu
|
||||
#
|
||||
trap 'rm -f $TMPFILE' 0 1 2 3 6 15
|
||||
|
||||
TMPFILE=$(mktemp -t cb.XXXXXX) || exit 1
|
||||
|
||||
T=$'\t'
|
||||
|
||||
cat << \EOF >$TMPFILE
|
||||
mkalias ()
|
||||
{
|
||||
case $2 in
|
||||
'') echo alias ${1}="''" ;;
|
||||
*[#\!]*)
|
||||
comm=$(echo $2 | sed 's/\!\*/"$\@"/g
|
||||
s/\!:\([1-9]\)/"$\1"/g
|
||||
s/#/\#/g')
|
||||
echo $1 \(\) "{" command "$comm" "; }"
|
||||
;;
|
||||
*) echo alias ${1}=\'$(echo "${2}" | sed "s:':'\\\\'':g")\' ;;
|
||||
esac
|
||||
}
|
||||
EOF
|
||||
|
||||
# the first thing we want to do is to protect single quotes in the alias,
|
||||
# since they whole thing is going to be surrounded by single quotes when
|
||||
# passed to mkalias
|
||||
|
||||
sed -e "s:':\\'\\\'\\':" -e "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>$TMPFILE
|
||||
|
||||
$BASH $TMPFILE | sed -e 's/\$cwd/\$PWD/g' \
|
||||
-e 's/\$term/\$TERM/g' \
|
||||
-e 's/\$home/\$HOME/g' \
|
||||
-e 's/\$user/\$USER/g' \
|
||||
-e 's/\$prompt/\$PS1/g'
|
||||
|
||||
exit 0
|
42
examples/misc/aliasconv.sh
Normal file
42
examples/misc/aliasconv.sh
Normal file
|
@ -0,0 +1,42 @@
|
|||
#! /bin/bash
|
||||
#
|
||||
# aliasconv.sh - convert csh aliases to bash aliases and functions
|
||||
#
|
||||
# usage: aliasconv.sh
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@po.cwru.edu
|
||||
#
|
||||
trap 'rm -f $TMPFILE' 0 1 2 3 6 15
|
||||
TMPFILE=$(mktemp -t cb.XXXXXX) || exit 1
|
||||
T=' '
|
||||
|
||||
cat << \EOF >$TMPFILE
|
||||
mkalias ()
|
||||
{
|
||||
case $2 in
|
||||
'') echo alias ${1}="''" ;;
|
||||
*[#\!]*)
|
||||
comm=`echo $2 | sed 's/\\!\*/"$\@"/g
|
||||
s/\\!:\([1-9]\)/"$\1"/g
|
||||
s/#/\#/g'`
|
||||
echo $1 \(\) "{" command "$comm" "; }"
|
||||
;;
|
||||
*) echo alias ${1}=\'`echo "${2}" | sed "s:':'\\\\\\\\'':"`\' ;;
|
||||
esac
|
||||
}
|
||||
EOF
|
||||
|
||||
# the first thing we want to do is to protect single quotes in the alias,
|
||||
# since they whole thing is going to be surrounded by single quotes when
|
||||
# passed to mkalias
|
||||
|
||||
sed -e "s:':\\'\\\'\\':" -e "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>$TMPFILE
|
||||
|
||||
sh $TMPFILE | sed -e 's/\$cwd/\$PWD/g' \
|
||||
-e 's/\$term/\$TERM/g' \
|
||||
-e 's/\$home/\$HOME/g' \
|
||||
-e 's/\$user/\$USER/g' \
|
||||
-e 's/\$prompt/\$PS1/g'
|
||||
|
||||
exit 0
|
139
examples/misc/cshtobash
Normal file
139
examples/misc/cshtobash
Normal file
|
@ -0,0 +1,139 @@
|
|||
#! /bin/bash
|
||||
#
|
||||
# cshtobash - convert csh aliases, environment variables, and variables to
|
||||
# bash equivalents
|
||||
#
|
||||
# usage: cshtobash [filename]
|
||||
#
|
||||
# If filename is given, that file is sourced. Note that csh always
|
||||
# sources .cshrc. To recreate your csh login environment, run
|
||||
# `cshtobash ~/.login'.
|
||||
#
|
||||
# Inspired by (and some borrowed from) a similar program distributed with
|
||||
# zsh-3.0.
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet@po.cwru.edu
|
||||
#
|
||||
trap 'rm -f $TMPFILE1 $TMPFILEa $TMPFILEe $TMPFILEv $TMPFILEco $TMPFILEci' 0 1 2 3 6 15
|
||||
|
||||
{ TMPFILE1=$(mktemp -t cb.1.XXXXXX) &&
|
||||
TMPFILEa=$(mktemp -t cb.a.XXXXXX) &&
|
||||
TMPFILEe=$(mktemp -t cb.e.XXXXXX) &&
|
||||
TMPFILEv=$(mktemp -t cb.v.XXXXXX) &&
|
||||
TMPFILEco=$(mktemp -t cshout.XXXXXX) &&
|
||||
TMPFILEci=$(mktemp -t cshin.XXXXXX)
|
||||
} || exit 1
|
||||
|
||||
|
||||
T=$'\t'
|
||||
|
||||
SOURCE="${1:+source $1}"
|
||||
|
||||
cat << EOF >$TMPFILEci
|
||||
$SOURCE
|
||||
alias >! $TMPFILEa
|
||||
setenv >! $TMPFILEe
|
||||
set >! $TMPFILEv
|
||||
EOF
|
||||
|
||||
# give csh a minimal environment, similar to what login would provide
|
||||
/usr/bin/env - USER=$USER HOME=$HOME PATH=/usr/bin:/bin:/usr/ucb:. TERM=$TERM SHELL=$SHELL /bin/csh -i < $TMPFILEci > $TMPFILEco 2>&1
|
||||
|
||||
# First convert aliases
|
||||
|
||||
cat << \EOF >$TMPFILE1
|
||||
mkalias ()
|
||||
{
|
||||
case $2 in
|
||||
'') echo alias ${1}="''" ;;
|
||||
*[#\!]*)
|
||||
comm=$(echo $2 | sed 's/\!\*/"$\@"/g
|
||||
s/\!:\([1-9]\)/"$\1"/g
|
||||
s/#/\#/g')
|
||||
echo $1 \(\) "{" command "$comm" "; }"
|
||||
;;
|
||||
*) echo alias ${1}=\'$(echo "${2}" | sed "s:':'\\\\'':")\' ;;
|
||||
esac
|
||||
}
|
||||
EOF
|
||||
|
||||
sed "s/^\([a-zA-Z0-9_]*\)$T\(.*\)$/mkalias \1 '\2'/" < $TMPFILEa >>$TMPFILE1
|
||||
|
||||
echo '# csh aliases'
|
||||
echo
|
||||
|
||||
$BASH $TMPFILE1 | sed -e 's/\$cwd/\$PWD/g' \
|
||||
-e 's/\$term/\$TERM/g' \
|
||||
-e 's/\$home/\$HOME/g' \
|
||||
-e 's/\$user/\$USER/g' \
|
||||
-e 's/\$prompt/\$PS1/g'
|
||||
|
||||
# Next, convert environment variables
|
||||
echo
|
||||
echo '# csh environment variables'
|
||||
echo
|
||||
|
||||
# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ...
|
||||
sed -e '/^SHLVL/d' \
|
||||
-e '/^PWD/d' \
|
||||
-e "s/'/'"\\\\"''"/g \
|
||||
-e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \
|
||||
-e "s/$/'/" < $TMPFILEe
|
||||
|
||||
# Finally, convert local variables
|
||||
echo
|
||||
echo '# csh variables'
|
||||
echo
|
||||
|
||||
sed -e 's/'"$T"'/=/' \
|
||||
-e "s/'/'"\\\\"''"/g \
|
||||
-e '/^[A-Za-z0-9_]*=[^(]/{
|
||||
s/=/='"'/"'
|
||||
s/$/'"'/"'
|
||||
}' < $TMPFILEv |
|
||||
sed -e '/^argv=/d' -e '/^cwd=/d' -e '/^filec=/d' -e '/^status=/d' \
|
||||
-e '/^verbose=/d' \
|
||||
-e '/^term=/d' \
|
||||
-e '/^home=/d' \
|
||||
-e '/^path=/d' \
|
||||
-e '/^user=/d' \
|
||||
-e '/^shell=/d' \
|
||||
-e '/^cdpath=/d' \
|
||||
-e '/^mail=/d' \
|
||||
-e '/^home=/s//HOME=/' \
|
||||
-e '/^prompt=/s//PS1=/' \
|
||||
-e '/^histfile=/s//HISTFILE=/' \
|
||||
-e '/^history=/s//HISTSIZE=/' \
|
||||
-e '/^savehist=$/s//HISTFILESIZE=${HISTSIZE-500}/' \
|
||||
-e '/^savehist=/s//HISTFILESIZE=/' \
|
||||
-e '/^ignoreeof=$/s/^.*$/set -o ignoreeof # ignoreeof/' \
|
||||
-e '/^ignoreeof=/s//IGNOREEOF=/' \
|
||||
-e '/^noclobber=/s/^.*$/set -C # noclobber/' \
|
||||
-e '/^notify=/s/^.*$/set -b # notify/' \
|
||||
-e '/^noglob=/s/^.*$/set -f # noglob/' \
|
||||
|
||||
|
||||
# now some special csh variables converted to bash equivalents
|
||||
echo
|
||||
echo '# special csh variables converted to bash equivalents'
|
||||
echo
|
||||
|
||||
sed -e 's/'"$T"'/=/' < $TMPFILEv |
|
||||
grep "^cdpath=" |
|
||||
sed 's/(//
|
||||
s/ /:/g
|
||||
s/)//
|
||||
s/cdpath=/CDPATH=/'
|
||||
|
||||
|
||||
sed -e 's/'"$T"'/=/' < $TMPFILEv |
|
||||
grep "^mail=" |
|
||||
sed 's/(//
|
||||
s/ /:/g
|
||||
s/)//
|
||||
s/mail=/MAILPATH=/' |
|
||||
sed -e 's/MAILPATH=\([0-9][0-9][^:]*\)$/MAILCHECK=\1/' \
|
||||
-e 's/MAILPATH=\([0-9][0-9][^:]*\):\(.*\)/MAILCHECK=\1 MAILPATH=\2/'
|
||||
|
||||
exit 0
|
104
examples/scripts/bcalc
Normal file
104
examples/scripts/bcalc
Normal file
|
@ -0,0 +1,104 @@
|
|||
#! /bin/bash
|
||||
#
|
||||
# bcalc - a coproc example that uses bc to evaluate floating point expressions
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# If supplied command-line arguments, it uses them as the expression to have
|
||||
# bc evaluate, and exits after reading the result. Otherwise, it enters an
|
||||
# interactive mode, reading expressions and passing them to bc for evaluation,
|
||||
# with line editing and history.
|
||||
#
|
||||
# You could even use this to write bc programs, but you'd have to rework the
|
||||
# single-line REPL a little bit to do that (and get over the annoying timeout
|
||||
# on the read)
|
||||
#
|
||||
# Chet Ramey
|
||||
# chet.ramey@case.edu
|
||||
|
||||
# we force stderr to avoid synchronization issues on calculation errors, even
|
||||
# with the read timeout
|
||||
init()
|
||||
{
|
||||
coproc BC { bc -q 2>&1; }
|
||||
# set scale
|
||||
printf "scale = 10\n" >&${BC[1]}
|
||||
# bash automatically sets BC_PID to the coproc pid; we store it so we
|
||||
# can be sure to use it even after bash reaps the coproc and unsets
|
||||
# the variables
|
||||
coproc_pid=$BC_PID
|
||||
}
|
||||
|
||||
# not strictly necessary; the pipes will be closed when the program exits
|
||||
# but we can use it in reset() below
|
||||
fini()
|
||||
{
|
||||
eval exec "${BC[1]}>&- ${BC[0]}<&-"
|
||||
}
|
||||
|
||||
reset()
|
||||
{
|
||||
fini # close the old pipes
|
||||
|
||||
sleep 1
|
||||
kill -1 $coproc_pid >/dev/null 2>&1 # make sure the coproc is dead
|
||||
unset coproc_pid
|
||||
|
||||
init
|
||||
}
|
||||
|
||||
# set a read timeout of a half second to avoid synchronization problems
|
||||
calc()
|
||||
{
|
||||
printf "%s\n" "$1" >&${BC[1]}
|
||||
read -t 0.5 ANSWER <&${BC[0]}
|
||||
}
|
||||
|
||||
init
|
||||
|
||||
# if we have command line options, process them as a single expression and
|
||||
# print the result. we could just run `bc <<<"scale = 10 ; $*"' and be done
|
||||
# with it, but we init the coproc before this and run the calculation through
|
||||
# the pipes in case we want to do something else with the answer
|
||||
|
||||
if [ $# -gt 0 ] ; then
|
||||
calc "$*"
|
||||
printf "%s\n" "$ANSWER"
|
||||
fini
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# we don't want to save the history anywhere
|
||||
unset HISTFILE
|
||||
|
||||
while read -e -p 'equation: ' EQN
|
||||
do
|
||||
case "$EQN" in
|
||||
'') continue ;;
|
||||
exit|quit) break ;;
|
||||
reset) reset ; continue ;;
|
||||
esac
|
||||
|
||||
# save to the history list
|
||||
history -s "$EQN"
|
||||
|
||||
# run it through bc
|
||||
calc "$EQN"
|
||||
if [ -n "$ANSWER" ] ; then
|
||||
printf "%s\n" "$ANSWER"
|
||||
fi
|
||||
done
|
||||
fini
|
||||
|
||||
exit 0
|
12
examples/scripts/cat.sh
Normal file
12
examples/scripts/cat.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
shcat()
|
||||
{
|
||||
while read -r ; do
|
||||
printf "%s\n" "$REPLY"
|
||||
done
|
||||
}
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
shcat < "$1"
|
||||
else
|
||||
shcat
|
||||
fi
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue