use re use str use ./common use ./list use ./map use ./num fn is-aggregate {|option| re:match '^\-\w{2,}$' $option } fn is-short {|option| re:match '^\-\w$' $option } fn is-long {|option| re:match '^\-\-\w+(=.*)?$' $option } fn is-option {|option| or (is-short $option) (is-long $option) (is-aggregate $option) } fn split {|option| if (is-aggregate $option) { each {|e| put -$e} $option[1..] } elif (is-long $option) { var i = (str:index $option '=') if (num:is-neg $i) { put $option } else { put $option[..$i] $option[(num:++ $i)..] } } else { put $option } } fn -j {|options| var o = (each {|o| put $o[1..] } $options | str:join '') if (not-eq $o '') { put -$o } } fn join {|@options| set options = (common:to-list $@options) var cb = {|_ o| or (is-short $o) (is-aggregate $o) } var i0 = 0 list:search-not $cb $options | each {|e| var i1 v = $@e -j $options[$i0..$i1] put $v set i0 = (num:++ $i1) } -j $options[$i0..] } fn expand {|@argv| each $split~ (common:to-list $@argv) } fn map {|@argv| set @argv = (expand $@argv) var result i c = [&] 0 (count $argv) var last = (num:-- $c) while (< $i $c) { var e = $argv[$i] if (is-option $e) { var k v = $e [] if (< $i $last) { var j = (num:++ $i) set e = $argv[$j] if (not (is-option $e)) { set i @v = $j $@v $e } } set result = (map:add $result $k $v) } else { set result = (map:add $result '' [$e]) } set i = (num:++ $i) } put $result }