@@ -54,7 +54,7 @@ static const char * const usage_msg =
54
54
"\t-V\t\tprint version string and exit\n"
55
55
"\t-t\t\tperform tests of JSON decode/encode functionality\n"
56
56
"\t-n\t\tdo not output newline after encode output (def: print final newline)\n"
57
- "\t-N\t\tignore final newline in input \n"
57
+ "\t-N\t\tignore all newline characters \n"
58
58
"\t-Q\t\tdo not encode double quotes that enclose the concatenation of args (def: do encode)\n"
59
59
"\t-e\t\tdo not output double quotes that enclose each arg (def: do not remove)\n"
60
60
"\n"
@@ -78,7 +78,7 @@ static const char * const usage_msg =
78
78
*/
79
79
static void usage (int exitcode , char const * prog , char const * str ) __attribute__((noreturn ));
80
80
static struct jstring * jstrencode_stream (FILE * in_stream , bool skip_enclosing , bool ignore_first , bool remove_last ,
81
- bool skip_eol_nl );
81
+ bool ignore_nl );
82
82
static struct jstring * add_encoded_string (char * string , size_t bufsiz );
83
83
static void free_json_encoded_strings (void );
84
84
@@ -178,6 +178,68 @@ free_json_encoded_strings(void)
178
178
}
179
179
180
180
181
+ /*
182
+ * dup_without_nl - duplicate a buffer and remove all newlines
183
+ *
184
+ * given:
185
+ * input original input buffer
186
+ * inputlen pointer to the length of the input buffer
187
+ *
188
+ * returns:
189
+ * malloced buffer without any newlines
190
+ * NULL ==> malloc error, or NULL argument
191
+ *
192
+ * NOTE: If newlines were removed in the copy, then *inputlen will be updated
193
+ * to account for the new length.
194
+ */
195
+ static char *
196
+ dup_without_nl (char * input , size_t * inputlen )
197
+ {
198
+ char * dup_input = NULL ; /* duplicate of input */
199
+ size_t i ;
200
+ size_t j ;
201
+
202
+ /*
203
+ * firewall
204
+ */
205
+ if (input == NULL ) {
206
+ warn (__func__ , "input is NULL" );
207
+ return NULL ;
208
+ }
209
+ if (inputlen == NULL ) {
210
+ warn (__func__ , "inputlen is NULL" );
211
+ return NULL ;
212
+ }
213
+
214
+ /*
215
+ * copy input removing all newlines
216
+ */
217
+ dup_input = malloc (* inputlen + 1 ); /* + 1 for guard NUL byte */
218
+ if (dup_input == NULL ) {
219
+ warn (__func__ , "malloc of input failed" );
220
+ return NULL ;
221
+ }
222
+ for (i = 0 , j = 0 ; i < * inputlen ; ++ i ) {
223
+ if (input [i ] != '\n' ) {
224
+ dup_input [j ++ ] = input [i ];
225
+ }
226
+ }
227
+ dup_input [j ] = '\0' ; /* paranoia */
228
+
229
+ /*
230
+ * update inputlen if we removed newlines
231
+ */
232
+ if (j != i ) {
233
+ * inputlen = j ;
234
+ }
235
+
236
+ /*
237
+ * return success
238
+ */
239
+ return dup_input ;
240
+ }
241
+
242
+
181
243
/*
182
244
* jstrencode_stream - encode an open file stream into a char *
183
245
*
@@ -189,7 +251,7 @@ free_json_encoded_strings(void)
189
251
* false ==> do not remove
190
252
* remove_last remove any final double quote
191
253
* false ==> do not remove
192
- * skip_eol_nl true ==> skip final newline
254
+ * ignore_nl true ==> ignore all newline characters
193
255
*
194
256
* returns:
195
257
* allocated struct jstring * ==> encoding was successful,
@@ -199,14 +261,15 @@ free_json_encoded_strings(void)
199
261
* encoded JSON strings.
200
262
*/
201
263
static struct jstring *
202
- jstrencode_stream (FILE * in_stream , bool skip_enclosing , bool ignore_first , bool remove_last , bool skip_eol_nl )
264
+ jstrencode_stream (FILE * in_stream , bool skip_enclosing , bool ignore_first , bool remove_last , bool ignore_nl )
203
265
{
204
266
char * orig_input = NULL ; /* argument to process */
205
267
char * input = NULL ; /* possibly updated orig_input */
206
268
size_t inputlen = 0 ; /* length of input buffer */
207
269
char * buf = NULL ; /* encode buffer */
208
270
size_t bufsiz ; /* length of the buffer */
209
271
struct jstring * jstr = NULL ; /* for jstring list */
272
+ char * dup_input = NULL ; /* duplicate of input w/o newlines */
210
273
211
274
/*
212
275
* firewall
@@ -226,13 +289,30 @@ jstrencode_stream(FILE *in_stream, bool skip_enclosing, bool ignore_first, bool
226
289
return NULL ;
227
290
}
228
291
dbg (DBG_MED , "stream read length: %ju" , (uintmax_t )inputlen );
292
+
293
+ /*
294
+ * if -N, remove all newlines from data
295
+ */
296
+ if (ignore_nl ) {
297
+
298
+ /*
299
+ * copy input removing all newlines, update inputlen if needed
300
+ */
301
+ dup_input = dup_without_nl (orig_input , & inputlen );
302
+ if (dup_input == NULL ) {
303
+ err (11 , __func__ , "dup_without_nl failed" );
304
+ not_reached ();
305
+ }
306
+
307
+ /*
308
+ * replace input with the duplicate w/o newline input if needed
309
+ */
310
+ free (orig_input );
311
+ orig_input = dup_input ;
312
+ }
229
313
input = orig_input ;
230
314
dbg (DBG_HIGH , "stream data is: <%s>" , input );
231
315
232
- if (skip_eol_nl && inputlen > 0 && input [inputlen - 1 ] == '\n' ) {
233
- input [inputlen - 1 ] = '\0' ;
234
- -- inputlen ;
235
- }
236
316
/*
237
317
* case: we need to remove BOTH a leading and a trailing double quote
238
318
*/
@@ -335,18 +415,19 @@ main(int argc, char **argv)
335
415
size_t outputlen ; /* length of write of encode buffer */
336
416
bool success = true; /* true ==> encoding OK, false ==> error while encoding */
337
417
bool nloutput = true; /* true ==> output newline after JSON encode */
338
- bool skip_eol_nl = false; /* true ==> ignore final newline when encoding */
418
+ bool ignore_nl = false; /* true ==> ignore all newlines when encoding */
339
419
bool skip_concat_quotes = false; /* true ==> skip enclosing quotes around the arg concatenation */
340
420
bool skip_each = false; /* true ==> skip enclosing quotes around each arg */
341
421
int ret ; /* libc return code */
342
422
int i ;
343
423
struct jstring * jstr = NULL ; /* to iterate through list */
424
+ char * dup_input = NULL ; /* duplicate of input w/o newlines */
344
425
345
426
/*
346
427
* set locale
347
428
*/
348
429
if (setlocale (LC_ALL , "" ) == NULL ) {
349
- err (11 , __func__ , "failed to set locale" );
430
+ err (12 , __func__ , "failed to set locale" );
350
431
not_reached ();
351
432
}
352
433
@@ -394,7 +475,7 @@ main(int argc, char **argv)
394
475
nloutput = false;
395
476
break ;
396
477
case 'N' :
397
- skip_eol_nl = true;
478
+ ignore_nl = true;
398
479
break ;
399
480
case 'Q' :
400
481
skip_concat_quotes = true;
@@ -444,7 +525,7 @@ main(int argc, char **argv)
444
525
*/
445
526
jstr = jstrencode_stream (stdin , skip_each ,
446
527
(skip_concat_quotes && i == optind ),
447
- (skip_concat_quotes && i == argc - 1 ), skip_eol_nl );
528
+ (skip_concat_quotes && i == argc - 1 ), ignore_nl );
448
529
if (!jstr ) {
449
530
warn (__func__ , "failed to encode string from stdin" );
450
531
success = false;
@@ -463,11 +544,25 @@ main(int argc, char **argv)
463
544
}
464
545
465
546
/*
466
- * case: we need to remove trailing newline
547
+ * If -N, and newlines in arg, remove them
467
548
*/
468
- if (skip_eol_nl && inputlen > 0 && input [inputlen - 1 ] == '\n' ) {
469
- input [inputlen - 1 ] = '\0' ;
470
- -- inputlen ;
549
+ if (ignore_nl ) {
550
+
551
+ /*
552
+ * copy input removing all newlines, update inputlen if needed
553
+ */
554
+ dup_input = dup_without_nl (input , & inputlen );
555
+ if (dup_input == NULL ) {
556
+ err (13 , __func__ , "dup_without_nl failed" );
557
+ not_reached ();
558
+ }
559
+
560
+ /*
561
+ * replace input with the duplicate w/o newline input if needed
562
+ */
563
+ input = dup_input ;
564
+ dbg (DBG_VHIGH , "-N and arg is now: %d: <%s>" , i - optind , input );
565
+ dbg (DBG_VHIGH , "-N and arg length is now: %ju" , (uintmax_t )inputlen );
471
566
}
472
567
473
568
/*
@@ -545,6 +640,14 @@ main(int argc, char **argv)
545
640
dbg (DBG_MED , "added string of size %ju to encoded strings list" , bufsiz );
546
641
}
547
642
}
643
+
644
+ /*
645
+ * free duplicated arg if -N
646
+ */
647
+ if (ignore_nl && input != NULL ) {
648
+ free (input );
649
+ input = NULL ;
650
+ }
548
651
}
549
652
550
653
/*
@@ -560,7 +663,7 @@ main(int argc, char **argv)
560
663
* NOTE: jstrencode_stream() adds the allocated struct jstring * to the
561
664
* encoded JSON strings list
562
665
*/
563
- jstr = jstrencode_stream (stdin , skip_concat_quotes , skip_each , skip_each , skip_eol_nl );
666
+ jstr = jstrencode_stream (stdin , skip_concat_quotes , skip_each , skip_each , ignore_nl );
564
667
if (jstr != NULL ) {
565
668
dbg (DBG_MED , "encode length: %ju" , jstr -> bufsiz );
566
669
} else {
0 commit comments