Browse Source

sub/command optarg parser refurbished from Tomb

Jaromil 3 years ago
parent
commit
a9b9d76b0d
1 changed files with 150 additions and 0 deletions
  1. 150 0
      zuper

+ 150 - 0
zuper

@@ -704,6 +704,7 @@ EOF
704 704
     func "$_num key/values stored in $_path"
705 705
 }
706 706
 
707
+
707 708
 # }}} Key/Value filesave
708 709
 
709 710
 # {{{ Get/Set REST API
@@ -845,6 +846,155 @@ EOF
845 846
 
846 847
 # }}} Get/Set REST API
847 848
 
849
+# {{{ Parse commandline options
850
+
851
+# for example usage, see Tomb http://tomb.dyne.org
852
+vars+=(subcommand)
853
+arrs+=(option_main option_params)
854
+maps+=(option option_subcommands)
855
+
856
+# Hi, dear developer!  Are you trying to add a new subcommand, or
857
+# to add some options?  Well, keep in mind that option names are
858
+# global: they cannot bear a different meaning or behaviour across
859
+# subcommands.  The only exception is "-o" which means: "options
860
+# passed to the local subcommand", and thus can bear a different
861
+# meaning for different subcommands.
862
+#
863
+# For example, "-s" means "size" and accepts one argument. If you
864
+# are tempted to add an alternate option "-s" (e.g., to mean
865
+# "silent", and that doesn't accept any argument) DON'T DO IT!
866
+#
867
+# There are two reasons for that:
868
+#    I. Usability; users expect that "-s" is "size"
869
+#   II. Option parsing WILL EXPLODE if you do this kind of bad
870
+#       things (it will complain: "option defined more than once")
871
+#
872
+# If you want to use the same option in multiple commands then you
873
+# can only use the non-abbreviated long-option version like:
874
+# -force and NOT -f
875
+
876
+option.is_set() {
877
+
878
+	# Check whether a commandline option is set.
879
+	#
880
+	# Synopsis: option_is_set -flag [out]
881
+	#
882
+	# First argument is the commandline flag (e.g., "-s").
883
+	# If the second argument is present and set to 'out', print out the
884
+	# result: either 'set' or 'unset' (useful for if conditions).
885
+	#
886
+	# Return 0 if is set, 1 otherwise
887
+    local -i r   # the return code (0 = set, 1 = unset)
888
+
889
+    [[ -n ${(k)option[$1]} ]];
890
+    r=$?
891
+
892
+    [[ $2 == "out" ]] && {
893
+        [[ $r == 0 ]] && { print 'set' } || { print 'unset' }
894
+    }
895
+
896
+    return $r;
897
+}
898
+# Print the option value matching the given flag
899
+# Unique argument is the commandline flag (e.g., "-s").
900
+option.value() {
901
+    print -n - "${option[$1]}"
902
+}
903
+option.parse() {
904
+
905
+    ### Detect subcommand
906
+    local -aU every_opts #every_opts behave like a set; that is, an array with unique elements
907
+    for optspec in ${option_subcommands}${option_main}; do
908
+        for opt in ${=optspec}; do
909
+            every_opts+=${opt}
910
+        done
911
+    done
912
+    local -a oldstar
913
+    oldstar=("${(@)argv}")
914
+    #### detect early: useful for --option-parsing
915
+    zparseopts -M -D -Adiscardme ${every_opts}
916
+    if [[ -n ${(k)discardme[--option-parsing]} ]]; then
917
+        print $1
918
+        if [[ -n "$1" ]]; then
919
+            return 1
920
+        fi
921
+        return 0
922
+    fi
923
+    unset discardme
924
+    if ! zparseopts -M -E -D -Adiscardme ${every_opts}; then
925
+        _failure "Error parsing."
926
+        return 127
927
+    fi
928
+    unset discardme
929
+    subcommand=${1}
930
+    if [[ -z $subcommand ]]; then
931
+        subcommand="__default"
932
+    fi
933
+
934
+    if [[ -z ${(k)option_subcommands[$subcommand]} ]]; then
935
+        _warning "There's no such command \"::1 subcommand::\"." $subcommand
936
+        exitv=127 _failure "Please try -h for help."
937
+    fi
938
+    argv=("${(@)oldstar}")
939
+    unset oldstar
940
+
941
+    ### Parsing global + command-specific options
942
+    # zsh magic: ${=string} will split to multiple arguments when spaces occur
943
+    set -A cmd_opts ${option_main} ${=option_subcommands[$subcommand]}
944
+    # if there is no option, we don't need parsing
945
+    if [[ -n $cmd_opts ]]; then
946
+        zparseopts -M -E -D -Aoption ${cmd_opts}
947
+        if [[ $? != 0 ]]; then
948
+            _warning "Some error occurred during option processing."
949
+            exitv=127 _failure "See \"sdk help\" for more info."
950
+        fi
951
+    fi
952
+    #build option_params (array of arguments) and check if there are unrecognized options
953
+    ok=0
954
+    option_params=()
955
+    for arg in $*; do
956
+        if [[ $arg == '--' || $arg == '-' ]]; then
957
+            ok=1
958
+            continue #it shouldn't be appended to option_params
959
+        elif [[ $arg[1] == '-'  ]]; then
960
+            if [[ $ok == 0 ]]; then
961
+                exitv=127 _failure "Unrecognized option ::1 arg:: for subcommand ::2 subcommand::" $arg $subcommand
962
+            fi
963
+        fi
964
+        option_params+=$arg
965
+    done
966
+    # First parameter actually is the subcommand: delete it and shift
967
+    [[ $subcommand != '__default' ]] && { option_params[1]=(); shift }
968
+
969
+    ### End parsing command-specific options
970
+
971
+    [[ "$option_params" == "" ]] && {
972
+        func "sdk command: ::1 subcommand::" $subcommand
973
+    } || {
974
+        func "sdk command: ::1 subcommand:: ::2 param::" $subcommand $option_params
975
+    }
976
+
977
+}
978
+
979
+# Later: process subcommand
980
+# case "$subcommand" in
981
+# 	help)
982
+# 		print "TODO: help"
983
+# 		;;
984
+# 	__default)
985
+# 		zdump
986
+# 		;;
987
+
988
+#     # Reject unknown command and suggest help
989
+#     *)
990
+#         _warning "Command \"::1 subcommand::\" not recognized." $subcommand
991
+#         _message "Try -h for help."
992
+#         return 1
993
+#         ;;
994
+# esac
995
+
996
+# }}}
997
+
848 998
 # {{{ Helpers
849 999
 
850 1000
 function helper.isfound isfound() {