├── .gitignore ├── src ├── .gitignore ├── makefile ├── dpaste.bash ├── url.bash ├── random.bash ├── echo.bash ├── rae.bash └── gcat.bash ├── lib ├── file.bashly ├── output.bashly ├── test-library-loader.bashly ├── number.bashly ├── terminal.bashly ├── concurrent.bashly ├── filecompare.bashly ├── math.bashly ├── command.bashly ├── directory.bashly ├── stream.bashly ├── common.bashly ├── string.bashly ├── shell.bashly ├── regex.bashly ├── log.bashly ├── network.bashly ├── process.bashly ├── bytes.bashly ├── array.bashly ├── date.bashly ├── ipv4.bashly ├── scheme.bashly ├── template.bashly ├── format │ └── csv.bashly ├── http.bashly └── cmdline.bashly ├── bin ├── gcat ├── dpaste ├── echo ├── random └── url ├── docs ├── meta │ ├── returning_arrays.txt │ └── module_name_collisions.txt └── lib │ └── cmdline.txt ├── tests ├── ipv4.bashly │ └── 001-test-dot-to-ip ├── http.bashly │ ├── 001-test-query-string-encode │ ├── 003-test-http-form-url-encode │ └── 002-test-url-parse ├── process.bashly │ └── 001-test-process-search ├── shell.bashly │ ├── 001-test-shell-quote │ └── 002-test-shell-double-quote ├── format │ ├── makefile │ └── csv.bashly │ │ └── 001-test-format-csv ├── bytes.bashly │ ├── 003-test-bytes-write-uint32-le │ ├── 001-test-ord │ └── 002-test-chr ├── array.bashly │ └── 001-test-array-has-element ├── makefile ├── regex.bashly │ └── 001-test-re-quote ├── template.bashly │ └── 001-test-template-simple ├── cmdline.bashly │ └── 001-test-cmdline-arguments-short └── date.bashly │ └── 001-test-date-time-to-unix-seconds ├── makefile.common ├── makefile ├── LICENSE ├── README └── bashly /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.cbash 2 | -------------------------------------------------------------------------------- /lib/file.bashly: -------------------------------------------------------------------------------- 1 | : file__temporary 2 | -------------------------------------------------------------------------------- /bin/gcat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dualbus/bashly/HEAD/bin/gcat -------------------------------------------------------------------------------- /lib/output.bashly: -------------------------------------------------------------------------------- 1 | : output__spinner 2 | : output__progress_bar 3 | -------------------------------------------------------------------------------- /lib/test-library-loader.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load common 4 | -------------------------------------------------------------------------------- /lib/number.bashly: -------------------------------------------------------------------------------- 1 | : number__is_natural 2 | : number__is_integer 3 | : number__is_float 4 | -------------------------------------------------------------------------------- /lib/terminal.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | : terminal__size 5 | : terminal__set_title 6 | -------------------------------------------------------------------------------- /lib/concurrent.bashly: -------------------------------------------------------------------------------- 1 | : concurrent__lock 2 | 3 | function concurrent__lock { 4 | : 5 | } 6 | -------------------------------------------------------------------------------- /lib/filecompare.bashly: -------------------------------------------------------------------------------- 1 | : filecompare__intersect 2 | : filecompare__substract 3 | : filecompare__union 4 | -------------------------------------------------------------------------------- /lib/math.bashly: -------------------------------------------------------------------------------- 1 | : math__divide 2 | : math__multiply 3 | : math__add 4 | : math__substract 5 | : math__logarithm 6 | : math__power 7 | -------------------------------------------------------------------------------- /lib/command.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function command__exists { 5 | typeset name=$1 6 | 7 | [[ -x $(type -P -- "$name") ]] 8 | } 9 | -------------------------------------------------------------------------------- /lib/directory.bashly: -------------------------------------------------------------------------------- 1 | : directory__list_by_date 2 | : directory__is_empty 3 | : directory__count *.mpg 4 | : directory__rename *.foo *bar 5 | : directory__temporary 6 | -------------------------------------------------------------------------------- /lib/stream.bashly: -------------------------------------------------------------------------------- 1 | : stream__split output-prefix 10 # 10 lines 2 | : stream__replace foo bar 3 | : stream__replace_global foo bar 4 | : stream__dos_to_unix 5 | : stream__unix_to_dos 6 | -------------------------------------------------------------------------------- /lib/common.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load log 4 | 5 | function common__die { 6 | typeset exit_status=$2 7 | 8 | log__error "$1" 9 | 10 | exit "${exit_status:-1}" 11 | } 12 | -------------------------------------------------------------------------------- /docs/meta/returning_arrays.txt: -------------------------------------------------------------------------------- 1 | Returning arrays from functions 2 | =============================== 3 | 4 | Since bash has no concept of pointers, there's actually no sane way 5 | of returning arrays from functions. 6 | -------------------------------------------------------------------------------- /tests/ipv4.bashly/001-test-dot-to-ip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load ipv4 4 | 5 | function test { 6 | (( $(ipv4__dot_to_ip '8.8.8.8') == 134744072 )) || return 1 7 | 8 | return 0 9 | } 10 | 11 | 12 | test 13 | -------------------------------------------------------------------------------- /tests/http.bashly/001-test-query-string-encode: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load http 4 | 5 | function test { 6 | [[ $(http__query_string_encode a b 1 2) = 'a=1&b=2' ]] || return 1 7 | 8 | return 0 9 | } 10 | 11 | test 12 | -------------------------------------------------------------------------------- /makefile.common: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | rm=rm -f 4 | bash=/bin/bash 5 | bashly=BASHLY_PATH=$(rootdir)/lib $(rootdir)/bashly 6 | 7 | bindir=$(rootdir)/bin 8 | testsdir=$(rootdir)/tests 9 | srcdir=$(rootdir)/src 10 | 11 | .SUFFIXES: .bash .cbash .bashly 12 | -------------------------------------------------------------------------------- /tests/process.bashly/001-test-process-search: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load process 4 | 5 | function test { 6 | process__search bash >/dev/null || return 1 7 | process__search bash-$RANDOM$RANDOM$RANDOM && return 1 8 | 9 | return 0 10 | } 11 | 12 | test 13 | -------------------------------------------------------------------------------- /tests/shell.bashly/001-test-shell-quote: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load shell 4 | 5 | function test { 6 | [[ $(shell__quote "a'b") = "'a'\\''b'" ]] || return 1 7 | [[ $(shell__quote "a\\'b") = "'a\\'\\''b'" ]] || return 1 8 | 9 | return 0 10 | } 11 | 12 | test 13 | -------------------------------------------------------------------------------- /tests/format/makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | rootdir=../.. 4 | 5 | include $(rootdir)/makefile.common 6 | 7 | tests=\ 8 | csv 9 | 10 | all: $(tests) 11 | 12 | .bashly: 13 | for t in $&2 18 | done 19 | } 20 | 21 | 22 | function log__info { 23 | log__with_type INFO "$@" 24 | } 25 | 26 | 27 | function log__warning { 28 | log__with_type WARNING "$@" 29 | } 30 | 31 | 32 | function log__error { 33 | log__with_type ERROR "$@" 34 | } 35 | 36 | 37 | function log__debug { 38 | typeset debug_level log_level; shift 2 39 | 40 | if ((log_level >= debug_level)); then 41 | log__with_type DEBUG "$@" 42 | fi 43 | } 44 | -------------------------------------------------------------------------------- /src/url.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load http 4 | : load cmdline 5 | 6 | function main { 7 | typeset IFS 8 | typeset -a commands arguments 9 | 10 | typeset -a options=( 11 | 'name=encode:short=e:long=encode:arguments=1' 12 | 'name=decode:short=d:long=decode:arguments=1' 13 | ) 14 | 15 | while read -rd '' type value; do 16 | case $type in 17 | @) 18 | echo bad "$value"; exit 1 19 | ;; 20 | -) 21 | echo bad "$value"; exit 1 22 | ;; 23 | encode) 24 | command=http__form_url_encode argument=$value; break 25 | ;; 26 | decode) 27 | command=http__form_url_decode argument=$value; break 28 | ;; 29 | esac 30 | done < <(cmdline__arguments "${options[@]}" -- "$@") 31 | 32 | "$command" "$argument" 33 | } 34 | 35 | main "$@" 36 | -------------------------------------------------------------------------------- /lib/network.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load common 4 | 5 | function network__socket_get_device { 6 | typeset type=$1 netloc=$2 port=$3 7 | 8 | [[ $type = @(tcp|udp) ]] || return 1 9 | [[ $netloc = @(*/*|____) ]] && return 1 10 | [[ $port = +([[:digit:]]) ]] || return 1 11 | 12 | printf %s "/dev/$type/$netloc/$port" 13 | } 14 | 15 | function network__tcp-send { 16 | typeset netloc=$1 port=$2 17 | typeset line socket fd 18 | 19 | socket=$(network__socket_get_device tcp "$netloc" "$port") || return 1 20 | 21 | ( 22 | exec 3<>"$socket" 23 | 24 | while IFS= read -r line; do 25 | printf '%s\n' "$line"; 26 | done >&3 27 | 28 | printf %s "$line" >&3 29 | 30 | while IFS= read -r line; do 31 | printf '%s\n' "$line"; 32 | done <&3 33 | 34 | printf %s "$line" 35 | 36 | exec 3>&- 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /lib/process.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function process__search { 5 | typeset name=$1 6 | typeset IFS pid comm return=1 7 | 8 | unset IFS 9 | 10 | while read -r pid comm; do 11 | if [[ $comm = *"$name"* ]]; then 12 | printf '%s\n' "$pid"; return=0 13 | fi 14 | done < <(ps -e -o pid= -o comm=) 15 | 16 | return "$return" 17 | } 18 | 19 | 20 | function process__is_alive { 21 | typeset pid=$1 22 | 23 | kill -0 "$pid" 2>/dev/null 24 | } 25 | 26 | 27 | function process__timeout { 28 | : process__timeout seconds command 29 | 30 | typeset seconds=$1 31 | 32 | ( 33 | { 34 | sleep "$seconds"; 35 | 36 | kill "$BASHPID" && \ 37 | sleep 1 && kill "$BASHPID" && \ 38 | sleep 3 && kill "$BASHPID" && \ 39 | sleep 5 && kill -9 "$BASHPID"; 40 | } & 41 | 42 | exec "$@" 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /tests/cmdline.bashly/001-test-cmdline-arguments-short: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load cmdline 4 | 5 | function r { 6 | typeset shift result 7 | 8 | shift=$("$@" 3>/dev/null) 9 | result=$("$@" 3>&1 >/dev/null | od -t x1 -An -v | tr -d '[:space:]') 10 | 11 | printf '%u:%s' "$shift" "$result" 12 | } 13 | 14 | 15 | function test { 16 | typeset -A short_map 17 | typeset -A arguments_map 18 | 19 | 20 | short_map=(['x']=x) arguments_map=(['x']=1) 21 | [[ $(r cmdline__p__arguments__short -x a) = '1:78206100' ]] || return 1 22 | 23 | : 'missing arguments' 24 | short_map=(['x']=x) arguments_map=(['x']=2) 25 | cmdline__p__arguments__short -x a >/dev/null 3>&1 26 | (($? == 4)) || return 1 27 | 28 | : 'unspecified option' 29 | short_map=() arguments_map=() 30 | cmdline__p__arguments__short -x a >/dev/null 3>&1 31 | (($? == 3)) || return 1 32 | 33 | : 'unspecified option (which)' 34 | short_map=() arguments_map=() 35 | [[ $(r cmdline__p__arguments__short -x a) = '0:2d202d7800' ]] || return 1 36 | 37 | return 0 38 | } 39 | 40 | test 41 | -------------------------------------------------------------------------------- /src/random.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load cmdline 4 | : load common 5 | : load log 6 | 7 | function main { 8 | typeset type_ value 9 | typeset type length source 10 | typeset -a options=( 11 | 'name=type:short=t:long=type:arguments=1' # alnum alpha digit ... 12 | 'name=length:short=n:long=length:arguments=1' 13 | 'name=source:short=s:long=source:arguments=1' 14 | 'name=help:short=h:long=help' 15 | ) 16 | 17 | # defaults 18 | type=xdigit length=8 source=/dev/urandom 19 | while read -rd '' type_ value; do 20 | case $type_ in 21 | type) type=$value;; 22 | length) length=$value;; 23 | source) source=$value;; 24 | help) cmdline__help "${options[@]}"; return 0;; 25 | *) common__die "unexpected ''$value''";; 26 | esac 27 | done < <(cmdline__arguments "${options[@]}" -- "$@") 28 | 29 | case $type in 30 | xdigit|alnum|alpha|digit) 31 | printf '%s\n' \ 32 | "$(tr -cd "[:$type:]" < "$source" | head -c "$length")" 33 | ;; 34 | *) 35 | common__die "wrong type ''$type''" 36 | ;; 37 | esac 38 | } 39 | 40 | main "$@" 41 | -------------------------------------------------------------------------------- /tests/http.bashly/002-test-url-parse: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load http 4 | 5 | function test { 6 | [[ $(http__url_parse 'http://netloc') = 'http:::netloc:80:/::' ]] || return 1 7 | [[ $(http__url_parse 'https://netloc') = 'https:::netloc:443:/::' ]] || return 1 8 | [[ $(http__url_parse '//netloc') = ':::netloc::/::' ]] || return 1 9 | [[ $(http__url_parse '//username:password@netloc') = ':username:password:netloc::/::' ]] || return 1 10 | [[ $(http__url_parse '///path') = ':::::///path::' ]] || return 1 11 | [[ $(http__url_parse 'http://username:password@netloc/path?query=string#fragment') = 'http:username:password:netloc:80:/path:query=string:fragment' ]] || return 1 12 | [[ $(http__url_parse 'http://netloc/path?query=string#fragment') = 'http:::netloc:80:/path:query=string:fragment' ]] || return 1 13 | [[ $(http__url_parse 'http://username:password@netloc?query=string#fragment') = 'http:username:password:netloc:80:/:query=string:fragment' ]] || return 1 14 | [[ $(http__url_parse 'http://netloc/path#fragment') = 'http:::netloc:80:/path::fragment' ]] || return 1 15 | 16 | return 0 17 | } 18 | 19 | test 20 | -------------------------------------------------------------------------------- /lib/bytes.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function bytes__chr { 4 | typeset dec=$1 5 | ((0 <= dec && dec < 256)) || return 1 6 | 7 | printf \\$((dec/64*100+dec%64/8*10+dec%8)) 8 | } 9 | 10 | 11 | function bytes__ord { 12 | LC_CTYPE=C printf '%d' "'$1" 13 | } 14 | 15 | 16 | function bytes__hex { 17 | LC_CTYPE=C printf '%x' "'$1" 18 | } 19 | 20 | 21 | function bytes__unhex { 22 | [[ $1 = ?([[:xdigit:]])[[:xdigit:]] ]] || return 1 23 | 24 | printf '\x'"$1" 25 | } 26 | 27 | 28 | function bytes__write_uint32_le { 29 | typeset number=$1 30 | typeset hex 31 | 32 | ((number >> 32)) && return 1 33 | 34 | printf -v hex '\\x%x' \ 35 | "$(( number & 0xff))" "$(( (number >> 8) & 0xff))" \ 36 | "$(( (number >> 16) & 0xff))" "$(( (number >> 24) & 0xff))" 37 | 38 | printf "$hex" 39 | } 40 | 41 | 42 | function bytes__write_uint32_be { 43 | typeset number=$1 44 | typeset hex 45 | 46 | ((number >> 32)) && return 1 47 | 48 | printf -v hex '\\x%x' \ 49 | "$(( (number >> 24) & 0xff))" "$(( (number >> 16) & 0xff))" \ 50 | "$(( (number >> 8) & 0xff))" "$(( number & 0xff))" 51 | 52 | printf "$hex" 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Eduardo Bustamante 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | bashly 2 | ====== 3 | 4 | This project, bashly, is yet another attempt of a library of reusable 5 | bash functions. Though its development is driven by the following 6 | core principles: 7 | 8 | - Encapsulate all state within the functions (no global variables) 9 | - Avoid ''eval'' at all costs. It is really hard to read scripts that 10 | (ab)use eval, and even more difficult to maintain. There are also 11 | security risks associated to the use of eval. 12 | - Avoid external commands, bashly attempts to be standalone. The only 13 | commands that are going to be used are: od (it's POSIX, and to 14 | overcome the binary stream handling of bash). This should make it 15 | very portable across systems where bash is available. 16 | - Lots of tests. Code should be written with testability in mind. 17 | - Follow best practices for bash programming. 18 | - Make it easy to create stand-alone scripts that are linked to the 19 | bashly modules, but also make it easy to update linked scripts. 20 | 21 | 22 | The modules (or libraries) reside in the lib/ hierarchy. They have 23 | the bashly extension, to easily identify them as libraries. Each 24 | library should have its own battery of tests under the test/ 25 | hierarchy. Also, each library should have its own documentation under 26 | docs/lib. 27 | 28 | You will find sample scripts based on bashly under the src/ 29 | directory, with their "linked" forms under bin/ 30 | 31 | 32 | Feed-back in the form of issues is greatly appreciated. 33 | -------------------------------------------------------------------------------- /src/echo.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load cmdline 4 | 5 | function main { 6 | : <>> import foo.json as json_a 31 | >>> import bar.json as json_b 32 | 33 | And that's it. You now use json_a.func for a ''func'' function in 34 | foo.json, and json_b.parse for a ''parse'' function in bar.json. 35 | 36 | It's really simple and convenient. 37 | 38 | 39 | So, what can be done within bashly to deal with this? 40 | 41 | Options: 42 | 43 | - Introduce a name rewriting feature that get's triggered on load 44 | time, so, the user just writes: '': load json as json_a'', which 45 | then loads ''json'' rewriting all the json.* functions to json_a.*. 46 | 47 | - What else? 48 | -------------------------------------------------------------------------------- /src/rae.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load http 4 | 5 | #recode() { 6 | # local -a args=() 7 | # if type -P recode >/dev/null 2>&1; then 8 | # command recode "$@" 9 | # elif type -P iconv >/dev/null 2>&1; then 10 | # IFS=. read -r from _ to <<< "$1" 11 | # args=() 12 | # [[ $from ]] && args+=(-f "$from") 13 | # [[ $to ]] && args+=(-t "$to") 14 | # iconv "${args[@]}" 15 | # else 16 | # die 'dependency: recode | iconv' 17 | # fi 18 | #} 19 | # 20 | #html2txt() { 21 | # local url=$1 22 | # 23 | # if type -P elinks >/dev/null 2>&1; then 24 | # elinks -no-numbering -no-references -dump "$url" | awk ' 25 | # {sub(/^[[:space:]]*/,"")} 26 | # NR==1,!/^[[:space:]]*$/{b=$0;next} 27 | # b{print b; b=""} 28 | # 1' 29 | # elif type -P lynx >/dev/null 2>&1; then 30 | # lynx -nolist -dump "$url" | recode ISO-8859-1.. | awk ' 31 | # {sub(/^[[:space:]]*/,"")} 32 | # NR==1,!/^[[:space:]]*$/{b=$0;next} 33 | # b{print b; b=""} 34 | # 1' 35 | # elif type -P w3m >/dev/null 2>&1; then 36 | # w3m -O ISO-8859-1 -dump "$url" | recode ISO-8859-1.. | awk ' 37 | # {sub(/^[[:space:]]*/,"")} 38 | # NR==1,!/^[[:space:]]*$/{b=$0;next} 39 | # b{print b; b=""} 40 | # d++{print c}{c=$0}' 41 | # elif type -P links >/dev/null 2>&1; then 42 | # links -codepage iso-8859-1 -dump "$url" | recode ISO-8859-1.. | awk ' 43 | # {sub(/^[[:space:]]*/,"")} 44 | # NR==1,!/^[[:space:]]*$/{b=$0;next} 45 | # b{print b; b=""} 46 | # 1' 47 | # else 48 | # die 'dependency: elinks | lynx | w3m | links' 49 | # fi 50 | #} 51 | 52 | ## Dependencies 53 | ## ------------ 54 | #recode /dev/null 55 | #html2txt . /dev/null 56 | 57 | 58 | function main { 59 | typeset base_url='http://lema.rae.es/drae/srv/search?val=%s' 60 | typeset term=$(http__form_url_encode "$1") 61 | 62 | #printf -v url "$base_url" "$(printf %s "$term" | fuenc | recode ..ISO-8859-1)" 63 | 64 | printf -v url "$base_url" "$term" 65 | 66 | echo "$url" 67 | } 68 | 69 | main "$@" 70 | -------------------------------------------------------------------------------- /lib/date.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function date__is_leap_year { 5 | typeset year=$((10#$1)) 6 | 7 | ((year % 400)) || return 0 8 | ((year % 100)) || return 1 9 | ((year % 4)) || return 0 10 | return 1 11 | } 12 | 13 | 14 | function date__day_of_year { 15 | typeset year=$((10#$1)) month=$((10#$2)) day=$((10#$3)) 16 | typeset offset offset_not_leap offset_leap 17 | 18 | typeset -a month_to_day_of_year=( 19 | [ 1]='1:1' [ 2]='32:32' [ 3]='60:61' 20 | [ 4]='91:92' [ 5]='121:122' [ 6]='152:153' 21 | [ 7]='182:183' [ 8]='213:214' [ 9]='244:245' 22 | [10]='274:275' [11]='305:306' [12]='335:336' 23 | ) 24 | 25 | IFS=: read -r offset_not_leap offset_leap \ 26 | <<< "${month_to_day_of_year[month]}" 27 | 28 | if date__is_leap_year "$year"; then 29 | offset=$offset_leap 30 | else 31 | offset=$offset_not_leap 32 | fi 33 | 34 | printf %u "$((offset + day - 1))" 35 | } 36 | 37 | 38 | function date__time_to_unix_seconds { 39 | : <> 24) & 0xff)) 34 | octet1=$(( (ipv4 >> 16) & 0xff)) 35 | octet2=$(( (ipv4 >> 8) & 0xff)) 36 | octet3=$(( (ipv4 >> 0) & 0xff)) 37 | 38 | printf '%u.%u.%u.%u' "$octet0" "$octet1" "$octet2" "$octet3" 39 | } 40 | 41 | 42 | function ipv4__bits_to_mask { 43 | : < 0; i-- )); do 63 | [[ $mask = "$(ipv4__bits_to_mask "$i")" ]] && { 64 | printf %u "$i"; return 65 | } 66 | done 67 | } 68 | 69 | 70 | function ipv4__mask_address { 71 | : < # Load argsparse library. 46 | > . argsparse.sh 47 | > 48 | > # Declaring an option not accepting a value and not having a 49 | > # single-char equivalent. 50 | > argsparse_use_option option1 "An option." 51 | > 52 | > # Declaring an option not accepting a value but with a single-char 53 | > # equivalent. 54 | > 55 | > # "short" is a property, and "o" is the value of the "short" property 56 | > # for this option. Argsparse can handle other properties, see other 57 | > # tutorials. 58 | > argsparse_use_option option2 "Another option." short:o 59 | 60 | This seems to have many features, and a clean interface, similar to 61 | shellOptions. And like shellOptions, it uses global variables to 62 | store the option-parsing-related data. So, the same criticism 63 | applies, namely, that it's difficult to use this more than once 64 | inside the same script (without resorting to subshells, or other 65 | tricks). Other than that it seems fine, and well tested. 66 | 67 | I also like the fact that it comes with some common validation code 68 | included, so you don't have to reinvent the wheel to validate 69 | numbers, files, addresses, and so on. 70 | 71 | 72 | - shellOptions: 73 | 74 | > This is a small library for handling command line options in bash and zsh. It is 75 | > inspired by the optparse python library. An example usage is 76 | > 77 | > addOption -n --number required help="Specify some number" dest=myNumber 78 | > addOption -a --aux flagTrue help="Another option, but without dest" 79 | > addOption -o help="Option with default" default="a b" dest=otherO 80 | > parseOptions "$@" 81 | 82 | The interface is really clear and feature full. It reminds me of 83 | Python's argparse . The only issue I have with it is that it 84 | appears to use global variables to handle the options (e.g. 85 | __longOptions__, __shortOptions__, and the rest). So, for simple 86 | scripts, which just have one argument parsing phase it's ok, as 87 | long as they do not accidentally touch the global variables, but if 88 | you want to reuse this functionality inside your own functions, or 89 | more than once in a script, it's not apparent how to resolve this. 90 | 91 | Other than that, it seems like a good piece of software (it would 92 | be better if it included some tests). 93 | 94 | -------------------------------------------------------------------------------- /lib/template.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function template__p__simple__emit { 5 | typeset character=$1 6 | 7 | printf '%s' "$character" >&3 8 | } 9 | 10 | 11 | function template__p__simple__emit_variable { 12 | typeset variable=$1 13 | typeset value=${!variable} 14 | 15 | printf '%s' "$value" >&3 16 | } 17 | 18 | 19 | function template__p__simple__string { 20 | typeset character=$1 variable=$2 21 | 22 | case $character in 23 | \$) echo 'dollar'; return;; 24 | \\) echo 'escape'; return;; 25 | esac 26 | 27 | template__p__simple__emit "$character" 28 | 29 | echo 'string' 30 | } 31 | 32 | 33 | function template__p__simple__escape { 34 | typeset character=$1 variable=$2 35 | 36 | template__p__simple__emit "$character" 37 | 38 | echo 'string' 39 | } 40 | 41 | 42 | function template__p__simple__dollar { 43 | typeset character=$1 variable=$2 44 | 45 | if [[ $character = '{' ]]; then 46 | echo 'left_brace'; return 47 | elif [[ $character = [[:alnum:]] ]]; then 48 | echo "variable:$variable$character"; return 49 | fi 50 | 51 | : invalid variable name character 52 | 53 | echo 'error' 54 | } 55 | 56 | 57 | function template__p__simple__variable { 58 | typeset character=$1 variable=$2 59 | 60 | if [[ $character = [[:alnum:]] ]]; then 61 | echo "variable:$variable$character"; return 62 | fi 63 | 64 | template__p__simple__emit_variable "$variable" 65 | 66 | template__p__simple__string "$character" 67 | } 68 | 69 | 70 | function template__p__simple__left_brace { 71 | typeset character=$1 variable=$2 72 | 73 | if [[ $character = [[:alnum:]] ]]; then 74 | echo "variable_brace:$variable$character"; return 75 | fi 76 | 77 | : invalid variable name character 78 | echo 'error' 79 | } 80 | 81 | 82 | function template__p__simple__right_brace { 83 | typeset character=$1 variable=$2 84 | 85 | template__p__simple__string "$character" 86 | } 87 | 88 | 89 | function template__p__simple__variable_brace { 90 | typeset character=$1 variable=$2 91 | 92 | if [[ $character = '}' ]]; then 93 | template__p__simple__emit_variable "$variable" 94 | 95 | echo 'right_brace'; return 96 | elif [[ $character = [[:alnum:]] ]]; then 97 | echo "variable_brace:$variable$character"; return 98 | fi 99 | 100 | : error missing closing right brace 101 | echo 'error' 102 | } 103 | 104 | 105 | function template__p__simple__error { 106 | typeset character=$1 variable=$2 107 | 108 | echo 'error' 109 | } 110 | 111 | 112 | function template__p__simple__fsm { 113 | : template__p__simple__fsm 114 | 115 | typeset state=$1 character=$2 variable=$3 116 | 117 | case $state in 118 | string) 119 | template__p__simple__string "$character" "$variable";; 120 | escape) 121 | template__p__simple__escape "$character" "$variable";; 122 | dollar) 123 | template__p__simple__dollar "$character" "$variable";; 124 | variable) 125 | template__p__simple__variable "$character" "$variable";; 126 | left_brace) 127 | template__p__simple__left_brace "$character" "$variable";; 128 | right_brace) 129 | template__p__simple__right_brace "$character" "$variable";; 130 | variable_brace) 131 | template__p__simple__variable_brace "$character" "$variable";; 132 | error) 133 | template__p__simple__error; return 1;; 134 | esac 135 | 136 | return 0 137 | } 138 | 139 | 140 | function template__simple { 141 | typeset i line character variable state=string 142 | 143 | { 144 | while IFS= read -r line; do 145 | for ((i = 0; i < ${#line}; i++)); do 146 | character=${line:i:1} 147 | 148 | IFS=: read -r state variable < \ 149 | <(template__p__simple__fsm "$state" "$character" \ 150 | "$variable") 151 | done 152 | 153 | IFS=: read -r state variable < \ 154 | <(template__p__simple__fsm "$state" $'\n' "$variable") 155 | done 156 | 157 | for ((i = 0; i < ${#line}; i++)); do 158 | character=${line:i:1} 159 | 160 | IFS=: read -r state variable < \ 161 | <(template__p__simple__fsm "$state" "$character" "$variable") 162 | done 163 | 164 | IFS=: read -r state variable < \ 165 | <(template__p__simple__fsm "$state" '' "$variable") 166 | 167 | [[ $state = 'error' ]] && return 1 168 | } 3>&1 169 | 170 | return 0 171 | } 172 | -------------------------------------------------------------------------------- /lib/format/csv.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load string 4 | 5 | 6 | function format__csv__escape { 7 | typeset string=$1 8 | 9 | printf %s "${string//\"/\"\"}" 10 | } 11 | 12 | 13 | function format__csv__oak { 14 | typeset buffer=$1 last_field=$2 state=$3 15 | typeset row column 16 | 17 | IFS=: read -r row column <<< "$state" 18 | 19 | printf '/[%d][%d]\t%s\n' \ 20 | "$row" "$column" \ 21 | "$(string__c-escape "$buffer")" >&3 22 | 23 | printf %d:%d "$((row+1))" "$((column+1))" 24 | } 25 | 26 | 27 | function format__csv__p__parse__emit-field { 28 | typeset buffer=$1 last_field=$2 29 | typeset state 30 | 31 | if [[ ! $callback ]]; then 32 | printf %q\\n "$buffer" >&3 33 | else 34 | IFS= read -r state < \ 35 | <("$callback" "$buffer" "$last_field") 36 | fi 37 | } 38 | 39 | 40 | function format__csv__p__parse__initial { 41 | typeset character=$1 buffer=$2 42 | 43 | if [[ $character = '"' ]]; then 44 | printf %s "double_quote:$buffer"; return 45 | elif [[ $character = ',' ]]; then 46 | format__csv__p__parse__emit-field "$buffer" 47 | printf %s 'initial'; return 48 | elif [[ $character = $'\n' ]]; then 49 | format__csv__p__parse__emit-field "$buffer" last 50 | printf %s 'initial'; return 51 | elif [[ $character = $'\r' ]]; then 52 | format__csv__p__parse__emit-field "$buffer" last 53 | printf %s 'carriage_return'; return 54 | elif [[ $character = '' ]]; then 55 | format__csv__p__parse__emit-field "$buffer" last 56 | printf %s 'initial'; return 57 | fi 58 | 59 | printf %s "field:$buffer$character" 60 | } 61 | 62 | 63 | function format__csv__p__parse__field { 64 | typeset character=$1 buffer=$2 65 | 66 | if [[ $character != '"' ]]; then 67 | format__csv__p__parse__initial "$character" "$buffer"; return 68 | fi 69 | 70 | printf %s "field:$buffer$character" 71 | } 72 | 73 | 74 | function format__csv__p__parse__double_quote { 75 | typeset character=$1 buffer=$2 76 | 77 | if [[ $character = '"' ]]; then 78 | printf %s "escape:$buffer"; return 79 | fi 80 | 81 | printf %s "double_quote:$buffer$character" 82 | } 83 | 84 | 85 | function format__csv__p__parse__escape { 86 | typeset state character=$1 buffer=$2 87 | 88 | : should not return field 89 | IFS=: read -rd '' state buffer < \ 90 | <(format__csv__p__parse__initial "$character" "$buffer") 91 | 92 | if [[ $state != 'field' ]]; then 93 | printf %s "$state:$buffer"; return 94 | fi 95 | 96 | : expecting double_quote, comma, carriage_return or line-feed 97 | echo panic >&2 98 | return 1 99 | } 100 | 101 | 102 | function format__csv__p__parse__carriage_return { 103 | if [[ $character = $'\n' ]]; then 104 | printf %s 'initial' 105 | fi 106 | 107 | : expecting line-feed 108 | echo panic >&2 109 | return 1 110 | } 111 | 112 | 113 | function format__csv__p__parse__fsm { 114 | typeset state=$1 character=$2 buffer=$3 115 | 116 | case $state in 117 | field) 118 | format__csv__p__parse__field "$character" "$buffer";; 119 | double_quote) 120 | format__csv__p__parse__double_quote "$character" "$buffer";; 121 | initial) 122 | format__csv__p__parse__initial "$character" "$buffer";; 123 | escape) 124 | format__csv__p__parse__escape "$character" "$buffer";; 125 | carriage_return) 126 | format__csv__p__parse__carriage_return "$character" "$buffer";; 127 | esac 128 | 129 | return 0 130 | } 131 | 132 | 133 | function format__csv__parse { 134 | : format__csv__parse 135 | 136 | typeset i line character variable saw_field=0 state=initial 137 | typeset -x callback=$1 138 | 139 | { 140 | while IFS= read -r line; do 141 | saw_field=0 142 | 143 | for ((i = 0; i < ${#line}; i++)); do 144 | character=${line:i:1} 145 | 146 | IFS=: read -rd '' state buffer < \ 147 | <(format__csv__p__parse__fsm "$state" "$character" "$buffer") 148 | 149 | [[ $state = field ]] && ((saw_field++)) 150 | done 151 | 152 | IFS=: read -rd '' state buffer < \ 153 | <(format__csv__p__parse__fsm "$state" $'\n' "$buffer") 154 | done 155 | 156 | saw_field=0 157 | 158 | for ((i = 0; i < ${#line}; i++)); do 159 | character=${line:i:1} 160 | 161 | IFS=: read -rd '' state buffer < \ 162 | <(format__csv__p__parse__fsm "$state" "$character" "$buffer") 163 | 164 | [[ $state = field ]] && ((saw_field++)) 165 | done 166 | 167 | if ((saw_field > 0)); then 168 | IFS=: read -rd '' state buffer < \ 169 | <(format__csv__p__parse__fsm "$state" '' "$buffer") 170 | fi 171 | } 3>&1 172 | 173 | return 0 174 | } 175 | -------------------------------------------------------------------------------- /bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash -T 2 | 3 | # Remove exported functions from the environment. Since builtins can 4 | # be masked by functions, these could cause us trouble if they 5 | # collide with a builtin we use, like read. 6 | while IFS=' ' builtin read -r _ _ function; do 7 | builtin unset -f "$function" 8 | done < <(builtin typeset -Fx) 9 | 10 | 11 | 12 | 13 | 14 | # We'll use this array to store the lines we're reading while 15 | # sourcing the file. 16 | typeset -a bashly_code_lines=() 17 | 18 | # Functions defined by bashly. The "random" prefix is a way to avoid 19 | # collisions with a user defined function. This array is used to 20 | # "clean up" the environment before exporting the function 21 | # definitions to the "compiled" script. 22 | typeset -a bashly_functions=( 23 | __b7ab299a__command_dispatcher 24 | __b7ab299a__compile_script 25 | __b7ab299a__load_bashly 26 | ) 27 | 28 | # Extensions used by bashly libraries. Just in case we might want to 29 | # add more in the future (like a shorter name). 30 | typeset -a bashly_extensions=( 31 | bashly 32 | ) 33 | 34 | # Set of loaded modules, to avoid loading twice the same module. I 35 | # don't know if this helps in the case of circular dependencies, but 36 | # I expect it to. Must investigate further. FIXME: test if it works 37 | # with circular dependencies. 38 | typeset -A bashlies=() 39 | 40 | 41 | 42 | 43 | 44 | # The command dispatcher function reads triggers from the source 45 | # code, and if it finds a special trigger, it executes its related 46 | # command. 47 | # 48 | # Currently, these are the defined triggers: 49 | # - : load 50 | # 51 | # Make sure to not use that name in your applications. 52 | function __b7ab299a__command_dispatcher { 53 | typeset bash_command=$1 IFS prefix trigger rest 54 | 55 | unset IFS 56 | 57 | read -r prefix trigger rest <<< "$bash_command" 58 | 59 | [[ $prefix = : ]] || { 60 | bashly_code_lines+=("$bash_command") 61 | return 1 62 | } 63 | 64 | case "$prefix $trigger" in 65 | ': load') 66 | __b7ab299a__load_bashly "$rest";; 67 | esac 68 | 69 | return 1 70 | } 71 | 72 | 73 | # Script "compilation" is more like sourcing snippets of code from 74 | # "libraries". So far, what this means is that you: 75 | # 76 | # 1) Load dependencies from a "source" script 77 | # 2) Dependencies are basically a compilation of functions. 78 | # 3) Functions are "scoped" using the following convention: 79 | # . 80 | # 4) Due to the way this script works, your main code has to be 81 | # wrapped in a function, because code outside functions is 82 | # evaluated on "compile" time. 83 | # 5) A "compiled" script is basically the original script with the 84 | # library functions expanded. 85 | # 86 | function __b7ab299a__compile_script { 87 | typeset function 88 | 89 | for function in "${bashly_functions[@]}"; do 90 | unset -f "$function" 91 | done 92 | 93 | # Emit the function declarations 94 | typeset -fp 95 | 96 | # Emit the source code 97 | printf '%s\n' "${bashly_code_lines[@]}" 98 | } 99 | 100 | 101 | # Library loading is achieved by a recursive call to this script. So, 102 | # make sure you install this script and run it in a way that it's 103 | # able to find itself (through $BASH_SOURCE). 104 | # 105 | # Libraries are searched PATH-style, from the BASHLY_PATH environment 106 | # variable. You just make sure to set its value before compiling. 107 | # Think of it as an "include path", if that makes sense. 108 | # 109 | function __b7ab299a__load_bashly { 110 | typeset bashly=$1 IFS=: 111 | typeset place extension fd module 112 | typeset -a places loaded_modules new_loaded_modules 113 | 114 | [[ $bashly ]] || return 1 115 | 116 | if [[ ${bashlies["$bashly"]} = loaded ]]; then 117 | return 0 118 | fi 119 | 120 | # Replace dots with forward slashes. 121 | bashly=${bashly//./\/} 122 | 123 | read -ra places <<< "$BASHLY_PATH" 124 | 125 | for place in "${places[@]}"; do 126 | for extension in "${bashly_extensions[@]}"; do 127 | [[ -r $place/$bashly.$extension ]] && { 128 | loaded_modules=("${!bashlies[@]}" "$bashly") 129 | 130 | BASHLY_MODULES="${loaded_modules[*]}" \ 131 | "$BASH_SOURCE" "$place/$bashly.$extension" 132 | 133 | bashlies["$bashly"]=loaded 134 | 135 | return 0; 136 | } 137 | done 138 | done 139 | 140 | return 1 141 | } 142 | 143 | 144 | 145 | 146 | 147 | unset IFS 148 | 149 | IFS=: read -ra bashly_loaded_modules <<< "$BASHLY_MODULES" 150 | for bashly_loaded_module in "${bashly_loaded_modules[@]}"; do 151 | bashlies["$bashly_loaded_module"]=loaded 152 | done 153 | 154 | if [[ $2 ]]; then 155 | exec > "$2" || exit 156 | 157 | if [[ -f "$2" ]]; then 158 | chmod +x "$2" || exit 159 | fi 160 | 161 | printf '%s\n' '#!/usr/bin/env bash' 162 | fi 163 | 164 | # The magic of the script comes from using the extdebug shell option. 165 | # It basically parses the input file, and loads all function 166 | # declarations, executing loops, conditionals, and other types of 167 | # statements, except that simple commands have no effect at all. 168 | shopt -s extdebug; set -T; 169 | 170 | trap ' 171 | if ((BASH_LINENO)); then 172 | __b7ab299a__command_dispatcher "$BASH_COMMAND" 173 | elif [[ "$BASH_COMMAND" = __b7ab299a__compile_script ]]; then 174 | __b7ab299a__compile_script 175 | exit 176 | fi 177 | ' DEBUG 178 | 179 | PATH= source "$1" 180 | 181 | __b7ab299a__compile_script 182 | -------------------------------------------------------------------------------- /lib/http.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load common 4 | : load bytes 5 | : load network 6 | 7 | 8 | # FIXME: Check against multibyte encodings! 9 | function http__percent_encode { 10 | typeset character position data=$1 11 | typeset -x LC_TYPE=C 12 | 13 | for ((position=0; position<${#data}; position++)); do 14 | character=${data:position:1} 15 | 16 | if [[ $character = [[:alnum:].~-] ]]; then 17 | printf %s "$character" 18 | else 19 | printf %%%02X "$(bytes__ord "$character")" 20 | fi 21 | done 22 | } 23 | 24 | 25 | function http__form_url_encode { 26 | : application/x-www-form-urlencoded 27 | 28 | typeset data=$(http__percent_encode "$1") 29 | 30 | printf %s "${data//%20/+}" 31 | } 32 | 33 | 34 | function http__percent_decode { 35 | typeset data=${1//\\/\\\\} 36 | 37 | printf "${data//%/\\x}" 38 | } 39 | 40 | 41 | function http__form_url_decode { 42 | typeset data=${1//+/%20} 43 | 44 | http__percent_decode "$data" 45 | } 46 | 47 | 48 | function http__query_string_encode { 49 | : </dev/null && printf y) 92 | typeset -a components 93 | 94 | shopt -s extglob 95 | 96 | : Parse the scheme, currently it is generic 97 | if [[ $url = +([!:])?(s)://* ]]; then 98 | scheme=${url%%://*} url=${url#+([!:])://} 99 | elif [[ $url = @(//[!/]*|//) ]]; then 100 | scheme=$default_scheme url=${url#//} 101 | fi 102 | 103 | : Parse username:password combination in URL 104 | if [[ $url = *([!@])@* ]]; then 105 | IFS=:@ read -r username password url <<< "$url" 106 | fi 107 | 108 | : Parse network location '(ip address or domain name)' 109 | if [[ $url = +([!:]):+([[:digit:]])?([/?#&]*) ]]; then 110 | netloc=${url%%:*} port=${url#"$netloc"} port=${port##*:} 111 | url=${url#"$netloc:$port"} 112 | elif [[ $url = +([!/?#&])?([/?#&]*) ]]; then 113 | netloc=${url%%[/?#&]*} 114 | url=${url#"$netloc"} 115 | 116 | : Default ports 117 | case $scheme in 118 | http) port=80;; 119 | https) port=443;; 120 | esac 121 | fi 122 | 123 | : Parse path 124 | path=/ 125 | if [[ $url = +([!?#&])?([?#&]*) ]]; then 126 | path=${url%%[?#&]*} 127 | url=${url#"$path"} 128 | fi 129 | 130 | : Parse query string 131 | if [[ $url = +([!#])?([#]*) ]]; then 132 | query_string=${url%%[#]*} query_string=${query_string#'?'} 133 | url=${url#"?$query_string"} 134 | fi 135 | 136 | : Parse fragment 137 | if [[ $url = '#'* ]]; then 138 | fragment=${url#'#'} 139 | fi 140 | 141 | : Return extglob to the state we found it 142 | [[ $extglob ]] || shopt -u extglob 143 | 144 | : Join the components 145 | components=( 146 | "$scheme" "$username" "$password" 147 | "$netloc" "$port" "$path" 148 | "$query_string" "$fragment" 149 | ) 150 | 151 | (IFS=':'; printf %s "${components[*]}") 152 | } 153 | 154 | 155 | function http__get { 156 | typeset url=$1 157 | typeset scheme username password netloc port path query_string 158 | typeset fragment resource IFS=: 159 | typeset -a request=() 160 | 161 | IFS=: read -r scheme _ _ netloc port path query_string _ \ 162 | < <(http__url_parse "$url") 163 | 164 | resource=$path 165 | 166 | [[ $query_string ]] && resource+=?$query_string 167 | 168 | request+=("GET $resource HTTP/1.0") 169 | request+=("Host: $netloc") 170 | request+=('') 171 | 172 | printf '%s\r\n' "${request[@]}" | network__tcp_send "$netloc" "$port" 173 | } 174 | 175 | # FIXME: check against header injection (i.e. $resource) 176 | function http__post { 177 | typeset url=$1 form=$2 178 | typeset scheme username password netloc port path query_string 179 | typeset fragment resource IFS=: 180 | typeset -a request=() 181 | 182 | read -r scheme _ _ netloc port path query_string _ \ 183 | < <(http__url_parse "$url") 184 | 185 | resource=$path 186 | 187 | [[ $query_string ]] && resource+=?$query_string 188 | 189 | request+=("POST $resource HTTP/1.0") 190 | request+=("Host: $netloc") 191 | request+=("Content-Type: application/x-www-form-urlencoded") 192 | request+=("Content-Length: $((${#form}+2))") # form + \r\n 193 | request+=('') 194 | request+=("$form") 195 | 196 | printf '%s\r\n' "${request[@]}" | network__tcp_send "$netloc" "$port" 197 | } 198 | -------------------------------------------------------------------------------- /lib/cmdline.bashly: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function cmdline__p__arguments__short { 5 | typeset argument=$1 6 | typeset name i arguments 7 | 8 | [[ $argument ]] || return 1 9 | 10 | shift 11 | 12 | { 13 | typeset -p short_map || return 2 14 | typeset -p arguments_map || return 2 15 | } >/dev/null 2>&1 16 | 17 | name=${short_map["${argument#-}"]} 18 | 19 | [[ $name ]] || { 20 | printf -- '- %s\0' "$argument" >&3 21 | return 3 22 | } 23 | 24 | arguments=${arguments_map["$name"]} 25 | 26 | if ((arguments == 0)); then 27 | printf '%s\0' "$name" >&3; return 0 28 | elif ((arguments > $#)); then 29 | return 4 30 | fi 31 | 32 | for ((i = 1; i <= arguments; i++)); do 33 | printf '%s %s\0' "$name" "${@:i:1}" >&3 34 | 35 | shift 36 | done 37 | 38 | printf %s "$arguments" 39 | } 40 | 41 | 42 | function cmdline__p__arguments__short_composed { 43 | typeset argument=$1 44 | typeset option remainder name arguments 45 | 46 | [[ $argument ]] || return 1 47 | 48 | shift 49 | 50 | { 51 | typeset -p short_map || return 2 52 | typeset -p arguments_map || return 2 53 | } >/dev/null 2>&1 54 | 55 | option=${argument#-} option=${option::1} 56 | remainder=${argument#-?} 57 | name=${short_map["$option"]} 58 | 59 | [[ $name ]] || { 60 | printf -- '- %s\0' "$argument" >&3 61 | return 3 62 | } 63 | 64 | arguments=${arguments_map["$name"]} 65 | 66 | if ((arguments == 0)); then 67 | printf '%s\0' "$name" >&3 68 | 69 | if [[ $remainder ]]; then 70 | cmdline__p__arguments__short_composed "-$remainder" "$@" || return 71 | fi 72 | else 73 | [[ $remainder ]] && set -- "$remainder" "$@" 74 | 75 | cmdline__p__arguments__short "-$option" "$@" || return 76 | fi 77 | } 78 | 79 | 80 | function cmdline__p__arguments__long { 81 | typeset argument=$1 82 | typeset name i arguments 83 | 84 | [[ $argument ]] || return 1 85 | 86 | shift 87 | 88 | { 89 | typeset -p long_map || return 2 90 | typeset -p arguments_map || return 2 91 | } >/dev/null 2>&1 92 | 93 | name=${long_map["${argument#--}"]} 94 | 95 | [[ $name ]] || { 96 | printf -- '- %s\0' "$argument" >&3 97 | return 3 98 | } 99 | 100 | arguments=${arguments_map["$name"]} 101 | 102 | if ((arguments == 0)); then 103 | printf '%s\0' "$name" >&3; return 0 104 | elif ((arguments > $#)); then 105 | return 4 106 | fi 107 | 108 | for ((i = 1; i <= arguments; i++)); do 109 | printf '%s %s\0' "$name" "${@:i:1}" >&3 110 | 111 | shift 112 | done 113 | 114 | printf %s "$arguments" 115 | } 116 | 117 | 118 | function cmdline__arguments { 119 | : < 0)); do 186 | argument=$1 187 | 188 | if [[ $stop_parsing ]]; then 189 | printf '@ %s\0' "$argument"; shift; continue; 190 | fi 191 | 192 | case $argument in 193 | -[!-]) 194 | { 195 | shift=$(cmdline__p__arguments__short "$@") || { 196 | return_code=$? 197 | 198 | [[ $errors_not_fatal ]] || return "$return_code"; 199 | } 200 | } 3>&1 201 | 202 | shift "$((shift + 1))" 203 | ;; 204 | 205 | -[!-]*) 206 | { 207 | shift=$(cmdline__p__arguments__short_composed "$@") || { 208 | return_code=$? 209 | 210 | [[ $errors_not_fatal ]] || return "$return_code"; 211 | } 212 | } 3>&1 213 | 214 | shift "$((shift + 1))" 215 | ;; 216 | 217 | --[!-]*) 218 | if [[ $argument = --+([!=])=* ]]; then 219 | IFS== read -rd '' key value <<< "$argument" 220 | 221 | shift; set -- "$key" "${value%$'\n'}" "$@" 222 | fi 223 | 224 | { 225 | shift=$(cmdline__p__arguments__long "$@") || { 226 | return_code=$? 227 | 228 | [[ $errors_not_fatal ]] || return "$return_code"; 229 | } 230 | } 3>&1 231 | 232 | shift "$((shift + 1))" 233 | ;; 234 | 235 | --) 236 | if [[ $dashdash_not_special ]]; then 237 | printf '@ %s\0' "$argument"; 238 | else 239 | stop_parsing=y 240 | fi 241 | 242 | shift 243 | ;; 244 | 245 | *) 246 | printf '@ %s\0' "$argument"; shift;; 247 | esac 248 | done 249 | } 250 | 251 | : cmdline__usage 252 | 253 | : cmdline__help 254 | function cmdline__help { 255 | typeset option_description name long short required arguments help 256 | typeset key value parameter 257 | typeset -a parameters 258 | 259 | for option_description do 260 | [[ $option_description = '--' ]] && break 261 | 262 | IFS=: read -ra parameters <<< "$option_description" 263 | 264 | name= long= short= required= arguments=0 help= 265 | for parameter in "${parameters[@]}"; do 266 | IFS== read -r key value <<< "$parameter" 267 | 268 | case $key in 269 | name) name=$value;; 270 | long) long=$value;; 271 | short) short=$value;; 272 | required) required=$value;; 273 | arguments) arguments=$value;; 274 | help) help=$value;; 275 | esac 276 | 277 | name=${name:-"$long"} 278 | name=${name:-"$short"} 279 | 280 | [[ $name ]] || return 1 281 | done 282 | 283 | if [[ $short && $long ]]; then 284 | printf '\t-%s, --%s\n\t\t%s\n' "$short" "$long" "$help" 285 | elif [[ $short ]]; then 286 | printf '\t-%s\n\t\t%s\n' "$short" "$help" 287 | elif [[ $long ]]; then 288 | printf '\t--%s\n\t\t%s\n' "$long" "$help" 289 | else 290 | : 291 | fi 292 | done 293 | } 294 | -------------------------------------------------------------------------------- /src/gcat.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load common 4 | : load cmdline 5 | 6 | 7 | function escape_line { 8 | typeset line=$1 9 | typeset i character escaped_line 10 | typeset -A replacements=( 11 | [$'\001']='^A' [$'\002']='^B' [$'\003']='^C' 12 | [$'\004']='^D' [$'\005']='^E' [$'\006']='^F' [$'\a']='^G' 13 | [$'\b']='^H' [$'\t']='^I' [$'\v']='^K' [$'\f']='^L' 14 | [$'\r']='^M' [$'\016']='^N' [$'\017']='^O' [$'\020']='^P' 15 | [$'\021']='^Q' [$'\022']='^R' [$'\023']='^S' [$'\024']='^T' 16 | [$'\025']='^U' [$'\026']='^V' [$'\027']='^W' [$'\030']='^X' 17 | [$'\031']='^Y' [$'\032']='^Z' [$'\E']='^[' [$'\034']='^\' 18 | [$'\035']='^]' [$'\036']='^^' [$'\037']='^_' [$'\177']='^?' 19 | [$'\200']='M-^@' [$'\201']='M-^A' [$'\202']='M-^B' [$'\203']='M-^C' 20 | [$'\204']='M-^D' [$'\205']='M-^E' [$'\206']='M-^F' [$'\207']='M-^G' 21 | [$'\210']='M-^H' [$'\211']='M-^I' [$'\212']='M-^J' [$'\213']='M-^K' 22 | [$'\214']='M-^L' [$'\215']='M-^M' [$'\216']='M-^N' [$'\217']='M-^O' 23 | [$'\220']='M-^P' [$'\221']='M-^Q' [$'\222']='M-^R' [$'\223']='M-^S' 24 | [$'\224']='M-^T' [$'\225']='M-^U' [$'\226']='M-^V' [$'\227']='M-^W' 25 | [$'\230']='M-^X' [$'\231']='M-^Y' [$'\232']='M-^Z' [$'\233']='M-^[' 26 | [$'\234']='M-^\' [$'\235']='M-^]' [$'\236']='M-^^' [$'\237']='M-^_' 27 | [$'\240']='M- ' [$'\241']='M-!' [$'\242']='M-"' [$'\243']='M-#' 28 | [$'\244']='M-$' [$'\245']='M-%' [$'\246']='M-&' [$'\247']="M-'" 29 | [$'\250']='M-(' [$'\251']='M-)' [$'\252']='M-*' [$'\253']='M-+' 30 | [$'\254']='M-,' [$'\255']='M--' [$'\256']='M-.' [$'\257']='M-/' 31 | [$'\260']='M-0' [$'\261']='M-1' [$'\262']='M-2' [$'\263']='M-3' 32 | [$'\264']='M-4' [$'\265']='M-5' [$'\266']='M-6' [$'\267']='M-7' 33 | [$'\270']='M-8' [$'\271']='M-9' [$'\272']='M-:' [$'\273']='M-;' 34 | [$'\274']='M-<' [$'\275']='M-=' [$'\276']='M->' [$'\277']='M-?' 35 | [$'\300']='M-@' [$'\301']='M-A' [$'\302']='M-B' [$'\303']='M-C' 36 | [$'\304']='M-D' [$'\305']='M-E' [$'\306']='M-F' [$'\307']='M-G' 37 | [$'\310']='M-H' [$'\311']='M-I' [$'\312']='M-J' [$'\313']='M-K' 38 | [$'\314']='M-L' [$'\315']='M-M' [$'\316']='M-N' [$'\317']='M-O' 39 | [$'\320']='M-P' [$'\321']='M-Q' [$'\322']='M-R' [$'\323']='M-S' 40 | [$'\324']='M-T' [$'\325']='M-U' [$'\326']='M-V' [$'\327']='M-W' 41 | [$'\330']='M-X' [$'\331']='M-Y' [$'\332']='M-Z' [$'\333']='M-[' 42 | [$'\334']='M-\' [$'\335']='M-]' [$'\336']='M-^' [$'\337']='M-_' 43 | [$'\340']='M-`' [$'\341']='M-a' [$'\342']='M-b' [$'\343']='M-c' 44 | [$'\344']='M-d' [$'\345']='M-e' [$'\346']='M-f' [$'\347']='M-g' 45 | [$'\350']='M-h' [$'\351']='M-i' [$'\352']='M-j' [$'\353']='M-k' 46 | [$'\354']='M-l' [$'\355']='M-m' [$'\356']='M-n' [$'\357']='M-o' 47 | [$'\360']='M-p' [$'\361']='M-q' [$'\362']='M-r' [$'\363']='M-s' 48 | [$'\364']='M-t' [$'\365']='M-u' [$'\366']='M-v' [$'\367']='M-w' 49 | [$'\370']='M-x' [$'\371']='M-y' [$'\372']='M-z' [$'\373']='M-{' 50 | [$'\374']='M-|' [$'\375']='M-}' [$'\376']='M-~' [$'\377']='M-^?' 51 | ) 52 | 53 | for ((i = 0; i < ${#line}; i++)); do 54 | character=${line:i:1} 55 | if [[ ! $character ]]; then 56 | escaped_line+='^@' 57 | else 58 | escaped_line+=${replacements["$character"]-"$character"} 59 | fi 60 | done 61 | 62 | printf %s "$escaped_line" 63 | } 64 | 65 | 66 | function emit_line { 67 | typeset line_number=$1 line=$2 68 | typeset LC_CTYPE=C 69 | 70 | : trailing_newline 71 | : opt_number_nonblank opt_show_ends opt_number 72 | : opt_squeeze_blank opt_show_tabs opt_show_nonprinting 73 | 74 | if [[ $opt_show_tabs ]]; then 75 | line=${line//$'\t'/^I} 76 | fi 77 | 78 | if [[ $opt_show_nonprinting ]]; then 79 | IFS= read -r line < <(escape_line "$line") 80 | fi 81 | 82 | 83 | if [[ $opt_number ]]; then 84 | printf '% 6d\t%s' "$line_number" "$line" 85 | elif [[ $opt_number_nonblank && $line ]]; then 86 | printf '% 6d\t%s' "$line_number" "$line" 87 | elif [[ $opt_number_nonblank ]]; then 88 | : 89 | else 90 | printf '%s' "$line" 91 | fi 92 | 93 | if [[ $opt_show_ends ]]; then 94 | printf '$' 95 | fi 96 | 97 | if [[ $trailing_newline || $opt_show_ends ]]; then 98 | printf '\n' 99 | fi 100 | } 101 | 102 | 103 | function main { 104 | : <= debug_level)); then 15 | log__with_type DEBUG "$@"; 16 | fi 17 | } 18 | log__error () 19 | { 20 | log__with_type ERROR "$@" 21 | } 22 | log__info () 23 | { 24 | log__with_type INFO "$@" 25 | } 26 | log__warning () 27 | { 28 | log__with_type WARNING "$@" 29 | } 30 | log__with_type () 31 | { 32 | typeset type=$1 argument; 33 | shift; 34 | for argument in "$@"; 35 | do 36 | log__basic "$type: $argument" 1>&2; 37 | done 38 | } 39 | 40 | common__die () 41 | { 42 | typeset exit_status=$2; 43 | log__error "$1"; 44 | exit "${exit_status:-1}" 45 | } 46 | 47 | bytes__chr () 48 | { 49 | typeset dec=$1; 50 | ((0 <= dec && dec < 256)) || return 1; 51 | printf \\$((dec/64*100+dec%64/8*10+dec%8)) 52 | } 53 | bytes__hex () 54 | { 55 | LC_CTYPE=C printf '%x' "'$1" 56 | } 57 | bytes__ord () 58 | { 59 | LC_CTYPE=C printf '%d' "'$1" 60 | } 61 | bytes__unhex () 62 | { 63 | [[ $1 = ?([[:xdigit:]])[[:xdigit:]] ]] || return 1; 64 | printf '\x'"$1" 65 | } 66 | bytes__write_uint32_be () 67 | { 68 | typeset number=$1; 69 | typeset hex; 70 | ((number >> 32)) && return 1; 71 | printf -v hex '\\x%x' "$(( (number >> 24) & 0xff))" "$(( (number >> 16) & 0xff))" "$(( (number >> 8) & 0xff))" "$(( number & 0xff))"; 72 | printf "$hex" 73 | } 74 | bytes__write_uint32_le () 75 | { 76 | typeset number=$1; 77 | typeset hex; 78 | ((number >> 32)) && return 1; 79 | printf -v hex '\\x%x' "$(( number & 0xff))" "$(( (number >> 8) & 0xff))" "$(( (number >> 16) & 0xff))" "$(( (number >> 24) & 0xff))"; 80 | printf "$hex" 81 | } 82 | 83 | network__socket_get_device () 84 | { 85 | typeset type=$1 netloc=$2 port=$3; 86 | [[ $type = @(tcp|udp) ]] || return 1; 87 | [[ $netloc = @(*/*|____) ]] && return 1; 88 | [[ $port = +([[:digit:]]) ]] || return 1; 89 | printf %s "/dev/$type/$netloc/$port" 90 | } 91 | network__tcp-send () 92 | { 93 | typeset netloc=$1 port=$2; 94 | typeset line socket fd; 95 | socket=$(network__socket_get_device tcp "$netloc" "$port") || return 1; 96 | ( exec 3<> "$socket"; 97 | while IFS= read -r line; do 98 | printf '%s\n' "$line"; 99 | done 1>&3; 100 | printf %s "$line" 1>&3; 101 | while IFS= read -r line; do 102 | printf '%s\n' "$line"; 103 | done 0<&3; 104 | printf %s "$line"; 105 | exec 3>&- ) 106 | } 107 | 108 | http__form_url_decode () 109 | { 110 | typeset data=${1//+/%20}; 111 | http__percent_decode "$data" 112 | } 113 | http__form_url_encode () 114 | { 115 | : application/x-www-form-urlencoded; 116 | typeset data=$(http__percent_encode "$1"); 117 | printf %s "${data//%20/+}" 118 | } 119 | http__get () 120 | { 121 | typeset url=$1; 122 | typeset scheme username password netloc port path query_string; 123 | typeset fragment resource IFS=:; 124 | typeset -a request=(); 125 | IFS=: read -r scheme _ _ netloc port path query_string _ < <(http__url_parse "$url"); 126 | resource=$path; 127 | [[ -n $query_string ]] && resource+=?$query_string; 128 | request+=("GET $resource HTTP/1.0"); 129 | request+=("Host: $netloc"); 130 | request+=(''); 131 | printf '%s\r\n' "${request[@]}" | network__tcp_send "$netloc" "$port" 132 | } 133 | http__percent_decode () 134 | { 135 | typeset data=${1//\\/\\\\}; 136 | printf "${data//%/\\x}" 137 | } 138 | http__percent_encode () 139 | { 140 | typeset character position data=$1; 141 | typeset -x LC_TYPE=C; 142 | for ((position=0; position<${#data}; position++)) 143 | do 144 | character=${data:position:1}; 145 | if [[ $character = [[:alnum:].~-] ]]; then 146 | printf %s "$character"; 147 | else 148 | printf %%%02X "$(bytes__ord "$character")"; 149 | fi; 150 | done 151 | } 152 | http__post () 153 | { 154 | typeset url=$1 form=$2; 155 | typeset scheme username password netloc port path query_string; 156 | typeset fragment resource IFS=:; 157 | typeset -a request=(); 158 | read -r scheme _ _ netloc port path query_string _ < <(http__url_parse "$url"); 159 | resource=$path; 160 | [[ -n $query_string ]] && resource+=?$query_string; 161 | request+=("POST $resource HTTP/1.0"); 162 | request+=("Host: $netloc"); 163 | request+=("Content-Type: application/x-www-form-urlencoded"); 164 | request+=("Content-Length: $((${#form}+2))"); 165 | request+=(''); 166 | request+=("$form"); 167 | printf '%s\r\n' "${request[@]}" | network__tcp_send "$netloc" "$port" 168 | } 169 | http__query_string_encode () 170 | { 171 | : </dev/null && printf y); 211 | typeset -a components; 212 | shopt -s extglob; 213 | : Parse the scheme, currently it is generic; 214 | if [[ $url = +([!:])?(s)://* ]]; then 215 | scheme=${url%%://*} url=${url#+([!:])://}; 216 | else 217 | if [[ $url = @(//[!/]*|//) ]]; then 218 | scheme=$default_scheme url=${url#//}; 219 | fi; 220 | fi; 221 | : Parse username:password combination in URL; 222 | if [[ $url = *([!@])@* ]]; then 223 | IFS=:@ read -r username password url <<< "$url"; 224 | fi; 225 | : Parse network location '(ip address or domain name)'; 226 | if [[ $url = +([!:]):+([[:digit:]])?([/?#&]*) ]]; then 227 | netloc=${url%%:*} port=${url#"$netloc"} port=${port##*:}; 228 | url=${url#"$netloc:$port"}; 229 | else 230 | if [[ $url = +([!/?#&])?([/?#&]*) ]]; then 231 | netloc=${url%%[/?#&]*}; 232 | url=${url#"$netloc"}; 233 | : Default ports; 234 | case $scheme in 235 | http) 236 | port=80 237 | ;; 238 | https) 239 | port=443 240 | ;; 241 | esac; 242 | fi; 243 | fi; 244 | : Parse path; 245 | path=/; 246 | if [[ $url = +([!?#&])?([?#&]*) ]]; then 247 | path=${url%%[?#&]*}; 248 | url=${url#"$path"}; 249 | fi; 250 | : Parse query string; 251 | if [[ $url = +([!#])?([#]*) ]]; then 252 | query_string=${url%%[#]*} query_string=${query_string#'?'}; 253 | url=${url#"?$query_string"}; 254 | fi; 255 | : Parse fragment; 256 | if [[ $url = '#'* ]]; then 257 | fragment=${url#'#'}; 258 | fi; 259 | : Return extglob to the state we found it; 260 | [[ -n $extglob ]] || shopt -u extglob; 261 | : Join the components; 262 | components=("$scheme" "$username" "$password" "$netloc" "$port" "$path" "$query_string" "$fragment"); 263 | ( IFS=':'; 264 | printf %s "${components[*]}" ) 265 | } 266 | 267 | main () 268 | { 269 | typeset content=$(http__form_url_encode "$(cat "${1:-/dev/stdin}")"); 270 | typeset query_string=$(http__query_string_encode content "$content"); 271 | typeset key value; 272 | { 273 | read; 274 | while IFS=' ' read -r key value _; do 275 | if [[ $key = Location: ]]; then 276 | printf '%s\n' "$value"; 277 | return 0; 278 | fi; 279 | done 280 | } < <(http__post 'http://dpaste.com/api/v1/' "$query_string"); 281 | return 1 282 | } 283 | main "$@" 284 | -------------------------------------------------------------------------------- /bin/echo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cmdline__arguments () 3 | { 4 | : < 0)); do 69 | argument=$1; 70 | if [[ -n $stop_parsing ]]; then 71 | printf '@ %s\0' "$argument"; 72 | shift; 73 | continue; 74 | fi; 75 | case $argument in 76 | -[!-]) 77 | { 78 | shift=$(cmdline__p__arguments__short "$@") || { 79 | return_code=$?; 80 | [[ -n $errors_not_fatal ]] || return "$return_code" 81 | } 82 | } 3>&1; 83 | shift "$((shift + 1))" 84 | ;; 85 | -[!-]*) 86 | { 87 | shift=$(cmdline__p__arguments__short_composed "$@") || { 88 | return_code=$?; 89 | [[ -n $errors_not_fatal ]] || return "$return_code" 90 | } 91 | } 3>&1; 92 | shift "$((shift + 1))" 93 | ;; 94 | --[!-]*) 95 | if [[ $argument = --+([!=])=* ]]; then 96 | IFS== read -rd '' key value <<< "$argument"; 97 | shift; 98 | set -- "$key" "${value% 99 | }" "$@"; 100 | fi; 101 | { 102 | shift=$(cmdline__p__arguments__long "$@") || { 103 | return_code=$?; 104 | [[ -n $errors_not_fatal ]] || return "$return_code" 105 | } 106 | } 3>&1; 107 | shift "$((shift + 1))" 108 | ;; 109 | --) 110 | if [[ -n $dashdash_not_special ]]; then 111 | printf '@ %s\0' "$argument"; 112 | else 113 | stop_parsing=y; 114 | fi; 115 | shift 116 | ;; 117 | *) 118 | printf '@ %s\0' "$argument"; 119 | shift 120 | ;; 121 | esac; 122 | done 123 | } 124 | cmdline__help () 125 | { 126 | typeset option_description name long short required arguments help; 127 | typeset key value parameter; 128 | typeset -a parameters; 129 | for option_description in "$@"; 130 | do 131 | [[ $option_description = '--' ]] && break; 132 | IFS=: read -ra parameters <<< "$option_description"; 133 | name= long= short= required= arguments=0 help=; 134 | for parameter in "${parameters[@]}"; 135 | do 136 | IFS== read -r key value <<< "$parameter"; 137 | case $key in 138 | name) 139 | name=$value 140 | ;; 141 | long) 142 | long=$value 143 | ;; 144 | short) 145 | short=$value 146 | ;; 147 | required) 148 | required=$value 149 | ;; 150 | arguments) 151 | arguments=$value 152 | ;; 153 | help) 154 | help=$value 155 | ;; 156 | esac; 157 | name=${name:-"$long"}; 158 | name=${name:-"$short"}; 159 | [[ -n $name ]] || return 1; 160 | done; 161 | if [[ -n $short && -n $long ]]; then 162 | printf '\t-%s, --%s\n\t\t%s\n' "$short" "$long" "$help"; 163 | else 164 | if [[ -n $short ]]; then 165 | printf '\t-%s\n\t\t%s\n' "$short" "$help"; 166 | else 167 | if [[ -n $long ]]; then 168 | printf '\t--%s\n\t\t%s\n' "$long" "$help"; 169 | else 170 | :; 171 | fi; 172 | fi; 173 | fi; 174 | done 175 | } 176 | cmdline__p__arguments__long () 177 | { 178 | typeset argument=$1; 179 | typeset name i arguments; 180 | [[ -n $argument ]] || return 1; 181 | shift; 182 | { 183 | typeset -p long_map || return 2; 184 | typeset -p arguments_map || return 2 185 | } > /dev/null 2>&1; 186 | name=${long_map["${argument#--}"]}; 187 | [[ -n $name ]] || { 188 | printf -- '- %s\0' "$argument" 1>&3; 189 | return 3 190 | }; 191 | arguments=${arguments_map["$name"]}; 192 | if ((arguments == 0)); then 193 | printf '%s\0' "$name" 1>&3; 194 | return 0; 195 | else 196 | if ((arguments > $#)); then 197 | return 4; 198 | fi; 199 | fi; 200 | for ((i = 1; i <= arguments; i++)) 201 | do 202 | printf '%s %s\0' "$name" "${@:i:1}" 1>&3; 203 | shift; 204 | done; 205 | printf %s "$arguments" 206 | } 207 | cmdline__p__arguments__short () 208 | { 209 | typeset argument=$1; 210 | typeset name i arguments; 211 | [[ -n $argument ]] || return 1; 212 | shift; 213 | { 214 | typeset -p short_map || return 2; 215 | typeset -p arguments_map || return 2 216 | } > /dev/null 2>&1; 217 | name=${short_map["${argument#-}"]}; 218 | [[ -n $name ]] || { 219 | printf -- '- %s\0' "$argument" 1>&3; 220 | return 3 221 | }; 222 | arguments=${arguments_map["$name"]}; 223 | if ((arguments == 0)); then 224 | printf '%s\0' "$name" 1>&3; 225 | return 0; 226 | else 227 | if ((arguments > $#)); then 228 | return 4; 229 | fi; 230 | fi; 231 | for ((i = 1; i <= arguments; i++)) 232 | do 233 | printf '%s %s\0' "$name" "${@:i:1}" 1>&3; 234 | shift; 235 | done; 236 | printf %s "$arguments" 237 | } 238 | cmdline__p__arguments__short_composed () 239 | { 240 | typeset argument=$1; 241 | typeset option remainder name arguments; 242 | [[ -n $argument ]] || return 1; 243 | shift; 244 | { 245 | typeset -p short_map || return 2; 246 | typeset -p arguments_map || return 2 247 | } > /dev/null 2>&1; 248 | option=${argument#-} option=${option::1}; 249 | remainder=${argument#-?}; 250 | name=${short_map["$option"]}; 251 | [[ -n $name ]] || { 252 | printf -- '- %s\0' "$argument" 1>&3; 253 | return 3 254 | }; 255 | arguments=${arguments_map["$name"]}; 256 | if ((arguments == 0)); then 257 | printf '%s\0' "$name" 1>&3; 258 | if [[ -n $remainder ]]; then 259 | cmdline__p__arguments__short_composed "-$remainder" "$@" || return; 260 | fi; 261 | else 262 | [[ -n $remainder ]] && set -- "$remainder" "$@"; 263 | cmdline__p__arguments__short "-$option" "$@" || return; 264 | fi 265 | } 266 | 267 | main () 268 | { 269 | : < 0)); do 69 | argument=$1; 70 | if [[ -n $stop_parsing ]]; then 71 | printf '@ %s\0' "$argument"; 72 | shift; 73 | continue; 74 | fi; 75 | case $argument in 76 | -[!-]) 77 | { 78 | shift=$(cmdline__p__arguments__short "$@") || { 79 | return_code=$?; 80 | [[ -n $errors_not_fatal ]] || return "$return_code" 81 | } 82 | } 3>&1; 83 | shift "$((shift + 1))" 84 | ;; 85 | -[!-]*) 86 | { 87 | shift=$(cmdline__p__arguments__short_composed "$@") || { 88 | return_code=$?; 89 | [[ -n $errors_not_fatal ]] || return "$return_code" 90 | } 91 | } 3>&1; 92 | shift "$((shift + 1))" 93 | ;; 94 | --[!-]*) 95 | if [[ $argument = --+([!=])=* ]]; then 96 | IFS== read -rd '' key value <<< "$argument"; 97 | shift; 98 | set -- "$key" "${value% 99 | }" "$@"; 100 | fi; 101 | { 102 | shift=$(cmdline__p__arguments__long "$@") || { 103 | return_code=$?; 104 | [[ -n $errors_not_fatal ]] || return "$return_code" 105 | } 106 | } 3>&1; 107 | shift "$((shift + 1))" 108 | ;; 109 | --) 110 | if [[ -n $dashdash_not_special ]]; then 111 | printf '@ %s\0' "$argument"; 112 | else 113 | stop_parsing=y; 114 | fi; 115 | shift 116 | ;; 117 | *) 118 | printf '@ %s\0' "$argument"; 119 | shift 120 | ;; 121 | esac; 122 | done 123 | } 124 | cmdline__help () 125 | { 126 | typeset option_description name long short required arguments help; 127 | typeset key value parameter; 128 | typeset -a parameters; 129 | for option_description in "$@"; 130 | do 131 | [[ $option_description = '--' ]] && break; 132 | IFS=: read -ra parameters <<< "$option_description"; 133 | name= long= short= required= arguments=0 help=; 134 | for parameter in "${parameters[@]}"; 135 | do 136 | IFS== read -r key value <<< "$parameter"; 137 | case $key in 138 | name) 139 | name=$value 140 | ;; 141 | long) 142 | long=$value 143 | ;; 144 | short) 145 | short=$value 146 | ;; 147 | required) 148 | required=$value 149 | ;; 150 | arguments) 151 | arguments=$value 152 | ;; 153 | help) 154 | help=$value 155 | ;; 156 | esac; 157 | name=${name:-"$long"}; 158 | name=${name:-"$short"}; 159 | [[ -n $name ]] || return 1; 160 | done; 161 | if [[ -n $short && -n $long ]]; then 162 | printf '\t-%s, --%s\n\t\t%s\n' "$short" "$long" "$help"; 163 | else 164 | if [[ -n $short ]]; then 165 | printf '\t-%s\n\t\t%s\n' "$short" "$help"; 166 | else 167 | if [[ -n $long ]]; then 168 | printf '\t--%s\n\t\t%s\n' "$long" "$help"; 169 | else 170 | :; 171 | fi; 172 | fi; 173 | fi; 174 | done 175 | } 176 | cmdline__p__arguments__long () 177 | { 178 | typeset argument=$1; 179 | typeset name i arguments; 180 | [[ -n $argument ]] || return 1; 181 | shift; 182 | { 183 | typeset -p long_map || return 2; 184 | typeset -p arguments_map || return 2 185 | } > /dev/null 2>&1; 186 | name=${long_map["${argument#--}"]}; 187 | [[ -n $name ]] || { 188 | printf -- '- %s\0' "$argument" 1>&3; 189 | return 3 190 | }; 191 | arguments=${arguments_map["$name"]}; 192 | if ((arguments == 0)); then 193 | printf '%s\0' "$name" 1>&3; 194 | return 0; 195 | else 196 | if ((arguments > $#)); then 197 | return 4; 198 | fi; 199 | fi; 200 | for ((i = 1; i <= arguments; i++)) 201 | do 202 | printf '%s %s\0' "$name" "${@:i:1}" 1>&3; 203 | shift; 204 | done; 205 | printf %s "$arguments" 206 | } 207 | cmdline__p__arguments__short () 208 | { 209 | typeset argument=$1; 210 | typeset name i arguments; 211 | [[ -n $argument ]] || return 1; 212 | shift; 213 | { 214 | typeset -p short_map || return 2; 215 | typeset -p arguments_map || return 2 216 | } > /dev/null 2>&1; 217 | name=${short_map["${argument#-}"]}; 218 | [[ -n $name ]] || { 219 | printf -- '- %s\0' "$argument" 1>&3; 220 | return 3 221 | }; 222 | arguments=${arguments_map["$name"]}; 223 | if ((arguments == 0)); then 224 | printf '%s\0' "$name" 1>&3; 225 | return 0; 226 | else 227 | if ((arguments > $#)); then 228 | return 4; 229 | fi; 230 | fi; 231 | for ((i = 1; i <= arguments; i++)) 232 | do 233 | printf '%s %s\0' "$name" "${@:i:1}" 1>&3; 234 | shift; 235 | done; 236 | printf %s "$arguments" 237 | } 238 | cmdline__p__arguments__short_composed () 239 | { 240 | typeset argument=$1; 241 | typeset option remainder name arguments; 242 | [[ -n $argument ]] || return 1; 243 | shift; 244 | { 245 | typeset -p short_map || return 2; 246 | typeset -p arguments_map || return 2 247 | } > /dev/null 2>&1; 248 | option=${argument#-} option=${option::1}; 249 | remainder=${argument#-?}; 250 | name=${short_map["$option"]}; 251 | [[ -n $name ]] || { 252 | printf -- '- %s\0' "$argument" 1>&3; 253 | return 3 254 | }; 255 | arguments=${arguments_map["$name"]}; 256 | if ((arguments == 0)); then 257 | printf '%s\0' "$name" 1>&3; 258 | if [[ -n $remainder ]]; then 259 | cmdline__p__arguments__short_composed "-$remainder" "$@" || return; 260 | fi; 261 | else 262 | [[ -n $remainder ]] && set -- "$remainder" "$@"; 263 | cmdline__p__arguments__short "-$option" "$@" || return; 264 | fi 265 | } 266 | 267 | log__basic () 268 | { 269 | typeset argument; 270 | for argument in "$@"; 271 | do 272 | printf '%s: %s\n' "${BASH_SOURCE##*/}" "$argument"; 273 | done 274 | } 275 | log__debug () 276 | { 277 | typeset debug_level log_level; 278 | shift 2; 279 | if ((log_level >= debug_level)); then 280 | log__with_type DEBUG "$@"; 281 | fi 282 | } 283 | log__error () 284 | { 285 | log__with_type ERROR "$@" 286 | } 287 | log__info () 288 | { 289 | log__with_type INFO "$@" 290 | } 291 | log__warning () 292 | { 293 | log__with_type WARNING "$@" 294 | } 295 | log__with_type () 296 | { 297 | typeset type=$1 argument; 298 | shift; 299 | for argument in "$@"; 300 | do 301 | log__basic "$type: $argument" 1>&2; 302 | done 303 | } 304 | 305 | common__die () 306 | { 307 | typeset exit_status=$2; 308 | log__error "$1"; 309 | exit "${exit_status:-1}" 310 | } 311 | 312 | log__basic () 313 | { 314 | typeset argument; 315 | for argument in "$@"; 316 | do 317 | printf '%s: %s\n' "${BASH_SOURCE##*/}" "$argument"; 318 | done 319 | } 320 | log__debug () 321 | { 322 | typeset debug_level log_level; 323 | shift 2; 324 | if ((log_level >= debug_level)); then 325 | log__with_type DEBUG "$@"; 326 | fi 327 | } 328 | log__error () 329 | { 330 | log__with_type ERROR "$@" 331 | } 332 | log__info () 333 | { 334 | log__with_type INFO "$@" 335 | } 336 | log__warning () 337 | { 338 | log__with_type WARNING "$@" 339 | } 340 | log__with_type () 341 | { 342 | typeset type=$1 argument; 343 | shift; 344 | for argument in "$@"; 345 | do 346 | log__basic "$type: $argument" 1>&2; 347 | done 348 | } 349 | 350 | main () 351 | { 352 | typeset type_ value; 353 | typeset type length source; 354 | typeset -a options=('name=type:short=t:long=type:arguments=1' 'name=length:short=n:long=length:arguments=1' 'name=source:short=s:long=source:arguments=1' 'name=help:short=h:long=help'); 355 | type=xdigit length=8 source=/dev/urandom; 356 | while read -rd '' type_ value; do 357 | case $type_ in 358 | type) 359 | type=$value 360 | ;; 361 | length) 362 | length=$value 363 | ;; 364 | source) 365 | source=$value 366 | ;; 367 | help) 368 | cmdline__help "${options[@]}"; 369 | return 0 370 | ;; 371 | *) 372 | common__die "unexpected ''$value''" 373 | ;; 374 | esac; 375 | done < <(cmdline__arguments "${options[@]}" -- "$@"); 376 | case $type in 377 | xdigit | alnum | alpha | digit) 378 | printf '%s\n' "$(tr -cd "[:$type:]" < "$source" | head -c "$length")" 379 | ;; 380 | *) 381 | common__die "wrong type ''$type''" 382 | ;; 383 | esac 384 | } 385 | main "$@" 386 | -------------------------------------------------------------------------------- /tests/bytes.bashly/001-test-ord: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load bytes 4 | 5 | function test { 6 | typeset newline 7 | 8 | [[ $(bytes__ord $'\x01') = 1 ]] || return 1 9 | [[ $(bytes__ord $'\x02') = 2 ]] || return 1 10 | [[ $(bytes__ord $'\x03') = 3 ]] || return 1 11 | [[ $(bytes__ord $'\x04') = 4 ]] || return 1 12 | [[ $(bytes__ord $'\x05') = 5 ]] || return 1 13 | [[ $(bytes__ord $'\x06') = 6 ]] || return 1 14 | [[ $(bytes__ord $'\x07') = 7 ]] || return 1 15 | [[ $(bytes__ord $'\x08') = 8 ]] || return 1 16 | [[ $(bytes__ord $'\x09') = 9 ]] || return 1 17 | 18 | IFS= read -rd '' newline < <(bytes__ord $'\x0a') 19 | [[ $newline = 10 ]] || return 1 20 | 21 | [[ $(bytes__ord $'\x0b') = 11 ]] || return 1 22 | [[ $(bytes__ord $'\x0c') = 12 ]] || return 1 23 | [[ $(bytes__ord $'\x0d') = 13 ]] || return 1 24 | [[ $(bytes__ord $'\x0e') = 14 ]] || return 1 25 | [[ $(bytes__ord $'\x0f') = 15 ]] || return 1 26 | [[ $(bytes__ord $'\x10') = 16 ]] || return 1 27 | [[ $(bytes__ord $'\x11') = 17 ]] || return 1 28 | [[ $(bytes__ord $'\x12') = 18 ]] || return 1 29 | [[ $(bytes__ord $'\x13') = 19 ]] || return 1 30 | [[ $(bytes__ord $'\x14') = 20 ]] || return 1 31 | [[ $(bytes__ord $'\x15') = 21 ]] || return 1 32 | [[ $(bytes__ord $'\x16') = 22 ]] || return 1 33 | [[ $(bytes__ord $'\x17') = 23 ]] || return 1 34 | [[ $(bytes__ord $'\x18') = 24 ]] || return 1 35 | [[ $(bytes__ord $'\x19') = 25 ]] || return 1 36 | [[ $(bytes__ord $'\x1a') = 26 ]] || return 1 37 | [[ $(bytes__ord $'\x1b') = 27 ]] || return 1 38 | [[ $(bytes__ord $'\x1c') = 28 ]] || return 1 39 | [[ $(bytes__ord $'\x1d') = 29 ]] || return 1 40 | [[ $(bytes__ord $'\x1e') = 30 ]] || return 1 41 | [[ $(bytes__ord $'\x1f') = 31 ]] || return 1 42 | [[ $(bytes__ord $'\x20') = 32 ]] || return 1 43 | [[ $(bytes__ord $'\x21') = 33 ]] || return 1 44 | [[ $(bytes__ord $'\x22') = 34 ]] || return 1 45 | [[ $(bytes__ord $'\x23') = 35 ]] || return 1 46 | [[ $(bytes__ord $'\x24') = 36 ]] || return 1 47 | [[ $(bytes__ord $'\x25') = 37 ]] || return 1 48 | [[ $(bytes__ord $'\x26') = 38 ]] || return 1 49 | [[ $(bytes__ord $'\x27') = 39 ]] || return 1 50 | [[ $(bytes__ord $'\x28') = 40 ]] || return 1 51 | [[ $(bytes__ord $'\x29') = 41 ]] || return 1 52 | [[ $(bytes__ord $'\x2a') = 42 ]] || return 1 53 | [[ $(bytes__ord $'\x2b') = 43 ]] || return 1 54 | [[ $(bytes__ord $'\x2c') = 44 ]] || return 1 55 | [[ $(bytes__ord $'\x2d') = 45 ]] || return 1 56 | [[ $(bytes__ord $'\x2e') = 46 ]] || return 1 57 | [[ $(bytes__ord $'\x2f') = 47 ]] || return 1 58 | [[ $(bytes__ord $'\x30') = 48 ]] || return 1 59 | [[ $(bytes__ord $'\x31') = 49 ]] || return 1 60 | [[ $(bytes__ord $'\x32') = 50 ]] || return 1 61 | [[ $(bytes__ord $'\x33') = 51 ]] || return 1 62 | [[ $(bytes__ord $'\x34') = 52 ]] || return 1 63 | [[ $(bytes__ord $'\x35') = 53 ]] || return 1 64 | [[ $(bytes__ord $'\x36') = 54 ]] || return 1 65 | [[ $(bytes__ord $'\x37') = 55 ]] || return 1 66 | [[ $(bytes__ord $'\x38') = 56 ]] || return 1 67 | [[ $(bytes__ord $'\x39') = 57 ]] || return 1 68 | [[ $(bytes__ord $'\x3a') = 58 ]] || return 1 69 | [[ $(bytes__ord $'\x3b') = 59 ]] || return 1 70 | [[ $(bytes__ord $'\x3c') = 60 ]] || return 1 71 | [[ $(bytes__ord $'\x3d') = 61 ]] || return 1 72 | [[ $(bytes__ord $'\x3e') = 62 ]] || return 1 73 | [[ $(bytes__ord $'\x3f') = 63 ]] || return 1 74 | [[ $(bytes__ord $'\x40') = 64 ]] || return 1 75 | [[ $(bytes__ord $'\x41') = 65 ]] || return 1 76 | [[ $(bytes__ord $'\x42') = 66 ]] || return 1 77 | [[ $(bytes__ord $'\x43') = 67 ]] || return 1 78 | [[ $(bytes__ord $'\x44') = 68 ]] || return 1 79 | [[ $(bytes__ord $'\x45') = 69 ]] || return 1 80 | [[ $(bytes__ord $'\x46') = 70 ]] || return 1 81 | [[ $(bytes__ord $'\x47') = 71 ]] || return 1 82 | [[ $(bytes__ord $'\x48') = 72 ]] || return 1 83 | [[ $(bytes__ord $'\x49') = 73 ]] || return 1 84 | [[ $(bytes__ord $'\x4a') = 74 ]] || return 1 85 | [[ $(bytes__ord $'\x4b') = 75 ]] || return 1 86 | [[ $(bytes__ord $'\x4c') = 76 ]] || return 1 87 | [[ $(bytes__ord $'\x4d') = 77 ]] || return 1 88 | [[ $(bytes__ord $'\x4e') = 78 ]] || return 1 89 | [[ $(bytes__ord $'\x4f') = 79 ]] || return 1 90 | [[ $(bytes__ord $'\x50') = 80 ]] || return 1 91 | [[ $(bytes__ord $'\x51') = 81 ]] || return 1 92 | [[ $(bytes__ord $'\x52') = 82 ]] || return 1 93 | [[ $(bytes__ord $'\x53') = 83 ]] || return 1 94 | [[ $(bytes__ord $'\x54') = 84 ]] || return 1 95 | [[ $(bytes__ord $'\x55') = 85 ]] || return 1 96 | [[ $(bytes__ord $'\x56') = 86 ]] || return 1 97 | [[ $(bytes__ord $'\x57') = 87 ]] || return 1 98 | [[ $(bytes__ord $'\x58') = 88 ]] || return 1 99 | [[ $(bytes__ord $'\x59') = 89 ]] || return 1 100 | [[ $(bytes__ord $'\x5a') = 90 ]] || return 1 101 | [[ $(bytes__ord $'\x5b') = 91 ]] || return 1 102 | [[ $(bytes__ord $'\x5c') = 92 ]] || return 1 103 | [[ $(bytes__ord $'\x5d') = 93 ]] || return 1 104 | [[ $(bytes__ord $'\x5e') = 94 ]] || return 1 105 | [[ $(bytes__ord $'\x5f') = 95 ]] || return 1 106 | [[ $(bytes__ord $'\x60') = 96 ]] || return 1 107 | [[ $(bytes__ord $'\x61') = 97 ]] || return 1 108 | [[ $(bytes__ord $'\x62') = 98 ]] || return 1 109 | [[ $(bytes__ord $'\x63') = 99 ]] || return 1 110 | [[ $(bytes__ord $'\x64') = 100 ]] || return 1 111 | [[ $(bytes__ord $'\x65') = 101 ]] || return 1 112 | [[ $(bytes__ord $'\x66') = 102 ]] || return 1 113 | [[ $(bytes__ord $'\x67') = 103 ]] || return 1 114 | [[ $(bytes__ord $'\x68') = 104 ]] || return 1 115 | [[ $(bytes__ord $'\x69') = 105 ]] || return 1 116 | [[ $(bytes__ord $'\x6a') = 106 ]] || return 1 117 | [[ $(bytes__ord $'\x6b') = 107 ]] || return 1 118 | [[ $(bytes__ord $'\x6c') = 108 ]] || return 1 119 | [[ $(bytes__ord $'\x6d') = 109 ]] || return 1 120 | [[ $(bytes__ord $'\x6e') = 110 ]] || return 1 121 | [[ $(bytes__ord $'\x6f') = 111 ]] || return 1 122 | [[ $(bytes__ord $'\x70') = 112 ]] || return 1 123 | [[ $(bytes__ord $'\x71') = 113 ]] || return 1 124 | [[ $(bytes__ord $'\x72') = 114 ]] || return 1 125 | [[ $(bytes__ord $'\x73') = 115 ]] || return 1 126 | [[ $(bytes__ord $'\x74') = 116 ]] || return 1 127 | [[ $(bytes__ord $'\x75') = 117 ]] || return 1 128 | [[ $(bytes__ord $'\x76') = 118 ]] || return 1 129 | [[ $(bytes__ord $'\x77') = 119 ]] || return 1 130 | [[ $(bytes__ord $'\x78') = 120 ]] || return 1 131 | [[ $(bytes__ord $'\x79') = 121 ]] || return 1 132 | [[ $(bytes__ord $'\x7a') = 122 ]] || return 1 133 | [[ $(bytes__ord $'\x7b') = 123 ]] || return 1 134 | [[ $(bytes__ord $'\x7c') = 124 ]] || return 1 135 | [[ $(bytes__ord $'\x7d') = 125 ]] || return 1 136 | [[ $(bytes__ord $'\x7e') = 126 ]] || return 1 137 | [[ $(bytes__ord $'\x7f') = 127 ]] || return 1 138 | [[ $(bytes__ord $'\x80') = 128 ]] || return 1 139 | [[ $(bytes__ord $'\x81') = 129 ]] || return 1 140 | [[ $(bytes__ord $'\x82') = 130 ]] || return 1 141 | [[ $(bytes__ord $'\x83') = 131 ]] || return 1 142 | [[ $(bytes__ord $'\x84') = 132 ]] || return 1 143 | [[ $(bytes__ord $'\x85') = 133 ]] || return 1 144 | [[ $(bytes__ord $'\x86') = 134 ]] || return 1 145 | [[ $(bytes__ord $'\x87') = 135 ]] || return 1 146 | [[ $(bytes__ord $'\x88') = 136 ]] || return 1 147 | [[ $(bytes__ord $'\x89') = 137 ]] || return 1 148 | [[ $(bytes__ord $'\x8a') = 138 ]] || return 1 149 | [[ $(bytes__ord $'\x8b') = 139 ]] || return 1 150 | [[ $(bytes__ord $'\x8c') = 140 ]] || return 1 151 | [[ $(bytes__ord $'\x8d') = 141 ]] || return 1 152 | [[ $(bytes__ord $'\x8e') = 142 ]] || return 1 153 | [[ $(bytes__ord $'\x8f') = 143 ]] || return 1 154 | [[ $(bytes__ord $'\x90') = 144 ]] || return 1 155 | [[ $(bytes__ord $'\x91') = 145 ]] || return 1 156 | [[ $(bytes__ord $'\x92') = 146 ]] || return 1 157 | [[ $(bytes__ord $'\x93') = 147 ]] || return 1 158 | [[ $(bytes__ord $'\x94') = 148 ]] || return 1 159 | [[ $(bytes__ord $'\x95') = 149 ]] || return 1 160 | [[ $(bytes__ord $'\x96') = 150 ]] || return 1 161 | [[ $(bytes__ord $'\x97') = 151 ]] || return 1 162 | [[ $(bytes__ord $'\x98') = 152 ]] || return 1 163 | [[ $(bytes__ord $'\x99') = 153 ]] || return 1 164 | [[ $(bytes__ord $'\x9a') = 154 ]] || return 1 165 | [[ $(bytes__ord $'\x9b') = 155 ]] || return 1 166 | [[ $(bytes__ord $'\x9c') = 156 ]] || return 1 167 | [[ $(bytes__ord $'\x9d') = 157 ]] || return 1 168 | [[ $(bytes__ord $'\x9e') = 158 ]] || return 1 169 | [[ $(bytes__ord $'\x9f') = 159 ]] || return 1 170 | [[ $(bytes__ord $'\xa0') = 160 ]] || return 1 171 | [[ $(bytes__ord $'\xa1') = 161 ]] || return 1 172 | [[ $(bytes__ord $'\xa2') = 162 ]] || return 1 173 | [[ $(bytes__ord $'\xa3') = 163 ]] || return 1 174 | [[ $(bytes__ord $'\xa4') = 164 ]] || return 1 175 | [[ $(bytes__ord $'\xa5') = 165 ]] || return 1 176 | [[ $(bytes__ord $'\xa6') = 166 ]] || return 1 177 | [[ $(bytes__ord $'\xa7') = 167 ]] || return 1 178 | [[ $(bytes__ord $'\xa8') = 168 ]] || return 1 179 | [[ $(bytes__ord $'\xa9') = 169 ]] || return 1 180 | [[ $(bytes__ord $'\xaa') = 170 ]] || return 1 181 | [[ $(bytes__ord $'\xab') = 171 ]] || return 1 182 | [[ $(bytes__ord $'\xac') = 172 ]] || return 1 183 | [[ $(bytes__ord $'\xad') = 173 ]] || return 1 184 | [[ $(bytes__ord $'\xae') = 174 ]] || return 1 185 | [[ $(bytes__ord $'\xaf') = 175 ]] || return 1 186 | [[ $(bytes__ord $'\xb0') = 176 ]] || return 1 187 | [[ $(bytes__ord $'\xb1') = 177 ]] || return 1 188 | [[ $(bytes__ord $'\xb2') = 178 ]] || return 1 189 | [[ $(bytes__ord $'\xb3') = 179 ]] || return 1 190 | [[ $(bytes__ord $'\xb4') = 180 ]] || return 1 191 | [[ $(bytes__ord $'\xb5') = 181 ]] || return 1 192 | [[ $(bytes__ord $'\xb6') = 182 ]] || return 1 193 | [[ $(bytes__ord $'\xb7') = 183 ]] || return 1 194 | [[ $(bytes__ord $'\xb8') = 184 ]] || return 1 195 | [[ $(bytes__ord $'\xb9') = 185 ]] || return 1 196 | [[ $(bytes__ord $'\xba') = 186 ]] || return 1 197 | [[ $(bytes__ord $'\xbb') = 187 ]] || return 1 198 | [[ $(bytes__ord $'\xbc') = 188 ]] || return 1 199 | [[ $(bytes__ord $'\xbd') = 189 ]] || return 1 200 | [[ $(bytes__ord $'\xbe') = 190 ]] || return 1 201 | [[ $(bytes__ord $'\xbf') = 191 ]] || return 1 202 | [[ $(bytes__ord $'\xc0') = 192 ]] || return 1 203 | [[ $(bytes__ord $'\xc1') = 193 ]] || return 1 204 | [[ $(bytes__ord $'\xc2') = 194 ]] || return 1 205 | [[ $(bytes__ord $'\xc3') = 195 ]] || return 1 206 | [[ $(bytes__ord $'\xc4') = 196 ]] || return 1 207 | [[ $(bytes__ord $'\xc5') = 197 ]] || return 1 208 | [[ $(bytes__ord $'\xc6') = 198 ]] || return 1 209 | [[ $(bytes__ord $'\xc7') = 199 ]] || return 1 210 | [[ $(bytes__ord $'\xc8') = 200 ]] || return 1 211 | [[ $(bytes__ord $'\xc9') = 201 ]] || return 1 212 | [[ $(bytes__ord $'\xca') = 202 ]] || return 1 213 | [[ $(bytes__ord $'\xcb') = 203 ]] || return 1 214 | [[ $(bytes__ord $'\xcc') = 204 ]] || return 1 215 | [[ $(bytes__ord $'\xcd') = 205 ]] || return 1 216 | [[ $(bytes__ord $'\xce') = 206 ]] || return 1 217 | [[ $(bytes__ord $'\xcf') = 207 ]] || return 1 218 | [[ $(bytes__ord $'\xd0') = 208 ]] || return 1 219 | [[ $(bytes__ord $'\xd1') = 209 ]] || return 1 220 | [[ $(bytes__ord $'\xd2') = 210 ]] || return 1 221 | [[ $(bytes__ord $'\xd3') = 211 ]] || return 1 222 | [[ $(bytes__ord $'\xd4') = 212 ]] || return 1 223 | [[ $(bytes__ord $'\xd5') = 213 ]] || return 1 224 | [[ $(bytes__ord $'\xd6') = 214 ]] || return 1 225 | [[ $(bytes__ord $'\xd7') = 215 ]] || return 1 226 | [[ $(bytes__ord $'\xd8') = 216 ]] || return 1 227 | [[ $(bytes__ord $'\xd9') = 217 ]] || return 1 228 | [[ $(bytes__ord $'\xda') = 218 ]] || return 1 229 | [[ $(bytes__ord $'\xdb') = 219 ]] || return 1 230 | [[ $(bytes__ord $'\xdc') = 220 ]] || return 1 231 | [[ $(bytes__ord $'\xdd') = 221 ]] || return 1 232 | [[ $(bytes__ord $'\xde') = 222 ]] || return 1 233 | [[ $(bytes__ord $'\xdf') = 223 ]] || return 1 234 | [[ $(bytes__ord $'\xe0') = 224 ]] || return 1 235 | [[ $(bytes__ord $'\xe1') = 225 ]] || return 1 236 | [[ $(bytes__ord $'\xe2') = 226 ]] || return 1 237 | [[ $(bytes__ord $'\xe3') = 227 ]] || return 1 238 | [[ $(bytes__ord $'\xe4') = 228 ]] || return 1 239 | [[ $(bytes__ord $'\xe5') = 229 ]] || return 1 240 | [[ $(bytes__ord $'\xe6') = 230 ]] || return 1 241 | [[ $(bytes__ord $'\xe7') = 231 ]] || return 1 242 | [[ $(bytes__ord $'\xe8') = 232 ]] || return 1 243 | [[ $(bytes__ord $'\xe9') = 233 ]] || return 1 244 | [[ $(bytes__ord $'\xea') = 234 ]] || return 1 245 | [[ $(bytes__ord $'\xeb') = 235 ]] || return 1 246 | [[ $(bytes__ord $'\xec') = 236 ]] || return 1 247 | [[ $(bytes__ord $'\xed') = 237 ]] || return 1 248 | [[ $(bytes__ord $'\xee') = 238 ]] || return 1 249 | [[ $(bytes__ord $'\xef') = 239 ]] || return 1 250 | [[ $(bytes__ord $'\xf0') = 240 ]] || return 1 251 | [[ $(bytes__ord $'\xf1') = 241 ]] || return 1 252 | [[ $(bytes__ord $'\xf2') = 242 ]] || return 1 253 | [[ $(bytes__ord $'\xf3') = 243 ]] || return 1 254 | [[ $(bytes__ord $'\xf4') = 244 ]] || return 1 255 | [[ $(bytes__ord $'\xf5') = 245 ]] || return 1 256 | [[ $(bytes__ord $'\xf6') = 246 ]] || return 1 257 | [[ $(bytes__ord $'\xf7') = 247 ]] || return 1 258 | [[ $(bytes__ord $'\xf8') = 248 ]] || return 1 259 | [[ $(bytes__ord $'\xf9') = 249 ]] || return 1 260 | [[ $(bytes__ord $'\xfa') = 250 ]] || return 1 261 | [[ $(bytes__ord $'\xfb') = 251 ]] || return 1 262 | [[ $(bytes__ord $'\xfc') = 252 ]] || return 1 263 | [[ $(bytes__ord $'\xfd') = 253 ]] || return 1 264 | [[ $(bytes__ord $'\xfe') = 254 ]] || return 1 265 | [[ $(bytes__ord $'\xff') = 255 ]] || return 1 266 | 267 | return 0 268 | } 269 | 270 | test 271 | 272 | # :r ! awk 'BEGIN{for(i=1;i<256;i++){printf " [[ $(bytes__ord $'\''\\x\%02x'\'') = \%03s ]] || return 1\n", i, i}}' 273 | -------------------------------------------------------------------------------- /tests/bytes.bashly/002-test-chr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load bytes 4 | 5 | function test { 6 | typeset newline 7 | 8 | [[ $(bytes__chr 1) = $'\x01' ]] || return 1 9 | [[ $(bytes__chr 2) = $'\x02' ]] || return 1 10 | [[ $(bytes__chr 3) = $'\x03' ]] || return 1 11 | [[ $(bytes__chr 4) = $'\x04' ]] || return 1 12 | [[ $(bytes__chr 5) = $'\x05' ]] || return 1 13 | [[ $(bytes__chr 6) = $'\x06' ]] || return 1 14 | [[ $(bytes__chr 7) = $'\x07' ]] || return 1 15 | [[ $(bytes__chr 8) = $'\x08' ]] || return 1 16 | [[ $(bytes__chr 9) = $'\x09' ]] || return 1 17 | 18 | IFS= read -rd '' newline < <(bytes__chr 10) 19 | [[ $newline = $'\x0a' ]] || return 1 20 | 21 | [[ $(bytes__chr 11) = $'\x0b' ]] || return 1 22 | [[ $(bytes__chr 12) = $'\x0c' ]] || return 1 23 | [[ $(bytes__chr 13) = $'\x0d' ]] || return 1 24 | [[ $(bytes__chr 14) = $'\x0e' ]] || return 1 25 | [[ $(bytes__chr 15) = $'\x0f' ]] || return 1 26 | [[ $(bytes__chr 16) = $'\x10' ]] || return 1 27 | [[ $(bytes__chr 17) = $'\x11' ]] || return 1 28 | [[ $(bytes__chr 18) = $'\x12' ]] || return 1 29 | [[ $(bytes__chr 19) = $'\x13' ]] || return 1 30 | [[ $(bytes__chr 20) = $'\x14' ]] || return 1 31 | [[ $(bytes__chr 21) = $'\x15' ]] || return 1 32 | [[ $(bytes__chr 22) = $'\x16' ]] || return 1 33 | [[ $(bytes__chr 23) = $'\x17' ]] || return 1 34 | [[ $(bytes__chr 24) = $'\x18' ]] || return 1 35 | [[ $(bytes__chr 25) = $'\x19' ]] || return 1 36 | [[ $(bytes__chr 26) = $'\x1a' ]] || return 1 37 | [[ $(bytes__chr 27) = $'\x1b' ]] || return 1 38 | [[ $(bytes__chr 28) = $'\x1c' ]] || return 1 39 | [[ $(bytes__chr 29) = $'\x1d' ]] || return 1 40 | [[ $(bytes__chr 30) = $'\x1e' ]] || return 1 41 | [[ $(bytes__chr 31) = $'\x1f' ]] || return 1 42 | [[ $(bytes__chr 32) = $'\x20' ]] || return 1 43 | [[ $(bytes__chr 33) = $'\x21' ]] || return 1 44 | [[ $(bytes__chr 34) = $'\x22' ]] || return 1 45 | [[ $(bytes__chr 35) = $'\x23' ]] || return 1 46 | [[ $(bytes__chr 36) = $'\x24' ]] || return 1 47 | [[ $(bytes__chr 37) = $'\x25' ]] || return 1 48 | [[ $(bytes__chr 38) = $'\x26' ]] || return 1 49 | [[ $(bytes__chr 39) = $'\x27' ]] || return 1 50 | [[ $(bytes__chr 40) = $'\x28' ]] || return 1 51 | [[ $(bytes__chr 41) = $'\x29' ]] || return 1 52 | [[ $(bytes__chr 42) = $'\x2a' ]] || return 1 53 | [[ $(bytes__chr 43) = $'\x2b' ]] || return 1 54 | [[ $(bytes__chr 44) = $'\x2c' ]] || return 1 55 | [[ $(bytes__chr 45) = $'\x2d' ]] || return 1 56 | [[ $(bytes__chr 46) = $'\x2e' ]] || return 1 57 | [[ $(bytes__chr 47) = $'\x2f' ]] || return 1 58 | [[ $(bytes__chr 48) = $'\x30' ]] || return 1 59 | [[ $(bytes__chr 49) = $'\x31' ]] || return 1 60 | [[ $(bytes__chr 50) = $'\x32' ]] || return 1 61 | [[ $(bytes__chr 51) = $'\x33' ]] || return 1 62 | [[ $(bytes__chr 52) = $'\x34' ]] || return 1 63 | [[ $(bytes__chr 53) = $'\x35' ]] || return 1 64 | [[ $(bytes__chr 54) = $'\x36' ]] || return 1 65 | [[ $(bytes__chr 55) = $'\x37' ]] || return 1 66 | [[ $(bytes__chr 56) = $'\x38' ]] || return 1 67 | [[ $(bytes__chr 57) = $'\x39' ]] || return 1 68 | [[ $(bytes__chr 58) = $'\x3a' ]] || return 1 69 | [[ $(bytes__chr 59) = $'\x3b' ]] || return 1 70 | [[ $(bytes__chr 60) = $'\x3c' ]] || return 1 71 | [[ $(bytes__chr 61) = $'\x3d' ]] || return 1 72 | [[ $(bytes__chr 62) = $'\x3e' ]] || return 1 73 | [[ $(bytes__chr 63) = $'\x3f' ]] || return 1 74 | [[ $(bytes__chr 64) = $'\x40' ]] || return 1 75 | [[ $(bytes__chr 65) = $'\x41' ]] || return 1 76 | [[ $(bytes__chr 66) = $'\x42' ]] || return 1 77 | [[ $(bytes__chr 67) = $'\x43' ]] || return 1 78 | [[ $(bytes__chr 68) = $'\x44' ]] || return 1 79 | [[ $(bytes__chr 69) = $'\x45' ]] || return 1 80 | [[ $(bytes__chr 70) = $'\x46' ]] || return 1 81 | [[ $(bytes__chr 71) = $'\x47' ]] || return 1 82 | [[ $(bytes__chr 72) = $'\x48' ]] || return 1 83 | [[ $(bytes__chr 73) = $'\x49' ]] || return 1 84 | [[ $(bytes__chr 74) = $'\x4a' ]] || return 1 85 | [[ $(bytes__chr 75) = $'\x4b' ]] || return 1 86 | [[ $(bytes__chr 76) = $'\x4c' ]] || return 1 87 | [[ $(bytes__chr 77) = $'\x4d' ]] || return 1 88 | [[ $(bytes__chr 78) = $'\x4e' ]] || return 1 89 | [[ $(bytes__chr 79) = $'\x4f' ]] || return 1 90 | [[ $(bytes__chr 80) = $'\x50' ]] || return 1 91 | [[ $(bytes__chr 81) = $'\x51' ]] || return 1 92 | [[ $(bytes__chr 82) = $'\x52' ]] || return 1 93 | [[ $(bytes__chr 83) = $'\x53' ]] || return 1 94 | [[ $(bytes__chr 84) = $'\x54' ]] || return 1 95 | [[ $(bytes__chr 85) = $'\x55' ]] || return 1 96 | [[ $(bytes__chr 86) = $'\x56' ]] || return 1 97 | [[ $(bytes__chr 87) = $'\x57' ]] || return 1 98 | [[ $(bytes__chr 88) = $'\x58' ]] || return 1 99 | [[ $(bytes__chr 89) = $'\x59' ]] || return 1 100 | [[ $(bytes__chr 90) = $'\x5a' ]] || return 1 101 | [[ $(bytes__chr 91) = $'\x5b' ]] || return 1 102 | [[ $(bytes__chr 92) = $'\x5c' ]] || return 1 103 | [[ $(bytes__chr 93) = $'\x5d' ]] || return 1 104 | [[ $(bytes__chr 94) = $'\x5e' ]] || return 1 105 | [[ $(bytes__chr 95) = $'\x5f' ]] || return 1 106 | [[ $(bytes__chr 96) = $'\x60' ]] || return 1 107 | [[ $(bytes__chr 97) = $'\x61' ]] || return 1 108 | [[ $(bytes__chr 98) = $'\x62' ]] || return 1 109 | [[ $(bytes__chr 99) = $'\x63' ]] || return 1 110 | [[ $(bytes__chr 100) = $'\x64' ]] || return 1 111 | [[ $(bytes__chr 101) = $'\x65' ]] || return 1 112 | [[ $(bytes__chr 102) = $'\x66' ]] || return 1 113 | [[ $(bytes__chr 103) = $'\x67' ]] || return 1 114 | [[ $(bytes__chr 104) = $'\x68' ]] || return 1 115 | [[ $(bytes__chr 105) = $'\x69' ]] || return 1 116 | [[ $(bytes__chr 106) = $'\x6a' ]] || return 1 117 | [[ $(bytes__chr 107) = $'\x6b' ]] || return 1 118 | [[ $(bytes__chr 108) = $'\x6c' ]] || return 1 119 | [[ $(bytes__chr 109) = $'\x6d' ]] || return 1 120 | [[ $(bytes__chr 110) = $'\x6e' ]] || return 1 121 | [[ $(bytes__chr 111) = $'\x6f' ]] || return 1 122 | [[ $(bytes__chr 112) = $'\x70' ]] || return 1 123 | [[ $(bytes__chr 113) = $'\x71' ]] || return 1 124 | [[ $(bytes__chr 114) = $'\x72' ]] || return 1 125 | [[ $(bytes__chr 115) = $'\x73' ]] || return 1 126 | [[ $(bytes__chr 116) = $'\x74' ]] || return 1 127 | [[ $(bytes__chr 117) = $'\x75' ]] || return 1 128 | [[ $(bytes__chr 118) = $'\x76' ]] || return 1 129 | [[ $(bytes__chr 119) = $'\x77' ]] || return 1 130 | [[ $(bytes__chr 120) = $'\x78' ]] || return 1 131 | [[ $(bytes__chr 121) = $'\x79' ]] || return 1 132 | [[ $(bytes__chr 122) = $'\x7a' ]] || return 1 133 | [[ $(bytes__chr 123) = $'\x7b' ]] || return 1 134 | [[ $(bytes__chr 124) = $'\x7c' ]] || return 1 135 | [[ $(bytes__chr 125) = $'\x7d' ]] || return 1 136 | [[ $(bytes__chr 126) = $'\x7e' ]] || return 1 137 | [[ $(bytes__chr 127) = $'\x7f' ]] || return 1 138 | [[ $(bytes__chr 128) = $'\x80' ]] || return 1 139 | [[ $(bytes__chr 129) = $'\x81' ]] || return 1 140 | [[ $(bytes__chr 130) = $'\x82' ]] || return 1 141 | [[ $(bytes__chr 131) = $'\x83' ]] || return 1 142 | [[ $(bytes__chr 132) = $'\x84' ]] || return 1 143 | [[ $(bytes__chr 133) = $'\x85' ]] || return 1 144 | [[ $(bytes__chr 134) = $'\x86' ]] || return 1 145 | [[ $(bytes__chr 135) = $'\x87' ]] || return 1 146 | [[ $(bytes__chr 136) = $'\x88' ]] || return 1 147 | [[ $(bytes__chr 137) = $'\x89' ]] || return 1 148 | [[ $(bytes__chr 138) = $'\x8a' ]] || return 1 149 | [[ $(bytes__chr 139) = $'\x8b' ]] || return 1 150 | [[ $(bytes__chr 140) = $'\x8c' ]] || return 1 151 | [[ $(bytes__chr 141) = $'\x8d' ]] || return 1 152 | [[ $(bytes__chr 142) = $'\x8e' ]] || return 1 153 | [[ $(bytes__chr 143) = $'\x8f' ]] || return 1 154 | [[ $(bytes__chr 144) = $'\x90' ]] || return 1 155 | [[ $(bytes__chr 145) = $'\x91' ]] || return 1 156 | [[ $(bytes__chr 146) = $'\x92' ]] || return 1 157 | [[ $(bytes__chr 147) = $'\x93' ]] || return 1 158 | [[ $(bytes__chr 148) = $'\x94' ]] || return 1 159 | [[ $(bytes__chr 149) = $'\x95' ]] || return 1 160 | [[ $(bytes__chr 150) = $'\x96' ]] || return 1 161 | [[ $(bytes__chr 151) = $'\x97' ]] || return 1 162 | [[ $(bytes__chr 152) = $'\x98' ]] || return 1 163 | [[ $(bytes__chr 153) = $'\x99' ]] || return 1 164 | [[ $(bytes__chr 154) = $'\x9a' ]] || return 1 165 | [[ $(bytes__chr 155) = $'\x9b' ]] || return 1 166 | [[ $(bytes__chr 156) = $'\x9c' ]] || return 1 167 | [[ $(bytes__chr 157) = $'\x9d' ]] || return 1 168 | [[ $(bytes__chr 158) = $'\x9e' ]] || return 1 169 | [[ $(bytes__chr 159) = $'\x9f' ]] || return 1 170 | [[ $(bytes__chr 160) = $'\xa0' ]] || return 1 171 | [[ $(bytes__chr 161) = $'\xa1' ]] || return 1 172 | [[ $(bytes__chr 162) = $'\xa2' ]] || return 1 173 | [[ $(bytes__chr 163) = $'\xa3' ]] || return 1 174 | [[ $(bytes__chr 164) = $'\xa4' ]] || return 1 175 | [[ $(bytes__chr 165) = $'\xa5' ]] || return 1 176 | [[ $(bytes__chr 166) = $'\xa6' ]] || return 1 177 | [[ $(bytes__chr 167) = $'\xa7' ]] || return 1 178 | [[ $(bytes__chr 168) = $'\xa8' ]] || return 1 179 | [[ $(bytes__chr 169) = $'\xa9' ]] || return 1 180 | [[ $(bytes__chr 170) = $'\xaa' ]] || return 1 181 | [[ $(bytes__chr 171) = $'\xab' ]] || return 1 182 | [[ $(bytes__chr 172) = $'\xac' ]] || return 1 183 | [[ $(bytes__chr 173) = $'\xad' ]] || return 1 184 | [[ $(bytes__chr 174) = $'\xae' ]] || return 1 185 | [[ $(bytes__chr 175) = $'\xaf' ]] || return 1 186 | [[ $(bytes__chr 176) = $'\xb0' ]] || return 1 187 | [[ $(bytes__chr 177) = $'\xb1' ]] || return 1 188 | [[ $(bytes__chr 178) = $'\xb2' ]] || return 1 189 | [[ $(bytes__chr 179) = $'\xb3' ]] || return 1 190 | [[ $(bytes__chr 180) = $'\xb4' ]] || return 1 191 | [[ $(bytes__chr 181) = $'\xb5' ]] || return 1 192 | [[ $(bytes__chr 182) = $'\xb6' ]] || return 1 193 | [[ $(bytes__chr 183) = $'\xb7' ]] || return 1 194 | [[ $(bytes__chr 184) = $'\xb8' ]] || return 1 195 | [[ $(bytes__chr 185) = $'\xb9' ]] || return 1 196 | [[ $(bytes__chr 186) = $'\xba' ]] || return 1 197 | [[ $(bytes__chr 187) = $'\xbb' ]] || return 1 198 | [[ $(bytes__chr 188) = $'\xbc' ]] || return 1 199 | [[ $(bytes__chr 189) = $'\xbd' ]] || return 1 200 | [[ $(bytes__chr 190) = $'\xbe' ]] || return 1 201 | [[ $(bytes__chr 191) = $'\xbf' ]] || return 1 202 | [[ $(bytes__chr 192) = $'\xc0' ]] || return 1 203 | [[ $(bytes__chr 193) = $'\xc1' ]] || return 1 204 | [[ $(bytes__chr 194) = $'\xc2' ]] || return 1 205 | [[ $(bytes__chr 195) = $'\xc3' ]] || return 1 206 | [[ $(bytes__chr 196) = $'\xc4' ]] || return 1 207 | [[ $(bytes__chr 197) = $'\xc5' ]] || return 1 208 | [[ $(bytes__chr 198) = $'\xc6' ]] || return 1 209 | [[ $(bytes__chr 199) = $'\xc7' ]] || return 1 210 | [[ $(bytes__chr 200) = $'\xc8' ]] || return 1 211 | [[ $(bytes__chr 201) = $'\xc9' ]] || return 1 212 | [[ $(bytes__chr 202) = $'\xca' ]] || return 1 213 | [[ $(bytes__chr 203) = $'\xcb' ]] || return 1 214 | [[ $(bytes__chr 204) = $'\xcc' ]] || return 1 215 | [[ $(bytes__chr 205) = $'\xcd' ]] || return 1 216 | [[ $(bytes__chr 206) = $'\xce' ]] || return 1 217 | [[ $(bytes__chr 207) = $'\xcf' ]] || return 1 218 | [[ $(bytes__chr 208) = $'\xd0' ]] || return 1 219 | [[ $(bytes__chr 209) = $'\xd1' ]] || return 1 220 | [[ $(bytes__chr 210) = $'\xd2' ]] || return 1 221 | [[ $(bytes__chr 211) = $'\xd3' ]] || return 1 222 | [[ $(bytes__chr 212) = $'\xd4' ]] || return 1 223 | [[ $(bytes__chr 213) = $'\xd5' ]] || return 1 224 | [[ $(bytes__chr 214) = $'\xd6' ]] || return 1 225 | [[ $(bytes__chr 215) = $'\xd7' ]] || return 1 226 | [[ $(bytes__chr 216) = $'\xd8' ]] || return 1 227 | [[ $(bytes__chr 217) = $'\xd9' ]] || return 1 228 | [[ $(bytes__chr 218) = $'\xda' ]] || return 1 229 | [[ $(bytes__chr 219) = $'\xdb' ]] || return 1 230 | [[ $(bytes__chr 220) = $'\xdc' ]] || return 1 231 | [[ $(bytes__chr 221) = $'\xdd' ]] || return 1 232 | [[ $(bytes__chr 222) = $'\xde' ]] || return 1 233 | [[ $(bytes__chr 223) = $'\xdf' ]] || return 1 234 | [[ $(bytes__chr 224) = $'\xe0' ]] || return 1 235 | [[ $(bytes__chr 225) = $'\xe1' ]] || return 1 236 | [[ $(bytes__chr 226) = $'\xe2' ]] || return 1 237 | [[ $(bytes__chr 227) = $'\xe3' ]] || return 1 238 | [[ $(bytes__chr 228) = $'\xe4' ]] || return 1 239 | [[ $(bytes__chr 229) = $'\xe5' ]] || return 1 240 | [[ $(bytes__chr 230) = $'\xe6' ]] || return 1 241 | [[ $(bytes__chr 231) = $'\xe7' ]] || return 1 242 | [[ $(bytes__chr 232) = $'\xe8' ]] || return 1 243 | [[ $(bytes__chr 233) = $'\xe9' ]] || return 1 244 | [[ $(bytes__chr 234) = $'\xea' ]] || return 1 245 | [[ $(bytes__chr 235) = $'\xeb' ]] || return 1 246 | [[ $(bytes__chr 236) = $'\xec' ]] || return 1 247 | [[ $(bytes__chr 237) = $'\xed' ]] || return 1 248 | [[ $(bytes__chr 238) = $'\xee' ]] || return 1 249 | [[ $(bytes__chr 239) = $'\xef' ]] || return 1 250 | [[ $(bytes__chr 240) = $'\xf0' ]] || return 1 251 | [[ $(bytes__chr 241) = $'\xf1' ]] || return 1 252 | [[ $(bytes__chr 242) = $'\xf2' ]] || return 1 253 | [[ $(bytes__chr 243) = $'\xf3' ]] || return 1 254 | [[ $(bytes__chr 244) = $'\xf4' ]] || return 1 255 | [[ $(bytes__chr 245) = $'\xf5' ]] || return 1 256 | [[ $(bytes__chr 246) = $'\xf6' ]] || return 1 257 | [[ $(bytes__chr 247) = $'\xf7' ]] || return 1 258 | [[ $(bytes__chr 248) = $'\xf8' ]] || return 1 259 | [[ $(bytes__chr 249) = $'\xf9' ]] || return 1 260 | [[ $(bytes__chr 250) = $'\xfa' ]] || return 1 261 | [[ $(bytes__chr 251) = $'\xfb' ]] || return 1 262 | [[ $(bytes__chr 252) = $'\xfc' ]] || return 1 263 | [[ $(bytes__chr 253) = $'\xfd' ]] || return 1 264 | [[ $(bytes__chr 254) = $'\xfe' ]] || return 1 265 | [[ $(bytes__chr 255) = $'\xff' ]] || return 1 266 | 267 | return 0 268 | } 269 | 270 | test 271 | 272 | # :r ! awk 'BEGIN{for(i=1;i<256;i++){printf " [[ $(bytes.chr \%03s) = $'\''\\x\%02x'\'' ]] || return 1\n", i, i}}' 273 | -------------------------------------------------------------------------------- /bin/url: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | log__basic () 3 | { 4 | typeset argument; 5 | for argument in "$@"; 6 | do 7 | printf '%s: %s\n' "${BASH_SOURCE##*/}" "$argument"; 8 | done 9 | } 10 | log__debug () 11 | { 12 | typeset debug_level log_level; 13 | shift 2; 14 | if ((log_level >= debug_level)); then 15 | log__with_type DEBUG "$@"; 16 | fi 17 | } 18 | log__error () 19 | { 20 | log__with_type ERROR "$@" 21 | } 22 | log__info () 23 | { 24 | log__with_type INFO "$@" 25 | } 26 | log__warning () 27 | { 28 | log__with_type WARNING "$@" 29 | } 30 | log__with_type () 31 | { 32 | typeset type=$1 argument; 33 | shift; 34 | for argument in "$@"; 35 | do 36 | log__basic "$type: $argument" 1>&2; 37 | done 38 | } 39 | 40 | common__die () 41 | { 42 | typeset exit_status=$2; 43 | log__error "$1"; 44 | exit "${exit_status:-1}" 45 | } 46 | 47 | bytes__chr () 48 | { 49 | typeset dec=$1; 50 | ((0 <= dec && dec < 256)) || return 1; 51 | printf \\$((dec/64*100+dec%64/8*10+dec%8)) 52 | } 53 | bytes__hex () 54 | { 55 | LC_CTYPE=C printf '%x' "'$1" 56 | } 57 | bytes__ord () 58 | { 59 | LC_CTYPE=C printf '%d' "'$1" 60 | } 61 | bytes__unhex () 62 | { 63 | [[ $1 = ?([[:xdigit:]])[[:xdigit:]] ]] || return 1; 64 | printf '\x'"$1" 65 | } 66 | bytes__write_uint32_be () 67 | { 68 | typeset number=$1; 69 | typeset hex; 70 | ((number >> 32)) && return 1; 71 | printf -v hex '\\x%x' "$(( (number >> 24) & 0xff))" "$(( (number >> 16) & 0xff))" "$(( (number >> 8) & 0xff))" "$(( number & 0xff))"; 72 | printf "$hex" 73 | } 74 | bytes__write_uint32_le () 75 | { 76 | typeset number=$1; 77 | typeset hex; 78 | ((number >> 32)) && return 1; 79 | printf -v hex '\\x%x' "$(( number & 0xff))" "$(( (number >> 8) & 0xff))" "$(( (number >> 16) & 0xff))" "$(( (number >> 24) & 0xff))"; 80 | printf "$hex" 81 | } 82 | 83 | network__socket_get_device () 84 | { 85 | typeset type=$1 netloc=$2 port=$3; 86 | [[ $type = @(tcp|udp) ]] || return 1; 87 | [[ $netloc = @(*/*|____) ]] && return 1; 88 | [[ $port = +([[:digit:]]) ]] || return 1; 89 | printf %s "/dev/$type/$netloc/$port" 90 | } 91 | network__tcp-send () 92 | { 93 | typeset netloc=$1 port=$2; 94 | typeset line socket fd; 95 | socket=$(network__socket_get_device tcp "$netloc" "$port") || return 1; 96 | ( exec 3<> "$socket"; 97 | while IFS= read -r line; do 98 | printf '%s\n' "$line"; 99 | done 1>&3; 100 | printf %s "$line" 1>&3; 101 | while IFS= read -r line; do 102 | printf '%s\n' "$line"; 103 | done 0<&3; 104 | printf %s "$line"; 105 | exec 3>&- ) 106 | } 107 | 108 | http__form_url_decode () 109 | { 110 | typeset data=${1//+/%20}; 111 | http__percent_decode "$data" 112 | } 113 | http__form_url_encode () 114 | { 115 | : application/x-www-form-urlencoded; 116 | typeset data=$(http__percent_encode "$1"); 117 | printf %s "${data//%20/+}" 118 | } 119 | http__get () 120 | { 121 | typeset url=$1; 122 | typeset scheme username password netloc port path query_string; 123 | typeset fragment resource IFS=:; 124 | typeset -a request=(); 125 | IFS=: read -r scheme _ _ netloc port path query_string _ < <(http__url_parse "$url"); 126 | resource=$path; 127 | [[ -n $query_string ]] && resource+=?$query_string; 128 | request+=("GET $resource HTTP/1.0"); 129 | request+=("Host: $netloc"); 130 | request+=(''); 131 | printf '%s\r\n' "${request[@]}" | network__tcp_send "$netloc" "$port" 132 | } 133 | http__percent_decode () 134 | { 135 | typeset data=${1//\\/\\\\}; 136 | printf "${data//%/\\x}" 137 | } 138 | http__percent_encode () 139 | { 140 | typeset character position data=$1; 141 | typeset -x LC_TYPE=C; 142 | for ((position=0; position<${#data}; position++)) 143 | do 144 | character=${data:position:1}; 145 | if [[ $character = [[:alnum:].~-] ]]; then 146 | printf %s "$character"; 147 | else 148 | printf %%%02X "$(bytes__ord "$character")"; 149 | fi; 150 | done 151 | } 152 | http__post () 153 | { 154 | typeset url=$1 form=$2; 155 | typeset scheme username password netloc port path query_string; 156 | typeset fragment resource IFS=:; 157 | typeset -a request=(); 158 | read -r scheme _ _ netloc port path query_string _ < <(http__url_parse "$url"); 159 | resource=$path; 160 | [[ -n $query_string ]] && resource+=?$query_string; 161 | request+=("POST $resource HTTP/1.0"); 162 | request+=("Host: $netloc"); 163 | request+=("Content-Type: application/x-www-form-urlencoded"); 164 | request+=("Content-Length: $((${#form}+2))"); 165 | request+=(''); 166 | request+=("$form"); 167 | printf '%s\r\n' "${request[@]}" | network__tcp_send "$netloc" "$port" 168 | } 169 | http__query_string_encode () 170 | { 171 | : </dev/null && printf y); 211 | typeset -a components; 212 | shopt -s extglob; 213 | : Parse the scheme, currently it is generic; 214 | if [[ $url = +([!:])?(s)://* ]]; then 215 | scheme=${url%%://*} url=${url#+([!:])://}; 216 | else 217 | if [[ $url = @(//[!/]*|//) ]]; then 218 | scheme=$default_scheme url=${url#//}; 219 | fi; 220 | fi; 221 | : Parse username:password combination in URL; 222 | if [[ $url = *([!@])@* ]]; then 223 | IFS=:@ read -r username password url <<< "$url"; 224 | fi; 225 | : Parse network location '(ip address or domain name)'; 226 | if [[ $url = +([!:]):+([[:digit:]])?([/?#&]*) ]]; then 227 | netloc=${url%%:*} port=${url#"$netloc"} port=${port##*:}; 228 | url=${url#"$netloc:$port"}; 229 | else 230 | if [[ $url = +([!/?#&])?([/?#&]*) ]]; then 231 | netloc=${url%%[/?#&]*}; 232 | url=${url#"$netloc"}; 233 | : Default ports; 234 | case $scheme in 235 | http) 236 | port=80 237 | ;; 238 | https) 239 | port=443 240 | ;; 241 | esac; 242 | fi; 243 | fi; 244 | : Parse path; 245 | path=/; 246 | if [[ $url = +([!?#&])?([?#&]*) ]]; then 247 | path=${url%%[?#&]*}; 248 | url=${url#"$path"}; 249 | fi; 250 | : Parse query string; 251 | if [[ $url = +([!#])?([#]*) ]]; then 252 | query_string=${url%%[#]*} query_string=${query_string#'?'}; 253 | url=${url#"?$query_string"}; 254 | fi; 255 | : Parse fragment; 256 | if [[ $url = '#'* ]]; then 257 | fragment=${url#'#'}; 258 | fi; 259 | : Return extglob to the state we found it; 260 | [[ -n $extglob ]] || shopt -u extglob; 261 | : Join the components; 262 | components=("$scheme" "$username" "$password" "$netloc" "$port" "$path" "$query_string" "$fragment"); 263 | ( IFS=':'; 264 | printf %s "${components[*]}" ) 265 | } 266 | 267 | cmdline__arguments () 268 | { 269 | : < 0)); do 334 | argument=$1; 335 | if [[ -n $stop_parsing ]]; then 336 | printf '@ %s\0' "$argument"; 337 | shift; 338 | continue; 339 | fi; 340 | case $argument in 341 | -[!-]) 342 | { 343 | shift=$(cmdline__p__arguments__short "$@") || { 344 | return_code=$?; 345 | [[ -n $errors_not_fatal ]] || return "$return_code" 346 | } 347 | } 3>&1; 348 | shift "$((shift + 1))" 349 | ;; 350 | -[!-]*) 351 | { 352 | shift=$(cmdline__p__arguments__short_composed "$@") || { 353 | return_code=$?; 354 | [[ -n $errors_not_fatal ]] || return "$return_code" 355 | } 356 | } 3>&1; 357 | shift "$((shift + 1))" 358 | ;; 359 | --[!-]*) 360 | if [[ $argument = --+([!=])=* ]]; then 361 | IFS== read -rd '' key value <<< "$argument"; 362 | shift; 363 | set -- "$key" "${value% 364 | }" "$@"; 365 | fi; 366 | { 367 | shift=$(cmdline__p__arguments__long "$@") || { 368 | return_code=$?; 369 | [[ -n $errors_not_fatal ]] || return "$return_code" 370 | } 371 | } 3>&1; 372 | shift "$((shift + 1))" 373 | ;; 374 | --) 375 | if [[ -n $dashdash_not_special ]]; then 376 | printf '@ %s\0' "$argument"; 377 | else 378 | stop_parsing=y; 379 | fi; 380 | shift 381 | ;; 382 | *) 383 | printf '@ %s\0' "$argument"; 384 | shift 385 | ;; 386 | esac; 387 | done 388 | } 389 | cmdline__help () 390 | { 391 | typeset option_description name long short required arguments help; 392 | typeset key value parameter; 393 | typeset -a parameters; 394 | for option_description in "$@"; 395 | do 396 | [[ $option_description = '--' ]] && break; 397 | IFS=: read -ra parameters <<< "$option_description"; 398 | name= long= short= required= arguments=0 help=; 399 | for parameter in "${parameters[@]}"; 400 | do 401 | IFS== read -r key value <<< "$parameter"; 402 | case $key in 403 | name) 404 | name=$value 405 | ;; 406 | long) 407 | long=$value 408 | ;; 409 | short) 410 | short=$value 411 | ;; 412 | required) 413 | required=$value 414 | ;; 415 | arguments) 416 | arguments=$value 417 | ;; 418 | help) 419 | help=$value 420 | ;; 421 | esac; 422 | name=${name:-"$long"}; 423 | name=${name:-"$short"}; 424 | [[ -n $name ]] || return 1; 425 | done; 426 | if [[ -n $short && -n $long ]]; then 427 | printf '\t-%s, --%s\n\t\t%s\n' "$short" "$long" "$help"; 428 | else 429 | if [[ -n $short ]]; then 430 | printf '\t-%s\n\t\t%s\n' "$short" "$help"; 431 | else 432 | if [[ -n $long ]]; then 433 | printf '\t--%s\n\t\t%s\n' "$long" "$help"; 434 | else 435 | :; 436 | fi; 437 | fi; 438 | fi; 439 | done 440 | } 441 | cmdline__p__arguments__long () 442 | { 443 | typeset argument=$1; 444 | typeset name i arguments; 445 | [[ -n $argument ]] || return 1; 446 | shift; 447 | { 448 | typeset -p long_map || return 2; 449 | typeset -p arguments_map || return 2 450 | } > /dev/null 2>&1; 451 | name=${long_map["${argument#--}"]}; 452 | [[ -n $name ]] || { 453 | printf -- '- %s\0' "$argument" 1>&3; 454 | return 3 455 | }; 456 | arguments=${arguments_map["$name"]}; 457 | if ((arguments == 0)); then 458 | printf '%s\0' "$name" 1>&3; 459 | return 0; 460 | else 461 | if ((arguments > $#)); then 462 | return 4; 463 | fi; 464 | fi; 465 | for ((i = 1; i <= arguments; i++)) 466 | do 467 | printf '%s %s\0' "$name" "${@:i:1}" 1>&3; 468 | shift; 469 | done; 470 | printf %s "$arguments" 471 | } 472 | cmdline__p__arguments__short () 473 | { 474 | typeset argument=$1; 475 | typeset name i arguments; 476 | [[ -n $argument ]] || return 1; 477 | shift; 478 | { 479 | typeset -p short_map || return 2; 480 | typeset -p arguments_map || return 2 481 | } > /dev/null 2>&1; 482 | name=${short_map["${argument#-}"]}; 483 | [[ -n $name ]] || { 484 | printf -- '- %s\0' "$argument" 1>&3; 485 | return 3 486 | }; 487 | arguments=${arguments_map["$name"]}; 488 | if ((arguments == 0)); then 489 | printf '%s\0' "$name" 1>&3; 490 | return 0; 491 | else 492 | if ((arguments > $#)); then 493 | return 4; 494 | fi; 495 | fi; 496 | for ((i = 1; i <= arguments; i++)) 497 | do 498 | printf '%s %s\0' "$name" "${@:i:1}" 1>&3; 499 | shift; 500 | done; 501 | printf %s "$arguments" 502 | } 503 | cmdline__p__arguments__short_composed () 504 | { 505 | typeset argument=$1; 506 | typeset option remainder name arguments; 507 | [[ -n $argument ]] || return 1; 508 | shift; 509 | { 510 | typeset -p short_map || return 2; 511 | typeset -p arguments_map || return 2 512 | } > /dev/null 2>&1; 513 | option=${argument#-} option=${option::1}; 514 | remainder=${argument#-?}; 515 | name=${short_map["$option"]}; 516 | [[ -n $name ]] || { 517 | printf -- '- %s\0' "$argument" 1>&3; 518 | return 3 519 | }; 520 | arguments=${arguments_map["$name"]}; 521 | if ((arguments == 0)); then 522 | printf '%s\0' "$name" 1>&3; 523 | if [[ -n $remainder ]]; then 524 | cmdline__p__arguments__short_composed "-$remainder" "$@" || return; 525 | fi; 526 | else 527 | [[ -n $remainder ]] && set -- "$remainder" "$@"; 528 | cmdline__p__arguments__short "-$option" "$@" || return; 529 | fi 530 | } 531 | 532 | main () 533 | { 534 | typeset IFS; 535 | typeset -a commands arguments; 536 | typeset -a options=('name=encode:short=e:long=encode:arguments=1' 'name=decode:short=d:long=decode:arguments=1'); 537 | while read -rd '' type value; do 538 | case $type in 539 | @) 540 | echo bad "$value"; 541 | exit 1 542 | ;; 543 | -) 544 | echo bad "$value"; 545 | exit 1 546 | ;; 547 | encode) 548 | command=http__form_url_encode argument=$value; 549 | break 550 | ;; 551 | decode) 552 | command=http__form_url_decode argument=$value; 553 | break 554 | ;; 555 | esac; 556 | done < <(cmdline__arguments "${options[@]}" -- "$@"); 557 | "$command" "$argument" 558 | } 559 | main "$@" 560 | -------------------------------------------------------------------------------- /tests/date.bashly/001-test-date-time-to-unix-seconds: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : load date 4 | 5 | function test { 6 | 7 | (( $(date__time_to_unix_seconds 1970 01 01 00 00 00) == 0 )) || return 1 8 | (( $(date__time_to_unix_seconds 1970 01 20 19 47 57) == 1712877 )) || return 1 9 | (( $(date__time_to_unix_seconds 1970 02 11 06 00 50) == 3564050 )) || return 1 10 | (( $(date__time_to_unix_seconds 1970 08 05 01 45 06) == 18668706 )) || return 1 11 | (( $(date__time_to_unix_seconds 1970 08 28 17 38 59) == 20713139 )) || return 1 12 | (( $(date__time_to_unix_seconds 1971 01 25 07 53 56) == 33638036 )) || return 1 13 | (( $(date__time_to_unix_seconds 1971 07 18 21 09 17) == 48719357 )) || return 1 14 | (( $(date__time_to_unix_seconds 1972 01 05 00 57 04) == 63421024 )) || return 1 15 | (( $(date__time_to_unix_seconds 1972 07 08 22 54 55) == 79484095 )) || return 1 16 | (( $(date__time_to_unix_seconds 1972 09 01 22 06 23) == 84233183 )) || return 1 17 | (( $(date__time_to_unix_seconds 1973 02 26 00 36 43) == 99535003 )) || return 1 18 | (( $(date__time_to_unix_seconds 1973 04 26 10 16 44) == 104667404 )) || return 1 19 | (( $(date__time_to_unix_seconds 1973 08 14 10 37 12) == 114172632 )) || return 1 20 | (( $(date__time_to_unix_seconds 1974 02 22 13 19 09) == 130771149 )) || return 1 21 | (( $(date__time_to_unix_seconds 1974 05 31 13 06 17) == 139237577 )) || return 1 22 | (( $(date__time_to_unix_seconds 1974 11 03 06 56 56) == 152693816 )) || return 1 23 | (( $(date__time_to_unix_seconds 1975 05 15 00 23 45) == 169345425 )) || return 1 24 | (( $(date__time_to_unix_seconds 1975 11 08 02 35 10) == 184646110 )) || return 1 25 | (( $(date__time_to_unix_seconds 1975 12 08 00 19 34) == 187229974 )) || return 1 26 | (( $(date__time_to_unix_seconds 1976 02 08 12 59 03) == 192632343 )) || return 1 27 | (( $(date__time_to_unix_seconds 1976 03 06 04 45 38) == 194935538 )) || return 1 28 | (( $(date__time_to_unix_seconds 1976 08 08 21 06 30) == 208386390 )) || return 1 29 | (( $(date__time_to_unix_seconds 1976 09 06 23 04 41) == 210899081 )) || return 1 30 | (( $(date__time_to_unix_seconds 1977 01 26 04 47 37) == 223102057 )) || return 1 31 | (( $(date__time_to_unix_seconds 1977 08 05 09 07 41) == 239620061 )) || return 1 32 | (( $(date__time_to_unix_seconds 1977 08 13 01 41 59) == 240284519 )) || return 1 33 | (( $(date__time_to_unix_seconds 1978 02 22 16 41 15) == 257013675 )) || return 1 34 | (( $(date__time_to_unix_seconds 1978 03 31 10 27 55) == 260188075 )) || return 1 35 | (( $(date__time_to_unix_seconds 1978 10 11 02 51 12) == 276922272 )) || return 1 36 | (( $(date__time_to_unix_seconds 1978 12 24 17 04 18) == 283367058 )) || return 1 37 | (( $(date__time_to_unix_seconds 1979 02 26 12 14 21) == 288879261 )) || return 1 38 | (( $(date__time_to_unix_seconds 1979 04 06 11 17 58) == 292245478 )) || return 1 39 | (( $(date__time_to_unix_seconds 1979 04 13 11 07 05) == 292849625 )) || return 1 40 | (( $(date__time_to_unix_seconds 1979 10 23 22 06 40) == 309564400 )) || return 1 41 | (( $(date__time_to_unix_seconds 1979 11 08 06 41 39) == 310891299 )) || return 1 42 | (( $(date__time_to_unix_seconds 1980 03 24 18 52 41) == 322771961 )) || return 1 43 | (( $(date__time_to_unix_seconds 1980 03 29 13 26 15) == 323184375 )) || return 1 44 | (( $(date__time_to_unix_seconds 1980 10 05 22 55 21) == 339634521 )) || return 1 45 | (( $(date__time_to_unix_seconds 1981 03 31 22 26 51) == 354925611 )) || return 1 46 | (( $(date__time_to_unix_seconds 1981 07 18 00 19 02) == 364263542 )) || return 1 47 | (( $(date__time_to_unix_seconds 1981 09 15 09 33 39) == 369394419 )) || return 1 48 | (( $(date__time_to_unix_seconds 1981 10 09 00 05 45) == 371433945 )) || return 1 49 | (( $(date__time_to_unix_seconds 1982 02 07 09 37 48) == 381922668 )) || return 1 50 | (( $(date__time_to_unix_seconds 1982 07 16 20 48 57) == 395700537 )) || return 1 51 | (( $(date__time_to_unix_seconds 1982 10 05 06 29 46) == 402647386 )) || return 1 52 | (( $(date__time_to_unix_seconds 1983 03 30 08 13 47) == 417860027 )) || return 1 53 | (( $(date__time_to_unix_seconds 1983 04 01 16 00 32) == 418060832 )) || return 1 54 | (( $(date__time_to_unix_seconds 1983 07 24 14 42 22) == 427905742 )) || return 1 55 | (( $(date__time_to_unix_seconds 1983 09 21 08 27 23) == 432980843 )) || return 1 56 | (( $(date__time_to_unix_seconds 1984 03 01 04 31 58) == 446963518 )) || return 1 57 | (( $(date__time_to_unix_seconds 1984 06 06 07 25 01) == 455354701 )) || return 1 58 | (( $(date__time_to_unix_seconds 1984 09 02 15 02 42) == 462985362 )) || return 1 59 | (( $(date__time_to_unix_seconds 1984 10 02 23 22 21) == 465607341 )) || return 1 60 | (( $(date__time_to_unix_seconds 1984 11 12 09 23 40) == 469099420 )) || return 1 61 | (( $(date__time_to_unix_seconds 1985 01 04 18 19 15) == 473710755 )) || return 1 62 | (( $(date__time_to_unix_seconds 1985 01 25 06 55 51) == 475484151 )) || return 1 63 | (( $(date__time_to_unix_seconds 1985 05 04 15 56 07) == 484070167 )) || return 1 64 | (( $(date__time_to_unix_seconds 1985 09 28 08 40 34) == 496744834 )) || return 1 65 | (( $(date__time_to_unix_seconds 1986 01 19 09 08 58) == 506509738 )) || return 1 66 | (( $(date__time_to_unix_seconds 1986 07 06 06 09 59) == 521014199 )) || return 1 67 | (( $(date__time_to_unix_seconds 1986 07 06 07 53 12) == 521020392 )) || return 1 68 | (( $(date__time_to_unix_seconds 1986 12 15 17 11 18) == 535050678 )) || return 1 69 | (( $(date__time_to_unix_seconds 1987 02 24 11 40 29) == 541165229 )) || return 1 70 | (( $(date__time_to_unix_seconds 1987 04 27 06 53 40) == 546504820 )) || return 1 71 | (( $(date__time_to_unix_seconds 1987 06 27 02 51 23) == 551760683 )) || return 1 72 | (( $(date__time_to_unix_seconds 1987 09 07 23 33 15) == 558055995 )) || return 1 73 | (( $(date__time_to_unix_seconds 1988 01 22 17 12 51) == 569869971 )) || return 1 74 | (( $(date__time_to_unix_seconds 1988 07 08 09 47 29) == 584358449 )) || return 1 75 | (( $(date__time_to_unix_seconds 1988 11 21 07 17 00) == 596099820 )) || return 1 76 | (( $(date__time_to_unix_seconds 1989 03 04 18 48 16) == 605040496 )) || return 1 77 | (( $(date__time_to_unix_seconds 1989 09 08 10 55 09) == 621255309 )) || return 1 78 | (( $(date__time_to_unix_seconds 1990 01 08 17 48 00) == 631820880 )) || return 1 79 | (( $(date__time_to_unix_seconds 1990 07 06 21 33 48) == 647300028 )) || return 1 80 | (( $(date__time_to_unix_seconds 1990 09 05 15 35 00) == 652548900 )) || return 1 81 | (( $(date__time_to_unix_seconds 1991 01 28 21 38 02) == 665098682 )) || return 1 82 | (( $(date__time_to_unix_seconds 1991 05 30 14 26 49) == 675613609 )) || return 1 83 | (( $(date__time_to_unix_seconds 1991 09 23 17 38 21) == 685647501 )) || return 1 84 | (( $(date__time_to_unix_seconds 1992 01 01 23 50 15) == 694309815 )) || return 1 85 | (( $(date__time_to_unix_seconds 1992 04 19 12 09 53) == 703685393 )) || return 1 86 | (( $(date__time_to_unix_seconds 1992 08 09 22 58 29) == 713401109 )) || return 1 87 | (( $(date__time_to_unix_seconds 1992 10 21 23 28 39) == 719710119 )) || return 1 88 | (( $(date__time_to_unix_seconds 1993 02 21 22 18 59) == 730333139 )) || return 1 89 | (( $(date__time_to_unix_seconds 1993 04 19 02 27 20) == 735186440 )) || return 1 90 | (( $(date__time_to_unix_seconds 1993 06 25 01 30 36) == 740971836 )) || return 1 91 | (( $(date__time_to_unix_seconds 1993 10 01 18 39 27) == 749500767 )) || return 1 92 | (( $(date__time_to_unix_seconds 1994 01 02 16 16 20) == 757527380 )) || return 1 93 | (( $(date__time_to_unix_seconds 1994 06 15 17 02 18) == 771699738 )) || return 1 94 | (( $(date__time_to_unix_seconds 1994 06 16 00 19 32) == 771725972 )) || return 1 95 | (( $(date__time_to_unix_seconds 1994 09 22 01 09 11) == 780196151 )) || return 1 96 | (( $(date__time_to_unix_seconds 1994 09 30 14 27 32) == 780935252 )) || return 1 97 | (( $(date__time_to_unix_seconds 1995 03 18 02 26 24) == 795493584 )) || return 1 98 | (( $(date__time_to_unix_seconds 1995 08 14 03 26 16) == 808370776 )) || return 1 99 | (( $(date__time_to_unix_seconds 1996 02 06 03 59 20) == 823579160 )) || return 1 100 | (( $(date__time_to_unix_seconds 1996 03 19 17 26 07) == 827256367 )) || return 1 101 | (( $(date__time_to_unix_seconds 1996 08 07 23 52 31) == 839461951 )) || return 1 102 | (( $(date__time_to_unix_seconds 1996 09 25 13 48 45) == 843659325 )) || return 1 103 | (( $(date__time_to_unix_seconds 1997 01 19 18 16 35) == 853697795 )) || return 1 104 | (( $(date__time_to_unix_seconds 1997 07 28 14 52 46) == 870101566 )) || return 1 105 | (( $(date__time_to_unix_seconds 1997 09 01 01 39 01) == 873077941 )) || return 1 106 | (( $(date__time_to_unix_seconds 1997 12 23 22 28 15) == 882916095 )) || return 1 107 | (( $(date__time_to_unix_seconds 1998 05 18 00 20 07) == 895450807 )) || return 1 108 | (( $(date__time_to_unix_seconds 1998 06 03 04 16 46) == 896847406 )) || return 1 109 | (( $(date__time_to_unix_seconds 1998 07 10 08 29 55) == 900059395 )) || return 1 110 | (( $(date__time_to_unix_seconds 1998 12 03 18 33 20) == 912710000 )) || return 1 111 | (( $(date__time_to_unix_seconds 1999 03 29 02 16 19) == 922673779 )) || return 1 112 | (( $(date__time_to_unix_seconds 1999 07 20 20 58 59) == 932504339 )) || return 1 113 | (( $(date__time_to_unix_seconds 1999 11 01 19 25 00) == 941484300 )) || return 1 114 | (( $(date__time_to_unix_seconds 2000 04 06 20 44 59) == 955053899 )) || return 1 115 | (( $(date__time_to_unix_seconds 2000 08 18 10 52 50) == 966595970 )) || return 1 116 | (( $(date__time_to_unix_seconds 2000 12 25 12 28 49) == 977747329 )) || return 1 117 | (( $(date__time_to_unix_seconds 2001 01 03 16 52 58) == 978540778 )) || return 1 118 | (( $(date__time_to_unix_seconds 2001 03 07 01 00 50) == 983926850 )) || return 1 119 | (( $(date__time_to_unix_seconds 2001 08 11 01 44 41) == 997494281 )) || return 1 120 | (( $(date__time_to_unix_seconds 2001 11 02 03 04 23) == 1004670263 )) || return 1 121 | (( $(date__time_to_unix_seconds 2001 11 28 20 39 37) == 1006979977 )) || return 1 122 | (( $(date__time_to_unix_seconds 2002 03 28 22 00 07) == 1017352807 )) || return 1 123 | (( $(date__time_to_unix_seconds 2002 06 19 00 58 39) == 1024448319 )) || return 1 124 | (( $(date__time_to_unix_seconds 2002 11 24 16 35 30) == 1038155730 )) || return 1 125 | (( $(date__time_to_unix_seconds 2003 01 05 17 04 41) == 1041786281 )) || return 1 126 | (( $(date__time_to_unix_seconds 2003 06 12 16 31 04) == 1055435464 )) || return 1 127 | (( $(date__time_to_unix_seconds 2003 08 08 17 26 42) == 1060363602 )) || return 1 128 | (( $(date__time_to_unix_seconds 2003 11 25 08 47 04) == 1069750024 )) || return 1 129 | (( $(date__time_to_unix_seconds 2004 01 12 09 39 48) == 1073900388 )) || return 1 130 | (( $(date__time_to_unix_seconds 2004 04 07 11 18 26) == 1081336706 )) || return 1 131 | (( $(date__time_to_unix_seconds 2004 08 27 14 47 16) == 1093618036 )) || return 1 132 | (( $(date__time_to_unix_seconds 2004 10 13 18 40 06) == 1097692806 )) || return 1 133 | (( $(date__time_to_unix_seconds 2005 04 08 01 31 33) == 1112923893 )) || return 1 134 | (( $(date__time_to_unix_seconds 2005 09 24 10 43 23) == 1127558603 )) || return 1 135 | (( $(date__time_to_unix_seconds 2006 02 20 11 17 50) == 1140434270 )) || return 1 136 | (( $(date__time_to_unix_seconds 2006 07 15 08 44 32) == 1152953072 )) || return 1 137 | (( $(date__time_to_unix_seconds 2006 07 25 08 52 49) == 1153817569 )) || return 1 138 | (( $(date__time_to_unix_seconds 2007 01 03 02 32 37) == 1167791557 )) || return 1 139 | (( $(date__time_to_unix_seconds 2007 04 22 11 45 04) == 1177242304 )) || return 1 140 | (( $(date__time_to_unix_seconds 2007 10 28 16 36 59) == 1193589419 )) || return 1 141 | (( $(date__time_to_unix_seconds 2008 04 24 01 09 04) == 1208999344 )) || return 1 142 | (( $(date__time_to_unix_seconds 2008 09 26 03 07 40) == 1222398460 )) || return 1 143 | (( $(date__time_to_unix_seconds 2009 01 05 01 29 16) == 1231118956 )) || return 1 144 | (( $(date__time_to_unix_seconds 2009 04 29 02 59 58) == 1240973998 )) || return 1 145 | (( $(date__time_to_unix_seconds 2009 06 13 19 56 55) == 1244923015 )) || return 1 146 | (( $(date__time_to_unix_seconds 2009 07 21 19 44 11) == 1248205451 )) || return 1 147 | (( $(date__time_to_unix_seconds 2009 08 29 14 42 27) == 1251556947 )) || return 1 148 | (( $(date__time_to_unix_seconds 2010 03 09 17 48 11) == 1268156891 )) || return 1 149 | (( $(date__time_to_unix_seconds 2010 06 17 03 41 53) == 1276746113 )) || return 1 150 | (( $(date__time_to_unix_seconds 2010 07 11 12 08 26) == 1278850106 )) || return 1 151 | (( $(date__time_to_unix_seconds 2010 10 12 03 12 02) == 1286853122 )) || return 1 152 | (( $(date__time_to_unix_seconds 2011 03 30 14 53 37) == 1301496817 )) || return 1 153 | (( $(date__time_to_unix_seconds 2011 10 01 01 20 23) == 1317432023 )) || return 1 154 | (( $(date__time_to_unix_seconds 2011 10 09 15 54 05) == 1318175645 )) || return 1 155 | (( $(date__time_to_unix_seconds 2012 04 11 18 48 59) == 1334170139 )) || return 1 156 | (( $(date__time_to_unix_seconds 2012 07 23 08 15 10) == 1343031310 )) || return 1 157 | (( $(date__time_to_unix_seconds 2012 08 06 06 46 11) == 1344235571 )) || return 1 158 | (( $(date__time_to_unix_seconds 2012 10 09 03 36 06) == 1349753766 )) || return 1 159 | (( $(date__time_to_unix_seconds 2012 10 09 23 43 54) == 1349826234 )) || return 1 160 | (( $(date__time_to_unix_seconds 2012 10 23 21 41 01) == 1351028461 )) || return 1 161 | (( $(date__time_to_unix_seconds 2012 11 11 23 51 30) == 1352677890 )) || return 1 162 | (( $(date__time_to_unix_seconds 2012 12 03 13 50 06) == 1354542606 )) || return 1 163 | (( $(date__time_to_unix_seconds 2013 02 21 09 06 29) == 1361437589 )) || return 1 164 | (( $(date__time_to_unix_seconds 2013 05 12 07 12 52) == 1368342772 )) || return 1 165 | (( $(date__time_to_unix_seconds 2013 08 18 03 58 12) == 1376798292 )) || return 1 166 | (( $(date__time_to_unix_seconds 2013 10 20 05 00 38) == 1382245238 )) || return 1 167 | (( $(date__time_to_unix_seconds 2013 12 19 05 39 28) == 1387431568 )) || return 1 168 | (( $(date__time_to_unix_seconds 2014 02 02 00 20 41) == 1391300441 )) || return 1 169 | (( $(date__time_to_unix_seconds 2014 05 07 21 54 27) == 1399499667 )) || return 1 170 | (( $(date__time_to_unix_seconds 2014 09 26 07 24 38) == 1411716278 )) || return 1 171 | (( $(date__time_to_unix_seconds 2015 03 26 15 40 17) == 1427384417 )) || return 1 172 | (( $(date__time_to_unix_seconds 2015 09 11 20 48 23) == 1442004503 )) || return 1 173 | (( $(date__time_to_unix_seconds 2015 12 18 19 48 35) == 1450468115 )) || return 1 174 | (( $(date__time_to_unix_seconds 2016 01 03 18 48 38) == 1451846918 )) || return 1 175 | (( $(date__time_to_unix_seconds 2016 05 18 19 58 56) == 1463601536 )) || return 1 176 | (( $(date__time_to_unix_seconds 2016 05 27 23 11 42) == 1464390702 )) || return 1 177 | (( $(date__time_to_unix_seconds 2016 08 01 10 17 46) == 1470046666 )) || return 1 178 | (( $(date__time_to_unix_seconds 2016 09 30 09 13 15) == 1475226795 )) || return 1 179 | (( $(date__time_to_unix_seconds 2016 11 09 17 48 32) == 1478713712 )) || return 1 180 | (( $(date__time_to_unix_seconds 2017 04 24 10 49 05) == 1493030945 )) || return 1 181 | (( $(date__time_to_unix_seconds 2017 07 14 00 28 31) == 1499992111 )) || return 1 182 | (( $(date__time_to_unix_seconds 2018 01 11 07 27 42) == 1515655662 )) || return 1 183 | (( $(date__time_to_unix_seconds 2018 04 20 23 27 42) == 1524266862 )) || return 1 184 | (( $(date__time_to_unix_seconds 2018 06 11 20 30 44) == 1528749044 )) || return 1 185 | (( $(date__time_to_unix_seconds 2018 09 08 02 03 39) == 1536372219 )) || return 1 186 | (( $(date__time_to_unix_seconds 2018 10 29 04 49 55) == 1540788595 )) || return 1 187 | (( $(date__time_to_unix_seconds 2019 01 22 12 05 12) == 1548158712 )) || return 1 188 | (( $(date__time_to_unix_seconds 2019 07 05 08 15 50) == 1562314550 )) || return 1 189 | (( $(date__time_to_unix_seconds 2019 10 24 07 23 35) == 1571901815 )) || return 1 190 | (( $(date__time_to_unix_seconds 2020 03 25 02 01 41) == 1585101701 )) || return 1 191 | (( $(date__time_to_unix_seconds 2020 07 09 13 35 12) == 1594301712 )) || return 1 192 | (( $(date__time_to_unix_seconds 2020 07 26 11 00 51) == 1595761251 )) || return 1 193 | (( $(date__time_to_unix_seconds 2020 08 26 19 24 22) == 1598469862 )) || return 1 194 | (( $(date__time_to_unix_seconds 2021 01 11 09 19 22) == 1610356762 )) || return 1 195 | (( $(date__time_to_unix_seconds 2021 03 11 17 39 03) == 1615484343 )) || return 1 196 | (( $(date__time_to_unix_seconds 2021 05 14 11 40 06) == 1620992406 )) || return 1 197 | (( $(date__time_to_unix_seconds 2021 05 24 16 40 02) == 1621874402 )) || return 1 198 | (( $(date__time_to_unix_seconds 2021 05 27 06 34 29) == 1622097269 )) || return 1 199 | (( $(date__time_to_unix_seconds 2021 08 27 21 06 46) == 1630098406 )) || return 1 200 | (( $(date__time_to_unix_seconds 2021 09 25 01 50 48) == 1632534648 )) || return 1 201 | (( $(date__time_to_unix_seconds 2022 03 24 23 03 27) == 1648163007 )) || return 1 202 | (( $(date__time_to_unix_seconds 2022 07 29 19 14 42) == 1659122082 )) || return 1 203 | (( $(date__time_to_unix_seconds 2022 08 16 12 15 25) == 1660652125 )) || return 1 204 | (( $(date__time_to_unix_seconds 2023 01 19 05 27 10) == 1674106030 )) || return 1 205 | (( $(date__time_to_unix_seconds 2023 07 29 11 46 37) == 1690631197 )) || return 1 206 | (( $(date__time_to_unix_seconds 2023 08 31 03 44 54) == 1693453494 )) || return 1 207 | (( $(date__time_to_unix_seconds 2023 11 29 13 17 53) == 1701263873 )) || return 1 208 | (( $(date__time_to_unix_seconds 2024 02 09 16 28 52) == 1707496132 )) || return 1 209 | (( $(date__time_to_unix_seconds 2024 05 19 09 38 43) == 1716111523 )) || return 1 210 | (( $(date__time_to_unix_seconds 2024 10 05 13 15 02) == 1728134102 )) || return 1 211 | (( $(date__time_to_unix_seconds 2025 03 22 13 15 45) == 1742649345 )) || return 1 212 | (( $(date__time_to_unix_seconds 2025 06 12 18 11 21) == 1749751881 )) || return 1 213 | (( $(date__time_to_unix_seconds 2025 08 23 06 39 33) == 1755931173 )) || return 1 214 | (( $(date__time_to_unix_seconds 2025 10 23 05 11 37) == 1761196297 )) || return 1 215 | (( $(date__time_to_unix_seconds 2026 02 20 21 03 33) == 1771621413 )) || return 1 216 | (( $(date__time_to_unix_seconds 2026 08 06 23 01 54) == 1786057314 )) || return 1 217 | (( $(date__time_to_unix_seconds 2026 11 01 11 52 51) == 1793533971 )) || return 1 218 | (( $(date__time_to_unix_seconds 2027 04 13 14 40 18) == 1807627218 )) || return 1 219 | (( $(date__time_to_unix_seconds 2027 07 07 03 59 31) == 1814932771 )) || return 1 220 | (( $(date__time_to_unix_seconds 2027 08 09 03 05 57) == 1817780757 )) || return 1 221 | (( $(date__time_to_unix_seconds 2027 09 24 18 19 45) == 1821809985 )) || return 1 222 | (( $(date__time_to_unix_seconds 2028 02 25 04 39 52) == 1835066392 )) || return 1 223 | (( $(date__time_to_unix_seconds 2028 04 12 11 57 38) == 1839153458 )) || return 1 224 | (( $(date__time_to_unix_seconds 2028 04 15 13 59 03) == 1839419943 )) || return 1 225 | (( $(date__time_to_unix_seconds 2028 07 22 10 37 43) == 1847875063 )) || return 1 226 | (( $(date__time_to_unix_seconds 2028 12 14 11 38 55) == 1860406735 )) || return 1 227 | (( $(date__time_to_unix_seconds 2029 02 10 09 55 33) == 1865411733 )) || return 1 228 | (( $(date__time_to_unix_seconds 2029 03 14 09 20 07) == 1868174407 )) || return 1 229 | (( $(date__time_to_unix_seconds 2029 05 18 23 45 05) == 1873842305 )) || return 1 230 | (( $(date__time_to_unix_seconds 2029 11 06 17 37 57) == 1888681077 )) || return 1 231 | (( $(date__time_to_unix_seconds 2030 01 23 06 12 18) == 1895379138 )) || return 1 232 | 233 | return 0 234 | } 235 | 236 | 237 | test 238 | 239 | # for ((seconds = 0; seconds < 86400 * 366*60; seconds += RANDOM & 0xffff | (RANDOM & 0xff) << 16)); do printf '(( $(date.time-to-unix-seconds %s) == % 10u ))\n' "$(date -ud @$seconds '+%Y %m %d %H %M %S')" $seconds; done 240 | --------------------------------------------------------------------------------