Skip various cmp-mem-const tests on lp64 hppa*-*-*
[official-gcc.git] / gcc / pretty-print.cc
blobde454ab7a4017ec8e007c466c2e6b7fa1dabc646
1 /* Various declarations for language-independent pretty-print subroutines.
2 Copyright (C) 2003-2024 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #define INCLUDE_VECTOR
23 #include "system.h"
24 #include "coretypes.h"
25 #include "intl.h"
26 #include "pretty-print.h"
27 #include "pretty-print-urlifier.h"
28 #include "diagnostic-color.h"
29 #include "diagnostic-event-id.h"
30 #include "selftest.h"
32 #if HAVE_ICONV
33 #include <iconv.h>
34 #endif
36 #ifdef __MINGW32__
38 /* Replacement for fputs() that handles ANSI escape codes on Windows NT.
39 Contributed by: Liu Hao (lh_mouse at 126 dot com)
41 XXX: This file is compiled into libcommon.a that will be self-contained.
42 It looks like that these functions can be put nowhere else. */
44 #include <io.h>
45 #define WIN32_LEAN_AND_MEAN 1
46 #include <windows.h>
48 /* Write all bytes in [s,s+n) into the specified stream.
49 Errors are ignored. */
50 static void
51 write_all (HANDLE h, const char *s, size_t n)
53 size_t rem = n;
54 DWORD step;
56 while (rem != 0)
58 if (rem <= UINT_MAX)
59 step = rem;
60 else
61 step = UINT_MAX;
62 if (!WriteFile (h, s + n - rem, step, &step, NULL))
63 break;
64 rem -= step;
68 /* Find the beginning of an escape sequence.
69 There are two cases:
70 1. If the sequence begins with an ESC character (0x1B) and a second
71 character X in [0x40,0x5F], returns X and stores a pointer to
72 the third character into *head.
73 2. If the sequence begins with a character X in [0x80,0x9F], returns
74 (X-0x40) and stores a pointer to the second character into *head.
75 Stores the number of ESC character(s) in *prefix_len.
76 Returns 0 if no such sequence can be found. */
77 static int
78 find_esc_head (int *prefix_len, const char **head, const char *str)
80 int c;
81 const char *r = str;
82 int escaped = 0;
84 for (;;)
86 c = (unsigned char) *r;
87 if (c == 0)
89 /* Not found. */
90 return 0;
92 if (escaped && 0x40 <= c && c <= 0x5F)
94 /* Found (case 1). */
95 *prefix_len = 2;
96 *head = r + 1;
97 return c;
99 if (0x80 <= c && c <= 0x9F)
101 /* Found (case 2). */
102 *prefix_len = 1;
103 *head = r + 1;
104 return c - 0x40;
106 ++r;
107 escaped = c == 0x1B;
111 /* Find the terminator of an escape sequence.
112 str should be the value stored in *head by a previous successful
113 call to find_esc_head().
114 Returns 0 if no such sequence can be found. */
115 static int
116 find_esc_terminator (const char **term, const char *str)
118 int c;
119 const char *r = str;
121 for (;;)
123 c = (unsigned char) *r;
124 if (c == 0)
126 /* Not found. */
127 return 0;
129 if (0x40 <= c && c <= 0x7E)
131 /* Found. */
132 *term = r;
133 return c;
135 ++r;
139 /* Handle a sequence of codes. Sequences that are invalid, reserved,
140 unrecognized or unimplemented are ignored silently.
141 There isn't much we can do because of lameness of Windows consoles. */
142 static void
143 eat_esc_sequence (HANDLE h, int esc_code,
144 const char *esc_head, const char *esc_term)
146 /* Numbers in an escape sequence cannot be negative, because
147 a minus sign in the middle of it would have terminated it. */
148 long n1, n2;
149 char *eptr, *delim;
150 CONSOLE_SCREEN_BUFFER_INFO sb;
151 COORD cr;
152 /* ED and EL parameters. */
153 DWORD cnt, step;
154 long rows;
155 /* SGR parameters. */
156 WORD attrib_add, attrib_rm;
157 const char *param;
159 switch (MAKEWORD (esc_code, *esc_term))
161 /* ESC [ n1 'A'
162 Move the cursor up by n1 characters. */
163 case MAKEWORD ('[', 'A'):
164 if (esc_head == esc_term)
165 n1 = 1;
166 else
168 n1 = strtol (esc_head, &eptr, 10);
169 if (eptr != esc_term)
170 break;
173 if (GetConsoleScreenBufferInfo (h, &sb))
175 cr = sb.dwCursorPosition;
176 /* Stop at the topmost boundary. */
177 if (cr.Y > n1)
178 cr.Y -= n1;
179 else
180 cr.Y = 0;
181 SetConsoleCursorPosition (h, cr);
183 break;
185 /* ESC [ n1 'B'
186 Move the cursor down by n1 characters. */
187 case MAKEWORD ('[', 'B'):
188 if (esc_head == esc_term)
189 n1 = 1;
190 else
192 n1 = strtol (esc_head, &eptr, 10);
193 if (eptr != esc_term)
194 break;
197 if (GetConsoleScreenBufferInfo (h, &sb))
199 cr = sb.dwCursorPosition;
200 /* Stop at the bottommost boundary. */
201 if (sb.dwSize.Y - cr.Y > n1)
202 cr.Y += n1;
203 else
204 cr.Y = sb.dwSize.Y;
205 SetConsoleCursorPosition (h, cr);
207 break;
209 /* ESC [ n1 'C'
210 Move the cursor right by n1 characters. */
211 case MAKEWORD ('[', 'C'):
212 if (esc_head == esc_term)
213 n1 = 1;
214 else
216 n1 = strtol (esc_head, &eptr, 10);
217 if (eptr != esc_term)
218 break;
221 if (GetConsoleScreenBufferInfo (h, &sb))
223 cr = sb.dwCursorPosition;
224 /* Stop at the rightmost boundary. */
225 if (sb.dwSize.X - cr.X > n1)
226 cr.X += n1;
227 else
228 cr.X = sb.dwSize.X;
229 SetConsoleCursorPosition (h, cr);
231 break;
233 /* ESC [ n1 'D'
234 Move the cursor left by n1 characters. */
235 case MAKEWORD ('[', 'D'):
236 if (esc_head == esc_term)
237 n1 = 1;
238 else
240 n1 = strtol (esc_head, &eptr, 10);
241 if (eptr != esc_term)
242 break;
245 if (GetConsoleScreenBufferInfo (h, &sb))
247 cr = sb.dwCursorPosition;
248 /* Stop at the leftmost boundary. */
249 if (cr.X > n1)
250 cr.X -= n1;
251 else
252 cr.X = 0;
253 SetConsoleCursorPosition (h, cr);
255 break;
257 /* ESC [ n1 'E'
258 Move the cursor to the beginning of the n1-th line downwards. */
259 case MAKEWORD ('[', 'E'):
260 if (esc_head == esc_term)
261 n1 = 1;
262 else
264 n1 = strtol (esc_head, &eptr, 10);
265 if (eptr != esc_term)
266 break;
269 if (GetConsoleScreenBufferInfo (h, &sb))
271 cr = sb.dwCursorPosition;
272 cr.X = 0;
273 /* Stop at the bottommost boundary. */
274 if (sb.dwSize.Y - cr.Y > n1)
275 cr.Y += n1;
276 else
277 cr.Y = sb.dwSize.Y;
278 SetConsoleCursorPosition (h, cr);
280 break;
282 /* ESC [ n1 'F'
283 Move the cursor to the beginning of the n1-th line upwards. */
284 case MAKEWORD ('[', 'F'):
285 if (esc_head == esc_term)
286 n1 = 1;
287 else
289 n1 = strtol (esc_head, &eptr, 10);
290 if (eptr != esc_term)
291 break;
294 if (GetConsoleScreenBufferInfo (h, &sb))
296 cr = sb.dwCursorPosition;
297 cr.X = 0;
298 /* Stop at the topmost boundary. */
299 if (cr.Y > n1)
300 cr.Y -= n1;
301 else
302 cr.Y = 0;
303 SetConsoleCursorPosition (h, cr);
305 break;
307 /* ESC [ n1 'G'
308 Move the cursor to the (1-based) n1-th column. */
309 case MAKEWORD ('[', 'G'):
310 if (esc_head == esc_term)
311 n1 = 1;
312 else
314 n1 = strtol (esc_head, &eptr, 10);
315 if (eptr != esc_term)
316 break;
319 if (GetConsoleScreenBufferInfo (h, &sb))
321 cr = sb.dwCursorPosition;
322 n1 -= 1;
323 /* Stop at the leftmost or rightmost boundary. */
324 if (n1 < 0)
325 cr.X = 0;
326 else if (n1 > sb.dwSize.X)
327 cr.X = sb.dwSize.X;
328 else
329 cr.X = n1;
330 SetConsoleCursorPosition (h, cr);
332 break;
334 /* ESC [ n1 ';' n2 'H'
335 ESC [ n1 ';' n2 'f'
336 Move the cursor to the (1-based) n1-th row and
337 (also 1-based) n2-th column. */
338 case MAKEWORD ('[', 'H'):
339 case MAKEWORD ('[', 'f'):
340 if (esc_head == esc_term)
342 /* Both parameters are omitted and set to 1 by default. */
343 n1 = 1;
344 n2 = 1;
346 else if (!(delim = (char *) memchr (esc_head, ';',
347 esc_term - esc_head)))
349 /* Only the first parameter is given. The second one is
350 set to 1 by default. */
351 n1 = strtol (esc_head, &eptr, 10);
352 if (eptr != esc_term)
353 break;
354 n2 = 1;
356 else
358 /* Both parameters are given. The first one shall be
359 terminated by the semicolon. */
360 n1 = strtol (esc_head, &eptr, 10);
361 if (eptr != delim)
362 break;
363 n2 = strtol (delim + 1, &eptr, 10);
364 if (eptr != esc_term)
365 break;
368 if (GetConsoleScreenBufferInfo (h, &sb))
370 cr = sb.dwCursorPosition;
371 n1 -= 1;
372 n2 -= 1;
373 /* The cursor position shall be relative to the view coord of
374 the console window, which is usually smaller than the actual
375 buffer. FWIW, the 'appropriate' solution will be shrinking
376 the buffer to match the size of the console window,
377 destroying scrollback in the process. */
378 n1 += sb.srWindow.Top;
379 n2 += sb.srWindow.Left;
380 /* Stop at the topmost or bottommost boundary. */
381 if (n1 < 0)
382 cr.Y = 0;
383 else if (n1 > sb.dwSize.Y)
384 cr.Y = sb.dwSize.Y;
385 else
386 cr.Y = n1;
387 /* Stop at the leftmost or rightmost boundary. */
388 if (n2 < 0)
389 cr.X = 0;
390 else if (n2 > sb.dwSize.X)
391 cr.X = sb.dwSize.X;
392 else
393 cr.X = n2;
394 SetConsoleCursorPosition (h, cr);
396 break;
398 /* ESC [ n1 'J'
399 Erase display. */
400 case MAKEWORD ('[', 'J'):
401 if (esc_head == esc_term)
402 /* This is one of the very few codes whose parameters have
403 a default value of zero. */
404 n1 = 0;
405 else
407 n1 = strtol (esc_head, &eptr, 10);
408 if (eptr != esc_term)
409 break;
412 if (GetConsoleScreenBufferInfo (h, &sb))
414 /* The cursor is not necessarily in the console window, which
415 makes the behavior of this code harder to define. */
416 switch (n1)
418 case 0:
419 /* If the cursor is in or above the window, erase from
420 it to the bottom of the window; otherwise, do nothing. */
421 cr = sb.dwCursorPosition;
422 cnt = sb.dwSize.X - sb.dwCursorPosition.X;
423 rows = sb.srWindow.Bottom - sb.dwCursorPosition.Y;
424 break;
425 case 1:
426 /* If the cursor is in or under the window, erase from
427 it to the top of the window; otherwise, do nothing. */
428 cr.X = 0;
429 cr.Y = sb.srWindow.Top;
430 cnt = sb.dwCursorPosition.X + 1;
431 rows = sb.dwCursorPosition.Y - sb.srWindow.Top;
432 break;
433 case 2:
434 /* Erase the entire window. */
435 cr.X = sb.srWindow.Left;
436 cr.Y = sb.srWindow.Top;
437 cnt = 0;
438 rows = sb.srWindow.Bottom - sb.srWindow.Top + 1;
439 break;
440 default:
441 /* Erase the entire buffer. */
442 cr.X = 0;
443 cr.Y = 0;
444 cnt = 0;
445 rows = sb.dwSize.Y;
446 break;
448 if (rows < 0)
449 break;
450 cnt += rows * sb.dwSize.X;
451 FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
452 FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
454 break;
456 /* ESC [ n1 'K'
457 Erase line. */
458 case MAKEWORD ('[', 'K'):
459 if (esc_head == esc_term)
460 /* This is one of the very few codes whose parameters have
461 a default value of zero. */
462 n1 = 0;
463 else
465 n1 = strtol (esc_head, &eptr, 10);
466 if (eptr != esc_term)
467 break;
470 if (GetConsoleScreenBufferInfo (h, &sb))
472 switch (n1)
474 case 0:
475 /* Erase from the cursor to the end. */
476 cr = sb.dwCursorPosition;
477 cnt = sb.dwSize.X - sb.dwCursorPosition.X;
478 break;
479 case 1:
480 /* Erase from the cursor to the beginning. */
481 cr = sb.dwCursorPosition;
482 cr.X = 0;
483 cnt = sb.dwCursorPosition.X + 1;
484 break;
485 default:
486 /* Erase the entire line. */
487 cr = sb.dwCursorPosition;
488 cr.X = 0;
489 cnt = sb.dwSize.X;
490 break;
492 FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
493 FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
495 break;
497 /* ESC [ n1 ';' n2 'm'
498 Set SGR parameters. Zero or more parameters will follow. */
499 case MAKEWORD ('[', 'm'):
500 attrib_add = 0;
501 attrib_rm = 0;
502 if (esc_head == esc_term)
504 /* When no parameter is given, reset the console. */
505 attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
506 | FOREGROUND_BLUE);
507 attrib_rm = -1; /* Removes everything. */
508 goto sgr_set_it;
510 param = esc_head;
513 /* Parse a parameter. */
514 n1 = strtol (param, &eptr, 10);
515 if (*eptr != ';' && eptr != esc_term)
516 goto sgr_set_it;
518 switch (n1)
520 case 0:
521 /* Reset. */
522 attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
523 | FOREGROUND_BLUE);
524 attrib_rm = -1; /* Removes everything. */
525 break;
526 case 1:
527 /* Bold. */
528 attrib_add |= FOREGROUND_INTENSITY;
529 break;
530 case 4:
531 /* Underline. */
532 attrib_add |= COMMON_LVB_UNDERSCORE;
533 break;
534 case 5:
535 /* Blink. */
536 /* XXX: It is not BLINKING at all! */
537 attrib_add |= BACKGROUND_INTENSITY;
538 break;
539 case 7:
540 /* Reverse. */
541 attrib_add |= COMMON_LVB_REVERSE_VIDEO;
542 break;
543 case 22:
544 /* No bold. */
545 attrib_add &= ~FOREGROUND_INTENSITY;
546 attrib_rm |= FOREGROUND_INTENSITY;
547 break;
548 case 24:
549 /* No underline. */
550 attrib_add &= ~COMMON_LVB_UNDERSCORE;
551 attrib_rm |= COMMON_LVB_UNDERSCORE;
552 break;
553 case 25:
554 /* No blink. */
555 /* XXX: It is not BLINKING at all! */
556 attrib_add &= ~BACKGROUND_INTENSITY;
557 attrib_rm |= BACKGROUND_INTENSITY;
558 break;
559 case 27:
560 /* No reverse. */
561 attrib_add &= ~COMMON_LVB_REVERSE_VIDEO;
562 attrib_rm |= COMMON_LVB_REVERSE_VIDEO;
563 break;
564 case 30:
565 case 31:
566 case 32:
567 case 33:
568 case 34:
569 case 35:
570 case 36:
571 case 37:
572 /* Foreground color. */
573 attrib_add &= ~(FOREGROUND_RED | FOREGROUND_GREEN
574 | FOREGROUND_BLUE);
575 n1 -= 30;
576 if (n1 & 1)
577 attrib_add |= FOREGROUND_RED;
578 if (n1 & 2)
579 attrib_add |= FOREGROUND_GREEN;
580 if (n1 & 4)
581 attrib_add |= FOREGROUND_BLUE;
582 attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
583 | FOREGROUND_BLUE);
584 break;
585 case 38:
586 /* Reserved for extended foreground color.
587 Don't know how to handle parameters remaining.
588 Bail out. */
589 goto sgr_set_it;
590 case 39:
591 /* Reset foreground color. */
592 /* Set to grey. */
593 attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
594 | FOREGROUND_BLUE);
595 attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
596 | FOREGROUND_BLUE);
597 break;
598 case 40:
599 case 41:
600 case 42:
601 case 43:
602 case 44:
603 case 45:
604 case 46:
605 case 47:
606 /* Background color. */
607 attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
608 | BACKGROUND_BLUE);
609 n1 -= 40;
610 if (n1 & 1)
611 attrib_add |= BACKGROUND_RED;
612 if (n1 & 2)
613 attrib_add |= BACKGROUND_GREEN;
614 if (n1 & 4)
615 attrib_add |= BACKGROUND_BLUE;
616 attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
617 | BACKGROUND_BLUE);
618 break;
619 case 48:
620 /* Reserved for extended background color.
621 Don't know how to handle parameters remaining.
622 Bail out. */
623 goto sgr_set_it;
624 case 49:
625 /* Reset background color. */
626 /* Set to black. */
627 attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
628 | BACKGROUND_BLUE);
629 attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
630 | BACKGROUND_BLUE);
631 break;
634 /* Prepare the next parameter. */
635 param = eptr + 1;
637 while (param != esc_term);
639 sgr_set_it:
640 /* 0xFFFF removes everything. If it is not the case,
641 care must be taken to preserve old attributes. */
642 if (attrib_rm != 0xFFFF && GetConsoleScreenBufferInfo (h, &sb))
644 attrib_add |= sb.wAttributes & ~attrib_rm;
646 if (attrib_add & COMMON_LVB_REVERSE_VIDEO)
648 /* COMMON_LVB_REVERSE_VIDEO is only effective for DBCS.
649 * Swap foreground and background colors by hand.
651 attrib_add = (attrib_add & 0xFF00)
652 | ((attrib_add & 0x00F0) >> 4)
653 | ((attrib_add & 0x000F) << 4);
654 attrib_add &= ~COMMON_LVB_REVERSE_VIDEO;
656 SetConsoleTextAttribute (h, attrib_add);
657 break;
662 mingw_ansi_fputs (const char *str, FILE *fp)
664 const char *read = str;
665 HANDLE h;
666 DWORD mode;
667 int esc_code, prefix_len;
668 const char *esc_head, *esc_term;
670 h = (HANDLE) _get_osfhandle (_fileno (fp));
671 if (h == INVALID_HANDLE_VALUE)
672 return EOF;
674 /* Don't mess up stdio functions with Windows APIs. */
675 fflush (fp);
677 if (GetConsoleMode (h, &mode))
678 /* If it is a console, translate ANSI escape codes as needed. */
679 for (;;)
681 if ((esc_code = find_esc_head (&prefix_len, &esc_head, read)) == 0)
683 /* Write all remaining characters, then exit. */
684 write_all (h, read, strlen (read));
685 break;
687 if (find_esc_terminator (&esc_term, esc_head) == 0)
688 /* Ignore incomplete escape sequences at the moment.
689 FIXME: The escape state shall be cached for further calls
690 to this function. */
691 break;
692 write_all (h, read, esc_head - prefix_len - read);
693 eat_esc_sequence (h, esc_code, esc_head, esc_term);
694 read = esc_term + 1;
696 else
697 /* If it is not a console, write everything as-is. */
698 write_all (h, read, strlen (read));
700 return 1;
703 #endif /* __MINGW32__ */
705 static int
706 decode_utf8_char (const unsigned char *, size_t len, unsigned int *);
707 static void pp_quoted_string (pretty_printer *, const char *, size_t = -1);
709 /* Overwrite the given location/range within this text_info's rich_location.
710 For use e.g. when implementing "+" in client format decoders. */
712 void
713 text_info::set_location (unsigned int idx, location_t loc,
714 enum range_display_kind range_display_kind)
716 gcc_checking_assert (m_richloc);
717 m_richloc->set_range (idx, loc, range_display_kind);
720 location_t
721 text_info::get_location (unsigned int index_of_location) const
723 gcc_checking_assert (m_richloc);
725 if (index_of_location == 0)
726 return m_richloc->get_loc ();
727 else
728 return UNKNOWN_LOCATION;
731 // Default construct an output buffer.
733 output_buffer::output_buffer ()
734 : formatted_obstack (),
735 chunk_obstack (),
736 obstack (&formatted_obstack),
737 cur_chunk_array (),
738 stream (stderr),
739 line_length (),
740 digit_buffer (),
741 flush_p (true)
743 obstack_init (&formatted_obstack);
744 obstack_init (&chunk_obstack);
747 // Release resources owned by an output buffer at the end of lifetime.
749 output_buffer::~output_buffer ()
751 obstack_free (&chunk_obstack, NULL);
752 obstack_free (&formatted_obstack, NULL);
756 /* Format an integer given by va_arg (ARG, type-specifier T) where
757 type-specifier is a precision modifier as indicated by PREC. F is
758 a string used to construct the appropriate format-specifier. */
759 #define pp_integer_with_precision(PP, ARG, PREC, T, F) \
760 do \
761 switch (PREC) \
763 case 0: \
764 pp_scalar (PP, "%" F, va_arg (ARG, T)); \
765 break; \
767 case 1: \
768 pp_scalar (PP, "%l" F, va_arg (ARG, long T)); \
769 break; \
771 case 2: \
772 pp_scalar (PP, "%" HOST_LONG_LONG_FORMAT F, va_arg (ARG, long long T)); \
773 break; \
775 default: \
776 break; \
778 while (0)
781 /* Subroutine of pp_set_maximum_length. Set up PRETTY-PRINTER's
782 internal maximum characters per line. */
783 static void
784 pp_set_real_maximum_length (pretty_printer *pp)
786 /* If we're told not to wrap lines then do the obvious thing. In case
787 we'll emit prefix only once per message, it is appropriate
788 not to increase unnecessarily the line-length cut-off. */
789 if (!pp_is_wrapping_line (pp)
790 || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ONCE
791 || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
792 pp->maximum_length = pp_line_cutoff (pp);
793 else
795 int prefix_length = pp->prefix ? strlen (pp->prefix) : 0;
796 /* If the prefix is ridiculously too long, output at least
797 32 characters. */
798 if (pp_line_cutoff (pp) - prefix_length < 32)
799 pp->maximum_length = pp_line_cutoff (pp) + 32;
800 else
801 pp->maximum_length = pp_line_cutoff (pp);
805 /* Clear PRETTY-PRINTER's output state. */
806 static inline void
807 pp_clear_state (pretty_printer *pp)
809 pp->emitted_prefix = false;
810 pp_indentation (pp) = 0;
813 /* Print X to PP in decimal. */
814 template<unsigned int N, typename T>
815 void
816 pp_wide_integer (pretty_printer *pp, const poly_int<N, T> &x)
818 if (x.is_constant ())
819 pp_wide_integer (pp, x.coeffs[0]);
820 else
822 pp_left_bracket (pp);
823 for (unsigned int i = 0; i < N; ++i)
825 if (i != 0)
826 pp_comma (pp);
827 pp_wide_integer (pp, x.coeffs[i]);
829 pp_right_bracket (pp);
833 template void pp_wide_integer (pretty_printer *, const poly_uint16 &);
834 template void pp_wide_integer (pretty_printer *, const poly_int64 &);
835 template void pp_wide_integer (pretty_printer *, const poly_uint64 &);
837 /* Flush the formatted text of PRETTY-PRINTER onto the attached stream. */
838 void
839 pp_write_text_to_stream (pretty_printer *pp)
841 const char *text = pp_formatted_text (pp);
842 #ifdef __MINGW32__
843 mingw_ansi_fputs (text, pp_buffer (pp)->stream);
844 #else
845 fputs (text, pp_buffer (pp)->stream);
846 #endif
847 pp_clear_output_area (pp);
850 /* As pp_write_text_to_stream, but for GraphViz label output.
852 Flush the formatted text of pretty-printer PP onto the attached stream.
853 Replace characters in PPF that have special meaning in a GraphViz .dot
854 file.
856 This routine is not very fast, but it doesn't have to be as this is only
857 be used by routines dumping intermediate representations in graph form. */
859 void
860 pp_write_text_as_dot_label_to_stream (pretty_printer *pp, bool for_record)
862 const char *text = pp_formatted_text (pp);
863 const char *p = text;
864 FILE *fp = pp_buffer (pp)->stream;
866 for (;*p; p++)
868 bool escape_char;
869 switch (*p)
871 /* Print newlines as a left-aligned newline. */
872 case '\n':
873 fputs ("\\l", fp);
874 escape_char = true;
875 break;
877 /* The following characters are only special for record-shape nodes. */
878 case '|':
879 case '{':
880 case '}':
881 case '<':
882 case '>':
883 case ' ':
884 escape_char = for_record;
885 break;
887 /* The following characters always have to be escaped
888 for use in labels. */
889 case '\\':
890 /* There is a bug in some (f.i. 2.36.0) versions of graphiz
891 ( http://www.graphviz.org/mantisbt/view.php?id=2524 ) related to
892 backslash as last char in label. Let's avoid triggering it. */
893 gcc_assert (*(p + 1) != '\0');
894 /* Fall through. */
895 case '"':
896 escape_char = true;
897 break;
899 default:
900 escape_char = false;
901 break;
904 if (escape_char)
905 fputc ('\\', fp);
907 fputc (*p, fp);
910 pp_clear_output_area (pp);
913 /* As pp_write_text_to_stream, but for GraphViz HTML-like strings.
915 Flush the formatted text of pretty-printer PP onto the attached stream,
916 escaping these characters
917 " & < >
918 using XML escape sequences.
920 http://www.graphviz.org/doc/info/lang.html#html states:
921 special XML escape sequences for ", &, <, and > may be necessary in
922 order to embed these characters in attribute values or raw text
923 This doesn't list "'" (which would normally be escaped in XML
924 as "&apos;" or in HTML as "&#39;");.
926 Experiments show that escaping "'" doesn't seem to be necessary. */
928 void
929 pp_write_text_as_html_like_dot_to_stream (pretty_printer *pp)
931 const char *text = pp_formatted_text (pp);
932 const char *p = text;
933 FILE *fp = pp_buffer (pp)->stream;
935 for (;*p; p++)
937 switch (*p)
939 case '"':
940 fputs ("&quot;", fp);
941 break;
942 case '&':
943 fputs ("&amp;", fp);
944 break;
945 case '<':
946 fputs ("&lt;", fp);
947 break;
948 case '>':
949 fputs ("&gt;",fp);
950 break;
952 default:
953 fputc (*p, fp);
954 break;
958 pp_clear_output_area (pp);
961 /* Wrap a text delimited by START and END into PRETTY-PRINTER. */
962 static void
963 pp_wrap_text (pretty_printer *pp, const char *start, const char *end)
965 bool wrapping_line = pp_is_wrapping_line (pp);
967 while (start != end)
969 /* Dump anything bordered by whitespaces. */
971 const char *p = start;
972 while (p != end && !ISBLANK (*p) && *p != '\n')
973 ++p;
974 if (wrapping_line
975 && p - start >= pp_remaining_character_count_for_line (pp))
976 pp_newline (pp);
977 pp_append_text (pp, start, p);
978 start = p;
981 if (start != end && ISBLANK (*start))
983 pp_space (pp);
984 ++start;
986 if (start != end && *start == '\n')
988 pp_newline (pp);
989 ++start;
994 /* Same as pp_wrap_text but wrap text only when in line-wrapping mode. */
995 static inline void
996 pp_maybe_wrap_text (pretty_printer *pp, const char *start, const char *end)
998 if (pp_is_wrapping_line (pp))
999 pp_wrap_text (pp, start, end);
1000 else
1001 pp_append_text (pp, start, end);
1004 /* Append to the output area of PRETTY-PRINTER a string specified by its
1005 STARTing character and LENGTH. */
1006 static inline void
1007 pp_append_r (pretty_printer *pp, const char *start, int length)
1009 output_buffer_append_r (pp_buffer (pp), start, length);
1012 /* Insert enough spaces into the output area of PRETTY-PRINTER to bring
1013 the column position to the current indentation level, assuming that a
1014 newline has just been written to the buffer. */
1015 void
1016 pp_indent (pretty_printer *pp)
1018 int n = pp_indentation (pp);
1019 int i;
1021 for (i = 0; i < n; ++i)
1022 pp_space (pp);
1025 static const char *get_end_url_string (pretty_printer *);
1027 /* Append STR to OSTACK, without a null-terminator. */
1029 static void
1030 obstack_append_string (obstack *ostack, const char *str)
1032 obstack_grow (ostack, str, strlen (str));
1035 /* Append STR to OSTACK, without a null-terminator. */
1037 static void
1038 obstack_append_string (obstack *ostack, const char *str, size_t len)
1040 obstack_grow (ostack, str, len);
1043 /* Given quoted text within the buffer OBSTACK
1044 at the half-open interval [QUOTED_TEXT_START_IDX, QUOTED_TEXT_END_IDX),
1045 potentially use URLIFIER (if non-null) to see if there's a URL for the
1046 quoted text.
1048 If so, replace the quoted part of the text in the buffer with a URLified
1049 version of the text, using PP's settings.
1051 For example, given this is the buffer:
1052 "this is a test `hello worldTRAILING-CONTENT"
1053 .................^~~~~~~~~~~
1054 with the quoted text starting at the 'h' of "hello world", the buffer
1055 becomes:
1056 "this is a test `BEGIN_URL(URL)hello worldEND(URL)TRAILING-CONTENT"
1057 .................^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1058 .................-----------replacement-----------
1060 Return the new offset into the buffer of the quoted text endpoint i.e.
1061 the offset of "TRAILING-CONTENT" in the above. */
1063 static size_t
1064 urlify_quoted_string (pretty_printer *pp,
1065 obstack *obstack,
1066 const urlifier *urlifier,
1067 size_t quoted_text_start_idx,
1068 size_t quoted_text_end_idx)
1070 if (pp->url_format == URL_FORMAT_NONE)
1071 return quoted_text_end_idx;
1072 if (!urlifier)
1073 return quoted_text_end_idx;
1075 const size_t quoted_len = quoted_text_end_idx - quoted_text_start_idx;
1076 if (quoted_len == 0)
1077 /* Empty quoted string; do nothing. */
1078 return quoted_text_end_idx;
1079 const char *start = (obstack->object_base + quoted_text_start_idx);
1080 char *url = urlifier->get_url_for_quoted_text (start, quoted_len);
1081 if (!url)
1082 /* No URL for this quoted text; do nothing. */
1083 return quoted_text_end_idx;
1085 /* Stash a copy of the remainder of the chunk. */
1086 char *text = xstrndup (start,
1087 obstack_object_size (obstack) - quoted_text_start_idx);
1089 /* Replace quoted text... */
1090 obstack->next_free = obstack->object_base + quoted_text_start_idx;
1092 /* ...with URLified version of the text. */
1093 /* Begin URL. */
1094 switch (pp->url_format)
1096 default:
1097 case URL_FORMAT_NONE:
1098 gcc_unreachable ();
1099 case URL_FORMAT_ST:
1100 obstack_append_string (obstack, "\33]8;;");
1101 obstack_append_string (obstack, url);
1102 obstack_append_string (obstack, "\33\\");
1103 break;
1104 case URL_FORMAT_BEL:
1105 obstack_append_string (obstack, "\33]8;;");
1106 obstack_append_string (obstack, url);
1107 obstack_append_string (obstack, "\a");
1108 break;
1110 /* Add back the quoted part of the text. */
1111 obstack_append_string (obstack, text, quoted_len);
1112 /* End URL. */
1113 obstack_append_string (obstack,
1114 get_end_url_string (pp));
1116 size_t new_end_idx = obstack_object_size (obstack);
1118 /* Add back the remainder of the text after the quoted part. */
1119 obstack_append_string (obstack, text + quoted_len);
1120 free (text);
1121 free (url);
1122 return new_end_idx;
1125 /* A class for tracking quoted text within a buffer for
1126 use by a urlifier. */
1128 class quoting_info
1130 public:
1131 /* Called when quoted text is begun in phase 1 or 2. */
1132 void on_begin_quote (const output_buffer &buf,
1133 unsigned chunk_idx)
1135 /* Stash location of start of quoted string. */
1136 size_t byte_offset = obstack_object_size (&buf.chunk_obstack);
1137 m_loc_last_open_quote = location (chunk_idx, byte_offset);
1140 /* Called when quoted text is ended in phase 1 or 2. */
1141 void on_end_quote (pretty_printer *pp,
1142 output_buffer &buf,
1143 unsigned chunk_idx,
1144 const urlifier &urlifier)
1146 /* If possible, do urlification now. */
1147 if (chunk_idx == m_loc_last_open_quote.m_chunk_idx)
1149 urlify_quoted_string (pp,
1150 &buf.chunk_obstack,
1151 &urlifier,
1152 m_loc_last_open_quote.m_byte_offset,
1153 obstack_object_size (&buf.chunk_obstack));
1154 m_loc_last_open_quote = location ();
1155 return;
1157 /* Otherwise the quoted text straddles multiple chunks.
1158 Stash the location of end of quoted string for use in phase 3. */
1159 size_t byte_offset = obstack_object_size (&buf.chunk_obstack);
1160 m_phase_3_quotes.push_back (run (m_loc_last_open_quote,
1161 location (chunk_idx, byte_offset)));
1162 m_loc_last_open_quote = location ();
1165 bool has_phase_3_quotes_p () const
1167 return m_phase_3_quotes.size () > 0;
1169 void handle_phase_3 (pretty_printer *pp,
1170 const urlifier &urlifier);
1172 private:
1173 struct location
1175 location ()
1176 : m_chunk_idx (UINT_MAX),
1177 m_byte_offset (SIZE_MAX)
1181 location (unsigned chunk_idx,
1182 size_t byte_offset)
1183 : m_chunk_idx (chunk_idx),
1184 m_byte_offset (byte_offset)
1188 unsigned m_chunk_idx;
1189 size_t m_byte_offset;
1192 struct run
1194 run (location start, location end)
1195 : m_start (start), m_end (end)
1199 location m_start;
1200 location m_end;
1203 location m_loc_last_open_quote;
1204 std::vector<run> m_phase_3_quotes;
1207 static void
1208 on_begin_quote (const output_buffer &buf,
1209 unsigned chunk_idx,
1210 const urlifier *urlifier)
1212 if (!urlifier)
1213 return;
1214 if (!buf.cur_chunk_array->m_quotes)
1215 buf.cur_chunk_array->m_quotes = new quoting_info ();
1216 buf.cur_chunk_array->m_quotes->on_begin_quote (buf, chunk_idx);
1219 static void
1220 on_end_quote (pretty_printer *pp,
1221 output_buffer &buf,
1222 unsigned chunk_idx,
1223 const urlifier *urlifier)
1225 if (!urlifier)
1226 return;
1227 if (!buf.cur_chunk_array->m_quotes)
1228 buf.cur_chunk_array->m_quotes = new quoting_info ();
1229 buf.cur_chunk_array->m_quotes->on_end_quote (pp, buf, chunk_idx, *urlifier);
1232 /* The following format specifiers are recognized as being client independent:
1233 %d, %i: (signed) integer in base ten.
1234 %u: unsigned integer in base ten.
1235 %o: unsigned integer in base eight.
1236 %x: unsigned integer in base sixteen.
1237 %ld, %li, %lo, %lu, %lx: long versions of the above.
1238 %lld, %lli, %llo, %llu, %llx: long long versions.
1239 %wd, %wi, %wo, %wu, %wx: HOST_WIDE_INT versions.
1240 %f: double
1241 %c: character.
1242 %s: string.
1243 %p: pointer (printed in a host-dependent manner).
1244 %r: if pp_show_color(pp), switch to color identified by const char *.
1245 %R: if pp_show_color(pp), reset color.
1246 %m: strerror(text->err_no) - does not consume a value from args_ptr.
1247 %%: '%'.
1248 %<: opening quote.
1249 %>: closing quote.
1250 %{: URL start. Consumes a const char * argument for the URL.
1251 %}: URL end. Does not consume any arguments.
1252 %': apostrophe (should only be used in untranslated messages;
1253 translations should use appropriate punctuation directly).
1254 %@: diagnostic_event_id_ptr, for which event_id->known_p () must be true.
1255 %.*s: a substring the length of which is specified by an argument
1256 integer.
1257 %Ns: likewise, but length specified as constant in the format string.
1258 Flag 'q': quote formatted text (must come immediately after '%').
1259 %Z: Requires two arguments - array of int, and len. Prints elements
1260 of the array.
1262 Arguments can be used sequentially, or through %N$ resp. *N$
1263 notation Nth argument after the format string. If %N$ / *N$
1264 notation is used, it must be used for all arguments, except %m, %%,
1265 %<, %>, %} and %', which may not have a number, as they do not consume
1266 an argument. When %M$.*N$s is used, M must be N + 1. (This may
1267 also be written %M$.*s, provided N is not otherwise used.) The
1268 format string must have conversion specifiers with argument numbers
1269 1 up to highest argument; each argument may only be used once.
1270 A format string can have at most 30 arguments. */
1272 /* Formatting phases 1 and 2: render TEXT->format_spec plus
1273 text->m_args_ptr into a series of chunks in pp_buffer (PP)->args[].
1274 Phase 3 is in pp_output_formatted_text.
1276 If URLIFIER is non-NULL, then use it to add URLs for quoted
1277 strings, so that e.g.
1278 "before %<quoted%> after"
1279 with a URLIFIER that has a URL for "quoted" might be emitted as:
1280 "before `BEGIN_URL(http://example.com)quotedEND_URL' after"
1281 This is handled here for message fragments that are:
1282 - quoted entirely in phase 1 (e.g. "%<this is quoted%>"), or
1283 - quoted entirely in phase 2 (e.g. "%qs"),
1284 Quoted fragments that use a mixture of both phases
1285 (e.g. "%<this is a mixture: %s %>")
1286 are stashed into the output_buffer's m_quotes for use in phase 3. */
1288 void
1289 pp_format (pretty_printer *pp,
1290 text_info *text,
1291 const urlifier *urlifier)
1293 output_buffer * const buffer = pp_buffer (pp);
1294 const char *p;
1295 const char **args;
1296 struct chunk_info *new_chunk_array;
1298 unsigned int curarg = 0, chunk = 0, argno;
1299 pp_wrapping_mode_t old_wrapping_mode;
1300 bool any_unnumbered = false, any_numbered = false;
1301 const char **formatters[PP_NL_ARGMAX];
1303 /* Allocate a new chunk structure. */
1304 new_chunk_array = XOBNEW (&buffer->chunk_obstack, struct chunk_info);
1306 new_chunk_array->prev = buffer->cur_chunk_array;
1307 new_chunk_array->m_quotes = nullptr;
1308 buffer->cur_chunk_array = new_chunk_array;
1309 args = new_chunk_array->args;
1311 /* Formatting phase 1: split up TEXT->format_spec into chunks in
1312 pp_buffer (PP)->args[]. Even-numbered chunks are to be output
1313 verbatim, odd-numbered chunks are format specifiers.
1314 %m, %%, %<, %>, %} and %' are replaced with the appropriate text at
1315 this point. */
1317 memset (formatters, 0, sizeof formatters);
1319 for (p = text->m_format_spec; *p; )
1321 while (*p != '\0' && *p != '%')
1323 obstack_1grow (&buffer->chunk_obstack, *p);
1324 p++;
1327 if (*p == '\0')
1328 break;
1330 switch (*++p)
1332 case '\0':
1333 gcc_unreachable ();
1335 case '%':
1336 obstack_1grow (&buffer->chunk_obstack, '%');
1337 p++;
1338 continue;
1340 case '<':
1342 obstack_grow (&buffer->chunk_obstack,
1343 open_quote, strlen (open_quote));
1344 const char *colorstr
1345 = colorize_start (pp_show_color (pp), "quote");
1346 obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
1347 p++;
1349 on_begin_quote (*buffer, chunk, urlifier);
1350 continue;
1353 case '>':
1355 on_end_quote (pp, *buffer, chunk, urlifier);
1357 const char *colorstr = colorize_stop (pp_show_color (pp));
1358 obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
1360 /* FALLTHRU */
1361 case '\'':
1362 obstack_grow (&buffer->chunk_obstack,
1363 close_quote, strlen (close_quote));
1364 p++;
1365 continue;
1367 case '}':
1369 const char *endurlstr = get_end_url_string (pp);
1370 obstack_grow (&buffer->chunk_obstack, endurlstr,
1371 strlen (endurlstr));
1373 p++;
1374 continue;
1376 case 'R':
1378 const char *colorstr = colorize_stop (pp_show_color (pp));
1379 obstack_grow (&buffer->chunk_obstack, colorstr,
1380 strlen (colorstr));
1381 p++;
1382 continue;
1385 case 'm':
1387 const char *errstr = xstrerror (text->m_err_no);
1388 obstack_grow (&buffer->chunk_obstack, errstr, strlen (errstr));
1390 p++;
1391 continue;
1393 default:
1394 /* Handled in phase 2. Terminate the plain chunk here. */
1395 obstack_1grow (&buffer->chunk_obstack, '\0');
1396 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1397 break;
1400 if (ISDIGIT (*p))
1402 char *end;
1403 argno = strtoul (p, &end, 10) - 1;
1404 p = end;
1405 gcc_assert (*p == '$');
1406 p++;
1408 any_numbered = true;
1409 gcc_assert (!any_unnumbered);
1411 else
1413 argno = curarg++;
1414 any_unnumbered = true;
1415 gcc_assert (!any_numbered);
1417 gcc_assert (argno < PP_NL_ARGMAX);
1418 gcc_assert (!formatters[argno]);
1419 formatters[argno] = &args[chunk];
1422 obstack_1grow (&buffer->chunk_obstack, *p);
1423 p++;
1425 while (strchr ("qwl+#", p[-1]));
1427 if (p[-1] == '.')
1429 /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
1430 (where M == N + 1). */
1431 if (ISDIGIT (*p))
1435 obstack_1grow (&buffer->chunk_obstack, *p);
1436 p++;
1438 while (ISDIGIT (p[-1]));
1439 gcc_assert (p[-1] == 's');
1441 else
1443 gcc_assert (*p == '*');
1444 obstack_1grow (&buffer->chunk_obstack, '*');
1445 p++;
1447 if (ISDIGIT (*p))
1449 char *end;
1450 unsigned int argno2 = strtoul (p, &end, 10) - 1;
1451 p = end;
1452 gcc_assert (argno2 == argno - 1);
1453 gcc_assert (!any_unnumbered);
1454 gcc_assert (*p == '$');
1456 p++;
1457 formatters[argno2] = formatters[argno];
1459 else
1461 gcc_assert (!any_numbered);
1462 formatters[argno+1] = formatters[argno];
1463 curarg++;
1465 gcc_assert (*p == 's');
1466 obstack_1grow (&buffer->chunk_obstack, 's');
1467 p++;
1470 if (*p == '\0')
1471 break;
1473 obstack_1grow (&buffer->chunk_obstack, '\0');
1474 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1475 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1478 obstack_1grow (&buffer->chunk_obstack, '\0');
1479 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1480 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1481 args[chunk] = 0;
1483 /* Set output to the argument obstack, and switch line-wrapping and
1484 prefixing off. */
1485 buffer->obstack = &buffer->chunk_obstack;
1486 const int old_line_length = buffer->line_length;
1487 old_wrapping_mode = pp_set_verbatim_wrapping (pp);
1489 /* Second phase. Replace each formatter with the formatted text it
1490 corresponds to. */
1492 for (argno = 0; formatters[argno]; argno++)
1494 int precision = 0;
1495 bool wide = false;
1496 bool plus = false;
1497 bool hash = false;
1498 bool quote = false;
1500 /* We do not attempt to enforce any ordering on the modifier
1501 characters. */
1503 for (p = *formatters[argno];; p++)
1505 switch (*p)
1507 case 'q':
1508 gcc_assert (!quote);
1509 quote = true;
1510 continue;
1512 case '+':
1513 gcc_assert (!plus);
1514 plus = true;
1515 continue;
1517 case '#':
1518 gcc_assert (!hash);
1519 hash = true;
1520 continue;
1522 case 'w':
1523 gcc_assert (!wide);
1524 wide = true;
1525 continue;
1527 case 'l':
1528 /* We don't support precision beyond that of "long long". */
1529 gcc_assert (precision < 2);
1530 precision++;
1531 continue;
1533 break;
1536 gcc_assert (!wide || precision == 0);
1538 if (quote)
1540 pp_begin_quote (pp, pp_show_color (pp));
1541 on_begin_quote (*buffer, chunk, urlifier);
1544 switch (*p)
1546 case 'r':
1547 pp_string (pp, colorize_start (pp_show_color (pp),
1548 va_arg (*text->m_args_ptr,
1549 const char *)));
1550 break;
1552 case 'c':
1554 /* When quoting, print alphanumeric, punctuation, and the space
1555 character unchanged, and all others in hexadecimal with the
1556 "\x" prefix. Otherwise print them all unchanged. */
1557 int chr = va_arg (*text->m_args_ptr, int);
1558 if (ISPRINT (chr) || !quote)
1559 pp_character (pp, chr);
1560 else
1562 const char str [2] = { chr, '\0' };
1563 pp_quoted_string (pp, str, 1);
1565 break;
1568 case 'd':
1569 case 'i':
1570 if (wide)
1571 pp_wide_integer (pp, va_arg (*text->m_args_ptr, HOST_WIDE_INT));
1572 else
1573 pp_integer_with_precision
1574 (pp, *text->m_args_ptr, precision, int, "d");
1575 break;
1577 case 'o':
1578 if (wide)
1579 pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
1580 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1581 else
1582 pp_integer_with_precision
1583 (pp, *text->m_args_ptr, precision, unsigned, "o");
1584 break;
1586 case 's':
1587 if (quote)
1588 pp_quoted_string (pp, va_arg (*text->m_args_ptr, const char *));
1589 else
1590 pp_string (pp, va_arg (*text->m_args_ptr, const char *));
1591 break;
1593 case 'p':
1594 pp_pointer (pp, va_arg (*text->m_args_ptr, void *));
1595 break;
1597 case 'u':
1598 if (wide)
1599 pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
1600 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1601 else
1602 pp_integer_with_precision
1603 (pp, *text->m_args_ptr, precision, unsigned, "u");
1604 break;
1606 case 'f':
1607 pp_double (pp, va_arg (*text->m_args_ptr, double));
1608 break;
1610 case 'Z':
1612 int *v = va_arg (*text->m_args_ptr, int *);
1613 unsigned len = va_arg (*text->m_args_ptr, unsigned);
1615 for (unsigned i = 0; i < len; ++i)
1617 pp_scalar (pp, "%i", v[i]);
1618 if (i < len - 1)
1620 pp_comma (pp);
1621 pp_space (pp);
1624 break;
1627 case 'x':
1628 if (wide)
1629 pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
1630 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1631 else
1632 pp_integer_with_precision
1633 (pp, *text->m_args_ptr, precision, unsigned, "x");
1634 break;
1636 case '.':
1638 int n;
1639 const char *s;
1641 /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
1642 (where M == N + 1). The format string should be verified
1643 already from the first phase. */
1644 p++;
1645 if (ISDIGIT (*p))
1647 char *end;
1648 n = strtoul (p, &end, 10);
1649 p = end;
1650 gcc_assert (*p == 's');
1652 else
1654 gcc_assert (*p == '*');
1655 p++;
1656 gcc_assert (*p == 's');
1657 n = va_arg (*text->m_args_ptr, int);
1659 /* This consumes a second entry in the formatters array. */
1660 gcc_assert (formatters[argno] == formatters[argno+1]);
1661 argno++;
1664 s = va_arg (*text->m_args_ptr, const char *);
1666 /* Append the lesser of precision and strlen (s) characters
1667 from the array (which need not be a nul-terminated string).
1668 Negative precision is treated as if it were omitted. */
1669 size_t len = n < 0 ? strlen (s) : strnlen (s, n);
1671 pp_append_text (pp, s, s + len);
1673 break;
1675 case '@':
1677 /* diagnostic_event_id_t *. */
1678 diagnostic_event_id_ptr event_id
1679 = va_arg (*text->m_args_ptr, diagnostic_event_id_ptr);
1680 gcc_assert (event_id->known_p ());
1682 pp_string (pp, colorize_start (pp_show_color (pp), "path"));
1683 pp_character (pp, '(');
1684 pp_decimal_int (pp, event_id->one_based ());
1685 pp_character (pp, ')');
1686 pp_string (pp, colorize_stop (pp_show_color (pp)));
1688 break;
1690 case '{':
1691 pp_begin_url (pp, va_arg (*text->m_args_ptr, const char *));
1692 break;
1694 default:
1696 bool ok;
1698 /* Call the format decoder.
1699 Pass the address of "quote" so that format decoders can
1700 potentially disable printing of the closing quote
1701 (e.g. when printing "'TYPEDEF' aka 'TYPE'" in the C family
1702 of frontends). */
1703 gcc_assert (pp_format_decoder (pp));
1704 ok = pp_format_decoder (pp) (pp, text, p,
1705 precision, wide, plus, hash, &quote,
1706 formatters[argno]);
1707 gcc_assert (ok);
1711 if (quote)
1713 on_end_quote (pp, *buffer, chunk, urlifier);
1714 pp_end_quote (pp, pp_show_color (pp));
1717 obstack_1grow (&buffer->chunk_obstack, '\0');
1718 *formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *);
1721 if (CHECKING_P)
1722 for (; argno < PP_NL_ARGMAX; argno++)
1723 gcc_assert (!formatters[argno]);
1725 /* If the client supplied a postprocessing object, call its "handle"
1726 hook here. */
1727 if (pp->m_format_postprocessor)
1728 pp->m_format_postprocessor->handle (pp);
1730 /* Revert to normal obstack and wrapping mode. */
1731 buffer->obstack = &buffer->formatted_obstack;
1732 buffer->line_length = old_line_length;
1733 pp_wrapping_mode (pp) = old_wrapping_mode;
1734 pp_clear_state (pp);
1737 struct auto_obstack
1739 auto_obstack ()
1741 obstack_init (&m_obstack);
1744 ~auto_obstack ()
1746 obstack_free (&m_obstack, NULL);
1749 void grow (const void *src, size_t length)
1751 obstack_grow (&m_obstack, src, length);
1754 void *object_base () const
1756 return m_obstack.object_base;
1759 size_t object_size () const
1761 return obstack_object_size (&m_obstack);
1764 obstack m_obstack;
1767 /* Subroutine of pp_output_formatted_text for the awkward case where
1768 quoted text straddles multiple chunks.
1770 Flush PP's buffer's chunks to PP's output buffer, whilst inserting
1771 URLs for any quoted text that should be URLified.
1773 For example, given:
1774 | pp_format (pp,
1775 | "unrecognized option %qs; did you mean %<-%s%>",
1776 | "foo", "foption");
1777 we would have these chunks:
1778 | chunk 0: "unrecognized option "
1779 | chunk 1: "`foo'" (already checked for urlification)
1780 | chunk 2: "; did you mean `-"
1781 | ^*
1782 | chunk 3: "foption"
1783 | *******
1784 | chunk 4: "'"
1786 and this quoting_info would have recorded the open quote near the end
1787 of chunk 2 and close quote at the start of chunk 4; this function would
1788 check the combination of the end of chunk 2 and all of chunk 3 ("-foption")
1789 for urlification. */
1791 void
1792 quoting_info::handle_phase_3 (pretty_printer *pp,
1793 const urlifier &urlifier)
1795 unsigned int chunk;
1796 output_buffer * const buffer = pp_buffer (pp);
1797 struct chunk_info *chunk_array = buffer->cur_chunk_array;
1798 const char **args = chunk_array->args;
1800 /* We need to construct the string into an intermediate buffer
1801 for this case, since using pp_string can introduce prefixes
1802 and line-wrapping, and omit whitespace at the start of lines. */
1803 auto_obstack combined_buf;
1805 /* Iterate simultaneously through both
1806 - the chunks and
1807 - the runs of quoted characters
1808 Accumulate text from the chunks into combined_buf, and handle
1809 runs of quoted characters when handling the chunks they
1810 correspond to. */
1811 size_t start_of_run_byte_offset = 0;
1812 std::vector<quoting_info::run>::const_iterator iter_run
1813 = buffer->cur_chunk_array->m_quotes->m_phase_3_quotes.begin ();
1814 std::vector<quoting_info::run>::const_iterator end_runs
1815 = buffer->cur_chunk_array->m_quotes->m_phase_3_quotes.end ();
1816 for (chunk = 0; args[chunk]; chunk++)
1818 size_t start_of_chunk_idx = combined_buf.object_size ();
1820 combined_buf.grow (args[chunk], strlen (args[chunk]));
1822 if (iter_run != end_runs
1823 && chunk == iter_run->m_end.m_chunk_idx)
1825 /* A run is ending; consider for it urlification. */
1826 const size_t end_of_run_byte_offset
1827 = start_of_chunk_idx + iter_run->m_end.m_byte_offset;
1828 const size_t end_offset
1829 = urlify_quoted_string (pp,
1830 &combined_buf.m_obstack,
1831 &urlifier,
1832 start_of_run_byte_offset,
1833 end_of_run_byte_offset);
1835 /* If URLification occurred it will have grown the buffer.
1836 We need to update start_of_chunk_idx so that offsets
1837 relative to it are still correct, for the case where
1838 we have a chunk that both ends a quoted run and starts
1839 another quoted run. */
1840 gcc_assert (end_offset >= end_of_run_byte_offset);
1841 start_of_chunk_idx += end_offset - end_of_run_byte_offset;
1843 iter_run++;
1845 if (iter_run != end_runs
1846 && chunk == iter_run->m_start.m_chunk_idx)
1848 /* Note where the run starts w.r.t. the composed buffer. */
1849 start_of_run_byte_offset
1850 = start_of_chunk_idx + iter_run->m_start.m_byte_offset;
1854 /* Now print to PP. */
1855 const char *start
1856 = static_cast <const char *> (combined_buf.object_base ());
1857 pp_maybe_wrap_text (pp, start, start + combined_buf.object_size ());
1860 /* Format of a message pointed to by TEXT.
1861 If URLIFIER is non-null then use it on any quoted text that was not
1862 handled in phases 1 or 2 to potentially add URLs. */
1864 void
1865 pp_output_formatted_text (pretty_printer *pp,
1866 const urlifier *urlifier)
1868 unsigned int chunk;
1869 output_buffer * const buffer = pp_buffer (pp);
1870 struct chunk_info *chunk_array = buffer->cur_chunk_array;
1871 const char **args = chunk_array->args;
1873 gcc_assert (buffer->obstack == &buffer->formatted_obstack);
1875 /* This is a third phase, first 2 phases done in pp_format_args.
1876 Now we actually print it. */
1878 /* If we have any deferred urlification, handle it now. */
1879 if (urlifier
1880 && pp->url_format != URL_FORMAT_NONE
1881 && buffer->cur_chunk_array->m_quotes
1882 && buffer->cur_chunk_array->m_quotes->has_phase_3_quotes_p ())
1883 buffer->cur_chunk_array->m_quotes->handle_phase_3 (pp, *urlifier);
1884 else
1885 for (chunk = 0; args[chunk]; chunk++)
1886 pp_string (pp, args[chunk]);
1888 /* Deallocate the chunk structure and everything after it (i.e. the
1889 associated series of formatted strings). */
1890 delete buffer->cur_chunk_array->m_quotes;
1891 buffer->cur_chunk_array = chunk_array->prev;
1892 obstack_free (&buffer->chunk_obstack, chunk_array);
1895 /* Helper subroutine of output_verbatim and verbatim. Do the appropriate
1896 settings needed by BUFFER for a verbatim formatting. */
1897 void
1898 pp_format_verbatim (pretty_printer *pp, text_info *text)
1900 /* Set verbatim mode. */
1901 pp_wrapping_mode_t oldmode = pp_set_verbatim_wrapping (pp);
1903 /* Do the actual formatting. */
1904 pp_format (pp, text);
1905 pp_output_formatted_text (pp);
1907 /* Restore previous settings. */
1908 pp_wrapping_mode (pp) = oldmode;
1911 /* Flush the content of BUFFER onto the attached stream. This
1912 function does nothing unless pp->output_buffer->flush_p. */
1913 void
1914 pp_flush (pretty_printer *pp)
1916 pp_clear_state (pp);
1917 if (!pp->buffer->flush_p)
1918 return;
1919 pp_write_text_to_stream (pp);
1920 fflush (pp_buffer (pp)->stream);
1923 /* Flush the content of BUFFER onto the attached stream independently
1924 of the value of pp->output_buffer->flush_p. */
1925 void
1926 pp_really_flush (pretty_printer *pp)
1928 pp_clear_state (pp);
1929 pp_write_text_to_stream (pp);
1930 fflush (pp_buffer (pp)->stream);
1933 /* Sets the number of maximum characters per line PRETTY-PRINTER can
1934 output in line-wrapping mode. A LENGTH value 0 suppresses
1935 line-wrapping. */
1936 void
1937 pp_set_line_maximum_length (pretty_printer *pp, int length)
1939 pp_line_cutoff (pp) = length;
1940 pp_set_real_maximum_length (pp);
1943 /* Clear PRETTY-PRINTER output area text info. */
1944 void
1945 pp_clear_output_area (pretty_printer *pp)
1947 obstack_free (pp_buffer (pp)->obstack,
1948 obstack_base (pp_buffer (pp)->obstack));
1949 pp_buffer (pp)->line_length = 0;
1952 /* Set PREFIX for PRETTY-PRINTER, taking ownership of PREFIX, which
1953 will eventually be free-ed. */
1955 void
1956 pp_set_prefix (pretty_printer *pp, char *prefix)
1958 free (pp->prefix);
1959 pp->prefix = prefix;
1960 pp_set_real_maximum_length (pp);
1961 pp->emitted_prefix = false;
1962 pp_indentation (pp) = 0;
1965 /* Take ownership of PP's prefix, setting it to NULL.
1966 This allows clients to save, override, and then restore an existing
1967 prefix, without it being free-ed. */
1969 char *
1970 pp_take_prefix (pretty_printer *pp)
1972 char *result = pp->prefix;
1973 pp->prefix = NULL;
1974 return result;
1977 /* Free PRETTY-PRINTER's prefix, a previously malloc()'d string. */
1978 void
1979 pp_destroy_prefix (pretty_printer *pp)
1981 if (pp->prefix != NULL)
1983 free (pp->prefix);
1984 pp->prefix = NULL;
1988 /* Write out PRETTY-PRINTER's prefix. */
1989 void
1990 pp_emit_prefix (pretty_printer *pp)
1992 if (pp->prefix != NULL)
1994 switch (pp_prefixing_rule (pp))
1996 default:
1997 case DIAGNOSTICS_SHOW_PREFIX_NEVER:
1998 break;
2000 case DIAGNOSTICS_SHOW_PREFIX_ONCE:
2001 if (pp->emitted_prefix)
2003 pp_indent (pp);
2004 break;
2006 pp_indentation (pp) += 3;
2007 /* Fall through. */
2009 case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE:
2011 int prefix_length = strlen (pp->prefix);
2012 pp_append_r (pp, pp->prefix, prefix_length);
2013 pp->emitted_prefix = true;
2015 break;
2020 /* Construct a PRETTY-PRINTER of MAXIMUM_LENGTH characters per line. */
2022 pretty_printer::pretty_printer (int maximum_length)
2023 : buffer (new (XCNEW (output_buffer)) output_buffer ()),
2024 prefix (),
2025 padding (pp_none),
2026 maximum_length (),
2027 indent_skip (),
2028 wrapping (),
2029 format_decoder (),
2030 m_format_postprocessor (NULL),
2031 emitted_prefix (),
2032 need_newline (),
2033 translate_identifiers (true),
2034 show_color (),
2035 url_format (URL_FORMAT_NONE),
2036 m_skipping_null_url (false)
2038 pp_line_cutoff (this) = maximum_length;
2039 /* By default, we emit prefixes once per message. */
2040 pp_prefixing_rule (this) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
2041 pp_set_prefix (this, NULL);
2044 /* Copy constructor for pretty_printer. */
2046 pretty_printer::pretty_printer (const pretty_printer &other)
2047 : buffer (new (XCNEW (output_buffer)) output_buffer ()),
2048 prefix (),
2049 padding (other.padding),
2050 maximum_length (other.maximum_length),
2051 indent_skip (other.indent_skip),
2052 wrapping (other.wrapping),
2053 format_decoder (other.format_decoder),
2054 m_format_postprocessor (NULL),
2055 emitted_prefix (other.emitted_prefix),
2056 need_newline (other.need_newline),
2057 translate_identifiers (other.translate_identifiers),
2058 show_color (other.show_color),
2059 url_format (other.url_format),
2060 m_skipping_null_url (false)
2062 pp_line_cutoff (this) = maximum_length;
2063 /* By default, we emit prefixes once per message. */
2064 pp_prefixing_rule (this) = pp_prefixing_rule (&other);
2065 pp_set_prefix (this, NULL);
2067 if (other.m_format_postprocessor)
2068 m_format_postprocessor = other.m_format_postprocessor->clone ();
2071 pretty_printer::~pretty_printer ()
2073 if (m_format_postprocessor)
2074 delete m_format_postprocessor;
2075 buffer->~output_buffer ();
2076 XDELETE (buffer);
2077 free (prefix);
2080 /* Base class implementation of pretty_printer::clone vfunc. */
2082 pretty_printer *
2083 pretty_printer::clone () const
2085 return new pretty_printer (*this);
2088 /* Append a string delimited by START and END to the output area of
2089 PRETTY-PRINTER. No line wrapping is done. However, if beginning a
2090 new line then emit PRETTY-PRINTER's prefix and skip any leading
2091 whitespace if appropriate. The caller must ensure that it is
2092 safe to do so. */
2093 void
2094 pp_append_text (pretty_printer *pp, const char *start, const char *end)
2096 /* Emit prefix and skip whitespace if we're starting a new line. */
2097 if (pp_buffer (pp)->line_length == 0)
2099 pp_emit_prefix (pp);
2100 if (pp_is_wrapping_line (pp))
2101 while (start != end && *start == ' ')
2102 ++start;
2104 pp_append_r (pp, start, end - start);
2107 /* Finishes constructing a NULL-terminated character string representing
2108 the PRETTY-PRINTED text. */
2109 const char *
2110 pp_formatted_text (pretty_printer *pp)
2112 return output_buffer_formatted_text (pp_buffer (pp));
2115 /* Return a pointer to the last character emitted in PRETTY-PRINTER's
2116 output area. A NULL pointer means no character available. */
2117 const char *
2118 pp_last_position_in_text (const pretty_printer *pp)
2120 return output_buffer_last_position_in_text (pp_buffer (pp));
2123 /* Return the amount of characters PRETTY-PRINTER can accept to
2124 make a full line. Meaningful only in line-wrapping mode. */
2126 pp_remaining_character_count_for_line (pretty_printer *pp)
2128 return pp->maximum_length - pp_buffer (pp)->line_length;
2132 /* Format a message into BUFFER a la printf. */
2133 void
2134 pp_printf (pretty_printer *pp, const char *msg, ...)
2136 va_list ap;
2138 va_start (ap, msg);
2139 text_info text (msg, &ap, errno);
2140 pp_format (pp, &text);
2141 pp_output_formatted_text (pp);
2142 va_end (ap);
2146 /* Output MESSAGE verbatim into BUFFER. */
2147 void
2148 pp_verbatim (pretty_printer *pp, const char *msg, ...)
2150 va_list ap;
2152 va_start (ap, msg);
2153 text_info text (msg, &ap, errno);
2154 pp_format_verbatim (pp, &text);
2155 va_end (ap);
2160 /* Have PRETTY-PRINTER start a new line. */
2161 void
2162 pp_newline (pretty_printer *pp)
2164 obstack_1grow (pp_buffer (pp)->obstack, '\n');
2165 pp_needs_newline (pp) = false;
2166 pp_buffer (pp)->line_length = 0;
2169 /* Have PRETTY-PRINTER add a CHARACTER. */
2170 void
2171 pp_character (pretty_printer *pp, int c)
2173 if (pp_is_wrapping_line (pp)
2174 /* If printing UTF-8, don't wrap in the middle of a sequence. */
2175 && (((unsigned int) c) & 0xC0) != 0x80
2176 && pp_remaining_character_count_for_line (pp) <= 0)
2178 pp_newline (pp);
2179 if (ISSPACE (c))
2180 return;
2182 obstack_1grow (pp_buffer (pp)->obstack, c);
2183 ++pp_buffer (pp)->line_length;
2186 /* Append a STRING to the output area of PRETTY-PRINTER; the STRING may
2187 be line-wrapped if in appropriate mode. */
2188 void
2189 pp_string (pretty_printer *pp, const char *str)
2191 gcc_checking_assert (str);
2192 pp_maybe_wrap_text (pp, str, str + strlen (str));
2195 /* Append code point C to the output area of PRETTY-PRINTER, encoding it
2196 as UTF-8. */
2198 void
2199 pp_unicode_character (pretty_printer *pp, unsigned c)
2201 static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
2202 static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
2203 size_t nbytes;
2204 uchar buf[6], *p = &buf[6];
2206 nbytes = 1;
2207 if (c < 0x80)
2208 *--p = c;
2209 else
2213 *--p = ((c & 0x3F) | 0x80);
2214 c >>= 6;
2215 nbytes++;
2217 while (c >= 0x3F || (c & limits[nbytes-1]));
2218 *--p = (c | masks[nbytes-1]);
2221 pp_append_r (pp, (const char *)p, nbytes);
2224 /* Append the leading N characters of STRING to the output area of
2225 PRETTY-PRINTER, quoting in hexadecimal non-printable characters.
2226 Setting N = -1 is as if N were set to strlen (STRING). The STRING
2227 may be line-wrapped if in appropriate mode. */
2228 static void
2229 pp_quoted_string (pretty_printer *pp, const char *str, size_t n /* = -1 */)
2231 gcc_checking_assert (str);
2233 const char *last = str;
2234 const char *ps;
2236 /* Compute the length if not specified. */
2237 if (n == (size_t) -1)
2238 n = strlen (str);
2240 for (ps = str; n; ++ps, --n)
2242 if (ISPRINT (*ps))
2243 continue;
2245 /* Don't escape a valid UTF-8 extended char. */
2246 const unsigned char *ups = (const unsigned char *) ps;
2247 if (*ups & 0x80)
2249 unsigned int extended_char;
2250 const int valid_utf8_len = decode_utf8_char (ups, n, &extended_char);
2251 if (valid_utf8_len > 0)
2253 ps += valid_utf8_len - 1;
2254 n -= valid_utf8_len - 1;
2255 continue;
2259 if (last < ps)
2260 pp_maybe_wrap_text (pp, last, ps);
2262 /* Append the hexadecimal value of the character. Allocate a buffer
2263 that's large enough for a 32-bit char plus the hex prefix. */
2264 char buf [11];
2265 int n = sprintf (buf, "\\x%02x", (unsigned char)*ps);
2266 pp_maybe_wrap_text (pp, buf, buf + n);
2267 last = ps + 1;
2270 pp_maybe_wrap_text (pp, last, ps);
2273 /* Maybe print out a whitespace if needed. */
2275 void
2276 pp_maybe_space (pretty_printer *pp)
2278 if (pp->padding != pp_none)
2280 pp_space (pp);
2281 pp->padding = pp_none;
2285 // Add a newline to the pretty printer PP and flush formatted text.
2287 void
2288 pp_newline_and_flush (pretty_printer *pp)
2290 pp_newline (pp);
2291 pp_flush (pp);
2292 pp_needs_newline (pp) = false;
2295 // Add a newline to the pretty printer PP, followed by indentation.
2297 void
2298 pp_newline_and_indent (pretty_printer *pp, int n)
2300 pp_indentation (pp) += n;
2301 pp_newline (pp);
2302 pp_indent (pp);
2303 pp_needs_newline (pp) = false;
2306 // Add separator C, followed by a single whitespace.
2308 void
2309 pp_separate_with (pretty_printer *pp, char c)
2311 pp_character (pp, c);
2312 pp_space (pp);
2315 /* Add a localized open quote, and if SHOW_COLOR is true, begin colorizing
2316 using the "quote" color. */
2318 void
2319 pp_begin_quote (pretty_printer *pp, bool show_color)
2321 pp_string (pp, open_quote);
2322 pp_string (pp, colorize_start (show_color, "quote"));
2325 /* If SHOW_COLOR is true, stop colorizing.
2326 Add a localized close quote. */
2328 void
2329 pp_end_quote (pretty_printer *pp, bool show_color)
2331 pp_string (pp, colorize_stop (show_color));
2332 pp_string (pp, close_quote);
2336 /* The string starting at P has LEN (at least 1) bytes left; if they
2337 start with a valid UTF-8 sequence, return the length of that
2338 sequence and set *VALUE to the value of that sequence, and
2339 otherwise return 0 and set *VALUE to (unsigned int) -1. */
2341 static int
2342 decode_utf8_char (const unsigned char *p, size_t len, unsigned int *value)
2344 unsigned int t = *p;
2346 if (len == 0)
2347 abort ();
2348 if (t & 0x80)
2350 size_t utf8_len = 0;
2351 unsigned int ch;
2352 size_t i;
2353 for (t = *p; t & 0x80; t <<= 1)
2354 utf8_len++;
2356 if (utf8_len > len || utf8_len < 2 || utf8_len > 6)
2358 *value = (unsigned int) -1;
2359 return 0;
2361 ch = *p & ((1 << (7 - utf8_len)) - 1);
2362 for (i = 1; i < utf8_len; i++)
2364 unsigned int u = p[i];
2365 if ((u & 0xC0) != 0x80)
2367 *value = (unsigned int) -1;
2368 return 0;
2370 ch = (ch << 6) | (u & 0x3F);
2372 if ( (ch <= 0x7F && utf8_len > 1)
2373 || (ch <= 0x7FF && utf8_len > 2)
2374 || (ch <= 0xFFFF && utf8_len > 3)
2375 || (ch <= 0x1FFFFF && utf8_len > 4)
2376 || (ch <= 0x3FFFFFF && utf8_len > 5)
2377 || (ch >= 0xD800 && ch <= 0xDFFF))
2379 *value = (unsigned int) -1;
2380 return 0;
2382 *value = ch;
2383 return utf8_len;
2385 else
2387 *value = t;
2388 return 1;
2392 /* Allocator for identifier_to_locale and corresponding function to
2393 free memory. */
2395 void *(*identifier_to_locale_alloc) (size_t) = xmalloc;
2396 void (*identifier_to_locale_free) (void *) = free;
2398 /* Given IDENT, an identifier in the internal encoding, return a
2399 version of IDENT suitable for diagnostics in the locale character
2400 set: either IDENT itself, or a string, allocated using
2401 identifier_to_locale_alloc, converted to the locale character set
2402 and using escape sequences if not representable in the locale
2403 character set or containing control characters or invalid byte
2404 sequences. Existing backslashes in IDENT are not doubled, so the
2405 result may not uniquely specify the contents of an arbitrary byte
2406 sequence identifier. */
2408 const char *
2409 identifier_to_locale (const char *ident)
2411 const unsigned char *uid = (const unsigned char *) ident;
2412 size_t idlen = strlen (ident);
2413 bool valid_printable_utf8 = true;
2414 bool all_ascii = true;
2415 size_t i;
2417 for (i = 0; i < idlen;)
2419 unsigned int c;
2420 size_t utf8_len = decode_utf8_char (&uid[i], idlen - i, &c);
2421 if (utf8_len == 0 || c <= 0x1F || (c >= 0x7F && c <= 0x9F))
2423 valid_printable_utf8 = false;
2424 break;
2426 if (utf8_len > 1)
2427 all_ascii = false;
2428 i += utf8_len;
2431 /* If IDENT contains invalid UTF-8 sequences (which may occur with
2432 attributes putting arbitrary byte sequences in identifiers), or
2433 control characters, we use octal escape sequences for all bytes
2434 outside printable ASCII. */
2435 if (!valid_printable_utf8)
2437 char *ret = (char *) identifier_to_locale_alloc (4 * idlen + 1);
2438 char *p = ret;
2439 for (i = 0; i < idlen; i++)
2441 if (uid[i] > 0x1F && uid[i] < 0x7F)
2442 *p++ = uid[i];
2443 else
2445 sprintf (p, "\\%03o", uid[i]);
2446 p += 4;
2449 *p = 0;
2450 return ret;
2453 /* Otherwise, if it is valid printable ASCII, or printable UTF-8
2454 with the locale character set being UTF-8, IDENT is used. */
2455 if (all_ascii || locale_utf8)
2456 return ident;
2458 /* Otherwise IDENT is converted to the locale character set if
2459 possible. */
2460 #if defined ENABLE_NLS && defined HAVE_LANGINFO_CODESET && HAVE_ICONV
2461 if (locale_encoding != NULL)
2463 iconv_t cd = iconv_open (locale_encoding, "UTF-8");
2464 bool conversion_ok = true;
2465 char *ret = NULL;
2466 if (cd != (iconv_t) -1)
2468 size_t ret_alloc = 4 * idlen + 1;
2469 for (;;)
2471 /* Repeat the whole conversion process as needed with
2472 larger buffers so non-reversible transformations can
2473 always be detected. */
2474 ICONV_CONST char *inbuf = CONST_CAST (char *, ident);
2475 char *outbuf;
2476 size_t inbytesleft = idlen;
2477 size_t outbytesleft = ret_alloc - 1;
2478 size_t iconv_ret;
2480 ret = (char *) identifier_to_locale_alloc (ret_alloc);
2481 outbuf = ret;
2483 if (iconv (cd, 0, 0, 0, 0) == (size_t) -1)
2485 conversion_ok = false;
2486 break;
2489 iconv_ret = iconv (cd, &inbuf, &inbytesleft,
2490 &outbuf, &outbytesleft);
2491 if (iconv_ret == (size_t) -1 || inbytesleft != 0)
2493 if (errno == E2BIG)
2495 ret_alloc *= 2;
2496 identifier_to_locale_free (ret);
2497 ret = NULL;
2498 continue;
2500 else
2502 conversion_ok = false;
2503 break;
2506 else if (iconv_ret != 0)
2508 conversion_ok = false;
2509 break;
2511 /* Return to initial shift state. */
2512 if (iconv (cd, 0, 0, &outbuf, &outbytesleft) == (size_t) -1)
2514 if (errno == E2BIG)
2516 ret_alloc *= 2;
2517 identifier_to_locale_free (ret);
2518 ret = NULL;
2519 continue;
2521 else
2523 conversion_ok = false;
2524 break;
2527 *outbuf = 0;
2528 break;
2530 iconv_close (cd);
2531 if (conversion_ok)
2532 return ret;
2535 #endif
2537 /* Otherwise, convert non-ASCII characters in IDENT to UCNs. */
2539 char *ret = (char *) identifier_to_locale_alloc (10 * idlen + 1);
2540 char *p = ret;
2541 for (i = 0; i < idlen;)
2543 unsigned int c;
2544 size_t utf8_len = decode_utf8_char (&uid[i], idlen - i, &c);
2545 if (utf8_len == 1)
2546 *p++ = uid[i];
2547 else
2549 sprintf (p, "\\U%08x", c);
2550 p += 10;
2552 i += utf8_len;
2554 *p = 0;
2555 return ret;
2559 /* Support for encoding URLs.
2560 See egmontkob/Hyperlinks_in_Terminal_Emulators.md
2561 ( https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda ).
2563 > A hyperlink is opened upon encountering an OSC 8 escape sequence with
2564 > the target URI. The syntax is
2566 > OSC 8 ; params ; URI ST
2568 > A hyperlink is closed with the same escape sequence, omitting the
2569 > parameters and the URI but keeping the separators:
2571 > OSC 8 ; ; ST
2573 > OSC (operating system command) is typically ESC ].
2575 Use BEL instead of ST, as that is currently rendered better in some
2576 terminal emulators that don't support OSC 8, like konsole. */
2578 /* If URL-printing is enabled, write an "open URL" escape sequence to PP
2579 for the given URL. */
2581 void
2582 pp_begin_url (pretty_printer *pp, const char *url)
2584 if (!url)
2586 /* Handle null URL by skipping all output here,
2587 and in the next pp_end_url. */
2588 pp->m_skipping_null_url = true;
2589 return;
2591 switch (pp->url_format)
2593 case URL_FORMAT_NONE:
2594 break;
2595 case URL_FORMAT_ST:
2596 pp_string (pp, "\33]8;;");
2597 pp_string (pp, url);
2598 pp_string (pp, "\33\\");
2599 break;
2600 case URL_FORMAT_BEL:
2601 pp_string (pp, "\33]8;;");
2602 pp_string (pp, url);
2603 pp_string (pp, "\a");
2604 break;
2605 default:
2606 gcc_unreachable ();
2610 /* Helper function for pp_end_url and pp_format, return the "close URL" escape
2611 sequence string. */
2613 static const char *
2614 get_end_url_string (pretty_printer *pp)
2616 switch (pp->url_format)
2618 case URL_FORMAT_NONE:
2619 return "";
2620 case URL_FORMAT_ST:
2621 return "\33]8;;\33\\";
2622 case URL_FORMAT_BEL:
2623 return "\33]8;;\a";
2624 default:
2625 gcc_unreachable ();
2629 /* If URL-printing is enabled, write a "close URL" escape sequence to PP. */
2631 void
2632 pp_end_url (pretty_printer *pp)
2634 if (pp->m_skipping_null_url)
2636 /* We gracefully handle pp_begin_url (NULL) by omitting output for
2637 both begin and end. Here we handle the latter. */
2638 pp->m_skipping_null_url = false;
2639 return;
2641 if (pp->url_format != URL_FORMAT_NONE)
2642 pp_string (pp, get_end_url_string (pp));
2645 #if CHECKING_P
2647 namespace selftest {
2649 /* Smoketest for pretty_printer. */
2651 static void
2652 test_basic_printing ()
2654 pretty_printer pp;
2655 pp_string (&pp, "hello");
2656 pp_space (&pp);
2657 pp_string (&pp, "world");
2659 ASSERT_STREQ ("hello world", pp_formatted_text (&pp));
2662 /* Helper function for testing pp_format.
2663 Verify that pp_format (FMT, ...) followed by pp_output_formatted_text
2664 prints EXPECTED, assuming that pp_show_color is SHOW_COLOR. */
2666 static void
2667 assert_pp_format_va (const location &loc, const char *expected,
2668 bool show_color, const char *fmt, va_list *ap)
2670 pretty_printer pp;
2671 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
2673 text_info ti (fmt, ap, 0, nullptr, &rich_loc);
2675 pp_show_color (&pp) = show_color;
2676 pp_format (&pp, &ti);
2677 pp_output_formatted_text (&pp);
2678 ASSERT_STREQ_AT (loc, expected, pp_formatted_text (&pp));
2681 /* Verify that pp_format (FMT, ...) followed by pp_output_formatted_text
2682 prints EXPECTED, with show_color disabled. */
2684 static void
2685 assert_pp_format (const location &loc, const char *expected,
2686 const char *fmt, ...)
2688 va_list ap;
2690 va_start (ap, fmt);
2691 assert_pp_format_va (loc, expected, false, fmt, &ap);
2692 va_end (ap);
2695 /* As above, but with colorization enabled. */
2697 static void
2698 assert_pp_format_colored (const location &loc, const char *expected,
2699 const char *fmt, ...)
2701 /* The tests of colorization assume the default color scheme.
2702 If GCC_COLORS is set, then the colors have potentially been
2703 overridden; skip the test. */
2704 if (getenv ("GCC_COLORS"))
2705 return;
2707 va_list ap;
2709 va_start (ap, fmt);
2710 assert_pp_format_va (loc, expected, true, fmt, &ap);
2711 va_end (ap);
2714 /* Helper function for calling testing pp_format,
2715 by calling assert_pp_format with various numbers of arguments.
2716 These exist mostly to avoid having to write SELFTEST_LOCATION
2717 throughout test_pp_format. */
2719 #define ASSERT_PP_FORMAT_1(EXPECTED, FMT, ARG1) \
2720 SELFTEST_BEGIN_STMT \
2721 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2722 (ARG1)); \
2723 SELFTEST_END_STMT
2725 #define ASSERT_PP_FORMAT_2(EXPECTED, FMT, ARG1, ARG2) \
2726 SELFTEST_BEGIN_STMT \
2727 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2728 (ARG1), (ARG2)); \
2729 SELFTEST_END_STMT
2731 #define ASSERT_PP_FORMAT_3(EXPECTED, FMT, ARG1, ARG2, ARG3) \
2732 SELFTEST_BEGIN_STMT \
2733 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2734 (ARG1), (ARG2), (ARG3)); \
2735 SELFTEST_END_STMT
2737 /* Verify that pp_format works, for various format codes. */
2739 static void
2740 test_pp_format ()
2742 /* Avoid introducing locale-specific differences in the results
2743 by hardcoding open_quote and close_quote. */
2744 auto_fix_quotes fix_quotes;
2746 /* Verify that plain text is passed through unchanged. */
2747 assert_pp_format (SELFTEST_LOCATION, "unformatted", "unformatted");
2749 /* Verify various individual format codes, in the order listed in the
2750 comment for pp_format above. For each code, we append a second
2751 argument with a known bit pattern (0x12345678), to ensure that we
2752 are consuming arguments correctly. */
2753 ASSERT_PP_FORMAT_2 ("-27 12345678", "%d %x", -27, 0x12345678);
2754 ASSERT_PP_FORMAT_2 ("-5 12345678", "%i %x", -5, 0x12345678);
2755 ASSERT_PP_FORMAT_2 ("10 12345678", "%u %x", 10, 0x12345678);
2756 ASSERT_PP_FORMAT_2 ("17 12345678", "%o %x", 15, 0x12345678);
2757 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%x %x", 0xcafebabe, 0x12345678);
2758 ASSERT_PP_FORMAT_2 ("-27 12345678", "%ld %x", (long)-27, 0x12345678);
2759 ASSERT_PP_FORMAT_2 ("-5 12345678", "%li %x", (long)-5, 0x12345678);
2760 ASSERT_PP_FORMAT_2 ("10 12345678", "%lu %x", (long)10, 0x12345678);
2761 ASSERT_PP_FORMAT_2 ("17 12345678", "%lo %x", (long)15, 0x12345678);
2762 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%lx %x", (long)0xcafebabe,
2763 0x12345678);
2764 ASSERT_PP_FORMAT_2 ("-27 12345678", "%lld %x", (long long)-27, 0x12345678);
2765 ASSERT_PP_FORMAT_2 ("-5 12345678", "%lli %x", (long long)-5, 0x12345678);
2766 ASSERT_PP_FORMAT_2 ("10 12345678", "%llu %x", (long long)10, 0x12345678);
2767 ASSERT_PP_FORMAT_2 ("17 12345678", "%llo %x", (long long)15, 0x12345678);
2768 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%llx %x", (long long)0xcafebabe,
2769 0x12345678);
2770 ASSERT_PP_FORMAT_2 ("-27 12345678", "%wd %x", (HOST_WIDE_INT)-27, 0x12345678);
2771 ASSERT_PP_FORMAT_2 ("-5 12345678", "%wi %x", (HOST_WIDE_INT)-5, 0x12345678);
2772 ASSERT_PP_FORMAT_2 ("10 12345678", "%wu %x", (unsigned HOST_WIDE_INT)10,
2773 0x12345678);
2774 ASSERT_PP_FORMAT_2 ("17 12345678", "%wo %x", (HOST_WIDE_INT)15, 0x12345678);
2775 ASSERT_PP_FORMAT_2 ("0xcafebabe 12345678", "%wx %x", (HOST_WIDE_INT)0xcafebabe,
2776 0x12345678);
2777 ASSERT_PP_FORMAT_2 ("1.000000 12345678", "%f %x", 1.0, 0x12345678);
2778 ASSERT_PP_FORMAT_2 ("A 12345678", "%c %x", 'A', 0x12345678);
2779 ASSERT_PP_FORMAT_2 ("hello world 12345678", "%s %x", "hello world",
2780 0x12345678);
2782 /* Not nul-terminated. */
2783 char arr[5] = { '1', '2', '3', '4', '5' };
2784 ASSERT_PP_FORMAT_3 ("123 12345678", "%.*s %x", 3, arr, 0x12345678);
2785 ASSERT_PP_FORMAT_3 ("1234 12345678", "%.*s %x", -1, "1234", 0x12345678);
2786 ASSERT_PP_FORMAT_3 ("12345 12345678", "%.*s %x", 7, "12345", 0x12345678);
2788 /* We can't test for %p; the pointer is printed in an implementation-defined
2789 manner. */
2790 ASSERT_PP_FORMAT_2 ("normal colored normal 12345678",
2791 "normal %rcolored%R normal %x",
2792 "error", 0x12345678);
2793 assert_pp_format_colored
2794 (SELFTEST_LOCATION,
2795 "normal \33[01;31m\33[Kcolored\33[m\33[K normal 12345678",
2796 "normal %rcolored%R normal %x", "error", 0x12345678);
2797 /* TODO:
2798 %m: strerror(text->err_no) - does not consume a value from args_ptr. */
2799 ASSERT_PP_FORMAT_1 ("% 12345678", "%% %x", 0x12345678);
2800 ASSERT_PP_FORMAT_1 ("` 12345678", "%< %x", 0x12345678);
2801 ASSERT_PP_FORMAT_1 ("' 12345678", "%> %x", 0x12345678);
2802 ASSERT_PP_FORMAT_1 ("' 12345678", "%' %x", 0x12345678);
2803 ASSERT_PP_FORMAT_3 ("abc 12345678", "%.*s %x", 3, "abcdef", 0x12345678);
2804 ASSERT_PP_FORMAT_2 ("abc 12345678", "%.3s %x", "abcdef", 0x12345678);
2806 /* Verify flag 'q'. */
2807 ASSERT_PP_FORMAT_2 ("`foo' 12345678", "%qs %x", "foo", 0x12345678);
2808 assert_pp_format_colored (SELFTEST_LOCATION,
2809 "`\33[01m\33[Kfoo\33[m\33[K' 12345678", "%qs %x",
2810 "foo", 0x12345678);
2811 /* Verify "%@". */
2813 diagnostic_event_id_t first (2);
2814 diagnostic_event_id_t second (7);
2816 ASSERT_PP_FORMAT_2 ("first `free' at (3); second `free' at (8)",
2817 "first %<free%> at %@; second %<free%> at %@",
2818 &first, &second);
2819 assert_pp_format_colored
2820 (SELFTEST_LOCATION,
2821 "first `\e[01m\e[Kfree\e[m\e[K' at \e[01;36m\e[K(3)\e[m\e[K;"
2822 " second `\e[01m\e[Kfree\e[m\e[K' at \e[01;36m\e[K(8)\e[m\e[K",
2823 "first %<free%> at %@; second %<free%> at %@",
2824 &first, &second);
2827 /* Verify %Z. */
2828 int v[] = { 1, 2, 3 };
2829 ASSERT_PP_FORMAT_3 ("1, 2, 3 12345678", "%Z %x", v, 3, 0x12345678);
2831 int v2[] = { 0 };
2832 ASSERT_PP_FORMAT_3 ("0 12345678", "%Z %x", v2, 1, 0x12345678);
2834 /* Verify that combinations work, along with unformatted text. */
2835 assert_pp_format (SELFTEST_LOCATION,
2836 "the quick brown fox jumps over the lazy dog",
2837 "the %s %s %s jumps over the %s %s",
2838 "quick", "brown", "fox", "lazy", "dog");
2839 assert_pp_format (SELFTEST_LOCATION, "item 3 of 7", "item %i of %i", 3, 7);
2840 assert_pp_format (SELFTEST_LOCATION, "problem with `bar' at line 10",
2841 "problem with %qs at line %i", "bar", 10);
2843 /* Verified numbered args. */
2844 assert_pp_format (SELFTEST_LOCATION,
2845 "foo: second bar: first",
2846 "foo: %2$s bar: %1$s",
2847 "first", "second");
2848 assert_pp_format (SELFTEST_LOCATION,
2849 "foo: 1066 bar: 1776",
2850 "foo: %2$i bar: %1$i",
2851 1776, 1066);
2852 assert_pp_format (SELFTEST_LOCATION,
2853 "foo: second bar: 1776",
2854 "foo: %2$s bar: %1$i",
2855 1776, "second");
2858 /* A subclass of pretty_printer for use by test_prefixes_and_wrapping. */
2860 class test_pretty_printer : public pretty_printer
2862 public:
2863 test_pretty_printer (enum diagnostic_prefixing_rule_t rule,
2864 int max_line_length)
2866 pp_set_prefix (this, xstrdup ("PREFIX: "));
2867 wrapping.rule = rule;
2868 pp_set_line_maximum_length (this, max_line_length);
2872 /* Verify that the various values of enum diagnostic_prefixing_rule_t work
2873 as expected, with and without line wrapping. */
2875 static void
2876 test_prefixes_and_wrapping ()
2878 /* Tests of the various prefixing rules, without wrapping.
2879 Newlines embedded in pp_string don't affect it; we have to
2880 explicitly call pp_newline. */
2882 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_ONCE, 0);
2883 pp_string (&pp, "the quick brown fox");
2884 pp_newline (&pp);
2885 pp_string (&pp, "jumps over the lazy dog");
2886 pp_newline (&pp);
2887 ASSERT_STREQ (pp_formatted_text (&pp),
2888 "PREFIX: the quick brown fox\n"
2889 " jumps over the lazy dog\n");
2892 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_NEVER, 0);
2893 pp_string (&pp, "the quick brown fox");
2894 pp_newline (&pp);
2895 pp_string (&pp, "jumps over the lazy dog");
2896 pp_newline (&pp);
2897 ASSERT_STREQ (pp_formatted_text (&pp),
2898 "the quick brown fox\n"
2899 "jumps over the lazy dog\n");
2902 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE, 0);
2903 pp_string (&pp, "the quick brown fox");
2904 pp_newline (&pp);
2905 pp_string (&pp, "jumps over the lazy dog");
2906 pp_newline (&pp);
2907 ASSERT_STREQ (pp_formatted_text (&pp),
2908 "PREFIX: the quick brown fox\n"
2909 "PREFIX: jumps over the lazy dog\n");
2912 /* Tests of the various prefixing rules, with wrapping. */
2914 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_ONCE, 20);
2915 pp_string (&pp, "the quick brown fox jumps over the lazy dog");
2916 pp_newline (&pp);
2917 pp_string (&pp, "able was I ere I saw elba");
2918 pp_newline (&pp);
2919 ASSERT_STREQ (pp_formatted_text (&pp),
2920 "PREFIX: the quick \n"
2921 " brown fox jumps \n"
2922 " over the lazy \n"
2923 " dog\n"
2924 " able was I ere I \n"
2925 " saw elba\n");
2928 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_NEVER, 20);
2929 pp_string (&pp, "the quick brown fox jumps over the lazy dog");
2930 pp_newline (&pp);
2931 pp_string (&pp, "able was I ere I saw elba");
2932 pp_newline (&pp);
2933 ASSERT_STREQ (pp_formatted_text (&pp),
2934 "the quick brown fox \n"
2935 "jumps over the lazy \n"
2936 "dog\n"
2937 "able was I ere I \n"
2938 "saw elba\n");
2941 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE, 20);
2942 pp_string (&pp, "the quick brown fox jumps over the lazy dog");
2943 pp_newline (&pp);
2944 pp_string (&pp, "able was I ere I saw elba");
2945 pp_newline (&pp);
2946 ASSERT_STREQ (pp_formatted_text (&pp),
2947 "PREFIX: the quick brown fox jumps over the lazy dog\n"
2948 "PREFIX: able was I ere I saw elba\n");
2953 /* Verify that URL-printing works as expected. */
2955 void
2956 test_urls ()
2959 pretty_printer pp;
2960 pp.url_format = URL_FORMAT_NONE;
2961 pp_begin_url (&pp, "http://example.com");
2962 pp_string (&pp, "This is a link");
2963 pp_end_url (&pp);
2964 ASSERT_STREQ ("This is a link",
2965 pp_formatted_text (&pp));
2969 pretty_printer pp;
2970 pp.url_format = URL_FORMAT_ST;
2971 pp_begin_url (&pp, "http://example.com");
2972 pp_string (&pp, "This is a link");
2973 pp_end_url (&pp);
2974 ASSERT_STREQ ("\33]8;;http://example.com\33\\This is a link\33]8;;\33\\",
2975 pp_formatted_text (&pp));
2979 pretty_printer pp;
2980 pp.url_format = URL_FORMAT_BEL;
2981 pp_begin_url (&pp, "http://example.com");
2982 pp_string (&pp, "This is a link");
2983 pp_end_url (&pp);
2984 ASSERT_STREQ ("\33]8;;http://example.com\aThis is a link\33]8;;\a",
2985 pp_formatted_text (&pp));
2989 /* Verify that we gracefully reject null URLs. */
2991 void
2992 test_null_urls ()
2995 pretty_printer pp;
2996 pp.url_format = URL_FORMAT_NONE;
2997 pp_begin_url (&pp, nullptr);
2998 pp_string (&pp, "This isn't a link");
2999 pp_end_url (&pp);
3000 ASSERT_STREQ ("This isn't a link",
3001 pp_formatted_text (&pp));
3005 pretty_printer pp;
3006 pp.url_format = URL_FORMAT_ST;
3007 pp_begin_url (&pp, nullptr);
3008 pp_string (&pp, "This isn't a link");
3009 pp_end_url (&pp);
3010 ASSERT_STREQ ("This isn't a link",
3011 pp_formatted_text (&pp));
3015 pretty_printer pp;
3016 pp.url_format = URL_FORMAT_BEL;
3017 pp_begin_url (&pp, nullptr);
3018 pp_string (&pp, "This isn't a link");
3019 pp_end_url (&pp);
3020 ASSERT_STREQ ("This isn't a link",
3021 pp_formatted_text (&pp));
3025 /* Verify that URLification works as expected. */
3027 static void
3028 pp_printf_with_urlifier (pretty_printer *pp,
3029 const urlifier *urlifier,
3030 const char *msg, ...)
3032 va_list ap;
3034 va_start (ap, msg);
3035 text_info text (msg, &ap, errno);
3036 pp_format (pp, &text, urlifier);
3037 pp_output_formatted_text (pp, urlifier);
3038 va_end (ap);
3042 void
3043 test_urlification ()
3045 class test_urlifier : public urlifier
3047 public:
3048 char *
3049 get_url_for_quoted_text (const char *p, size_t sz) const final override
3051 if (!strncmp (p, "-foption", sz))
3052 return xstrdup ("http://example.com");
3053 return nullptr;
3057 auto_fix_quotes fix_quotes;
3058 const test_urlifier urlifier;
3060 /* Uses of "%<" and "%>". */
3063 pretty_printer pp;
3064 pp.url_format = URL_FORMAT_NONE;
3065 pp_printf_with_urlifier (&pp, &urlifier,
3066 "foo %<-foption%> %<unrecognized%> bar");
3067 ASSERT_STREQ ("foo `-foption' `unrecognized' bar",
3068 pp_formatted_text (&pp));
3071 pretty_printer pp;
3072 pp.url_format = URL_FORMAT_ST;
3073 pp_printf_with_urlifier (&pp, &urlifier,
3074 "foo %<-foption%> %<unrecognized%> bar");
3075 ASSERT_STREQ
3076 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
3077 " `unrecognized' bar",
3078 pp_formatted_text (&pp));
3081 pretty_printer pp;
3082 pp.url_format = URL_FORMAT_BEL;
3083 pp_printf_with_urlifier (&pp, &urlifier,
3084 "foo %<-foption%> %<unrecognized%> bar");
3085 ASSERT_STREQ
3086 ("foo `\33]8;;http://example.com\a-foption\33]8;;\a'"
3087 " `unrecognized' bar",
3088 pp_formatted_text (&pp));
3092 /* Use of "%qs". */
3094 pretty_printer pp;
3095 pp.url_format = URL_FORMAT_ST;
3096 pp_printf_with_urlifier (&pp, &urlifier,
3097 "foo %qs %qs bar",
3098 "-foption", "unrecognized");
3099 ASSERT_STREQ
3100 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
3101 " `unrecognized' bar",
3102 pp_formatted_text (&pp));
3105 /* Mixed usage of %< and %s, where the quoted string is built between
3106 a mixture of phase 1 and phase 2. */
3108 pretty_printer pp;
3109 pp.url_format = URL_FORMAT_ST;
3110 pp_printf_with_urlifier (&pp, &urlifier,
3111 "foo %<-f%s%> bar",
3112 "option");
3113 ASSERT_STREQ
3114 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3115 pp_formatted_text (&pp));
3118 /* Likewise, where there is trailing phase 1 content within the
3119 quoted region. */
3121 pretty_printer pp;
3122 pp.url_format = URL_FORMAT_ST;
3123 pp_printf_with_urlifier (&pp, &urlifier,
3124 "foo %<-f%sion%> bar %<-f%sion%> baz",
3125 "opt", "opt");
3126 ASSERT_STREQ
3127 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' baz",
3128 pp_formatted_text (&pp));
3131 /* Likewise. */
3133 pretty_printer pp;
3134 pp.url_format = URL_FORMAT_ST;
3135 pp_printf_with_urlifier (&pp, &urlifier,
3136 "foo %<%sption%> bar %<-f%sion%> baz",
3137 "-fo", "opt");
3138 ASSERT_STREQ
3139 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' baz",
3140 pp_formatted_text (&pp));
3143 /* Another mixed usage of %< and %s, where the quoted string is built
3144 between a mixture of phase 1 and multiple phase 2. */
3146 pretty_printer pp;
3147 pp.url_format = URL_FORMAT_ST;
3148 pp_printf_with_urlifier (&pp, &urlifier,
3149 "foo %<-f%s%s%> bar",
3150 "opt", "ion");
3151 ASSERT_STREQ
3152 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3153 pp_formatted_text (&pp));
3156 /* Mixed usage of %< and %s with a prefix. */
3158 pretty_printer pp;
3159 pp.url_format = URL_FORMAT_ST;
3160 pp_set_prefix (&pp, xstrdup ("PREFIX"));
3161 pp_printf_with_urlifier (&pp, &urlifier,
3162 "foo %<-f%s%> bar",
3163 "option");
3164 ASSERT_STREQ
3165 ("PREFIXfoo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3166 pp_formatted_text (&pp));
3169 /* Example of mixed %< and %s with numbered args. */
3171 pretty_printer pp;
3172 pp.url_format = URL_FORMAT_ST;
3173 pp_printf_with_urlifier (&pp, &urlifier,
3174 "foo %<-f%2$st%1$sn%> bar",
3175 "io", "op");
3176 ASSERT_STREQ
3177 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3178 pp_formatted_text (&pp));
3182 /* Test multibyte awareness. */
3183 static void test_utf8 ()
3186 /* Check that pp_quoted_string leaves valid UTF-8 alone. */
3188 pretty_printer pp;
3189 const char *s = "\xf0\x9f\x98\x82";
3190 pp_quoted_string (&pp, s);
3191 ASSERT_STREQ (pp_formatted_text (&pp), s);
3194 /* Check that pp_quoted_string escapes non-UTF-8 nonprintable bytes. */
3196 pretty_printer pp;
3197 pp_quoted_string (&pp, "\xf0!\x9f\x98\x82");
3198 ASSERT_STREQ (pp_formatted_text (&pp),
3199 "\\xf0!\\x9f\\x98\\x82");
3202 /* Check that pp_character will line-wrap at the beginning of a UTF-8
3203 sequence, but not in the middle. */
3205 pretty_printer pp (3);
3206 const char s[] = "---\xf0\x9f\x98\x82";
3207 for (int i = 0; i != sizeof (s) - 1; ++i)
3208 pp_character (&pp, s[i]);
3209 pp_newline (&pp);
3210 for (int i = 1; i != sizeof (s) - 1; ++i)
3211 pp_character (&pp, s[i]);
3212 pp_character (&pp, '-');
3213 ASSERT_STREQ (pp_formatted_text (&pp),
3214 "---\n"
3215 "\xf0\x9f\x98\x82\n"
3216 "--\xf0\x9f\x98\x82\n"
3217 "-");
3222 /* Run all of the selftests within this file. */
3224 void
3225 pretty_print_cc_tests ()
3227 test_basic_printing ();
3228 test_pp_format ();
3229 test_prefixes_and_wrapping ();
3230 test_urls ();
3231 test_null_urls ();
3232 test_urlification ();
3233 test_utf8 ();
3236 } // namespace selftest
3238 #endif /* CHECKING_P */