@@ -34,6 +34,7 @@ using namespace c4;
3434struct Args
3535{
3636 c4::csubstr filename = " -" ;
37+ c4::csubstr output = {};
3738 c4::yml::id_type reserve_size = false ;
3839 bool resolve_refs = false ;
3940 bool keep_refs = false ;
@@ -54,6 +55,7 @@ Parse yaml from file (or stdin when file is `-`) and emit to stdout.
5455
5556Options:
5657
58+ -h,--help print this message
5759 -e [N],--reserve [N] reserve tree size before parsing (default: N=%d):
5860 0=do not reserve
5961 1=reserve by estimating size
@@ -63,9 +65,10 @@ Parse yaml from file (or stdin when file is `-`) and emit to stdout.
6365 -p,--print-tree print parsed rapidyaml tree before emitting (default: %s)
6466 -q,--quiet do not emit (default: %s)
6567 -j,--json emit json instead of yaml (default: %s)
66- -s,--string emit to string before dumping to stdout.
68+ -s,--string emit to string before dumping to stdout/file .
6769 otherwise, emit directly to stdout (default: %s)
6870 -t,--timed time sections (print timings to stderr) (default: %s)
71+ -o,--output <filename> emit to the given filename (default: %s)
6972
7073)" ,
7174 exename,
@@ -76,20 +79,15 @@ Parse yaml from file (or stdin when file is `-`) and emit to stdout.
7679 defs.quiet ? " do not emit" : " emit" ,
7780 defs.emit_as_json ? " emit as json" : " emit as yaml" ,
7881 defs.emit_to_string ? " emit to string" : " no" ,
79- defs.timed_sections ? " show timings" : " no"
82+ defs.timed_sections ? " show timings" : " no" ,
83+ defs.output .empty () ? " no" : defs.output .str
8084 );
8185}
8286bool timing_enabled = false ;
83- Args parse_args (int argc, const char *argv[])
87+ bool parse_args (int argc, const char *argv[], Args &args )
8488{
85- if (argc < 2 )
86- {
87- print_usage (argv[0 ]);
88- c4::yml::error (" missing filename (use - to read from stdin)" );
89- }
90- Args args = {};
91- args.filename = c4::to_csubstr (argv[argc - 1 ]);
92- for (int i = 1 ; i+1 < argc; ++i)
89+ args = {};
90+ for (int i = 1 ; i < argc; ++i)
9391 {
9492 c4::csubstr arg = c4::to_csubstr (argv[i]);
9593 auto arg0_is = [&](c4::csubstr argshort, c4::csubstr arglong){
@@ -106,20 +104,32 @@ Args parse_args(int argc, const char *argv[])
106104 };
107105 if /* */ (arg1_is (" -e" , " --reserve" )) C4_CHECK (c4::from_chars (c4::to_csubstr (argv[++i]), &args.reserve_size ));
108106 else if (arg1_is (" -r" , " --resolve" )) args.resolve_refs = true ;
107+ else if (arg1_is (" -o" , " --output" )) args.output = c4::to_csubstr (argv[++i]);
109108 else if (arg0_is (" -k" , " --keep-refs" )) args.keep_refs = true ;
110109 else if (arg0_is (" -p" , " --print-tree" )) args.print_tree = true ;
111110 else if (arg0_is (" -q" , " --quiet" )) args.quiet = true ;
112111 else if (arg0_is (" -j" , " --json" )) args.emit_as_json = true ;
113112 else if (arg0_is (" -s" , " --string" )) args.emit_to_string = true ;
114113 else if (arg0_is (" -t" , " --timed" )) args.timed_sections = true ;
115- else
114+ else if (arg0_is (" -h" , " --help" ))
115+ {
116+ print_usage (argv[0 ]);
117+ return false ;
118+ }
119+ else if (i+1 < argc)
116120 {
117121 print_usage (argv[0 ]);
118122 c4::yml::error (" unknown argument" );
119123 }
120124 }
121125 timing_enabled = args.timed_sections ;
122- return args;
126+ if (argc < 2 )
127+ {
128+ print_usage (argv[0 ]);
129+ c4::yml::error (" missing filename (use - to read from stdin)" );
130+ }
131+ args.filename = c4::to_csubstr (argv[argc - 1 ]);
132+ return true ;
123133}
124134
125135void read_file (csubstr filename, std::string *buf)
@@ -167,6 +177,20 @@ void emit_json_docs(yml::Tree const& tree, std::string *dst=nullptr)
167177 emitnode (doc);
168178}
169179
180+ void emit_json_docs (yml::Tree const & tree, FILE *output)
181+ {
182+ auto emitnode = [&](yml::ConstNodeRef node){
183+ emit_json (node, output);
184+ (void )fputc (' \n ' , output);
185+ };
186+ yml::ConstNodeRef root = tree.rootref ();
187+ if (!root.is_stream ())
188+ emitnode (root);
189+ else
190+ for (yml::ConstNodeRef doc : root.children ())
191+ emitnode (doc);
192+ }
193+
170194void report_error (const char * msg, size_t length, yml::Location loc, FILE *f)
171195{
172196 if (!loc.name .empty ())
@@ -287,18 +311,36 @@ void process_file(Args const& args)
287311 }
288312 else if (!args.quiet )
289313 {
290- TS (emit_to_stdout);
291- if (!args.emit_as_json )
292- yml::emit_yaml (tree);
314+ if (args.output .empty ())
315+ {
316+ TS (emit_to_stdout);
317+ if (!args.emit_as_json )
318+ yml::emit_yaml (tree);
319+ else
320+ emit_json_docs (tree);
321+ }
293322 else
294- emit_json_docs (tree);
323+ {
324+ FILE *output = fopen (args.output .str , " wb" );
325+ if (!output) c4::yml::error (" could not open file" );
326+ {
327+ TS (emit_to_file);
328+ if (!args.emit_as_json )
329+ yml::emit_yaml (tree, output);
330+ else
331+ emit_json_docs (tree, output);
332+ }
333+ (void )fclose (output);
334+ }
295335 }
296336}
297337// LCOV_EXCL_STOP
298338
299339int main (int argc, const char *argv[])
300340{
301- const Args args = parse_args (argc, argv);
341+ Args args;
342+ if (!parse_args (argc, argv, args))
343+ return 0 ;
302344 TS (TOTAL);
303345 set_callbacks (create_custom_callbacks ());
304346 C4_IF_EXCEPTIONS_ (try , if (setjmp (jmp_env) == 0 ))
0 commit comments