Let example/jsonptr take a filename arg
diff --git a/example/jsonptr/jsonptr.cc b/example/jsonptr/jsonptr.cc
index 70bc44e..1fa8659 100644
--- a/example/jsonptr/jsonptr.cc
+++ b/example/jsonptr/jsonptr.cc
@@ -66,6 +66,8 @@
*/
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -112,9 +114,9 @@
static const char* eod = "main: end of data";
static const char* usage =
- "Usage: jsonptr -flags < input.json\n"
+ "Usage: jsonptr -flags input.json\n"
"\n"
- "Note the \"<\". It only reads from stdin, not named files.\n"
+ "The input.json filename is optional. If absent, it reads from stdin.\n"
"\n"
"jsonptr is a JSON formatter (pretty-printer) that supports the JSON\n"
"Pointer (RFC 6901) query syntax. It reads UTF-8 JSON from stdin and\n"
@@ -122,7 +124,7 @@
"\n"
"Canonicalized means that e.g. \"abc\\u000A\\tx\\u0177z\" is re-written\n"
"as \"abc\\n\\txŷz\". It does not sort object keys, nor does it reject\n"
- "duplicate keys.\n"
+ "duplicate keys. Canonicalization does not imply Unicode normalization.\n"
"\n"
"Formatted means that arrays' and objects' elements are indented, each\n"
"on its own line. Configure this with the -c / -compact, -i=N / -indent=N\n"
@@ -130,8 +132,8 @@
"\n"
"The -q=etc or -query=etc flag gives an optional JSON Pointer query, to\n"
"print a subset of the input. For example, given RFC 6901 section 5's\n"
- "[sample input](https://tools.ietf.org/rfc/rfc6901.txt), this command:\n"
- " jsonptr -query=/foo/1 < rfc-6901-json-pointer.json\n"
+ "sample input (https://tools.ietf.org/rfc/rfc6901.txt), this command:\n"
+ " jsonptr -query=/foo/1 rfc-6901-json-pointer.json\n"
"will print:\n"
" \"baz\"\n"
"\n"
@@ -145,7 +147,7 @@
"did not find a value, or found an invalid one, this program returns a\n"
"non-zero exit code, but may still print partial output to stdout.\n"
"\n"
- "The [JSON specification](https://json.org/) permits implementations that\n"
+ "The JSON specification (https://json.org/) permits implementations that\n"
"allow duplicate keys, as this one does. This JSON Pointer implementation\n"
"is also greedy, following the first match for each fragment without\n"
"back-tracking. For example, the \"/foo/bar\" query will fail if the root\n"
@@ -160,6 +162,8 @@
bool sandboxed = false;
+int input_file_descriptor = 0; // A 0 default means stdin.
+
#define MAX_INDENT 8
#define INDENT_SPACES_STRING " "
#define INDENT_TAB_STRING "\t"
@@ -530,7 +534,8 @@
if (flags.fail_if_unsandboxed && !sandboxed) {
return "main: unsandboxed";
}
- if (flags.remaining_argc > 0) {
+ const int stdin_fd = 0;
+ if (flags.remaining_argc > ((input_file_descriptor != stdin_fd) ? 1 : 0)) {
return usage;
}
@@ -561,9 +566,8 @@
return "main: src buffer is full";
}
while (true) {
- const int stdin_fd = 0;
- ssize_t n =
- read(stdin_fd, src.data.ptr + src.meta.wi, src.data.len - src.meta.wi);
+ ssize_t n = read(input_file_descriptor, src.data.ptr + src.meta.wi,
+ src.data.len - src.meta.wi);
if (n >= 0) {
src.meta.wi += n;
src.meta.closed = n == 0;
@@ -950,10 +954,15 @@
if (!status_msg) {
return 0;
}
- size_t n = strnlen(status_msg, 2047);
- if (n >= 2047) {
- status_msg = "main: internal error: error message is too long";
+ size_t n;
+ if (status_msg == usage) {
+ n = strlen(status_msg);
+ } else {
n = strnlen(status_msg, 2047);
+ if (n >= 2047) {
+ status_msg = "main: internal error: error message is too long";
+ n = strnlen(status_msg, 2047);
+ }
}
const int stderr_fd = 2;
ignore_return_value(write(stderr_fd, status_msg, n));
@@ -974,6 +983,28 @@
int //
main(int argc, char** argv) {
+ // Look for an input filename (the first non-flag argument) in argv. If there
+ // is one, open it (but do not read from it) before we self-impose a sandbox.
+ //
+ // Flags start with "-", unless it comes after a bare "--" arg.
+ {
+ bool dash_dash = false;
+ int a;
+ for (a = 1; a < argc; a++) {
+ char* arg = argv[a];
+ if ((arg[0] == '-') && !dash_dash) {
+ dash_dash = (arg[1] == '-') && (arg[2] == '\x00');
+ continue;
+ }
+ input_file_descriptor = open(arg, O_RDONLY);
+ if (input_file_descriptor < 0) {
+ fprintf(stderr, "%s: %s\n", arg, strerror(errno));
+ return 1;
+ }
+ break;
+ }
+ }
+
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
sandboxed = true;