]> granicus.if.org Git - jq/blob - src/main.c
Add -b / --binary option for Windows
[jq] / src / main.c
1 #include <assert.h>
2 #include <ctype.h>
3 #include <errno.h>
4 #include <libgen.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #ifdef WIN32
11 #include <windows.h>
12 #include <io.h>
13 #include <fcntl.h>
14 #include <processenv.h>
15 #include <shellapi.h>
16 #include <wchar.h>
17 #include <wtypes.h>
18 #endif
19
20 #if !defined(HAVE_ISATTY) && defined(HAVE__ISATTY)
21 #undef isatty
22 #define isatty _isatty
23 #endif
24
25 #if defined(HAVE_ISATTY) || defined(HAVE__ISATTY)
26 #define USE_ISATTY
27 #endif
28
29 #include "compile.h"
30 #include "jv.h"
31 #include "jq.h"
32 #include "jv_alloc.h"
33 #include "util.h"
34 #include "src/version.h"
35
36 int jq_testsuite(jv lib_dirs, int verbose, int argc, char* argv[]);
37
38 static const char* progname;
39
40 /*
41  * For a longer help message we could use a better option parsing
42  * strategy, one that lets stack options.
43  */
44 static void usage(int code, int keep_it_short) {
45   FILE *f = stderr;
46
47   if (code == 0)
48     f = stdout;
49
50   int ret = fprintf(f,
51     "jq - commandline JSON processor [version %s]\n"
52     "\nUsage:\t%s [options] <jq filter> [file...]\n"
53     "\t%s [options] --args <jq filter> [strings...]\n"
54     "\t%s [options] --jsonargs <jq filter> [JSON_TEXTS...]\n\n"
55     "jq is a tool for processing JSON inputs, applying the given filter to\n"
56     "its JSON text inputs and producing the filter's results as JSON on\n"
57     "standard output.\n\n"
58     "The simplest filter is ., which copies jq's input to its output\n"
59     "unmodified (except for formatting, but note that IEEE754 is used\n"
60     "for number representation internally, with all that that implies).\n\n"
61     "For more advanced filters see the jq(1) manpage (\"man jq\")\n"
62     "and/or https://stedolan.github.io/jq\n\n"
63     "Example:\n\n\t$ echo '{\"foo\": 0}' | jq .\n"
64     "\t{\n\t\t\"foo\": 0\n\t}\n\n",
65     JQ_VERSION, progname, progname, progname);
66   if (keep_it_short) {
67     fprintf(f,
68       "For a listing of options, use %s --help.\n",
69       progname);
70   } else {
71     (void) fprintf(f,
72       "Some of the options include:\n"
73       "  -c               compact instead of pretty-printed output;\n"
74       "  -n               use `null` as the single input value;\n"
75       "  -e               set the exit status code based on the output;\n"
76       "  -s               read (slurp) all inputs into an array; apply filter to it;\n"
77       "  -r               output raw strings, not JSON texts;\n"
78       "  -R               read raw strings, not JSON texts;\n"
79       "  -C               colorize JSON;\n"
80       "  -M               monochrome (don't colorize JSON);\n"
81       "  -S               sort keys of objects on output;\n"
82       "  --tab            use tabs for indentation;\n"
83       "  --arg a v        set variable $a to value <v>;\n"
84       "  --argjson a v    set variable $a to JSON value <v>;\n"
85       "  --slurpfile a f  set variable $a to an array of JSON texts read from <f>;\n"
86       "  --rawfile a f    set variable $a to a string consisting of the contents of <f>;\n"
87       "  --args           remaining arguments are string arguments, not files;\n"
88       "  --jsonargs       remaining arguments are JSON arguments, not files;\n"
89       "  --               terminates argument processing;\n\n"
90       "Named arguments are also available as $ARGS.named[], while\n"
91       "positional arguments are available as $ARGS.positional[].\n"
92       "\nSee the manpage for more options.\n");
93   }
94   exit((ret < 0 && code == 0) ? 2 : code);
95 }
96
97 static void die() {
98   fprintf(stderr, "Use %s --help for help with command-line options,\n", progname);
99   fprintf(stderr, "or see the jq manpage, or online docs  at https://stedolan.github.io/jq\n");
100   exit(2);
101 }
102
103
104
105
106 static int isoptish(const char* text) {
107   return text[0] == '-' && (text[1] == '-' || isalpha(text[1]));
108 }
109
110 static int isoption(const char* text, char shortopt, const char* longopt, size_t *short_opts) {
111   if (text[0] != '-' || text[1] == '-')
112     *short_opts = 0;
113   if (text[0] != '-') return 0;
114
115   // check long option
116   if (text[1] == '-' && !strcmp(text+2, longopt)) return 1;
117   else if (text[1] == '-') return 0;
118
119   // must be short option; check it and...
120   if (!shortopt) return 0;
121   if (strchr(text, shortopt) != NULL) {
122     (*short_opts)++; // ...count it (for option stacking)
123     return 1;
124   }
125   return 0;
126 }
127
128 enum {
129   SLURP                 = 1,
130   RAW_INPUT             = 2,
131   PROVIDE_NULL          = 4,
132   RAW_OUTPUT            = 8,
133   ASCII_OUTPUT          = 32,
134   COLOR_OUTPUT          = 64,
135   NO_COLOR_OUTPUT       = 128,
136   SORTED_OUTPUT         = 256,
137   FROM_FILE             = 512,
138   RAW_NO_LF             = 1024,
139   UNBUFFERED_OUTPUT     = 2048,
140   EXIT_STATUS           = 4096,
141   EXIT_STATUS_EXACT     = 8192,
142   SEQ                   = 16384,
143   RUN_TESTS             = 32768,
144   /* debugging only */
145   DUMP_DISASM           = 65536,
146 };
147 static int options = 0;
148
149 enum {
150     JQ_OK              =  0,
151     JQ_OK_NULL_KIND    = -1, /* exit 0 if --exit-status is not set*/
152     JQ_ERROR_SYSTEM    =  2,
153     JQ_ERROR_COMPILE   =  3,
154     JQ_OK_NO_OUTPUT    = -4, /* exit 0 if --exit-status is not set*/
155     JQ_ERROR_UNKNOWN   =  5,
156 };
157 #define jq_exit_with_status(r)  exit(abs(r))
158 #define jq_exit(r)              exit( r > 0 ? r : 0 )
159
160 static const char *skip_shebang(const char *p) {
161   if (strncmp(p, "#!", sizeof("#!") - 1) != 0)
162     return p;
163   const char *n = strchr(p, '\n');
164   if (n == NULL || n[1] != '#')
165     return p;
166   n = strchr(n + 1, '\n');
167   if (n == NULL || n[1] == '#' || n[1] == '\0' || n[-1] != '\\' || n[-2] == '\\')
168     return p;
169   n = strchr(n + 1, '\n');
170   if (n == NULL)
171     return p;
172   return n+1;
173 }
174
175 static int process(jq_state *jq, jv value, int flags, int dumpopts) {
176   int ret = JQ_OK_NO_OUTPUT; // No valid results && -e -> exit(4)
177   jq_start(jq, value, flags);
178   jv result;
179   while (jv_is_valid(result = jq_next(jq))) {
180     if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) {
181       if (options & ASCII_OUTPUT) {
182         jv_dumpf(jv_copy(result), stdout, JV_PRINT_ASCII);
183       } else {
184         fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result)), stdout);
185       }
186       ret = JQ_OK;
187       jv_free(result);
188     } else {
189       if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND_NULL)
190         ret = JQ_OK_NULL_KIND;
191       else
192         ret = JQ_OK;
193       if (options & SEQ)
194         priv_fwrite("\036", 1, stdout, dumpopts & JV_PRINT_ISATTY);
195       jv_dump(result, dumpopts);
196     }
197     if (!(options & RAW_NO_LF))
198       priv_fwrite("\n", 1, stdout, dumpopts & JV_PRINT_ISATTY);
199     if (options & UNBUFFERED_OUTPUT)
200       fflush(stdout);
201   }
202   if (jq_halted(jq)) {
203     // jq program invoked `halt` or `halt_error`
204     options |= EXIT_STATUS_EXACT;
205     jv exit_code = jq_get_exit_code(jq);
206     if (!jv_is_valid(exit_code))
207       ret = JQ_OK;
208     else if (jv_get_kind(exit_code) == JV_KIND_NUMBER)
209       ret = jv_number_value(exit_code);
210     else
211       ret = JQ_ERROR_UNKNOWN;
212     jv_free(exit_code);
213     jv error_message = jq_get_error_message(jq);
214     if (jv_get_kind(error_message) == JV_KIND_STRING) {
215       fprintf(stderr, "%s", jv_string_value(error_message));
216     } else if (jv_get_kind(error_message) == JV_KIND_NULL) {
217       // Halt with no output
218     } else if (jv_is_valid(error_message)) {
219       error_message = jv_dump_string(jv_copy(error_message), 0);
220       fprintf(stderr, "%s\n", jv_string_value(error_message));
221     } // else no message on stderr; use --debug-trace to see a message
222     fflush(stderr);
223     jv_free(error_message);
224   } else if (jv_invalid_has_msg(jv_copy(result))) {
225     // Uncaught jq exception
226     jv msg = jv_invalid_get_msg(jv_copy(result));
227     jv input_pos = jq_util_input_get_position(jq);
228     if (jv_get_kind(msg) == JV_KIND_STRING) {
229       fprintf(stderr, "jq: error (at %s): %s\n",
230               jv_string_value(input_pos), jv_string_value(msg));
231     } else {
232       msg = jv_dump_string(msg, 0);
233       fprintf(stderr, "jq: error (at %s) (not a string): %s\n",
234               jv_string_value(input_pos), jv_string_value(msg));
235     }
236     ret = JQ_ERROR_UNKNOWN;
237     jv_free(input_pos);
238     jv_free(msg);
239   }
240   jv_free(result);
241   return ret;
242 }
243
244 static void debug_cb(void *data, jv input) {
245   int dumpopts = *(int *)data;
246   jv_dumpf(JV_ARRAY(jv_string("DEBUG:"), input), stderr, dumpopts & ~(JV_PRINT_PRETTY));
247   fprintf(stderr, "\n");
248 }
249
250 #ifdef WIN32
251 int umain(int argc, char* argv[]);
252
253 int wmain(int argc, wchar_t* wargv[]) {
254   size_t arg_sz;
255   char **argv = alloca(argc * sizeof(wchar_t*));
256   for (int i = 0; i < argc; i++) {
257     argv[i] = alloca((arg_sz = WideCharToMultiByte(CP_UTF8,
258                                                    0,
259                                                    wargv[i],
260                                                    -1, 0, 0, 0, 0)));
261     WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], arg_sz, 0, 0);
262   }
263   return umain(argc, argv);
264 }
265
266 int umain(int argc, char* argv[]) {
267 #else /*}*/
268 int main(int argc, char* argv[]) {
269 #endif
270   jq_state *jq = NULL;
271   int ret = JQ_OK_NO_OUTPUT;
272   int compiled = 0;
273   int parser_flags = 0;
274   int nfiles = 0;
275   int last_result = -1; /* -1 = no result, 0=null or false, 1=true */
276   int badwrite;
277   jv ARGS = jv_array(); /* positional arguments */
278   jv program_arguments = jv_object(); /* named arguments */
279
280 #ifdef WIN32
281   fflush(stdout);
282   fflush(stderr);
283   _setmode(fileno(stdout), _O_TEXT | _O_U8TEXT);
284   _setmode(fileno(stderr), _O_TEXT | _O_U8TEXT);
285 #endif
286
287   if (argc) progname = argv[0];
288
289   jq = jq_init();
290   if (jq == NULL) {
291     perror("malloc");
292     ret = JQ_ERROR_SYSTEM;
293     goto out;
294   }
295
296   int dumpopts = JV_PRINT_INDENT_FLAGS(2);
297   const char* program = 0;
298
299   jq_util_input_state *input_state = jq_util_input_init(NULL, NULL); // XXX add err_cb
300
301   int further_args_are_strings = 0;
302   int further_args_are_json = 0;
303   int args_done = 0;
304   int jq_flags = 0;
305   size_t short_opts = 0;
306   jv lib_search_paths = jv_null();
307   for (int i=1; i<argc; i++, short_opts = 0) {
308     if (args_done) {
309       if (further_args_are_strings) {
310         ARGS = jv_array_append(ARGS, jv_string(argv[i]));
311       } else if (further_args_are_json) {
312         ARGS = jv_array_append(ARGS, jv_parse(argv[i]));
313       } else {
314         jq_util_input_add_input(input_state, argv[i]);
315         nfiles++;
316       }
317     } else if (!strcmp(argv[i], "--")) {
318       if (!program) usage(2, 1);
319       args_done = 1;
320     } else if (!isoptish(argv[i])) {
321       if (program) {
322         if (further_args_are_strings) {
323           ARGS = jv_array_append(ARGS, jv_string(argv[i]));
324         } else if (further_args_are_json) {
325           ARGS = jv_array_append(ARGS, jv_parse(argv[i]));
326         } else {
327           jq_util_input_add_input(input_state, argv[i]);
328           nfiles++;
329         }
330       } else {
331         program = argv[i];
332       }
333     } else {
334       if (argv[i][1] == 'L') {
335         if (jv_get_kind(lib_search_paths) == JV_KIND_NULL)
336           lib_search_paths = jv_array();
337         if (argv[i][2] != 0) { // -Lname (faster check than strlen)
338             lib_search_paths = jv_array_append(lib_search_paths, jq_realpath(jv_string(argv[i]+2)));
339         } else if (i >= argc - 1) {
340           fprintf(stderr, "-L takes a parameter: (e.g. -L /search/path or -L/search/path)\n");
341           die();
342         } else {
343           lib_search_paths = jv_array_append(lib_search_paths, jq_realpath(jv_string(argv[i+1])));
344           i++;
345         }
346         continue;
347       }
348
349       if (isoption(argv[i], 's', "slurp", &short_opts)) {
350         options |= SLURP;
351         if (!short_opts) continue;
352       }
353       if (isoption(argv[i], 'r', "raw-output", &short_opts)) {
354         options |= RAW_OUTPUT;
355         if (!short_opts) continue;
356       }
357       if (isoption(argv[i], 'c', "compact-output", &short_opts)) {
358         dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7));
359         if (!short_opts) continue;
360       }
361       if (isoption(argv[i], 'C', "color-output", &short_opts)) {
362         options |= COLOR_OUTPUT;
363         if (!short_opts) continue;
364       }
365       if (isoption(argv[i], 'M', "monochrome-output", &short_opts)) {
366         options |= NO_COLOR_OUTPUT;
367         if (!short_opts) continue;
368       }
369       if (isoption(argv[i], 'a', "ascii-output", &short_opts)) {
370         options |= ASCII_OUTPUT;
371         if (!short_opts) continue;
372       }
373       if (isoption(argv[i], 0, "unbuffered", &short_opts)) {
374         options |= UNBUFFERED_OUTPUT;
375         continue;
376       }
377       if (isoption(argv[i], 'S', "sort-keys", &short_opts)) {
378         options |= SORTED_OUTPUT;
379         if (!short_opts) continue;
380       }
381       if (isoption(argv[i], 'R', "raw-input", &short_opts)) {
382         options |= RAW_INPUT;
383         if (!short_opts) continue;
384       }
385       if (isoption(argv[i], 'n', "null-input", &short_opts)) {
386         options |= PROVIDE_NULL;
387         if (!short_opts) continue;
388       }
389       if (isoption(argv[i], 'f', "from-file", &short_opts)) {
390         options |= FROM_FILE;
391         if (!short_opts) continue;
392       }
393       if (isoption(argv[i], 'j', "join-output", &short_opts)) {
394         options |= RAW_OUTPUT | RAW_NO_LF;
395         if (!short_opts) continue;
396       }
397       if (isoption(argv[i], 'b', "binary", &short_opts)) {
398 #ifdef WIN32
399         fflush(stdout);
400         fflush(stderr);
401         _setmode(fileno(stdin),  _O_BINARY);
402         _setmode(fileno(stdout), _O_BINARY);
403         _setmode(fileno(stderr), _O_BINARY);
404         if (!short_opts) continue;
405 #endif
406       }
407       if (isoption(argv[i], 0, "tab", &short_opts)) {
408         dumpopts &= ~JV_PRINT_INDENT_FLAGS(7);
409         dumpopts |= JV_PRINT_TAB | JV_PRINT_PRETTY;
410         continue;
411       }
412       if (isoption(argv[i], 0, "indent", &short_opts)) {
413         if (i >= argc - 1) {
414           fprintf(stderr, "%s: --indent takes one parameter\n", progname);
415           die();
416         }
417         dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7));
418         int indent = atoi(argv[i+1]);
419         if (indent < -1 || indent > 7) {
420           fprintf(stderr, "%s: --indent takes a number between -1 and 7\n", progname);
421           die();
422         }
423         dumpopts |= JV_PRINT_INDENT_FLAGS(indent);
424         i++;
425         continue;
426       }
427       if (isoption(argv[i], 0, "seq", &short_opts)) {
428         options |= SEQ;
429         continue;
430       }
431       if (isoption(argv[i], 0, "stream", &short_opts)) {
432         parser_flags |= JV_PARSE_STREAMING;
433         continue;
434       }
435       if (isoption(argv[i], 0, "stream-errors", &short_opts)) {
436         parser_flags |= JV_PARSE_STREAM_ERRORS;
437         continue;
438       }
439       if (isoption(argv[i], 'e', "exit-status", &short_opts)) {
440         options |= EXIT_STATUS;
441         if (!short_opts) continue;
442       }
443       // FIXME: For --arg* we should check that the varname is acceptable
444       if (isoption(argv[i], 0, "args", &short_opts)) {
445         further_args_are_strings = 1;
446         further_args_are_json = 0;
447         continue;
448       }
449       if (isoption(argv[i], 0, "jsonargs", &short_opts)) {
450         further_args_are_strings = 0;
451         further_args_are_json = 1;
452         continue;
453       }
454       if (isoption(argv[i], 0, "arg", &short_opts)) {
455         if (i >= argc - 2) {
456           fprintf(stderr, "%s: --arg takes two parameters (e.g. --arg varname value)\n", progname);
457           die();
458         }
459         if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1])))
460           program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), jv_string(argv[i+2]));
461         i += 2; // skip the next two arguments
462         continue;
463       }
464       if (isoption(argv[i], 0, "argjson", &short_opts)) {
465         if (i >= argc - 2) {
466           fprintf(stderr, "%s: --argjson takes two parameters (e.g. --argjson varname text)\n", progname);
467           die();
468         }
469         if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) {
470           jv v = jv_parse(argv[i+2]);
471           if (!jv_is_valid(v)) {
472             fprintf(stderr, "%s: invalid JSON text passed to --argjson\n", progname);
473             die();
474           }
475           program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), v);
476         }
477         i += 2; // skip the next two arguments
478         continue;
479       }
480       if (isoption(argv[i], 0, "argfile", &short_opts) ||
481           isoption(argv[i], 0, "rawfile", &short_opts) ||
482           isoption(argv[i], 0, "slurpfile", &short_opts)) {
483         int raw = isoption(argv[i], 0, "rawfile", &short_opts);
484         const char *which;
485         if (isoption(argv[i], 0, "argfile", &short_opts))
486           which = "argfile";
487         else if (raw)
488           which = "rawfile";
489         else
490           which = "slurpfile";
491         if (i >= argc - 2) {
492           fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname filename)\n", progname, which, which);
493           die();
494         }
495         if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) {
496           jv data = jv_load_file(argv[i+2], raw);
497           if (!jv_is_valid(data)) {
498             data = jv_invalid_get_msg(data);
499             fprintf(stderr, "%s: Bad JSON in --%s %s %s: %s\n", progname, which,
500                     argv[i+1], argv[i+2], jv_string_value(data));
501             jv_free(data);
502             ret = JQ_ERROR_SYSTEM;
503             goto out;
504           }
505           if (strcmp(which, "argfile") == 0 &&
506               jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data)) == 1)
507               data = jv_array_get(data, 0);
508           program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), data);
509         }
510         i += 2; // skip the next two arguments
511         continue;
512       }
513       if (isoption(argv[i],  0,  "debug-dump-disasm", &short_opts)) {
514         options |= DUMP_DISASM;
515         continue;
516       }
517       if (isoption(argv[i],  0,  "debug-trace=all", &short_opts)) {
518         jq_flags |= JQ_DEBUG_TRACE_ALL;
519         if (!short_opts) continue;
520       }
521       if (isoption(argv[i],  0,  "debug-trace", &short_opts)) {
522         jq_flags |= JQ_DEBUG_TRACE;
523         continue;
524       }
525       if (isoption(argv[i], 'h', "help", &short_opts)) {
526         usage(0, 0);
527         if (!short_opts) continue;
528       }
529       if (isoption(argv[i], 'V', "version", &short_opts)) {
530         printf("jq-%s\n", JQ_VERSION);
531         ret = JQ_OK;
532         goto out;
533       }
534       if (isoption(argv[i], 0, "run-tests", &short_opts)) {
535         i++;
536         // XXX Pass program_arguments, even a whole jq_state *, through;
537         // could be useful for testing
538         ret = jq_testsuite(lib_search_paths,
539                            (options & DUMP_DISASM) || (jq_flags & JQ_DEBUG_TRACE),
540                            argc - i, argv + i);
541         goto out;
542       }
543
544       // check for unknown options... if this argument was a short option
545       if (strlen(argv[i]) != short_opts + 1) {
546         fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]);
547         die();
548       }
549     }
550   }
551
552 #ifdef USE_ISATTY
553   if (isatty(STDOUT_FILENO)) {
554 #ifndef WIN32
555     dumpopts |= JV_PRINT_ISATTY | JV_PRINT_COLOR;
556 #else
557   /* Verify we actually have the console, as the NUL device is also regarded as
558      tty.  Windows can handle color if ANSICON (or ConEmu) is installed, or
559      Windows 10 supports the virtual terminal */
560     DWORD mode;
561     HANDLE con = GetStdHandle(STD_OUTPUT_HANDLE);
562     if (GetConsoleMode(con, &mode)) {
563       dumpopts |= JV_PRINT_ISATTY;
564       if (getenv("ANSICON") != NULL ||
565           SetConsoleMode(con, mode | 4/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/))
566         dumpopts |= JV_PRINT_COLOR;
567     }
568 #endif
569   }
570 #endif
571   if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED;
572   if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII;
573   if (options & COLOR_OUTPUT) dumpopts |= JV_PRINT_COLOR;
574   if (options & NO_COLOR_OUTPUT) dumpopts &= ~JV_PRINT_COLOR;
575
576   if (getenv("JQ_COLORS") != NULL && !jq_set_colors(getenv("JQ_COLORS")))
577       fprintf(stderr, "Failed to set $JQ_COLORS\n");
578
579   if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) {
580     // Default search path list
581     lib_search_paths = JV_ARRAY(jv_string("~/.jq"),
582                                 jv_string("$ORIGIN/../lib/jq"),
583                                 jv_string("$ORIGIN/lib"));
584   }
585   jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_search_paths);
586
587   char *origin = strdup(argv[0]);
588   if (origin == NULL) {
589     fprintf(stderr, "Error: out of memory\n");
590     exit(1);
591   }
592   jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string(dirname(origin)));
593   free(origin);
594
595   if (strchr(JQ_VERSION, '-') == NULL)
596     jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string(JQ_VERSION));
597   else
598     jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string_fmt("%.*s-master", (int)(strchr(JQ_VERSION, '-') - JQ_VERSION), JQ_VERSION));
599
600 #ifdef USE_ISATTY
601   if (!program && (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO)))
602     program = ".";
603 #endif
604
605   if (!program) usage(2, 1);
606
607   if (options & FROM_FILE) {
608     char *program_origin = strdup(program);
609     if (program_origin == NULL) {
610       perror("malloc");
611       exit(2);
612     }
613
614     jv data = jv_load_file(program, 1);
615     if (!jv_is_valid(data)) {
616       data = jv_invalid_get_msg(data);
617       fprintf(stderr, "%s: %s\n", progname, jv_string_value(data));
618       jv_free(data);
619       ret = JQ_ERROR_SYSTEM;
620       goto out;
621     }
622     jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(program_origin))));
623     ARGS = JV_OBJECT(jv_string("positional"), ARGS,
624                      jv_string("named"), jv_copy(program_arguments));
625     program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_copy(ARGS));
626     compiled = jq_compile_args(jq, skip_shebang(jv_string_value(data)), jv_copy(program_arguments));
627     free(program_origin);
628     jv_free(data);
629   } else {
630     jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string("."))); // XXX is this good?
631     ARGS = JV_OBJECT(jv_string("positional"), ARGS,
632                      jv_string("named"), jv_copy(program_arguments));
633     program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_copy(ARGS));
634     compiled = jq_compile_args(jq, program, jv_copy(program_arguments));
635   }
636   if (!compiled){
637     ret = JQ_ERROR_COMPILE;
638     goto out;
639   }
640
641   if (options & DUMP_DISASM) {
642     jq_dump_disassembly(jq, 0);
643     printf("\n");
644   }
645
646   if ((options & SEQ))
647     parser_flags |= JV_PARSE_SEQ;
648
649   if ((options & RAW_INPUT))
650     jq_util_input_set_parser(input_state, NULL, (options & SLURP) ? 1 : 0);
651   else
652     jq_util_input_set_parser(input_state, jv_parser_new(parser_flags), (options & SLURP) ? 1 : 0);
653
654   // Let jq program read from inputs
655   jq_set_input_cb(jq, jq_util_input_next_input_cb, input_state);
656
657   // Let jq program call `debug` builtin and have that go somewhere
658   jq_set_debug_cb(jq, debug_cb, &dumpopts);
659
660   if (nfiles == 0)
661     jq_util_input_add_input(input_state, "-");
662
663   if (options & PROVIDE_NULL) {
664     ret = process(jq, jv_null(), jq_flags, dumpopts);
665   } else {
666     jv value;
667     while (jq_util_input_errors(input_state) == 0 &&
668            (jv_is_valid((value = jq_util_input_next_input(input_state))) || jv_invalid_has_msg(jv_copy(value)))) {
669       if (jv_is_valid(value)) {
670         ret = process(jq, value, jq_flags, dumpopts);
671         if (ret <= 0 && ret != JQ_OK_NO_OUTPUT)
672           last_result = (ret != JQ_OK_NULL_KIND);
673         continue;
674       }
675
676       // Parse error
677       jv msg = jv_invalid_get_msg(value);
678       if (!(options & SEQ)) {
679         // --seq -> errors are not fatal
680         ret = JQ_OK_NO_OUTPUT;
681         fprintf(stderr, "parse error: %s\n", jv_string_value(msg));
682         jv_free(msg);
683         break;
684       }
685       fprintf(stderr, "ignoring parse error: %s\n", jv_string_value(msg));
686       jv_free(msg);
687     }
688   }
689
690   if (jq_util_input_errors(input_state) != 0)
691     ret = JQ_ERROR_SYSTEM;
692
693 out:
694   badwrite = ferror(stdout);
695   if (fclose(stdout)!=0 || badwrite) {
696     fprintf(stderr,"Error: writing output failed: %s\n", strerror(errno));
697     ret = JQ_ERROR_SYSTEM;
698   }
699
700   jv_free(ARGS);
701   jv_free(program_arguments);
702   jq_util_input_free(&input_state);
703   jq_teardown(&jq);
704
705   if (options & (EXIT_STATUS|EXIT_STATUS_EXACT)) {
706     if (ret != JQ_OK_NO_OUTPUT)
707       jq_exit_with_status(ret);
708     else
709       switch (last_result) {
710         case -1: jq_exit_with_status(JQ_OK_NO_OUTPUT);
711         case  0: jq_exit_with_status(JQ_OK_NULL_KIND);
712         default: jq_exit_with_status(JQ_OK);
713       }
714   } else
715     jq_exit(ret);
716 }