diff options
Diffstat (limited to 'examples')
-rwxr-xr-x[-rw-r--r--] | examples/bashdb/bashdb | 596 | ||||
-rw-r--r-- | examples/bashdb/bashdb.el | 177 | ||||
-rw-r--r-- | examples/complete/complete-examples | 14 | ||||
-rw-r--r-- | examples/functions/inetaddr | 2 | ||||
-rw-r--r-- | examples/functions/isvalidip | 14 | ||||
-rw-r--r-- | examples/functions/manpage | 2 | ||||
-rw-r--r-- | examples/functions/mhfold | 2 | ||||
-rw-r--r-- | examples/loadables/Makefile.in | 7 | ||||
-rw-r--r-- | examples/loadables/finfo.c | 8 | ||||
-rw-r--r-- | examples/loadables/getconf.c | 10 | ||||
-rw-r--r-- | examples/loadables/print.c | 9 | ||||
-rw-r--r-- | examples/obashdb/PERMISSION | 27 | ||||
-rw-r--r-- | examples/obashdb/README (renamed from examples/bashdb/README) | 0 | ||||
-rw-r--r-- | examples/obashdb/bashdb | 33 | ||||
-rw-r--r-- | examples/obashdb/bashdb.fns (renamed from examples/bashdb/bashdb.fns) | 0 | ||||
-rw-r--r-- | examples/obashdb/bashdb.pre (renamed from examples/bashdb/bashdb.pre) | 0 | ||||
-rw-r--r-- | examples/scripts.v2/pmtop | 2 | ||||
-rw-r--r-- | examples/scripts.v2/ren | 585 | ||||
-rwxr-xr-x | examples/scripts/bcsh.sh | 6 | ||||
-rw-r--r-- | examples/scripts/self-repro | 9 | ||||
-rwxr-xr-x | examples/scripts/vtree2 | 2 | ||||
-rw-r--r-- | examples/startup-files/apple/aliases | 2 |
22 files changed, 1461 insertions, 46 deletions
diff --git a/examples/bashdb/bashdb b/examples/bashdb/bashdb index 97d287d..2bca9f9 100644..100755 --- a/examples/bashdb/bashdb +++ b/examples/bashdb/bashdb @@ -1,33 +1,581 @@ -# kshdb - Korn Shell Debugger main file -# adapted from 'Learning the Korn Shell' by Bill Rosenblatt (O'Reilly) -# by Cigy Cyriac (cigy@felix.tulblr.unisys.com) -# Main driver: constructs full script (with preamble) and runs it +#! /bin/bash +# bashdb - Bash shell debugger +# +# Adapted from an idea in O'Reilly's `Learning the Korn Shell' +# Copyright (C) 1993-1994 O'Reilly and Associates, Inc. +# Copyright (C) 1998, 1999, 2001 Gary V. Vaughan <gvv@techie.com>> +# +# 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 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. -echo 'Bourne-Again Shell Debugger version 0.1' +# NOTE: +# +# This program requires bash 2.x. +# If bash 2.x is installed as "bash2", you can invoke bashdb like this: +# +# DEBUG_SHELL=/bin/bash2 /bin/bash2 bashdb script.sh -_pname=${0##*/} +# TODO: +# +# break [regexp] +# cond [break] [condition] +# tbreak [regexp|+lines] +# restart +# Variable watchpoints +# Instrument `source' and `.' files in $_potbelliedpig +# be cleverer about lines we allow breakpoints to be set on +# break [function_name] -[ $# -eq 0 ] && { - echo "${_pname}: usage: ${_pname} <script_file>" - exit 1 -} +echo 'Bash Debugger version 1.2.4' + +export _dbname=${0##*/} + +if test $# -lt 1; then + echo "$_dbname: Usage: $_dbname filename" >&2 + exit 1 +fi _guineapig=$1 -[ -r $_guineapig ] || { - echo "${_pname}: cannot read $_guineapig." >&2 - exit 1 -} +if test ! -r $1; then + echo "$_dbname: Cannot read file '$_guineapig'." >&2 + exit 1 +fi + shift -_tmpdir=/tmp -_libdir=. -_dbgfile=$_tmpdir/bashdb$$ #temp file for script being debugged +__debug=${TMPDIR-/tmp}/bashdb.$$ +sed -e '/^# bashdb - Bash shell debugger/,/^# -- DO NOT DELETE THIS LINE -- /d' "$0" > $__debug +cat $_guineapig >> $__debug +exec ${DEBUG_SHELL-bash} $__debug $_guineapig "$@" -cat $_libdir/bashdb.pre $_guineapig > $_dbgfile -if [ -f "$BASH" ]; then - exec $BASH $_dbgfile $_guineapig $_tmpdir $_libdir "$@" -else - exec bash $_dbgfile $_guineapig $_tmpdir $_libdir "$@" -fi -# end of bashdb +exit 1 + +# -- DO NOT DELETE THIS LINE -- The program depends on it + +#bashdb preamble +# $1 name of the original guinea pig script + +__debug=$0 +_guineapig=$1 +__steptrap_calls=0 + +shift + +shopt -s extglob # turn on extglob so we can parse the debugger funcs + +function _steptrap +{ + local i=0 + + _curline=$1 + + if (( ++__steptrap_calls > 1 && $_curline == 1 )); then + return + fi + + if [ -n "$_disps" ]; then + while (( $i < ${#_disps[@]} )) + do + if [ -n "${_disps[$i]}" ]; then + _msg "${_disps[$i]}: \c" + eval _msg ${_disps[$i]} + fi + let i=$i+1 + done + fi + + if (( $_trace )); then + _showline $_curline + fi + + if (( $_steps >= 0 )); then + let _steps="$_steps - 1" + fi + + if _at_linenumbp ; then + _msg "Reached breakpoint at line $_curline" + _showline $_curline + _cmdloop + elif [ -n "$_brcond" ] && eval $_brcond; then + _msg "Break condition $_brcond true at line $_curline" + _showline $_curline + _cmdloop + elif (( $_steps == 0 )); then + # Assuming a real script will have the "#! /bin/sh" at line 1, + # assume that when $_curline == 1 we are inside backticks. + if (( ! $_trace )); then + _msg "Stopped at line $_curline" + _showline $_curline + fi + _cmdloop + fi +} + +function _setbp +{ + local i f line _x + + if [ -z "$1" ]; then + _listbp + return + fi + + eval "$_seteglob" + + if [[ $1 == *(\+)[1-9]*([0-9]) ]]; then + case $1 in + +*) + # normalize argument, then double it (+2 -> +2 + 2 = 4) + _x=${1##*([!1-9])} # cut off non-numeric prefix + _x=${x%%*([!0-9])} # cut off non-numeric suffix + f=$(( $1 + $_x )) + ;; + *) + f=$(( $1 )) + ;; + esac + + # find the next valid line + line="${_lines[$f]}" + while _invalidbreakp $f + do + (( f++ )) + line="${_lines[$f]}" + done + + if (( $f != $1 )) + then + _msg "Line $1 is not a valid breakpoint" + fi + + if [ -n "${_lines[$f]}" ]; then + _linebp[$1]=$1; + _msg "Breakpoint set at line $f" + else + _msg "Breakpoints can only be set on executable lines" + fi + else + _msg "Please specify a numeric line number" + fi + + eval "$_resteglob" +} + +function _listbp +{ + local i + + if [ -n "$_linebp" ]; then + _msg "Breakpoints:" + for i in ${_linebp[*]}; do + _showline $i + done + else + _msg "No breakpoints have been set" + fi +} + +function _clearbp +{ + local i + + if [ -z "$1" ]; then + read -e -p "Delete all breakpoints? " + case $REPLY in + [yY]*) + unset _linebp[*] + _msg "All breakpoints have been cleared" + ;; + esac + return 0 + fi + + eval "$_seteglob" + + if [[ $1 == [1-9]*([0-9]) ]]; then + unset _linebp[$1] + _msg "Breakpoint cleared at line $1" + else + _msg "Please specify a numeric line number" + fi + + eval "$_resteglob" +} + +function _setbc +{ + if (( $# > 0 )); then + _brcond=$@ + _msg "Break when true: $_brcond" + else + _brcond= + _msg "Break condition cleared" + fi +} + +function _setdisp +{ + if [ -z "$1" ]; then + _listdisp + else + _disps[${#_disps[@]}]="$1" + if (( ${#_disps[@]} < 10 )) + then + _msg " ${#_disps[@]}: $1" + else + _msg "${#_disps[@]}: $1" + fi + fi +} + +function _listdisp +{ + local i=0 j + + if [ -n "$_disps" ]; then + while (( $i < ${#_disps[@]} )) + do + let j=$i+1 + if (( ${#_disps[@]} < 10 )) + then + _msg " $j: ${_disps[$i]}" + else + _msg "$j: ${_disps[$i]}" + fi + let i=$j + done + else + _msg "No displays have been set" + fi +} + +function _cleardisp +{ + if (( $# < 1 )) ; then + read -e -p "Delete all display expressions? " + case $REPLY in + [Yy]*) + unset _disps[*] + _msg "All breakpoints have been cleared" + ;; + esac + return 0 + fi + + eval "$_seteglob" + + if [[ $1 == [1-9]*([0-9]) ]]; then + unset _disps[$1] + _msg "Display $i has been cleared" + else + _listdisp + _msg "Please specify a numeric display number" + fi + + eval "$_resteglob" +} + +# usage _ftrace -u funcname [funcname...] +function _ftrace +{ + local _opt=-t _tmsg="enabled" _func + if [[ $1 == -u ]]; then + _opt=+t + _tmsg="disabled" + shift + fi + for _func; do + declare -f $_opt $_func + _msg "Tracing $_tmsg for function $_func" + done +} + +function _cmdloop +{ + local cmd args + + while read -e -p "bashdb> " cmd args; do + test -n "$cmd" && history -s "$cmd $args" # save on history list + test -n "$cmd" || { set $_lastcmd; cmd=$1; shift; args=$*; } + if [ -n "$cmd" ] + then + case $cmd in + b|br|bre|brea|break) + _setbp $args + _lastcmd="break $args" + ;; + co|con) + _msg "ambiguous command: '$cmd', condition, continue?" + ;; + cond|condi|condit|conditi|conditio|condition) + _setbc $args + _lastcmd="condition $args" + ;; + c|cont|conti|contin|continu|continue) + _lastcmd="continue" + return + ;; + d) + _msg "ambiguous command: '$cmd', delete, display?" + ;; + de|del|dele|delet|delete) + _clearbp $args + _lastcmd="delete $args" + ;; + di|dis|disp|displ|displa|display) + _setdisp $args + _lastcmd="display $args" + ;; + f|ft|ftr|ftra|ftrace) + _ftrace $args + _lastcmd="ftrace $args" + ;; + \?|h|he|hel|help) + _menu + _lastcmd="help" + ;; + l|li|lis|list) + _displayscript $args + # _lastcmd is set in the _displayscript function + ;; + p|pr|pri|prin|print) + _examine $args + _lastcmd="print $args" + ;; + q|qu|qui|quit) + exit + ;; + s|st|ste|step|n|ne|nex|next) + let _steps=${args:-1} + _lastcmd="next $args" + return + ;; + t|tr|tra|trac|trace) + _xtrace + ;; + u|un|und|undi|undis|undisp|undispl|undispla|undisplay) + _cleardisp $args + _lastcmd="undisplay $args" + ;; + !*) + eval ${cmd#!} $args + _lastcmd="$cmd $args" + ;; + *) + _msg "Invalid command: '$cmd'" + ;; + esac + fi + done +} + +function _at_linenumbp +{ + [[ -n ${_linebp[$_curline]} ]] +} + +function _invalidbreakp +{ + local line=${_lines[$1]} + + # XXX - should use shell patterns + if test -z "$line" \ + || expr "$line" : '[ \t]*#.*' > /dev/null \ + || expr "$line" : '[ \t]*;;[ \t]*$' > /dev/null \ + || expr "$line" : '[ \t]*[^)]*)[ \t]*$' > /dev/null \ + || expr "$line" : '[ \t]*;;[ \t]*#.**$' > /dev/null \ + || expr "$line" : '[ \t]*[^)]*)[ \t]*;;[ \t]*$' > /dev/null \ + || expr "$line" : '[ \t]*[^)]*)[ \t]*;;*[ \t]*#.*$' > /dev/null + then + return 0 + fi + + return 1 +} + +function _examine +{ + if [ -n "$*" ]; then + _msg "$args: \c" + eval _msg $args + else + _msg "Nothing to print" + fi +} + +function _displayscript +{ + local i j start end bp cl + + if (( $# == 1 )); then # list 5 lines on either side of $1 + if [ $1 = "%" ]; then + let start=1 + let end=${#_lines[@]} + else + let start=$1-5 + let end=$1+5 + fi + elif (( $# > 1 )); then # list between start and end + if [ $1 = "^" ]; then + let start=1 + else + let start=$1 + fi + + if [ $2 = "\$" ]; then + let end=${#_lines[@]} + else + let end=$2 + fi + else # list 5 lines on either side of current line + let start=$_curline-5 + let end=$_curline+5 + fi + + # normalize start and end + if (( $start < 1 )); then + start=1 + fi + if (( $end > ${#_lines[@]} )); then + end=${#_lines[@]} + fi + + cl=$(( $end - $start )) + if (( $cl > ${LINES-24} )); then + pager=${PAGER-more} + else + pager=cat + fi + + i=$start + ( while (( $i <= $end )); do + _showline $i + let i=$i+1 + done ) 2>&1 | $pager + + # calculate the next block of lines + start=$(( $end + 1 )) + end=$(( $start + 11 )) + if (( $end > ${#_lines[@]} )) + then + end=${#_lines[@]} + fi + + _lastcmd="list $start $end" +} + +function _xtrace +{ + let _trace="! $_trace" + if (( $_trace )); then + _msg "Execution trace on" + else + _msg "Execution trace off" + fi +} + +function _msg +{ + echo -e "$@" >&2 +} + +function _showline +{ + local i=0 bp=' ' line=$1 cl=' ' + + if [[ -n ${_linebp[$line]} ]]; then + bp='*' + fi + + if (( $_curline == $line )); then + cl=">" + fi + + if (( $line < 100 )); then + _msg "$_guineapig:$line $bp $cl${_lines[$line]}" + elif (( $line < 10 )); then + _msg "$_guineapig:$line $bp $cl${_lines[$line]}" + elif (( $line > 0 )); then + _msg "$_guineapig:$line $bp $cl${_lines[$line]}" + fi +} + +function _cleanup +{ + rm -f $__debug $_potbelliedpig 2> /dev/null +} + +function _menu +{ + _msg 'bashdb commands: + break N set breakpoint at line N + break list breakpoints & break condition + condition foo set break condition to foo + condition clear break condition + delete N clear breakpoint at line N + delete clear all breakpoints + display EXP evaluate and display EXP for each debug step + display show a list of display expressions + undisplay N remove display expression N + list N M display all lines of script between N and M + list N display 5 lines of script either side of line N + list display 5 lines if script either side of current line + continue continue execution upto next breakpoint + next [N] execute [N] statements (default 1) + print expr prints the value of an expression + trace toggle execution trace on/off + ftrace [-u] func make the debugger step into function FUNC + (-u turns off tracing FUNC) + help print this menu + ! string passes string to a shell + quit quit' +} + +shopt -u extglob + +HISTFILE=~/.bashdb_history +set -o history +set +H + +# strings to save and restore the setting of `extglob' in debugger functions +# that need it +_seteglob='local __eopt=-u ; shopt -q extglob && __eopt=-s ; shopt -s extglob' +_resteglob='shopt $__eopt extglob' + +_linebp=() +let _trace=0 +let _i=1 + +# Be careful about quoted newlines +_potbelliedpig=${TMPDIR-/tmp}/$_guineapig.$$ +sed 's,\\$,\\\\,' $_guineapig > $_potbelliedpig + +_msg "Reading source from file: $_guineapig" +while read; do + _lines[$_i]=$REPLY + let _i=$_i+1 +done < $_potbelliedpig + +trap _cleanup EXIT +# Assuming a real script will have the "#! /bin/sh" at line 1, +# don't stop at line 1 on the first run +let _steps=1 +LINENO=-1 +trap '_steptrap $LINENO' DEBUG diff --git a/examples/bashdb/bashdb.el b/examples/bashdb/bashdb.el new file mode 100644 index 0000000..40584dd --- /dev/null +++ b/examples/bashdb/bashdb.el @@ -0,0 +1,177 @@ +;;; bashdb.el --- Grand Unified Debugger mode for running bashdb +;; Copyright (C) 2000, 2001 Masatake YAMATO + +;; Author: Masatake YAMATO <jet@gyve.org> + +;; 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 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, write to the Free Software Foundation, +;; Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +;; Commentary: +;; This program may run on Emacs 21.0.91 and XEmacs 21.1. +;; +;; Put +;; (autoload 'bashdb "bashdb" "Run bashdb" t nil) +;; to your .emacs. +;; M-x bashdb +;; Run bashdb (like this): bashdb target.sh +;; +;; About bashdb: +;; You can get bashdb from +;; http://www.oranda.demon.co.uk/development.html +;; +;; bashdb.el is based on perldb in gud.el in XEmacs 21.1. + +;; Revision: +;; $Revision: 1.6 $ +;; $Log: bashdb.el,v $ +;; Revision 1.6 2001/01/06 12:18:06 masata-y +;; Write note about XEmacs. +;; +;; + + +;;; Code: +(require 'gud) + +;; User customizable variable +(defcustom gud-bashdb-command-name "bashdb" + "File name for executing Bashdb." + :type 'string + :group 'gud) + +;; History of argument lists passed to bashdb. +(defvar gud-bashdb-history nil) + +(defun gud-bashdb-massage-args (file args) + (if xemacsp + (cons (file-name-nondirectory file) args) + args)) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(if xemacsp + (defvar gud-bashdb-marker-acc "")) +(defun gud-bashdb-marker-acc () + (if xemacsp + gud-bashdb-marker-acc + gud-marker-acc)) +(defun gud-bashdb-marker-acc-quote () + (if xemacsp + 'gud-bashdb-marker-acc + 'gud-marker-acc)) + +(defun gud-bashdb-marker-filter (string) + (save-match-data + (set (gud-bashdb-marker-acc-quote) + (concat (gud-bashdb-marker-acc) string)) + (let ((output "")) + ;; Process all the complete markers in this chunk. + (while (string-match "^\\([^:\n]+\\):\\([0-9]+\\)[ *]*>.*\n" + (gud-bashdb-marker-acc)) + (setq + ;; Extract the frame position from the marker. + gud-last-frame (cons + (substring (gud-bashdb-marker-acc) + (match-beginning 1) + (match-end 1)) + (string-to-int + (substring (gud-bashdb-marker-acc) + (match-beginning 2) + (match-end 2)))) + ;; Append any text before the marker to the output we're going + ;; to return - we don't include the marker in this text. + output (concat output + (substring (gud-bashdb-marker-acc) 0 (match-beginning 0)))) + ;; Set the accumulator to the remaining text. + (set + (gud-bashdb-marker-acc-quote) (substring + (gud-bashdb-marker-acc) (match-end 0)))) + + ;; Does the remaining text look like it might end with the + ;; beginning of another marker? If it does, then keep it in + ;; (gud-bashdb-marker-acc) until we receive the rest of it. Since we + ;; know the full marker regexp above failed, it's pretty simple to + ;; test for marker starts. + (if (string-match "^\\([^:\n]+\\):\\([0-9]+\\)[ *]*>" (gud-bashdb-marker-acc)) + (progn + ;; Everything before the potential marker start can be output. + (setq output (concat output (substring (gud-bashdb-marker-acc) + 0 (match-beginning 0)))) + ;; Everything after, we save, to combine with later input. + (set (gud-bashdb-marker-acc-quote) + (substring (gud-bashdb-marker-acc) (match-beginning 0)))) + + (setq output (concat output (gud-bashdb-marker-acc))) + (set (gud-bashdb-marker-acc-quote) "")) + + output))) + +(defun gud-bashdb-find-file (f) + (find-file-noselect f)) + +;;;###autoload +(defun bashdb (command-line) + "Run bashdb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (if xemacsp + (list (read-from-minibuffer "Run bashdb (like this): " + (if (consp gud-bashdb-history) + (car gud-bashdb-history) + (format "%s " gud-bashdb-command-name)) + nil nil + '(gud-bashdb-history . 1))) + (list (gud-query-cmdline 'bashdb)) + )) + + (if xemacsp + (progn + (gud-overload-functions '((gud-massage-args . gud-bashdb-massage-args) + (gud-marker-filter . gud-bashdb-marker-filter) + (gud-find-file . gud-bashdb-find-file))) + (gud-common-init command-line gud-bashdb-command-name)) + (gud-common-init command-line 'gud-bashdb-massage-args + 'gud-bashdb-marker-filter 'gud-bashdb-find-file) + (set (make-local-variable 'gud-minor-mode) 'bashdb)) + +;; Unsupported commands +;; condition foo set break condition to foo +;; condition clear break condition +;; display EXP evaluate and display EXP for each debug step +;; display show a list of display expressions +;; undisplay N remove display expression N +;; ! string passes string to a shell +;; quit quit + + (gud-def gud-break "break %l" "\C-b" "Set breakpoint at current line.") + (gud-def gud-list-break "break" "b" "List breakpoints & break condition.") + (gud-def gud-remove "delete %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-remove-all "delete" "d" "Clear all breakpoints") + (gud-def gud-cont "continue" "\C-r" "Continue with display.") + (gud-def gud-next "next" "\C-n" "Step one line (skip functions).") + (gud-def gud-print "print %e" "\C-p" "Evaluate bash expression at point.") + (gud-def gud-help "help" "h" "Show all commands.") + (gud-def gud-trace "trace" "t" "Toggle execution trace on/off") + + (setq comint-prompt-regexp "^bashdb> ") + (setq paragraph-start comint-prompt-regexp) + (run-hooks 'bashdb-mode-hook)) + +(provide 'bashdb) +;; bashdb.el ends here diff --git a/examples/complete/complete-examples b/examples/complete/complete-examples index 9c0721d..baa97e3 100644 --- a/examples/complete/complete-examples +++ b/examples/complete/complete-examples @@ -162,11 +162,11 @@ _declare_func() COMPREPLY=() if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then - COMPREPLY=(-a -f -F -i -r -x -p) + COMPREPLY=(-a -f -F -i -p -r -t -x) return 0; fi if [[ $cur == '+' ]]; then - COMPREPLY=(+i +x) + COMPREPLY=(+i +t +x) return 0; fi if [[ $prev == '-p' ]]; then @@ -252,7 +252,7 @@ _hash_func() prev=${COMP_WORDS[COMP_CWORD-1]} if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then - COMPREPLY=(-p -r) + COMPREPLY=(-p -r -t) return 0; fi @@ -344,8 +344,8 @@ _complete_meta_func() if (( $COMP_CWORD <= 1 )) || [[ "$cur" == '-' ]]; then case "$cmd" in - complete) COMPREPLY=(-a -b -c -d -e -f -j -k -v -u -r -p -A -G -W -P -S -X -F -C);; - compgen) COMPREPLY=(-a -b -c -d -e -f -j -k -v -u -A -G -W -P -S -X -F -C);; + 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 @@ -353,7 +353,7 @@ _complete_meta_func() if [[ $prev == -A ]]; then COMPREPLY=(alias arrayvar binding builtin command directory \ disabled enabled export file 'function' helptopic hostname job keyword \ -running setopt shopt signal stopped variable) +running service setopt shopt signal stopped variable) return 0 elif [[ $prev == -F ]]; then COMPREPLY=( $( compgen -A function $cur ) ) @@ -466,7 +466,7 @@ 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 +complete -f -X '!*.bz2' bunzip2 bzcat complete -f -X '!*.zip' unzip complete -f -X '!*.+(gif|jpg|jpeg|GIF|JPG|JPEG|bmp)' xv diff --git a/examples/functions/inetaddr b/examples/functions/inetaddr index 08086ae..f3e228f 100644 --- a/examples/functions/inetaddr +++ b/examples/functions/inetaddr @@ -30,7 +30,7 @@ hex2inet () do case "$o" in r) rev=true;; - *) echo "hex2inet: usage: hex2inet [0x]XXXXXXXX" >&2 ; exit 2;; + *) echo "hex2inet: usage: hex2inet [-r] [0x]XXXXXXXX" >&2 ; exit 2;; esac done shift $(( $OPTIND - 1 )) diff --git a/examples/functions/isvalidip b/examples/functions/isvalidip new file mode 100644 index 0000000..0b2dafe --- /dev/null +++ b/examples/functions/isvalidip @@ -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 ] +} diff --git a/examples/functions/manpage b/examples/functions/manpage index 3fdc7ac..224643e 100644 --- a/examples/functions/manpage +++ b/examples/functions/manpage @@ -25,7 +25,7 @@ function manpage () set $file file="$1" if [ -f "$file" ]; then - zot=$(head -1 "$file") + zot=$(sed 1q "$file") cmd=${MANROFF:-"nroff -man - | col | cat -s"} h=${zot##"'"'\"'} if [ "$h" != "$zot" ]; then diff --git a/examples/functions/mhfold b/examples/functions/mhfold index a4a5f70..3c0c743 100644 --- a/examples/functions/mhfold +++ b/examples/functions/mhfold @@ -7,7 +7,7 @@ mhfold() { - list=`folders | tail +2 | awk '{print $1}'` + list=`folders | awk '{if (1 < NR) print $1}'` /bin/ls -lag ~/Mail > /tmp/fold$$ for i in $list; do grep $i /tmp/fold$$ diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in index 4851ff8..ed1721f 100644 --- a/examples/loadables/Makefile.in +++ b/examples/loadables/Makefile.in @@ -42,6 +42,11 @@ host_cpu = @host_cpu@ host_vendor = @host_vendor@ CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +DEFS = @DEFS@ +LOCAL_DEFS = @LOCAL_DEFS@ + +CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS) # # These values are generated for configure by ${topdir}/support/shobj-conf. @@ -62,7 +67,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ -I$(BUILD_DIR)/builtins .c.o: - $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ $< + $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $< ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ diff --git a/examples/loadables/finfo.c b/examples/loadables/finfo.c index 1c53860..b633629 100644 --- a/examples/loadables/finfo.c +++ b/examples/loadables/finfo.c @@ -2,6 +2,10 @@ * finfo - print file info */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <sys/types.h> #include "posixstat.h" #include <stdio.h> @@ -127,10 +131,10 @@ char *f; { static struct stat st; int fd, r; - long lfd; + intmax_t lfd; if (strncmp(f, "/dev/fd/", 8) == 0) { - if (legal_number(f + 8, &lfd) == 0) { + if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) { builtin_error("%s: invalid fd", f + 8); return ((struct stat *)0); } diff --git a/examples/loadables/getconf.c b/examples/loadables/getconf.c index fc1c1d1..5d079b6 100644 --- a/examples/loadables/getconf.c +++ b/examples/loadables/getconf.c @@ -49,10 +49,19 @@ #endif #include <stdio.h> +#ifdef HAVE_LIMITS_H #include <limits.h> +#endif +#ifdef HAVE_LOCALE_H #include <locale.h> +#endif +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif #include <errno.h> + +#include "typemax.h" + #include "bashansi.h" #include "shell.h" #include "builtins.h" @@ -857,7 +866,6 @@ static const struct conf_variable conf_table[] = static int num_getconf_variables = sizeof(conf_table) / sizeof(struct conf_variable) - 1; extern char *this_command_name; -extern char *xmalloc (); extern char **make_builtin_argv (); static void getconf_help (); diff --git a/examples/loadables/print.c b/examples/loadables/print.c index 80943bc..ad658a7 100644 --- a/examples/loadables/print.c +++ b/examples/loadables/print.c @@ -2,6 +2,10 @@ * print -- loadable ksh-93 style print builtin */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include "bashtypes.h" #include <errno.h> @@ -50,6 +54,7 @@ print_builtin (list) WORD_LIST *list; { int c, r, nflag, raw, ofd, sflag; + intmax_t lfd; char **v, *pfmt, *arg; WORD_LIST *l; @@ -83,8 +88,8 @@ print_builtin (list) case 'p': break; /* NOP */ case 'u': - if (all_digits (list_optarg)) - ofd = atoi (list_optarg); + 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); diff --git a/examples/obashdb/PERMISSION b/examples/obashdb/PERMISSION new file mode 100644 index 0000000..4e9460c --- /dev/null +++ b/examples/obashdb/PERMISSION @@ -0,0 +1,27 @@ +From mikel@ora.com Tue Aug 1 12:13:20 1995 +Flags: 10 +Return-Path: mikel@ora.com +Received: from ruby.ora.com (ruby.ora.com [198.112.208.25]) by odin.INS.CWRU.Edu with ESMTP (8.6.12+cwru/CWRU-2.1-ins) + id MAA01565; Tue, 1 Aug 1995 12:13:18 -0400 (from mikel@ora.com for <chet@odin.INS.CWRU.Edu>) +Received: (from fax@localhost) by ruby.ora.com (8.6.12/8.6.11) with UUCP id MAA23251; Tue, 1 Aug 1995 12:07:51 -0400 +Received: by los.ora.com (4.1/Spike-2.1) + id AA00672; Tue, 1 Aug 95 08:57:32 EDT +Date: Tue, 1 Aug 95 08:57:32 EDT +From: mikel@ora.com (Michael Loukides) +Message-Id: <9508011257.AA00672@los.ora.com> +Subject: Re: Ksh debugger from Rosenblatt's book [for bash] +To: Chet Ramey <chet@odin.INS.CWRU.Edu> +Cc: cmarie@ora.com, cam@iinet.com.au, brosenblatt@tm.com +In-Reply-To: Chet Ramey <chet@odin.INS.CWRU.Edu>, Mon, 31 Jul 1995 16:22:48 -0400 + + I've modified a (modified) version of Bill Rosenblatt's ksh debugger + to work with bash-2.0. Does ORA have any problem with me distributing + it with bash-2.0? + +That's great! + +Go ahead and circulate it; in fact, we should probably grab it and +stick it in our ftp archive, and put a reference to it in the book. +(Too late to actually discuss the thing, at least for this edition). +------- + diff --git a/examples/bashdb/README b/examples/obashdb/README index aa3aea7..aa3aea7 100644 --- a/examples/bashdb/README +++ b/examples/obashdb/README diff --git a/examples/obashdb/bashdb b/examples/obashdb/bashdb new file mode 100644 index 0000000..97d287d --- /dev/null +++ b/examples/obashdb/bashdb @@ -0,0 +1,33 @@ +# kshdb - Korn Shell Debugger main file +# adapted from 'Learning the Korn Shell' by Bill Rosenblatt (O'Reilly) +# by Cigy Cyriac (cigy@felix.tulblr.unisys.com) +# Main driver: constructs full script (with preamble) and runs it + +echo 'Bourne-Again Shell Debugger version 0.1' + +_pname=${0##*/} + +[ $# -eq 0 ] && { + echo "${_pname}: usage: ${_pname} <script_file>" + exit 1 +} + +_guineapig=$1 + +[ -r $_guineapig ] || { + echo "${_pname}: cannot read $_guineapig." >&2 + exit 1 +} +shift + +_tmpdir=/tmp +_libdir=. +_dbgfile=$_tmpdir/bashdb$$ #temp file for script being debugged + +cat $_libdir/bashdb.pre $_guineapig > $_dbgfile +if [ -f "$BASH" ]; then + exec $BASH $_dbgfile $_guineapig $_tmpdir $_libdir "$@" +else + exec bash $_dbgfile $_guineapig $_tmpdir $_libdir "$@" +fi +# end of bashdb diff --git a/examples/bashdb/bashdb.fns b/examples/obashdb/bashdb.fns index 79d9737..79d9737 100644 --- a/examples/bashdb/bashdb.fns +++ b/examples/obashdb/bashdb.fns diff --git a/examples/bashdb/bashdb.pre b/examples/obashdb/bashdb.pre index c9cdb72..c9cdb72 100644 --- a/examples/bashdb/bashdb.pre +++ b/examples/obashdb/bashdb.pre diff --git a/examples/scripts.v2/pmtop b/examples/scripts.v2/pmtop index 9344d90..cc419ac 100644 --- a/examples/scripts.v2/pmtop +++ b/examples/scripts.v2/pmtop @@ -16,7 +16,7 @@ while : do $CLEAR echo "$HEADER" - ps -aux | sort -nr +2 | sed ${SS}q + ps -aux | sort -nr -k 3 | sed ${SS}q sleep 5 done diff --git a/examples/scripts.v2/ren b/examples/scripts.v2/ren new file mode 100644 index 0000000..da76026 --- /dev/null +++ b/examples/scripts.v2/ren @@ -0,0 +1,585 @@ +#!/bin/bash +#@ This program came from: ftp://ftp.armory.com/pub/scripts/ren +#@ Look there for the latest version. +#@ If you don't find it, look through http://www.armory.com/~ftp/ +# +# @(#) ren 2.1.1 2002-03-17 +# 1990-06-01 John H. DuBois III (john@armory.com) +# 1991-02-25 Improved help info +# 1992-06-07 Remove quotes from around shell pattern as required by new ksh +# 1994-05-10 Exit if no globbing chars given. +# 1995-01-23 Allow filename set to be given on command line. +# 1997-09-24 1.4 Let [] be used for globbing. Added x option. +# 1997-11-26 1.4.1 Notice if the sequences of globbing chars aren't the same. +# 1999-05-13 Changed name to ren to avoid conflict with /etc/rename +# 2000-01-01 1.4.2 Let input patterns that contain whitespace be used. +# 2001-02-14 1.5 Better test for whether old & new globbing seqs are identical. +# 2001-02-20 1.6 Added pP options. +# 2001-02-27 1.7 Added qf options. Improved interpretation of rename patterns. +# 2001-05-10 1.8 Allow multiple pP options. Added Qr options. +# 2001-07-25 2.0 Added mz options. +# 2001-11-25 2.1 Allow segment ranges to be given with -m. Work under ksh93. +# 2002-03-17 2.1.1 Fixed bug in test for legal expressions. + +# todo: It would be nice to be able to escape metacharacters with '\' +# todo: Should enhance patterns to make ] in a pair of brackets work ([]]) +# todo: Allow use of all ksh globbing patterns. +# todo: Allow use of extended regexps, with () to enumerate pieces and \num to +# todo: select them. +# +# Modifications for bash made by Chet Ramey <chet@po.cwru.edu> + +name=${0##*/} +Usage="Usage: +$name [-fhqtv] [-m<segstart[:segend]=operation>] [-z<len>] [-[pP]<pattern>] + oldpattern [newpattern [filename ...]] +or +$name -r [same options as above] oldpattern newpattern directory ..." +tell=false +verbose=false +warn=true +warnNoFiles=true +debug=false +recurse=false +inclPat= +exclPat= +declare -i inclCt=0 exclCt=0 +check=true +declare -i j op_end_seg + +# Begin bash additions +shopt -s extglob + +# +# 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 +} + +# End bash additions + +while getopts :htvxp:P:fqQrm:z: opt; do + case $opt in + h) + print -r -- \ +"$name: rename files by changing parts of filenames that match a pattern. +$Usage +oldpattern and newpattern are subsets of sh filename patterns; the only +globbing operators (wildcards) allowed are ?, *, and []. All filenames that +match oldpattern will be renamed with the filename characters that match the +constant (non-globbing) characters of oldpattern changed to the corresponding +constant characters of newpattern. The characters of the filename that match +the globbing operators of oldpattern will be preserved. Globbing operators +in oldpattern must occur in the same order in newpattern; for every globbing +operators in newpattern there must be an identical globbing operators in +oldpattern in the same sequence. Both arguments should be quoted since +globbing operators are special to the shell. If filenames are given, only +those named are acted on; if not, all filenames that match oldpattern are acted +on. newpattern is required in all cases except when -m is given and no further +arguments are given. +If you are unsure whether a $name command will do what you intend, issue it +with the -t option first to be sure. +Examples: +$name \"/tmp/foo*.ba.?\" \"/tmp/new*x?\" + All filenames in /tmp that match foo*.ba.? will have the \"foo\" part + replaced by \"new\" and the \".ba.\" part replaced by \"x\". + For example, /tmp/fooblah.ba.baz would be renamed to /tmp/newblahxbaz. +$name \* \*- foo bar baz + foo, bar, and baz will be renamed to foo-, bar-, and baz-. +$name '????????' '????-??-??' + All filenames that are 8 characters long will be changed such that dashes + are inserted after the 4th and 6th characters. +Options: +-h: Print this help. +-r: Recursive operation. Filenames given on the command line after oldpattern + and newpattern are taken to be directories to traverse recursively. For + each subdirectory found, the specified renaming is applied to any matching + filenames. oldpattern and newpattern should not include any directory + components. +-p<pattern>, -P<pattern>: Act only on filenames that do (if -p is given) or do + not (if -P is given) match the sh-style filename globbing pattern + <pattern>. This further restricts the filenames that are acted on, beyond + the filename selection produced by oldpattern and the filename list (if + any). <pattern> must be quoted to prevent it from being interpreted by the + shell. Multiple instances of these options may be given. In this case, + filenames are acted on only if they match at least one of the patterns + given with -p and do not match any of the patterns given with -P. +-m<segstart[:segend]=operation>: For each file being renamed, perform a + mathematical operation on the string that results from concatenating + together the filename segments that matched globbing operator numbers + segstart through segend, where operators are numbered in order of + occurrence from the left. For example, in the pattern a?b*c[0-9]f, segment + 1 consists of the character that matched ?, segment 2 consists of the + character(s) that matched *, and segment 3 consists of the character that + matched [0-9]. The selected segments are replaced with the result of the + mathematical operation. + The concatenated string must consist of characters that can be interpreted + as a decimal integer; if it does not, the filename is not acted on. This + number is assigned to the variable 'i', which can be referenced by the + operation. The operations available are those understood by the ksh + interpreter, which includes most of the operators and syntax of the C + language. The original filename segment is replaced by the result of the + operation. If -m is used, newpattern may be an empty string or not given + at all (if no directory/file names are given). In this case, it is taken + to be the same as oldpattern. + If segend is given, any fixed text that occurs in the pattern between the + starting and ending globbing segments is discarded. If there are fewer + globbing segments than segend, no complaint is issued; the string is formed + from segment segstart through the last segment that does exist. + If segend is not given, the only segment acted on is startseg. + Examples: + $name -m3=i+6 '??*.ppm' + This is equivalent to: + $name -m3=i+6 '??*.ppm' '??*.ppm' + Since the old pattern and new pattern are identical, this would + normally be a no-op. But in this case, if a filename of ab079.ppm is + given, it is changed to ab85.ppm. + $name '-m1:2=i*2' 'foo??bar' + This will change a file named foo12bar to foo24bar + $name '-m1:2=i*2' 'foo?xyz?bar' + This will also change a file named foo1xyz2bar to foo24bar +-z<len>: Set the size of the number fields that result when -m is used. The + field is truncated to the trailing <len> digits or filled out to <len> + digits with leading zeroes. In the above example, if -z3 is given, the + output filename will be ab085.ppm. +-f: Force rename. By default, $name will not rename files if a file with the + new filename already exists. If -f is given, $name will carry out the + rename anyway. +-q: Quiet operation. By default, if -f is given, $name will still notify the + user if a rename results in replacement of an already-existing filename. + If -q is given, no notification is issued. +-Q: Suppress other warnings. By default, a warning is issued if no files are + selected for acting upon. If -Q is given, no warning is issued. +-v: Show the rename commands being executed. +-t: Show what rename commands would be done, but do not carry them out." + exit 0 + ;; + f) + check=false + ;; + q) + warn=false + ;; + Q) + warnNoFiles=false + ;; + r) + warnNoFiles=false + recurse=true + ;; + t) + tell=true + ;; + v) + verbose=true + ;; + x) + verbose=true + debug=true + ;; + p) + inclPats[inclCt]=$OPTARG + ((inclCt+=1)) + ;; + P) + exclPats[exclCt]=$OPTARG + ((exclCt+=1)) + ;; + m) + # Store operation for each segment number in ops[num] + # Store ending segment number in op_end_seg[num] + range=${OPTARG%%=*} + op=${OPTARG#*=} + start=${range%%:*} + end=${range#*:} + if [[ "$start" != +([0-9]) || "$start" -eq 0 ]]; then + print -ru2 -- "$name: Bad starting segment number given with -m: $start" + exit 1 + fi + if [[ "$end" != +([0-9]) || "$end" -eq 0 ]]; then + print -ru2 -- "$name: Bad ending segment number given with -m: $end" + exit 1 + fi + if [[ start -gt end ]]; then + print -ru2 -- "$name: Ending segment ($end) is less than starting segment ($start)" + exit 1 + fi + if [[ "$op" != @(|*[!_a-zA-Z0-9])i@(|[!_a-zA-Z0-9]*) ]]; then + print -ru2 -- \ + "$name: Operation given with -m does not reference 'i': $op" + exit 1 + fi + # Test whether operation is legal. let returns 1 both for error + # indication and when last expression evaluates to 0, so evaluate 1 + # after test expression. + i=1 + let "$op" 1 2>/dev/null || { + print -ru2 -- \ + "$name: Bad operation given with -m: $op" + exit 1 + } + ops[start]=$op + op_end_seg[start]=$end + ;; + z) + if [[ "$OPTARG" != +([0-9]) || "$OPTARG" -eq 0 ]]; then + print -ru2 -- "$name: Bad length given with -z: $OPTARG" + exit 1 + fi + typeset -Z$OPTARG j || exit 1 + ;; + +?) # no way to tell getopts to not treat +x as an option + print -r -u2 "$name: Do not prefix options with '+'." + exit 1 + ;; + :) + print -r -u2 \ +"$name: Option -$OPTARG requires a value. +$Usage +Use -h for help." + exit 1 + ;; + \?) + print -r -u2 \ +"$name: -$OPTARG: no such option. +$Usage +Use -h for help." + exit 1 + ;; + esac +done + +# remove args that were options +let OPTIND=OPTIND-1 +shift $OPTIND + +oldpat=$1 +newpat=$2 + +# If -m is given, a non-existant or null newpat should be set to oldpat +if [ ${#ops[*]} -gt 0 ]; then + case $# in + 0) + ;; + 1) + set -- "$oldpat" "$oldpat" + newpat=$oldpat + $debug && print -ru2 -- "Set new pattern to: $newpat" + ;; + *) + if [ -z "$newpat" ]; then + shift 2 + set -- "$oldpat" "$oldpat" "$@" + newpat=$oldpat + $debug && print -ru2 -- "Set new pattern to: $newpat" + fi + ;; + esac +fi + +# Make sure input patterns that contain whitespace can be expanded properly +IFS= + +origPat=$oldpat + +# Generate list of filenames to act on. +case $# in +[01]) + print -u2 "$Usage\nUse -h for help." + exit 1 + ;; +2) + if $recurse; then + print -r -u2 "$name: No directory names given with -r. Use -h for help." + exit 1 + fi + set -- $oldpat # Get list of all filenames that match 1st globbing pattern. + if [[ ! -a $1 ]]; then + $warnNoFiles && print -r -- "$name: No filenames match this pattern: $oldpat" + exit + fi + ;; +*) + shift 2 + ;; +esac + +integer patSegNum=1 numPatSegs + +# For old ksh +# while [[ "$oldpat" = *'[\*\?]'* ]]; do + +# Example oldpat: foo*.a +# Example newpat: bar*.b + +# Build list of non-pattern segments and globbing segments found in arguments. +# Note the patterns given are used to get the list of filenames to act on, +# to delimit constant segments, and to determine which parts of filenames are +# to be replaced. +# Examples given for first iteration (in the example, the only iteration) +# The || newpat is to ensure that new pattern does not have more globbing +# segments than old pattern +while [[ "$oldpat" = *@([\*\?]|\[+([!\]])\])* || + "$newpat" = *@([\*\?]|\[+([!\]])\])* ]]; do + ## Get leftmost globbing pattern in oldpat + + # Make r be oldpat with smallest left piece that includes a globbing + # pattern removed from it + r=${oldpat#*@([\*\?]|\[+([!\]])\])} # r=.a + # Make pat be oldpat with the above removed from it, leaving smallest + # left piece that includes a globbing pattern + pat=${oldpat%%"$r"} # pat=foo* + # Make l be pat with the globbing pattern removed from the right, + # leaving a constant string + l=${pat%@([\*\?]|\[+([!\]])\])} # l=foo + # Remove the constant part of pat from the left, leaving the globbing + # pattern + pat=${pat#"$l"} # pat=* + + # Do the same thing for newpat, solely to provide a reliable test that + # both oldpat & newpat contain exactly the same sequence of globbing + # patterns. + r=${newpat#*@([\*\?]|\[+([!\]])\])} # r=.b + npat=${newpat%%"$r"} # pat=bar* + l=${npat%@([\*\?]|\[+([!\]])\])} # l=bar + npat=${npat#"$l"} # npat=* + + if [[ "$pat" != "$npat" ]]; then + print -ru2 -- \ +"$name: Old-pattern and new-pattern do not have the same sequence of globbing chars. +Pattern segment $patSegNum: Old pattern: $pat New pattern: $npat" + exit 1 + fi + + ## Find parts before & after pattern + # oldpre[] stores the old constant part before the pattern, + # so that it can be removed and replaced with the new constant part. + oldpre[patSegNum]=${oldpat%%"$pat"*} # oldpre[1]=foo + # oldsuf stores the part that follows the globbing pattern, + # so that it too can be removed. + # After oldpre[] & oldsuf[] have been removed from a filename, what remains + # is the part matched by the globbing pattern, which is to be retained. + oldsuf[patSegNum]=${oldpat#*"$pat"} # oldsuf[1]=.a + # newpre[] stores the new constant part before the pattern, + # so that it can be used to replace the old constant part. + newpre[patSegNum]=${newpat%%"$pat"*} # newpre[1]=bar + # Get rid of processed part of patterns + oldpat=${oldpat#${oldpre[patSegNum]}"$pat"} # oldpat=.a + newpat=${newpat#${newpre[patSegNum]}"$pat"} # newpat=.b + # Store either * or ? in pats[], depending on whether this segment matches 1 + # or any number of characters. + [[ "$pat" = \[* ]] && pat=? + pats[patSegNum]=$pat + ((patSegNum+=1)) +done + +if [ patSegNum -eq 1 ]; then + print -u2 "No globbing chars in pattern." + exit 1 +fi + +oldpre[patSegNum]=${oldpat%%"$pat"*} # oldpre[2]=.a +oldsuf[patSegNum]=${oldpat#*"$pat"} # oldsuf[2]=.a +newpre[patSegNum]=${newpat%%"$pat"*} # newpre[2]=.b + +numPatSegs=patSegNum + +if $debug; then + patSegNum=1 + while [[ patSegNum -le numPatSegs ]]; do + print -ru2 -- \ +"Old prefix: <${oldpre[patSegNum]}> Old suffix: <${oldsuf[patSegNum]}> New prefix: <${newpre[patSegNum]}> Pattern: <${pats[patSegNum]}>" + ((patSegNum+=1)) + done +fi + +# Example filename: foox.a +# Example oldpat: foo*.a +# Example newpat: bar*.b + +integer numFiles=0 + +# Usage: renameFile filename [dirname] +# [dirname] is a directory name to prefix filenames with when they are printed +# for informational purposes. +# Uses globals: +# inclCt exclCt inclPats[] exclPats[] ops[] +# numPatSegs oldpre[] oldsuf[] newpre[] pats[] +# check warn tell verbose name +# Modifies globals: numFiles +function renameFile { + typeset file=$1 subdir=$2 + integer patSegNum patnum + typeset origname porigname newfile matchtext pnewfile matchsegs + integer startseg endseg + + origname=$file # origname=foox.a + porigname=$subdir$file + # Unfortunately, ksh88 does not do a good job of allowing for patterns + # stored in variables. Without the conditional expression being eval'ed, + # only sh patterns are recognized. If the expression is eval'ed, full + # ksh expressions can be used, but then expressions that contain whitespace + # break unless the user passed a pattern with the whitespace properly + # quoted, which is not intuititive. This is fixed in ksh93; full patterns + # work without being eval'ed. + if [ inclCt -gt 0 ]; then + patnum=0 + while [ patnum -lt inclCt ]; do + [[ "$file" = ${inclPats[patnum]} ]] && break + ((patnum+=1)) + done + if [ patnum -eq inclCt ]; then + $debug && print -ru2 -- "Skipping not-included filename '$porigname'" + return 1 + fi + fi + patnum=0 + while [ patnum -lt exclCt ]; do + if [[ "$file" = ${exclPats[patnum]} ]]; then + $debug && print -ru2 -- "Skipping excluded filename '$porigname'" + return 1 + fi + ((patnum+=1)) + done + # Extract matching segments from filename + ((numFiles+=1)) + patSegNum=1 + while [[ patSegNum -le numPatSegs ]]; do + # Remove a fixed prefix iteration: 1 2 + file=${file#${oldpre[patSegNum]}} # file=x.a file= + # Save the part of this suffix that is to be retained. To do this, we + # need to know what part of the suffix matched the current globbing + # segment. If the globbing segment is a *, this is done by removing + # the minimum part of the suffix that matches oldsuf (since * matches + # the longest segment possible). If the globbing segment is ? or [] + # (the latter has already been coverted to ?), it is done by taking the + # next character. + if [ "${pats[patSegNum]}" == \? ]; then + matchtext=${file#?} + matchtext=${file%$matchtext} + else + matchtext=${file%${oldsuf[patSegNum]}} # matchtext=x matchtext= + fi + $debug && print -ru2 -- "Matching segment $patSegNum: $matchtext" + file=${file#$matchtext} # file=.a file=.a + + matchsegs[patSegNum]=$matchtext + ((patSegNum+=1)) + done + + # Paste fixed and matching segments together to form new filename. + patSegNum=0 + newfile= + while [[ patSegNum -le numPatSegs ]]; do + matchtext=${matchsegs[patSegNum]} + startseg=patSegNum + if [ -n "${ops[startseg]}" ]; then + endseg=${op_end_seg[startseg]} + while [ patSegNum -lt endseg ]; do + ((patSegNum+=1)) + matchtext=$matchtext${matchsegs[patSegNum]} + done + if [[ "$matchtext" != +([-0-9]) ]]; then + print -ru2 -- \ +"Segment(s) $startseg - $endseg ($matchtext) of file '$porigname' do not form an integer; skipping this file." + return 2 + fi + i=$matchtext + let "j=${ops[startseg]}" || { + print -ru2 -- \ +"Operation failed on segment(s) $startseg - $endseg ($matchtext) of file '$file'; skipping this file." + return 2 + } + $debug && print -ru2 -- "Converted $matchtext to $j" + matchtext=$j + fi + newfile=$newfile${newpre[startseg]}$matchtext # newfile=barx newfile=barx.b + ((patSegNum+=1)) + done + + pnewfile=$subdir$newfile + if $check && [ -e "$newfile" ]; then + $warn && + print -ru2 -- "$name: Not renaming \"$porigname\"; destination filename \"$pnewfile\" already exists." + return 2 + fi + if $tell; then + print -n -r -- "Would move: $porigname -> $pnewfile" + $warn && [ -e "$newfile" ] && print -n -r " (destination filename already exists; would replace it)" + print "" + else + if $verbose; then + print -n -r -- "Moving: $porigname -> $pnewfile" + $warn && [ -e "$newfile" ] && print -n -r -- " (replacing old destination filename \"$pnewfile\")" + print "" + elif $warn && [ -e "$newfile" ]; then + print -r -- "$name: Note: Replacing old file \"$pnewfile\"" + fi + mv -f -- "$origname" "$newfile" + fi +} + +if $recurse; then + oPWD=$PWD + find "$@" -depth -type d ! -name '* +*' -print | while read dir; do + cd -- "$oPWD" + if cd -- "$dir"; then + for file in $origPat; do + renameFile "$file" "$dir/" + done + else + print -ru2 -- "$name: Could not access directory '$dir' - skipped." + fi + done +else + for file; do + renameFile "$file" + done +fi + +if [ numFiles -eq 0 ]; then + $warnNoFiles && print -ru2 -- \ + "$name: All filenames were excluded by patterns given with -p or -P." +fi diff --git a/examples/scripts/bcsh.sh b/examples/scripts/bcsh.sh index 9d93b30..509fe88 100755 --- a/examples/scripts/bcsh.sh +++ b/examples/scripts/bcsh.sh @@ -335,7 +335,7 @@ if test -s "$histfile" then cmdno="`set - \`wc -l $histfile\`;echo $1`" cmdno="`expr \"$cmdno\" + 1`" - lastcmd="`tail -1 $histfile`" + lastcmd="`sed -n '$p' $histfile`" copy=false ohist=$histfile while test ! -w "$histfile" @@ -689,7 +689,7 @@ esac/ rest= ;; esac - i="`grep \"$wanted\" $histfile | tail -1`" + i="`grep \"$wanted\" $histfile | sed -n '$p'`" ;; *) # find which 'start-of-command' match is wanted @@ -708,7 +708,7 @@ esac/ rest= ;; esac - i="`grep \"^$wanted\" $histfile | tail -1`" + i="`grep \"^$wanted\" $histfile | sed -n '$p'`" ;; esac diff --git a/examples/scripts/self-repro b/examples/scripts/self-repro new file mode 100644 index 0000000..951d4e4 --- /dev/null +++ b/examples/scripts/self-repro @@ -0,0 +1,9 @@ +# self-reproducing script (except for these comment lines -- remove them) +# i got this from the ksh93 faq: +# http://www.kornshell.com/doc/faq.html +# +n=" +" q="'" x="cat <<-!" y=! z='n="$n" q="$q" x="$x" y=$y z=$q$z$q$n$x$n$z$n$y' +cat <<-! +n="$n" q="$q" x="$x" y=$y z=$q$z$q$n$x$n$z$n$yb +! diff --git a/examples/scripts/vtree2 b/examples/scripts/vtree2 index 62aa948..878cbab 100755 --- a/examples/scripts/vtree2 +++ b/examples/scripts/vtree2 @@ -32,7 +32,7 @@ do cd "$1" || { shift; [ $# -ge 1 ] && echo >&2; continue; } echo -n "$PWD" - du $andfiles | sort +1f | sed \ + du $andfiles | sort -k 2f | sed \ -e 's/\([^ ]*\) \(.*\)/\2 (\1)/' \ -e "s#^$1##" \ -e 's#[^/]*/\([^/]*\)$#|____\1#' \ diff --git a/examples/startup-files/apple/aliases b/examples/startup-files/apple/aliases index d04821c..23d3399 100644 --- a/examples/startup-files/apple/aliases +++ b/examples/startup-files/apple/aliases @@ -24,7 +24,7 @@ ff () { find . -name ${1} -print ; } ll () { ls -lag "$@" | more ; } word () { fgrep -i "$*" /usr/dict/web2 ; } wordcount () { cat "${1}" | tr -s ' .,;:?\!()[]"' '\012' | \ - cat -n | tail -1 | awk '{print $1}' ; } + awk 'END {print NR}' ; } ## # Read user's aliases |