refactoring

removes optional switches
moved some helpers. in string.
completed more documentation
This commit is contained in:
Jaromil 2016-06-08 12:33:02 +02:00
parent b7a0dca0ec
commit 5464a0f9d5
2 changed files with 235 additions and 239 deletions

View File

@ -11,7 +11,7 @@
(_) (_)
``` ```
**Z**sh **U**ltimate **P**rogrammer's **E**xtensions **R**efurbished - version 0.2 **Z**sh **U**ltimate **P**rogrammer's **E**xtensions **R**efurbished
# Introduction # Introduction
@ -29,6 +29,14 @@ used as a programming language.
- improved temp file handling - improved temp file handling
- more to come... - more to come...
# Requirements
Zuper requires the following programs to be installed:
```
zsh curl sed awk hexdump
```
# Usage # Usage
Documentation is still lacking, however to use Zuper in Zsh scripts Documentation is still lacking, however to use Zuper in Zsh scripts
@ -42,23 +50,24 @@ program call `endgame` for a clean exit. Example test program:
# switch on debugging output # switch on debugging output
DEBUG=1 DEBUG=1
# switch on zuper's key/value load/save extension
zkv=1
# switch off zuper's consul kv get/set extension
unset consul
# switch on zuper's helper extensions
helper=1
# switch logging into test.log # switch logging into test.log
LOG=test.log LOG=test.log
##### INIT
# load our zuper library # load our zuper library
source zuper source zuper
# declare a custom global variable # declare a custom global variable
vars+=(myvar) vars+=(myvar)
# assign a default value to our global variable # assign a default value to our global variable
myvar=${myvar:-ok} myvar=${myvar:-ok}
# declare a global associative map
maps+=(mymap)
# conclude the init phase
source zuper.init
#####
# register the zdump debug function to be executed on exit
destruens+=(zdump)
# declare a custom function to print it out # declare a custom function to print it out
@ -79,14 +88,6 @@ testfun() {
# but can also be delete earlier here, optionally # but can also be delete earlier here, optionally
} }
# declare a global associative map
maps+=(mymap)
# conclude the init phase
source zuper.init
# register the zdump debug function to be executed on exit
destruens+=(zdump)
# call our custom function # call our custom function
testfun testfun
@ -121,7 +122,7 @@ done
Here we reference applications where zuper is used succesfully: Here we reference applications where zuper is used succesfully:
- Devuan Simple Development Toolkit https://git.devuan.org/devuan/devuan-sdk#tab-readme - Devuan Simple Development Toolkit https://git.devuan.org/groups/sdk
- Dowse IoT awareness OS http://dyne.org/software/dowse - Dowse IoT awareness OS http://dyne.org/software/dowse
- Jaro Mail terminal email http://dyne.org/software/jaro-mail - Jaro Mail terminal email http://dyne.org/software/jaro-mail

437
zuper
View File

@ -31,10 +31,13 @@ vars=(DEBUG QUIET LOG)
arrs=(req freq) arrs=(req freq)
vars+=(zuper_version) vars+=(zuper_version)
zuper_version=0.2 zuper_version=0.3
# load necessary zsh extensions
zmodload zsh/regex
zmodload zsh/system zmodload zsh/system
zmodload zsh/net/tcp zmodload zsh/net/tcp
zmodload zsh/mapfile
# {{{ Messaging # {{{ Messaging
@ -158,7 +161,7 @@ zerr() {
} }
ckreq reqck() { function ckreq reqck() {
err=0 err=0
for v in $req; do for v in $req; do
[[ "${(P)v}" = "" ]] && { [[ "${(P)v}" = "" ]] && {
@ -240,9 +243,9 @@ endgame() {
return 0 return 0
} }
# Register endgame() to be called at exit. # Use this to make sure endgame() is called at exit.
# unlike TRAPEXIT, the zshexit() hook is not called when functions exit. # unlike TRAPEXIT, the zshexit() hook is not called when functions exit.
zshexit() { endgame EXIT; return $? } function zuper.exit zshexit() { endgame EXIT; return $? }
# }}} Debugging # }}} Debugging
@ -281,7 +284,7 @@ destruens+=(_ztmp_destructor)
# tokenizer, works only with one char length delimiters # tokenizer, works only with one char length delimiters
# saves everything in global array tok=() # saves everything in global array tok=()
arrs+=(tok) arrs+=(tok)
strtok() { function string.strtok strtok() {
fn "strtok $*" fn "strtok $*"
_string="$1" _string="$1"
_delim="$2" _delim="$2"
@ -313,7 +316,149 @@ strtok() {
fi fi
} }
# TODO: move in here some helpers # remote leading and trailing spaces in a string taken from stdin
function string.trim trim() {
sed -e 's/^[[:space:]]*//g ; s/[[:space:]]*\$//g'
}
# extract all emails found in a text from stdin
# outputs them one per line
function string.extract_emails extract_emails() {
awk '{ for (i=1;i<=NF;i++)
if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) {
gsub(/<|>|,/ , "" , $i); print $i } }'
}
# takes a string as argument, returns success if is an email
function string.isemail isemail() {
[[ "$1" -regex-match "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" ]] && return 0
return 1
}
# takes a numeric argument and prints out a human readable size
function string.human_size human_size() {
[[ $1 -gt 0 ]] || {
error "human_size() called with invalid argument"
return 1
}
# we use the binary operation for speed
# shift right 10 is divide by 1024
# gigabytes
[[ $1 -gt 1073741824 ]] && {
print -n "$(( $1 >> 30 )) GB"
return 0
}
# megabytes
[[ $1 -gt 1048576 ]] && {
print -n "$(( $1 >> 20 )) MB"
return 0
}
# kilobytes
[[ $1 -gt 1024 ]] && {
print -n "$(( $1 >> 10 )) KB"
return 0
}
# bytes
print -n "$1 Bytes"
return 0
}
# strips out all html/xml tags (everything between < >)
function string.html_strip xml_strip html_strip() { sed 's/<[^>]\+>//g' }
# changes stdin string special chars to be shown in html
function string.escape_html escape_html() {
sed -e '
s/\&/\&amp;/g
s/>/\&gt;/g
s/</\&lt;/g
s/"/\&quot;/g
'
}
# escapes special chars in urls
function string.decode_url decode_url urldecode() {
sed -e '
s/%25/%/gi
s/%20/ /gi
s/%09/ /gi
s/%21/!/gi
s/%22/"/gi
s/%23/#/gi
s/%24/\$/gi
s/%26/\&/gi
s/%27/'\''/gi
s/%28/(/gi
s/%29/)/gi
s/%2a/\*/gi
s/%2b/+/gi
s/%2c/,/gi
s/%2d/-/gi
s/%2e/\./gi
s/%2f/\//gi
s/%3a/:/gi
s/%3b/;/gi
s/%3d/=/gi
s/%3e//gi
s/%3f/?/gi
s/%40/@/gi
s/%5b/\[/gi
s/%5c/\\/gi
s/%5d/\]/gi
s/%5e/\^/gi
s/%5f/_/gi
s/%60/`/gi
s/%7b/{/gi
s/%7c/|/gi
s/%7d/}/gi
s/%7e/~/gi
s/%09/ /gi
'
}
function helper.encode-url encode_url urlencode() {
sed -e '
s/%/%25/g
s/ /%20/g
s/ /%09/g
s/!/%21/g
s/"/%22/g
s/#/%23/g
s/\$/%24/g
s/\&/%26/g
s/'\''/%27/g
s/(/%28/g
s/)/%29/g
s/\*/%2a/g
s/+/%2b/g
s/,/%2c/g
s/-/%2d/g
s/\./%2e/g
s/\//%2f/g
s/:/%3a/g
s/;/%3b/g
s//%3e/g
s/?/%3f/g
s/@/%40/g
s/\[/%5b/g
s/\\/%5c/g
s/\]/%5d/g
s/\^/%5e/g
s/_/%5f/g
s/`/%60/g
s/{/%7b/g
s/|/%7c/g
s/}/%7d/g
s/~/%7e/g
s/ /%09/g
'
}
# }}} Strings # }}} Strings
@ -425,69 +570,67 @@ net.scan_exits() {
# optional: define zkv=1 on source # optional: define zkv=1 on source
[[ "$zkv" = "" ]] || { ##########################
# Key/Value file storage using ZSh associative maps
##########################
# Key/Value file storage using ZSh associative maps
# load a map from a file # load a map from a file
# map must be already instantiated with typeset -A by called # map must be already instantiated with typeset -A by called
# name of map is defined inside the file # name of map is defined inside the file
function zkv.load() { function zkv.load() {
fn "zkv-load $*" fn "zkv-load $*"
file=$1 file=$1
[[ "$file" = "" ]] && { [[ "$file" = "" ]] && {
error "zkv-open() missing argument: file-path" error "zkv-open() missing argument: file-path"
zerr zerr
return 1 } return 1 }
[[ -r "$file" ]] || { [[ -r "$file" ]] || {
error "zkv-open() file not found $file" error "zkv-open() file not found $file"
zerr zerr
return 1 } return 1 }
[[ -s "$file" ]] || { [[ -s "$file" ]] || {
error "zkv-open() file is empty" error "zkv-open() file is empty"
zerr zerr
return 1 } return 1 }
source $file source $file
}
# save a map in a file
# $1 = name of the map associative array
# $2 = full path to the file
function zkv.save() {
fn "zkv.save $*"
_map=$1
_path=$2
[[ "$_path" = "" ]] && {
error "zkv.save() missing argument: map-name path-to-file"
zerr
return 1
} }
[[ -r $_path ]] && {
func "zkv.close() overwriting $_path"
func "backup turd left behind: ${_path}~"
mv $_path $_path~
}
touch $_path
# save a map in a file # wondering about http://www.zsh.org/mla/users/2015/msg00286.html
# $1 = name of the map associative array # meanwhile solved using a double array, wasting a full map memcpy
# $2 = full path to the file _karr=(${(Pk)_map})
function zkv.save() { _varr=(${(Pv)_map})
fn "zkv.save $*" _num="${#_karr}"
for c in {1..$_num}; do
_map=$1 # can also be cat here, however for speed we use builtins
_path=$2 # switch to cat if compatibility is an issue
[[ "$_path" = "" ]] && { sysread -o 1 <<EOF >> $_path
error "zkv.save() missing argument: map-name path-to-file"
zerr
return 1
}
[[ -r $_path ]] && {
func "zkv.close() overwriting $_path"
func "backup turd left behind: ${_path}~"
mv $_path $_path~
}
touch $_path
# wondering about http://www.zsh.org/mla/users/2015/msg00286.html
# meanwhile solved using a double array, wasting a full map memcpy
_karr=(${(Pk)_map})
_varr=(${(Pv)_map})
_num="${#_karr}"
for c in {1..$_num}; do
# can also be cat here, however for speed we use builtins
# switch to cat if compatibility is an issue
sysread -o 1 <<EOF >> $_path
$_map+=("${_karr[$c]}" "${(v)_varr[$c]}") $_map+=("${_karr[$c]}" "${(v)_varr[$c]}")
EOF EOF
done done
func "$_num key/values stored in $_path" func "$_num key/values stored in $_path"
} }
} }
@ -496,7 +639,7 @@ EOF
# {{{ Get/Set REST API # {{{ Get/Set REST API
######## ########
# Restful API client # Restful API client (WIP, needs more testing)
# there is a clear zsh optimization here in get/set kv # there is a clear zsh optimization here in get/set kv
# using zsh/tcp instead of spawning curl # using zsh/tcp instead of spawning curl
# and perhaps querying with one call using ?recursive # and perhaps querying with one call using ?recursive
@ -633,165 +776,17 @@ EOF
# }}} Get/Set REST API # }}} Get/Set REST API
# {{{ Helpers # {{{ Helpers
[[ "$helpers" = "" ]] || {
function helper.isfound isfound() {
command -v $1 1>/dev/null 2>/dev/null
return $?
}
# remote leading and trailing spaces in a string taken from stdin
function helper.trim trim() {
sed -e 's/^[[:space:]]*//g ; s/[[:space:]]*\$//g'
}
zmodload zsh/mapfile
# faster substitute for cat
function helper.printfile printfile() {
print ${mapfile[$1]}
}
# extract all emails found in a text from stdin
# outputs them one per line
function helper.extract-emails extract_emails() {
awk '{ for (i=1;i<=NF;i++)
if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) {
gsub(/<|>|,/ , "" , $i); print $i } }'
}
zmodload zsh/regex
# takes a string as argument, returns success if is an email
function helper.isemail isemail() {
[[ "$1" -regex-match "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" ]] && return 0
return 1
}
# takes a numeric argument and prints out a human readable size
function helper.human-size human_size() {
[[ $1 -gt 0 ]] || {
error "human_size() called with invalid argument"
return 1
}
# we use the binary operation for speed
# shift right 10 is divide by 1024
# gigabytes
[[ $1 -gt 1073741824 ]] && {
print -n "$(( $1 >> 30 )) GB"
return 0
}
# megabytes
[[ $1 -gt 1048576 ]] && {
print -n "$(( $1 >> 20 )) MB"
return 0
}
# kilobytes
[[ $1 -gt 1024 ]] && {
print -n "$(( $1 >> 10 )) KB"
return 0
}
# bytes
print -n "$1 Bytes"
return 0
}
# strips out all html/xml tags (everything between < >)
function helper.html-strip xml_strip html_strip() { sed 's/<[^>]\+>//g' }
# changes stdin string special chars to be shown in html
function helper.escape-html escape_html() {
sed -e '
s/\&/\&amp;/g
s/>/\&gt;/g
s/</\&lt;/g
s/"/\&quot;/g
'
}
# escapes special chars in urls
function helper.decode-url decode_url urldecode() {
sed -e '
s/%25/%/gi
s/%20/ /gi
s/%09/ /gi
s/%21/!/gi
s/%22/"/gi
s/%23/#/gi
s/%24/\$/gi
s/%26/\&/gi
s/%27/'\''/gi
s/%28/(/gi
s/%29/)/gi
s/%2a/\*/gi
s/%2b/+/gi
s/%2c/,/gi
s/%2d/-/gi
s/%2e/\./gi
s/%2f/\//gi
s/%3a/:/gi
s/%3b/;/gi
s/%3d/=/gi
s/%3e//gi
s/%3f/?/gi
s/%40/@/gi
s/%5b/\[/gi
s/%5c/\\/gi
s/%5d/\]/gi
s/%5e/\^/gi
s/%5f/_/gi
s/%60/`/gi
s/%7b/{/gi
s/%7c/|/gi
s/%7d/}/gi
s/%7e/~/gi
s/%09/ /gi
'
}
function helper.encode-url encode_url urlencode() {
sed -e '
s/%/%25/g
s/ /%20/g
s/ /%09/g
s/!/%21/g
s/"/%22/g
s/#/%23/g
s/\$/%24/g
s/\&/%26/g
s/'\''/%27/g
s/(/%28/g
s/)/%29/g
s/\*/%2a/g
s/+/%2b/g
s/,/%2c/g
s/-/%2d/g
s/\./%2e/g
s/\//%2f/g
s/:/%3a/g
s/;/%3b/g
s//%3e/g
s/?/%3f/g
s/@/%40/g
s/\[/%5b/g
s/\\/%5c/g
s/\]/%5d/g
s/\^/%5e/g
s/_/%5f/g
s/`/%60/g
s/{/%7b/g
s/|/%7c/g
s/}/%7d/g
s/~/%7e/g
s/ /%09/g
'
}
function helper.isfound isfound() {
command -v $1 1>/dev/null 2>/dev/null
return $?
} }
# faster substitute for cat
function helper.printfile printfile() {
print ${mapfile[$1]}
}
# }}} Helpers # }}} Helpers
# {{{ Config # {{{ Config
@ -807,7 +802,7 @@ vars+=(config_section_type)
arrs+=(config_section) arrs+=(config_section)
config_section_type=org-mode config_section_type=org-mode
config.section.type() { config.section_type() {
fn config.section.type fn config.section.type
_type=$1 _type=$1
req=(_type) req=(_type)
@ -829,7 +824,7 @@ config.section.type() {
} }
# fills in contents of section in array config_section # fills in contents of section in array config_section
config.section.read() { config.section_read() {
fn config.section.read fn config.section.read
_file=$1 _file=$1
_section=$2 _section=$2