@@ -360,15 +360,16 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
360360 return t - r ;
361361}
362362
363- char * xescape_full (const char * s , const char * bad , size_t console_width , bool eight_bits ) {
363+ char * xescape_full (const char * s , const char * bad , size_t console_width , XEscapeFlags flags ) {
364364 char * ans , * t , * prev , * prev2 ;
365365 const char * f ;
366366
367367 /* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
368- * reversed with cunescape(). If eight_bits is true , characters >= 127 are let through unchanged.
369- * This corresponds to non-ASCII printable characters in pre-unicode encodings.
368+ * reversed with cunescape(). If XESCAPE_8_BIT is specified , characters >= 127 are let through
369+ * unchanged. This corresponds to non-ASCII printable characters in pre-unicode encodings.
370370 *
371- * If console_width is reached, output is truncated and "..." is appended. */
371+ * If console_width is reached, or XESCAPE_FORCE_ELLIPSIS is set, output is truncated and "..." is
372+ * appended. */
372373
373374 if (console_width == 0 )
374375 return strdup ("" );
@@ -380,25 +381,31 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, bool ei
380381 memset (ans , '_' , MIN (strlen (s ), console_width ) * 4 );
381382 ans [MIN (strlen (s ), console_width ) * 4 ] = 0 ;
382383
384+ bool force_ellipsis = FLAGS_SET (flags , XESCAPE_FORCE_ELLIPSIS );
385+
383386 for (f = s , t = prev = prev2 = ans ; ; f ++ ) {
384387 char * tmp_t = t ;
385388
386389 if (!* f ) {
390+ if (force_ellipsis )
391+ break ;
392+
387393 * t = 0 ;
388394 return ans ;
389395 }
390396
391- if ((unsigned char ) * f < ' ' || (!eight_bits && (unsigned char ) * f >= 127 ) ||
397+ if ((unsigned char ) * f < ' ' ||
398+ (!FLAGS_SET (flags , XESCAPE_8_BIT ) && (unsigned char ) * f >= 127 ) ||
392399 * f == '\\' || strchr (bad , * f )) {
393- if ((size_t ) (t - ans ) + 4 > console_width )
400+ if ((size_t ) (t - ans ) + 4 + 3 * force_ellipsis > console_width )
394401 break ;
395402
396403 * (t ++ ) = '\\' ;
397404 * (t ++ ) = 'x' ;
398405 * (t ++ ) = hexchar (* f >> 4 );
399406 * (t ++ ) = hexchar (* f );
400407 } else {
401- if ((size_t ) (t - ans ) + 1 > console_width )
408+ if ((size_t ) (t - ans ) + 1 + 3 * force_ellipsis > console_width )
402409 break ;
403410
404411 * (t ++ ) = * f ;
@@ -427,11 +434,13 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, bool ei
427434 return ans ;
428435}
429436
430- char * escape_non_printable_full (const char * str , size_t console_width , bool eight_bit ) {
431- if (eight_bit )
432- return xescape_full (str , "" , console_width , true );
437+ char * escape_non_printable_full (const char * str , size_t console_width , XEscapeFlags flags ) {
438+ if (FLAGS_SET ( flags , XESCAPE_8_BIT ) )
439+ return xescape_full (str , "" , console_width , flags );
433440 else
434- return utf8_escape_non_printable_full (str , console_width );
441+ return utf8_escape_non_printable_full (str ,
442+ console_width ,
443+ FLAGS_SET (flags , XESCAPE_FORCE_ELLIPSIS ));
435444}
436445
437446char * octescape (const char * s , size_t len ) {
@@ -462,88 +471,74 @@ char* octescape(const char *s, size_t len) {
462471
463472}
464473
465- static char * strcpy_backslash_escaped (char * t , const char * s , const char * bad , bool escape_tab_nl ) {
474+ static char * strcpy_backslash_escaped (char * t , const char * s , const char * bad ) {
466475 assert (bad );
467476
468- for (; * s ; s ++ ) {
469- if (escape_tab_nl && IN_SET (* s , '\n' , '\t' )) {
470- * (t ++ ) = '\\' ;
471- * (t ++ ) = * s == '\n' ? 'n' : 't' ;
472- continue ;
477+ for (; * s ; s ++ )
478+ if (char_is_cc (* s ))
479+ t += cescape_char (* s , t );
480+ else {
481+ if (* s == '\\' || strchr (bad , * s ))
482+ * (t ++ ) = '\\' ;
483+ * (t ++ ) = * s ;
473484 }
474485
475- if (* s == '\\' || strchr (bad , * s ))
476- * (t ++ ) = '\\' ;
477-
478- * (t ++ ) = * s ;
479- }
480-
481486 return t ;
482487}
483488
484489char * shell_escape (const char * s , const char * bad ) {
485- char * r , * t ;
490+ char * buf , * t ;
486491
487- r = new (char , strlen (s )* 2 + 1 );
488- if (!r )
492+ buf = new (char , strlen (s )* 4 + 1 );
493+ if (!buf )
489494 return NULL ;
490495
491- t = strcpy_backslash_escaped (r , s , bad , false );
496+ t = strcpy_backslash_escaped (buf , s , bad );
492497 * t = 0 ;
493498
494- return r ;
499+ return buf ;
495500}
496501
497- char * shell_maybe_quote (const char * s , EscapeStyle style ) {
502+ char * shell_maybe_quote (const char * s , ShellEscapeFlags flags ) {
498503 const char * p ;
499- char * r , * t ;
504+ char * buf , * t ;
500505
501506 assert (s );
502507
503- /* Encloses a string in quotes if necessary to make it OK as a shell
504- * string. Note that we treat benign UTF-8 characters as needing
505- * escaping too, but that should be OK. */
508+ /* Encloses a string in quotes if necessary to make it OK as a shell string. */
509+
510+ if (FLAGS_SET (flags , SHELL_ESCAPE_EMPTY ) && isempty (s ))
511+ return strdup ("\"\"" ); /* We don't use $'' here in the POSIX mode. "" is fine too. */
506512
507513 for (p = s ; * p ; p ++ )
508- if (* p <= ' ' ||
509- * p >= 127 ||
510- strchr (SHELL_NEED_QUOTES , * p ))
514+ if (char_is_cc (* p ) ||
515+ strchr (WHITESPACE SHELL_NEED_QUOTES , * p ))
511516 break ;
512517
513518 if (!* p )
514519 return strdup (s );
515520
516- r = new (char , ( style == ESCAPE_POSIX ) + 1 + strlen (s )* 2 + 1 + 1 );
517- if (!r )
521+ buf = new (char , FLAGS_SET ( flags , SHELL_ESCAPE_POSIX ) + 1 + strlen (s )* 4 + 1 + 1 );
522+ if (!buf )
518523 return NULL ;
519524
520- t = r ;
521- switch (style ) {
522- case ESCAPE_BACKSLASH :
523- case ESCAPE_BACKSLASH_ONELINE :
524- * (t ++ ) = '"' ;
525- break ;
526- case ESCAPE_POSIX :
525+ t = buf ;
526+ if (FLAGS_SET (flags , SHELL_ESCAPE_POSIX )) {
527527 * (t ++ ) = '$' ;
528528 * (t ++ ) = '\'' ;
529- break ;
530- default :
531- assert_not_reached ("Bad EscapeStyle" );
532- }
529+ } else
530+ * (t ++ ) = '"' ;
533531
534532 t = mempcpy (t , s , p - s );
535533
536- if (IN_SET (style , ESCAPE_BACKSLASH , ESCAPE_BACKSLASH_ONELINE ))
537- t = strcpy_backslash_escaped (t , p , SHELL_NEED_ESCAPE ,
538- style == ESCAPE_BACKSLASH_ONELINE );
539- else
540- t = strcpy_backslash_escaped (t , p , SHELL_NEED_ESCAPE_POSIX , true);
534+ t = strcpy_backslash_escaped (t , p ,
535+ FLAGS_SET (flags , SHELL_ESCAPE_POSIX ) ? SHELL_NEED_ESCAPE_POSIX : SHELL_NEED_ESCAPE );
541536
542- if (IN_SET (style , ESCAPE_BACKSLASH , ESCAPE_BACKSLASH_ONELINE ))
543- * (t ++ ) = '"' ;
544- else
537+ if (FLAGS_SET (flags , SHELL_ESCAPE_POSIX ))
545538 * (t ++ ) = '\'' ;
539+ else
540+ * (t ++ ) = '"' ;
546541 * t = 0 ;
547542
548- return r ;
543+ return str_realloc ( buf ) ;
549544}
0 commit comments