2022-02-21 00:25:46 +03:00
|
|
|
include "internal";
|
2022-07-16 19:39:57 +03:00
|
|
|
include "interp";
|
2022-02-21 00:25:46 +03:00
|
|
|
include "query";
|
|
|
|
include "eval";
|
|
|
|
include "repl";
|
2022-03-03 15:37:35 +03:00
|
|
|
include "decode";
|
|
|
|
include "funcs";
|
|
|
|
include "options";
|
|
|
|
include "args";
|
2022-02-21 00:25:46 +03:00
|
|
|
|
|
|
|
# TODO: variants, values, keywords?
|
|
|
|
# TODO: store some other way?
|
|
|
|
def _help_functions:
|
|
|
|
{ length: {
|
|
|
|
summary: "Length of string, array, object, etc",
|
|
|
|
doc:
|
|
|
|
"- For string number of unicode codepoints
|
|
|
|
- For array number of elements in array
|
|
|
|
- For object number of key-value pairs
|
|
|
|
- For null zero
|
|
|
|
- For number the number itself
|
|
|
|
- For boolean is an error
|
|
|
|
",
|
|
|
|
examples:
|
|
|
|
[ [[1,2,3], "length"]
|
|
|
|
, ["abc", "length"]
|
|
|
|
, [{a: 1, b: 2}, "length"]
|
|
|
|
, [null, "length"]
|
|
|
|
, [123, "length"]
|
|
|
|
, [true, "length"]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"..": {
|
|
|
|
summary: "Recursive descent of .",
|
|
|
|
doc:
|
|
|
|
"Recursively descend . and output each value.
|
|
|
|
Same as recurse without argument.
|
|
|
|
",
|
|
|
|
examples:
|
|
|
|
[ ["a", ".."]
|
|
|
|
, [[1,2,3], ".."]
|
|
|
|
, [{a: 1, b: {c: 3}}, ".."]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
empty: {
|
|
|
|
summary: "Output nothing",
|
|
|
|
doc:
|
|
|
|
"Output no value, not even null, and cause backtrack.
|
|
|
|
",
|
|
|
|
examples:
|
|
|
|
[ ["empty"]
|
|
|
|
, ["[1,empty,2]"]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
def help($_): error("help must be alone or last in pipeline. ex: help(length) or ... | help");
|
|
|
|
def help: help(null);
|
|
|
|
|
2021-12-09 19:15:21 +03:00
|
|
|
def _help_format_enrich($arg0; $f; $include_basic):
|
|
|
|
( if $include_basic then
|
|
|
|
.examples +=
|
2022-05-26 13:51:54 +03:00
|
|
|
[ {comment: "Decode file as \($f.name)", shell: "fq -d \($f.name) . file"}
|
2021-12-09 19:15:21 +03:00
|
|
|
, {comment: "Decode value as \($f.name)", expr: "\($f.name)"}
|
|
|
|
]
|
|
|
|
end
|
|
|
|
| if $f.decode_in_arg then
|
|
|
|
.examples +=
|
2022-05-26 13:51:54 +03:00
|
|
|
[ { comment: "Decode file using \($f.name) options"
|
|
|
|
, shell: "\($arg0) -d \($f.name)\($f.decode_in_arg | to_entries | map(" -o ", .key, "=", (.value | tojson)) | join("")) . file"
|
2021-12-09 19:15:21 +03:00
|
|
|
}
|
|
|
|
, { comment: "Decode value as \($f.name)"
|
2022-12-21 15:59:54 +03:00
|
|
|
, expr: "\($f.name)(\($f.decode_in_arg | to_jq))"
|
2021-12-09 19:15:21 +03:00
|
|
|
}
|
|
|
|
]
|
|
|
|
end
|
|
|
|
);
|
|
|
|
|
2022-03-03 15:37:35 +03:00
|
|
|
def _help($arg0; $topic):
|
|
|
|
( $topic
|
|
|
|
| if . == "usage" then
|
|
|
|
"Usage: \($arg0) [OPTIONS] [--] [EXPR] [FILE...]"
|
|
|
|
elif . == "example_usage" then
|
|
|
|
( "Example usages:"
|
|
|
|
, " fq . file"
|
|
|
|
, " fq d file"
|
|
|
|
, " fq tovalue file"
|
2022-12-21 15:59:54 +03:00
|
|
|
, " fq -r to_toml file.yml"
|
2022-07-30 21:21:35 +03:00
|
|
|
, " fq -s -d html 'map(.html.head.title?)' *.html"
|
2022-03-03 15:37:35 +03:00
|
|
|
, " cat file.cbor | fq -d cbor torepr"
|
|
|
|
, " fq 'grep(\"^main$\") | parent' /bin/ls"
|
2022-07-30 21:21:35 +03:00
|
|
|
, " fq -r 'grep_by(.protocol==\"icmp\").source_ip | tovalue' *.pcap"
|
|
|
|
, " fq -i"
|
2022-03-03 15:37:35 +03:00
|
|
|
)
|
|
|
|
elif . == "banner" then
|
|
|
|
( "fq - jq for binary formats"
|
2022-07-30 21:21:35 +03:00
|
|
|
, "Tool, language and decoders for working with binary data."
|
2022-03-03 15:37:35 +03:00
|
|
|
, "For more information see https://github.com/wader/fq"
|
|
|
|
)
|
|
|
|
elif . == "args" then
|
|
|
|
args_help_text(_opt_cli_opts)
|
2021-12-09 19:15:21 +03:00
|
|
|
elif . == "options" then
|
2022-03-03 15:37:35 +03:00
|
|
|
( [ ( options
|
2021-12-09 19:15:21 +03:00
|
|
|
| _opt_cli_arg_from_options
|
2022-03-03 15:37:35 +03:00
|
|
|
)
|
|
|
|
| to_entries[]
|
|
|
|
| [(.key+" "), .value | tostring]
|
|
|
|
]
|
|
|
|
| table(
|
|
|
|
.;
|
|
|
|
map(
|
|
|
|
( . as $rc
|
|
|
|
# right pad format name to align description
|
|
|
|
| if .column == 0 then .string | rpad(" "; $rc.maxwidth)
|
|
|
|
else $rc.string
|
|
|
|
end
|
|
|
|
)
|
|
|
|
) | join("")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
elif . == "formats" then
|
|
|
|
( [ formats
|
2021-12-09 19:15:21 +03:00
|
|
|
| to_entries[]
|
|
|
|
| [(.key+" "), .value.description]
|
|
|
|
]
|
2022-03-03 15:37:35 +03:00
|
|
|
| table(
|
|
|
|
.;
|
|
|
|
map(
|
|
|
|
( . as $rc
|
|
|
|
# right pad format name to align description
|
|
|
|
| if .column == 0 then .string | rpad(" "; $rc.maxwidth)
|
|
|
|
else $rc.string
|
|
|
|
end
|
|
|
|
)
|
|
|
|
) | join("")
|
|
|
|
)
|
|
|
|
)
|
2021-12-09 19:15:21 +03:00
|
|
|
elif _registry.formats | has($topic) then
|
|
|
|
( _registry.formats[$topic] as $f
|
|
|
|
| (_format_func($f.name; "_help")? // {} | _help_format_enrich($arg0; $f; true)) as $fhelp
|
2022-09-10 19:28:54 +03:00
|
|
|
| ((_registry.files[][] | select(.name=="\($topic).md").data) // false) as $doc
|
2021-12-09 19:15:21 +03:00
|
|
|
| "\($f.name): \($f.description) decoder"
|
2022-09-22 19:32:13 +03:00
|
|
|
, ""
|
2021-12-09 19:15:21 +03:00
|
|
|
, if $f.decode_in_arg then
|
|
|
|
( $f.decode_in_arg
|
|
|
|
| to_entries
|
2023-03-04 11:53:33 +03:00
|
|
|
| map([" \(.key)=\(.value | tojson) ", $f.decode_in_arg_doc[.key]])
|
2022-09-22 19:32:13 +03:00
|
|
|
| "Options"
|
|
|
|
, "======="
|
2022-09-10 19:28:54 +03:00
|
|
|
, ""
|
2021-12-09 19:15:21 +03:00
|
|
|
, table(
|
|
|
|
.;
|
|
|
|
map(
|
|
|
|
( . as $rc
|
|
|
|
# right pad format name to align description
|
|
|
|
| if .column == 0 then .string | rpad(" "; $rc.maxwidth)
|
|
|
|
else $rc.string
|
|
|
|
end
|
|
|
|
)
|
|
|
|
) | join("")
|
|
|
|
)
|
2022-09-22 19:32:13 +03:00
|
|
|
, ""
|
2021-12-09 19:15:21 +03:00
|
|
|
)
|
|
|
|
else empty
|
|
|
|
end
|
2022-09-22 19:32:13 +03:00
|
|
|
, "Decode examples"
|
|
|
|
, "==============="
|
2022-09-10 19:28:54 +03:00
|
|
|
, ""
|
2021-12-09 19:15:21 +03:00
|
|
|
, ( $fhelp.examples[]
|
2022-09-10 19:28:54 +03:00
|
|
|
| " # \(.comment)"
|
2021-12-09 19:15:21 +03:00
|
|
|
, if .shell then " $ \(.shell)"
|
|
|
|
elif .expr then " ... | \(.expr)"
|
|
|
|
else empty
|
|
|
|
end
|
|
|
|
)
|
2022-09-10 19:28:54 +03:00
|
|
|
, ""
|
2023-03-03 01:18:31 +03:00
|
|
|
, if $doc then $doc | markdown | _markdown_to_text(options.width; -2)
|
2021-12-09 19:15:21 +03:00
|
|
|
else empty
|
|
|
|
end
|
|
|
|
)
|
|
|
|
elif _help_functions | has($topic) then
|
|
|
|
( _help_functions[$topic] as $hf
|
|
|
|
| "\($topic): \($hf.summary)"
|
|
|
|
, $hf.doc
|
|
|
|
, if $hf.examples then
|
|
|
|
( "Examples:"
|
|
|
|
, ( $hf.examples[]
|
|
|
|
| . as $e
|
|
|
|
| if length == 1 then
|
|
|
|
( "> \($e[0])"
|
2022-07-16 19:39:57 +03:00
|
|
|
, (null | try (_eval($e[0]; {}) | tojson) catch "error: \(.)")
|
2021-12-09 19:15:21 +03:00
|
|
|
)
|
|
|
|
else
|
|
|
|
( "> \($e[0] | tojson) | \($e[1])"
|
2022-07-16 19:39:57 +03:00
|
|
|
, ($e[0] | try (_eval($e[1]; {}) | tojson) catch "error: \(.)")
|
2021-12-09 19:15:21 +03:00
|
|
|
)
|
|
|
|
end
|
|
|
|
)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
)
|
2022-03-03 15:37:35 +03:00
|
|
|
else
|
2021-12-09 19:15:21 +03:00
|
|
|
# help(unknown)
|
|
|
|
# TODO: check builtin
|
|
|
|
( ( . # TODO: extract
|
|
|
|
| builtins
|
|
|
|
| map(split("/") | {key: .[0], value: true})
|
|
|
|
| from_entries
|
|
|
|
) as $builtins
|
|
|
|
| ( . # TODO: extract
|
|
|
|
| scope
|
|
|
|
| map({key: ., value: true})
|
|
|
|
| from_entries
|
|
|
|
) as $scope
|
|
|
|
| if $builtins | has($topic) then
|
|
|
|
"\($topic) is builtin function"
|
|
|
|
elif $scope | has($topic) then
|
|
|
|
"\($topic) is a function or variable"
|
|
|
|
else
|
|
|
|
"don't know what \($topic) is "
|
|
|
|
end
|
|
|
|
| println
|
|
|
|
)
|
2022-03-03 15:37:35 +03:00
|
|
|
end
|
|
|
|
);
|
|
|
|
|
2022-02-21 00:25:46 +03:00
|
|
|
# TODO: refactor
|
|
|
|
def _help_slurp($query):
|
|
|
|
def _name:
|
|
|
|
if _query_is_func then _query_func_name
|
2021-12-09 19:15:21 +03:00
|
|
|
elif _query_is_string then _query_string_str
|
2022-02-21 00:25:46 +03:00
|
|
|
else _query_tostring
|
|
|
|
end;
|
|
|
|
if $query.orig | _query_is_func then
|
|
|
|
( ($query.orig | _query_func_args) as $args
|
|
|
|
| ($args | length) as $argc
|
|
|
|
| if $args == null then
|
|
|
|
# help
|
|
|
|
( "Type expression to evaluate"
|
2021-12-09 19:15:21 +03:00
|
|
|
, "help(...) Help for topic. Ex: help(mp4), help(\"mp4\")"
|
2022-02-21 00:25:46 +03:00
|
|
|
, "\\t Completion"
|
|
|
|
, "Up/Down History"
|
|
|
|
, "... | repl Start a new REPL"
|
2021-12-09 19:15:21 +03:00
|
|
|
, "^C Interrupt execution"
|
2022-02-21 00:25:46 +03:00
|
|
|
, "^D Exit REPL"
|
|
|
|
) | println
|
|
|
|
elif $argc == 1 then
|
2021-12-09 19:15:21 +03:00
|
|
|
( _help("fq"; $args[0] | _name)
|
|
|
|
| println
|
2022-02-21 00:25:46 +03:00
|
|
|
)
|
|
|
|
else
|
|
|
|
_eval_error("compile"; "help must be last in pipeline. ex: help(length) or ... | help")
|
|
|
|
end
|
|
|
|
)
|
|
|
|
else
|
|
|
|
# ... | help
|
|
|
|
# TODO: check builtin
|
|
|
|
( _repl_slurp_eval($query.rewrite) as $outputs
|
|
|
|
| "value help"
|
|
|
|
, $outputs
|
2022-03-11 18:22:23 +03:00
|
|
|
| display
|
2022-02-21 00:25:46 +03:00
|
|
|
)
|
|
|
|
end;
|