nish-functions-0.5.1/000075500000000000000000000000001116771214200144645ustar00rootroot00000000000000nish-functions-0.5.1/Makefile000064400000000000000000000012771116771214200161330ustar00rootroot00000000000000DESTDIR= PREFIX=$(DESTDIR)/usr LIBEXEC=libexec LIBEXECDIR=$(PREFIX)/$(LIBEXEC)/nish BINDIR=$(PREFIX)/bin LIBS=functions JUNK= o oo ooo o.* *~ GENERATED=functions.locate.new all: functions.locate.new README clean: rm -rf $(JUNK) $(GENERATED) README: README.in sed 's@LIBEXEC@$(LIBEXECDIR)@g' $< > $@ echo | sh ./functions >> $@ functions.locate.new: functions.locate sed 's@^__LIBEXEC=.*@__LIBEXEC="\$(LIBEXECDIR)"@g' $< > $@ install: all mkdir -p "$(LIBEXECDIR)" "$(BINDIR)" install -m755 functions.locate.new "$(BINDIR)"/functions.locate install -m755 $(LIBS) "$(LIBEXECDIR)" suck: cd ~ && git pull cp ~/bin/functions* ./ spit: install functions ~/bin/ install functions.locate ~/bin nish-functions-0.5.1/README.in000064400000000000000000000001051116771214200157450ustar00rootroot00000000000000Run LIBEXEC/functions itself to get this detailed help on functions: nish-functions-0.5.1/functions000075500000000000000000000313421116771214200164250ustar00rootroot00000000000000#!/bin/sh ################################################ # # This is supplementary functions file # it is not intended to be called directly # see functions digest below # # Any global variable or function name defined here MUST start with "_" # to avoid namespace clash (all user-defined names must NOT start with "_") # Names started with two _'s are internals and should not be used outside ################################################ # Variables: export _Me=`basename "$0"` # script name test -n "$_GMe" || export _GMe="$_Me" # global script name (for set of scripts) export _FMe=`realpath "$0"` # script fullpath export _MeDir=`dirname "$_FMe"` # script directory export _MePID="$$" # PID of current shell test -n "$_Home" || export _Home="$HOME" # base directory export _AMe=`echo "$_Me" | tr -cd "[:alnum:]"` # script name alphanumeric part (for generating filenames) test -n "$__RC_SUFFIX" || __RC_SUFFIX="rc" # config file suffix export _RC="$_Home/.$_GMe$__RC_SUFFIX" # config file export _SYSRC="/etc/$_GMe$__RC_SUFFIX" # system-wide config file export _RC_HOST="$_Home/.$_GMe$__RC_SUFFIX.`hostname`" # host specific config file export _Verb=0 # verbosity level export _Options="" # getopts options (generated!) export _Usage="" # short help string export _Help="" # long help string export _TmpFiles="" # temporary files export _TmpDirs="" # temporary directories export _LC_COLLATE=C # LC_COLLATE submissions export __Version=0.5.1 # this functions file version export _Version=0.0 # software version __CR=" " __Unsafe="" # set this to non-empty to enable unsafe actions #(like non-/tmp/-directory deleting etc.) # LC_COLLATE wrappers (e. g. for [a-z] regexps work properly etc.) # sed grep sed() { env LC_COLLATE="$_LC_COLLATE" sed "$@"; } grep() { env LC_COLLATE="$_LC_COLLATE" grep "$@"; } ################################################ # Message displaying and error system # Internal: display a message # Onw may redefine this (e.g. with XDialog) for another displaying method __Message() { # message [title] { test -n "$2" && echo "$2: $1" || echo "$1"; } >&2 } # Display an error to stderr # check _Verb if to display message # exit if errorlevel >0 # do not display error type in "Q" (quiet) mode _Error() { # errormsg [errorlevel|"q" [errorlevel]] local ER ret case "${2:-1}" in [1-9]*) ER="ERROR"; ret="${2:-1}" ;; [0Ii]*) ER="INFO"; ret=0 ;; [-Ww]*) ER="WARNING"; ret=-1 ;; [Qq]*) ER=""; ret="${3:--1}";; *) ER="ERROR"; ret=1 ;; esac if [ "$_Verb" -ge 1 ] # verbose then __Message "$1" "$ER" elif [ "$_Verb" -ge 0 ] # normal then test "$ret" -eq 0 || __Message "$1" "$ER" >&2 else # quiet test "$ret" -le 0 || __Message "$1" "$ER" >&2 fi test $ret -le 0 || exit $ret } # Display a message to stderr _Msg() { # [message] _Error "${*:-}" q } ################################################ # Temporary files and exit handler # Remove all temporary files and directory _clean_tmp() { local F test -z "$_TmpFiles" || echo "$_TmpFiles" | while read F do test -z "$F" || rm -f "$F"; done test -z "$_TmpDirs" || echo "$_TmpDirs" | while read F do case "$F" in */tmp/?*) # it seems safe to delete this rm -rf "$F";; "") ;; *) _Error "It seems unsafe to delete '$F' directory" w ;; esac done _TmpDirs=""; _TmpFiles="" } __cleanup_handler() { # [exit status] trap - EXIT _clean_tmp exit "$1" } # Perform actions on exit _exit_handler() { __cleanup_handler "$?" } # Perform actions on deadly signal and exit _signal_handler() { __cleanup_handler 143 # SIGTERM+128 } trap _exit_handler EXIT trap _signal_handler HUP INT QUIT PIPE TERM # create a temporary file and store its name to _TmpFiles # second parameter: [-]d* -- directory, [-]p* -- pipe, other -- file # assign filename to "variable" _TmpFile() { # variable [type] local _F _P _Z _N="file" case "$1" in *[!_a-zA-Z0-9]*) _Error "Cannot store valuse to '$1' variable, please user alphanumeric name" ;; "") _Error "no variable name provided to _TmpFile function" ;; esac case "$2" in *p|p*) _P=""; _N="pipe";; *d|d*) _P="-d"; _N="directory";; esac _F=`mktemp -t $_P $_AMe.$_N.XXXXXXXXXXXX` || _Error "Cannot create '$_F' temporary $_N" case "$2" in *p|p*) # XXX look for race conditions here _Z="`mktemp XXXXXXXXXXXX`" mv "$_F" "$_Z" mkfifo "$_F" rm -f "$_Z" ;; esac case "$_N" in directory) _TmpDirs="$_TmpDirs $_F" ;; *) _TmpFiles="$_TmpFiles $_F" ;; esac eval "export $1='$_F'" } # create a temporary directory and store its' name to _TmpDirs # assign filename to "variable" _TmpDir() { # variable _TmpFile "$1" directory } ################################################ # Help system # TODO long options # WARNING: this function strongly depends on "case" operator programming style: # key) # help string # if help string contains capitalized word, it will be used as parameter name # E. g.: # o) # redirect output to FILE # will produce this help string: # -o FILE redirect output to FILE # By default, help strings are searched # from the first occurance of " getopts " string to the first " esac$" pattern # so keep a commentary after additional "esac" if it emerges inside # # Generted varsiables: # _Options -- option string in getopts format # Store a help information _MakeHelp() { # description [tail_text [additional_help [start_pattern end_pattern]]] local descr local selfname case "$1" in *--*) selfname="${1%% -- *}"; descr="${1##* -- }" ;; ?*) selfname="$_Me"; descr="$1" ;; "") _Error "Insufficient parameters in _MakeHelp" ;; esac local st="${4:-" getopts "}" local en="${5:-"[ ]esac[ ]*$"}" local sedfilter="/$st/,/$en/" local sedFpattern='^[ ]*\([^)]*\))[ ]*#[ ]*\(.*\)' local sedUpattern='^[ ]*\([^)]*\))[ ]*#[ ]*![ ]*\(.*\)' local sedPpattern='^[ ]*\([^)]*\))[ ]*#[ ]*\([^!]*[^!A-Z]\([A-Z]\{3,\}\).*\)' local genhelp="$(sed -n "$sedfilter{ /$sedPpattern/s/$sedPpattern/ -\1 <\3> \2/p /$sedUpattern/s/$sedUpattern/(TODO) -\1 \2/p /$sedFpattern/s/$sedFpattern/ -\1 \2/p }" "$_FMe")" _Options=$(sed -n "$sedfilter{ /$sedPpattern/s/$sedPpattern/\1:/p /$sedUpattern/n /$sedFpattern/s/$sedFpattern/\1/p }" "$_FMe" | tr -d '\n') _Usage="$selfname v$_Version -- $descr Usage: $_Me [-$_Options]${2:+" "}$2" _Help=" $genhelp${3:+$__CR}$3" } ################################################ # Configuration file editing # Set "Variable=Value" inside Context of File or append it at the start of the Context _CfgEqSet() { # File Variable Value [Context=0,$] local Context="${4:-1,\$}" N=$(sed -n "$Context{/^[ ]*$2[ ]*=/=}" "$1") # if Variable=Value exists test -n "$N" && for n in $N do # Replace sed -i "$n""s/^\([ ]*$2[ ]*=[ ]*\).*/\1$(_Quote "$3")/" "$1" done || { # Append N=$(sed -n "$Context{=;q}" "$1") test -n "$N" && sed -i "$N""a\ $2=$3 " "$1" || _Error "No '$Context' context found in $1" -1 } } __CfGet() { # File Context Variable Div Value Tail test -z "$(sed -n "$2{=}" "$1")" && _Error "No '$2' context found in $1" -1 || { local ret=$(sed -n "$2{/$3$4$5$6/{s/$3$4\($5\)$6/\1/p;q}}" "$1") echo -n $ret test -n "$ret" } } # Print Value from "Variable=Value" inside Context of File _CfgEqGet() { # File Variable [Context=1,$] __CfGet "$1" "${3:-1,\$}" "^[ ]*$2" "[ ]*=[ ]*" ".*" "" } # Print Value from "Variable Value" inside Context of File _CfgBlGet() { # File Variable [Context=1,$] __CfGet "$1" "${3:-1,\$}" "^[ ]*$2" " *" ".*" "" } # Delete all "Variable=" entries inside Context of File _CfgEqDel() { # File Variable [Context=1,$] local Context="${3:-1,\$}" test -z "$(sed -n "$Context{=}" "$1")" && _Error "No '$Context' context found in $1" -1 || sed -i "$Context{/^[ ]*$2[ ]*=/d}" "$1" } # Comment all "Variable=" entries inside Context of File _CfgEqComm() { # File Variable [Context=1,$] local Context="${3:-1,\$}" test -z "$(sed -n "$Context{=}" "$1")" && _Error "No '$Context' context found in $1" -1 || sed -i "$Context{s/^\([ ]*$2[ ]*=.*\)/#\1/}" "$1" } # Uncomment all "#Variable=" entries inside Context of File _CfgEqUnComm() { # File Variable [Context=1,$] local Context="${3:-1,\$}" test -z "$(sed -n "$Context{=}" "$1")" && _Error "No '$Context' context found in $1" -1 || sed -i "$Context{s/^[ ]*#\([ ]*$2[ ]*=.*\)/\1/}" "$1" } ################################################ # Parallel execution functions # To run a number of tasks in parallel: # first call _II_init # next call _II_run [] for each task # and last call _II_wait to wait for last task to be done # Detect number of cores _II_cores() { # N="`ls -d /proc/sys/kernel/sched_domain/cpu* 2>/dev/null | wc -l`" || N="`sysctl -n kern.smp.cpus 2>/dev/null`" test -z "$N" && _Msg "Warning: cannot determine number of CPUs" echo "$(($N+0))" } # Initialize parallel environment for running maxproc tasks at once _II_init() { # [maxproc] _TmpFile __II_count # number of processes _TmpFile __II_sync pipe # pipe for end-of-proc catching __II_maxproc="${1:-$(_II_cores)}" # parallel slots number __II_current=0 # tasks already executed } __II_done() { wc -l < $__II_count; } __II_exit() { trap - EXIT echo $__II_err >> $__II_count echo $__II_err > $__II_sync exit $__II_err } ___II_next() { o.par2sat.sh $__II_sync $__II_count "$@" } __II_next() { __II_err=0 trap __II_exit EXIT "$@" __II_err="$?" } __II_pause() { { read __II_err < $__II_sync; } 2>/dev/null || :; } # Wait for empty slot becomes available, then execute a task _II_run() { # task [args ...] test $(($__II_current - $(__II_done) )) -lt $__II_maxproc || __II_pause (__II_next "$@") & __II_current=$(($__II_current + 1)) } # Wait for all tasks to be done _II_wait() { while test $(($__II_current - $(__II_done) )) -ne 0 do __II_pause; done } ################################################ # XTerm voodoo __XTTTY="/dev/tty" # tty to output and input # Tackle XTerm to push response on string (e. g. ^[]50;?^G respond with fontname) # Response must end with response_end (default "t") # WARNING: this can freeze your terminal to death! _XTResponse() { # string [response_end [response_start [tty]]] local XT STTY STTY=`stty -g < "$__XTTTY"` stty raw -echo < "$__XTTTY" echo -n "$1" > "$__XTTTY" XT=`awk -v RS="${2:-t}" '{print; exit; }'` stty $STTY < "$__XTTTY" test -z "$3" && echo -n "$XT" || echo -n "${XT#$3}" } # Get/set current XTerm font _XTFont() { # [font_to_set] test -z "$1" && _XTResponse "]50;?" "" "]50;" || echo -n "]50;$1" > "$__XTTTY" } __XT_CSI_t() { # seqn [args ...] # internal: send a CSI sequence, get a response if no args local __XT="$1"; shift if [ "$#" = 0 ]; then _XTResponse "[1$__XT""t" "t" "[$__XT;"; else echo -n "[$__XT;`echo -n "$@" | tr " " ";"`t" > "$__XTTTY"; fi } # Get/set XTerm size in characters _XTSize() { # [width height] __XT_CSI_t 8 $2 $1; } # Get/set XTerm size in pixels _XTWH() { # [width height] __XT_CSI_t 4 $2 $1; } # Get/set XTerm position in pixels _XTPos() { # [x y] __XT_CSI_t 3 $@; } ################################################ # Misc functions # TODO: "A_b_c" "D_e" -> "A b c" "D e" call # print pseudo-random 0..Max (32767 if Max undefined) _Random() { # [Max] echo $((`dd if=/dev/urandom count=2 bs=1 2>/dev/null | od -An -t u4`%${1:-32768})) } # parse "ipcalc Parameters" and get Field value _IpCalc() { # Parameters Field local ipc="ipcalc" $ipc $1 | sed -n "/$2/s/$2[ ][ ]*\([^ /]*\).*/\1/p" } # decode utf-8 output if not utf-8 locale is used _DeU8() { # [locale] local l="${1:-$LANG}" case "$l" in *[uU][Tt][fF]*8*) cat ;; *) iconv -f utf-8 -t "${l##*.}" -r. ;; esac } # remove arg from argument_string _DelArg() { # argument_string arg local a=" $1 " a="${a% $2 *} ${a#* $2 }" a="${a% }"; a="${a# }" echo "$a" } # translate string of format "3-5,12,15" to "3 4 5 12 15" and print it _ExpandEnum() { # number_list [divider [diapazone_divider]] local div="${2:-,}" local dia="${3:--}" local d n for d in $(echo "$1" | tr "$div" " "); do case "$d" in *-*) for n in $(seq $(echo "$d" | tr "-" " ") ); do echo $n; done ;; *) echo "$d" ;; esac done } # quote Chars_regexp in Str (e. g. /home/dir -> \/home\/dir) _Quote() { # Str [Chars_regexp="[/]"] echo "$1" | sed "s@\(${2:-[/]}\)@\\\\\1@g" } # use this to cat the stdin and echo args instead of running filter-like program _CatEcho() { # [text] # TODO: prog name or something tty -s || cat echo " $@" } case "$_GMe" in functions|*.functions) # directly called echo "$_GMe v$__Version" >&2 tty -s && PG=less || PG="cat -s" sed -n '/^__/d /^_/p /^[ ]*$/p /^#[^!]/p /^export _/s/^export \(_[^ = ,]*\)[^#]*#[ ]*\(.*\)/\1 \2/p ' "$_FMe" | $PG ;; esac nish-functions-0.5.1/functions.locate000075500000000000000000000002431116771214200176670ustar00rootroot00000000000000#!/bin/sh # You can modify this depending on where functions files are stored __LIBEXEC="$(dirname "$(realpath "$0")")" echo "$__LIBEXEC/$(basename "$0" .locate)"