doc: Describe limitations re Ada, D, and Go on FreeBSD
[official-gcc.git] / gcc / pretty-print.cc
blobeb59bf424b7c6534d0511a24bc843456242a1a82
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);
755 #ifndef PTRDIFF_MAX
756 #define PTRDIFF_MAX INTTYPE_MAXIMUM (ptrdiff_t)
757 #endif
759 /* Format an integer given by va_arg (ARG, type-specifier T) where
760 type-specifier is a precision modifier as indicated by PREC. F is
761 a string used to construct the appropriate format-specifier. */
762 #define pp_integer_with_precision(PP, ARG, PREC, T, F) \
763 do \
764 switch (PREC) \
766 case 0: \
767 pp_scalar (PP, "%" F, va_arg (ARG, T)); \
768 break; \
770 case 1: \
771 pp_scalar (PP, "%l" F, va_arg (ARG, long T)); \
772 break; \
774 case 2: \
775 pp_scalar (PP, "%" HOST_LONG_LONG_FORMAT F, \
776 va_arg (ARG, long long T)); \
777 break; \
779 case 3: \
780 if (T (-1) < T (0)) \
781 pp_scalar (PP, "%" GCC_PRISZ F, \
782 (fmt_size_t) va_arg (ARG, ssize_t)); \
783 else \
784 pp_scalar (PP, "%" GCC_PRISZ F, \
785 (fmt_size_t) va_arg (ARG, size_t)); \
786 break; \
788 case 4: \
789 if (T (-1) >= T (0)) \
791 unsigned long long a = va_arg (ARG, ptrdiff_t); \
792 unsigned long long m = PTRDIFF_MAX; \
793 m = 2 * m + 1; \
794 pp_scalar (PP, "%" HOST_LONG_LONG_FORMAT F, \
795 a & m); \
797 else if (sizeof (ptrdiff_t) <= sizeof (int)) \
798 pp_scalar (PP, "%" F, \
799 (int) va_arg (ARG, ptrdiff_t)); \
800 else if (sizeof (ptrdiff_t) <= sizeof (long)) \
801 pp_scalar (PP, "%l" F, \
802 (long int) va_arg (ARG, ptrdiff_t)); \
803 else \
804 pp_scalar (PP, "%" HOST_LONG_LONG_FORMAT F, \
805 (long long int) \
806 va_arg (ARG, ptrdiff_t)); \
807 break; \
809 default: \
810 break; \
812 while (0)
815 /* Subroutine of pp_set_maximum_length. Set up PRETTY-PRINTER's
816 internal maximum characters per line. */
817 static void
818 pp_set_real_maximum_length (pretty_printer *pp)
820 /* If we're told not to wrap lines then do the obvious thing. In case
821 we'll emit prefix only once per message, it is appropriate
822 not to increase unnecessarily the line-length cut-off. */
823 if (!pp_is_wrapping_line (pp)
824 || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ONCE
825 || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
826 pp->maximum_length = pp_line_cutoff (pp);
827 else
829 int prefix_length = pp->prefix ? strlen (pp->prefix) : 0;
830 /* If the prefix is ridiculously too long, output at least
831 32 characters. */
832 if (pp_line_cutoff (pp) - prefix_length < 32)
833 pp->maximum_length = pp_line_cutoff (pp) + 32;
834 else
835 pp->maximum_length = pp_line_cutoff (pp);
839 /* Clear PRETTY-PRINTER's output state. */
840 static inline void
841 pp_clear_state (pretty_printer *pp)
843 pp->emitted_prefix = false;
844 pp_indentation (pp) = 0;
847 /* Print X to PP in decimal. */
848 template<unsigned int N, typename T>
849 void
850 pp_wide_integer (pretty_printer *pp, const poly_int<N, T> &x)
852 if (x.is_constant ())
853 pp_wide_integer (pp, x.coeffs[0]);
854 else
856 pp_left_bracket (pp);
857 for (unsigned int i = 0; i < N; ++i)
859 if (i != 0)
860 pp_comma (pp);
861 pp_wide_integer (pp, x.coeffs[i]);
863 pp_right_bracket (pp);
867 template void pp_wide_integer (pretty_printer *, const poly_uint16 &);
868 template void pp_wide_integer (pretty_printer *, const poly_int64 &);
869 template void pp_wide_integer (pretty_printer *, const poly_uint64 &);
871 /* Flush the formatted text of PRETTY-PRINTER onto the attached stream. */
872 void
873 pp_write_text_to_stream (pretty_printer *pp)
875 const char *text = pp_formatted_text (pp);
876 #ifdef __MINGW32__
877 mingw_ansi_fputs (text, pp_buffer (pp)->stream);
878 #else
879 fputs (text, pp_buffer (pp)->stream);
880 #endif
881 pp_clear_output_area (pp);
884 /* As pp_write_text_to_stream, but for GraphViz label output.
886 Flush the formatted text of pretty-printer PP onto the attached stream.
887 Replace characters in PPF that have special meaning in a GraphViz .dot
888 file.
890 This routine is not very fast, but it doesn't have to be as this is only
891 be used by routines dumping intermediate representations in graph form. */
893 void
894 pp_write_text_as_dot_label_to_stream (pretty_printer *pp, bool for_record)
896 const char *text = pp_formatted_text (pp);
897 const char *p = text;
898 FILE *fp = pp_buffer (pp)->stream;
900 for (;*p; p++)
902 bool escape_char;
903 switch (*p)
905 /* Print newlines as a left-aligned newline. */
906 case '\n':
907 fputs ("\\l", fp);
908 escape_char = true;
909 break;
911 /* The following characters are only special for record-shape nodes. */
912 case '|':
913 case '{':
914 case '}':
915 case '<':
916 case '>':
917 case ' ':
918 escape_char = for_record;
919 break;
921 /* The following characters always have to be escaped
922 for use in labels. */
923 case '\\':
924 /* There is a bug in some (f.i. 2.36.0) versions of graphiz
925 ( http://www.graphviz.org/mantisbt/view.php?id=2524 ) related to
926 backslash as last char in label. Let's avoid triggering it. */
927 gcc_assert (*(p + 1) != '\0');
928 /* Fall through. */
929 case '"':
930 escape_char = true;
931 break;
933 default:
934 escape_char = false;
935 break;
938 if (escape_char)
939 fputc ('\\', fp);
941 fputc (*p, fp);
944 pp_clear_output_area (pp);
947 /* As pp_write_text_to_stream, but for GraphViz HTML-like strings.
949 Flush the formatted text of pretty-printer PP onto the attached stream,
950 escaping these characters
951 " & < >
952 using XML escape sequences.
954 http://www.graphviz.org/doc/info/lang.html#html states:
955 special XML escape sequences for ", &, <, and > may be necessary in
956 order to embed these characters in attribute values or raw text
957 This doesn't list "'" (which would normally be escaped in XML
958 as "&apos;" or in HTML as "&#39;");.
960 Experiments show that escaping "'" doesn't seem to be necessary. */
962 void
963 pp_write_text_as_html_like_dot_to_stream (pretty_printer *pp)
965 const char *text = pp_formatted_text (pp);
966 const char *p = text;
967 FILE *fp = pp_buffer (pp)->stream;
969 for (;*p; p++)
971 switch (*p)
973 case '"':
974 fputs ("&quot;", fp);
975 break;
976 case '&':
977 fputs ("&amp;", fp);
978 break;
979 case '<':
980 fputs ("&lt;", fp);
981 break;
982 case '>':
983 fputs ("&gt;",fp);
984 break;
986 default:
987 fputc (*p, fp);
988 break;
992 pp_clear_output_area (pp);
995 /* Wrap a text delimited by START and END into PRETTY-PRINTER. */
996 static void
997 pp_wrap_text (pretty_printer *pp, const char *start, const char *end)
999 bool wrapping_line = pp_is_wrapping_line (pp);
1001 while (start != end)
1003 /* Dump anything bordered by whitespaces. */
1005 const char *p = start;
1006 while (p != end && !ISBLANK (*p) && *p != '\n')
1007 ++p;
1008 if (wrapping_line
1009 && p - start >= pp_remaining_character_count_for_line (pp))
1010 pp_newline (pp);
1011 pp_append_text (pp, start, p);
1012 start = p;
1015 if (start != end && ISBLANK (*start))
1017 pp_space (pp);
1018 ++start;
1020 if (start != end && *start == '\n')
1022 pp_newline (pp);
1023 ++start;
1028 /* Same as pp_wrap_text but wrap text only when in line-wrapping mode. */
1029 static inline void
1030 pp_maybe_wrap_text (pretty_printer *pp, const char *start, const char *end)
1032 if (pp_is_wrapping_line (pp))
1033 pp_wrap_text (pp, start, end);
1034 else
1035 pp_append_text (pp, start, end);
1038 /* Append to the output area of PRETTY-PRINTER a string specified by its
1039 STARTing character and LENGTH. */
1040 static inline void
1041 pp_append_r (pretty_printer *pp, const char *start, int length)
1043 output_buffer_append_r (pp_buffer (pp), start, length);
1046 /* Insert enough spaces into the output area of PRETTY-PRINTER to bring
1047 the column position to the current indentation level, assuming that a
1048 newline has just been written to the buffer. */
1049 void
1050 pp_indent (pretty_printer *pp)
1052 int n = pp_indentation (pp);
1053 int i;
1055 for (i = 0; i < n; ++i)
1056 pp_space (pp);
1059 static const char *get_end_url_string (pretty_printer *);
1061 /* Append STR to OSTACK, without a null-terminator. */
1063 static void
1064 obstack_append_string (obstack *ostack, const char *str)
1066 obstack_grow (ostack, str, strlen (str));
1069 /* Append STR to OSTACK, without a null-terminator. */
1071 static void
1072 obstack_append_string (obstack *ostack, const char *str, size_t len)
1074 obstack_grow (ostack, str, len);
1077 /* Given quoted text within the buffer OBSTACK
1078 at the half-open interval [QUOTED_TEXT_START_IDX, QUOTED_TEXT_END_IDX),
1079 potentially use URLIFIER (if non-null) to see if there's a URL for the
1080 quoted text.
1082 If so, replace the quoted part of the text in the buffer with a URLified
1083 version of the text, using PP's settings.
1085 For example, given this is the buffer:
1086 "this is a test `hello worldTRAILING-CONTENT"
1087 .................^~~~~~~~~~~
1088 with the quoted text starting at the 'h' of "hello world", the buffer
1089 becomes:
1090 "this is a test `BEGIN_URL(URL)hello worldEND(URL)TRAILING-CONTENT"
1091 .................^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1092 .................-----------replacement-----------
1094 Return the new offset into the buffer of the quoted text endpoint i.e.
1095 the offset of "TRAILING-CONTENT" in the above. */
1097 static size_t
1098 urlify_quoted_string (pretty_printer *pp,
1099 obstack *obstack,
1100 const urlifier *urlifier,
1101 size_t quoted_text_start_idx,
1102 size_t quoted_text_end_idx)
1104 if (pp->url_format == URL_FORMAT_NONE)
1105 return quoted_text_end_idx;
1106 if (!urlifier)
1107 return quoted_text_end_idx;
1109 const size_t quoted_len = quoted_text_end_idx - quoted_text_start_idx;
1110 if (quoted_len == 0)
1111 /* Empty quoted string; do nothing. */
1112 return quoted_text_end_idx;
1113 const char *start = (obstack->object_base + quoted_text_start_idx);
1114 char *url = urlifier->get_url_for_quoted_text (start, quoted_len);
1115 if (!url)
1116 /* No URL for this quoted text; do nothing. */
1117 return quoted_text_end_idx;
1119 /* Stash a copy of the remainder of the chunk. */
1120 char *text = xstrndup (start,
1121 obstack_object_size (obstack) - quoted_text_start_idx);
1123 /* Replace quoted text... */
1124 obstack->next_free = obstack->object_base + quoted_text_start_idx;
1126 /* ...with URLified version of the text. */
1127 /* Begin URL. */
1128 switch (pp->url_format)
1130 default:
1131 case URL_FORMAT_NONE:
1132 gcc_unreachable ();
1133 case URL_FORMAT_ST:
1134 obstack_append_string (obstack, "\33]8;;");
1135 obstack_append_string (obstack, url);
1136 obstack_append_string (obstack, "\33\\");
1137 break;
1138 case URL_FORMAT_BEL:
1139 obstack_append_string (obstack, "\33]8;;");
1140 obstack_append_string (obstack, url);
1141 obstack_append_string (obstack, "\a");
1142 break;
1144 /* Add back the quoted part of the text. */
1145 obstack_append_string (obstack, text, quoted_len);
1146 /* End URL. */
1147 obstack_append_string (obstack,
1148 get_end_url_string (pp));
1150 size_t new_end_idx = obstack_object_size (obstack);
1152 /* Add back the remainder of the text after the quoted part. */
1153 obstack_append_string (obstack, text + quoted_len);
1154 free (text);
1155 free (url);
1156 return new_end_idx;
1159 /* A class for tracking quoted text within a buffer for
1160 use by a urlifier. */
1162 class quoting_info
1164 public:
1165 /* Called when quoted text is begun in phase 1 or 2. */
1166 void on_begin_quote (const output_buffer &buf,
1167 unsigned chunk_idx)
1169 /* Stash location of start of quoted string. */
1170 size_t byte_offset = obstack_object_size (&buf.chunk_obstack);
1171 m_loc_last_open_quote = location (chunk_idx, byte_offset);
1174 /* Called when quoted text is ended in phase 1 or 2. */
1175 void on_end_quote (pretty_printer *pp,
1176 output_buffer &buf,
1177 unsigned chunk_idx,
1178 const urlifier &urlifier)
1180 /* If possible, do urlification now. */
1181 if (chunk_idx == m_loc_last_open_quote.m_chunk_idx)
1183 urlify_quoted_string (pp,
1184 &buf.chunk_obstack,
1185 &urlifier,
1186 m_loc_last_open_quote.m_byte_offset,
1187 obstack_object_size (&buf.chunk_obstack));
1188 m_loc_last_open_quote = location ();
1189 return;
1191 /* Otherwise the quoted text straddles multiple chunks.
1192 Stash the location of end of quoted string for use in phase 3. */
1193 size_t byte_offset = obstack_object_size (&buf.chunk_obstack);
1194 m_phase_3_quotes.push_back (run (m_loc_last_open_quote,
1195 location (chunk_idx, byte_offset)));
1196 m_loc_last_open_quote = location ();
1199 bool has_phase_3_quotes_p () const
1201 return m_phase_3_quotes.size () > 0;
1203 void handle_phase_3 (pretty_printer *pp,
1204 const urlifier &urlifier);
1206 private:
1207 struct location
1209 location ()
1210 : m_chunk_idx (UINT_MAX),
1211 m_byte_offset (SIZE_MAX)
1215 location (unsigned chunk_idx,
1216 size_t byte_offset)
1217 : m_chunk_idx (chunk_idx),
1218 m_byte_offset (byte_offset)
1222 unsigned m_chunk_idx;
1223 size_t m_byte_offset;
1226 struct run
1228 run (location start, location end)
1229 : m_start (start), m_end (end)
1233 location m_start;
1234 location m_end;
1237 location m_loc_last_open_quote;
1238 std::vector<run> m_phase_3_quotes;
1241 static void
1242 on_begin_quote (const output_buffer &buf,
1243 unsigned chunk_idx,
1244 const urlifier *urlifier)
1246 if (!urlifier)
1247 return;
1248 if (!buf.cur_chunk_array->m_quotes)
1249 buf.cur_chunk_array->m_quotes = new quoting_info ();
1250 buf.cur_chunk_array->m_quotes->on_begin_quote (buf, chunk_idx);
1253 static void
1254 on_end_quote (pretty_printer *pp,
1255 output_buffer &buf,
1256 unsigned chunk_idx,
1257 const urlifier *urlifier)
1259 if (!urlifier)
1260 return;
1261 if (!buf.cur_chunk_array->m_quotes)
1262 buf.cur_chunk_array->m_quotes = new quoting_info ();
1263 buf.cur_chunk_array->m_quotes->on_end_quote (pp, buf, chunk_idx, *urlifier);
1266 /* The following format specifiers are recognized as being client independent:
1267 %d, %i: (signed) integer in base ten.
1268 %u: unsigned integer in base ten.
1269 %o: unsigned integer in base eight.
1270 %x: unsigned integer in base sixteen.
1271 %ld, %li, %lo, %lu, %lx: long versions of the above.
1272 %lld, %lli, %llo, %llu, %llx: long long versions.
1273 %wd, %wi, %wo, %wu, %wx: HOST_WIDE_INT versions.
1274 %zd, %zi, %zo, %zu, %zx: size_t versions.
1275 %td, %ti, %to, %tu, %tx: ptrdiff_t versions.
1276 %f: double
1277 %c: character.
1278 %s: string.
1279 %p: pointer (printed in a host-dependent manner).
1280 %r: if pp_show_color(pp), switch to color identified by const char *.
1281 %R: if pp_show_color(pp), reset color.
1282 %m: strerror(text->err_no) - does not consume a value from args_ptr.
1283 %%: '%'.
1284 %<: opening quote.
1285 %>: closing quote.
1286 %{: URL start. Consumes a const char * argument for the URL.
1287 %}: URL end. Does not consume any arguments.
1288 %': apostrophe (should only be used in untranslated messages;
1289 translations should use appropriate punctuation directly).
1290 %@: diagnostic_event_id_ptr, for which event_id->known_p () must be true.
1291 %.*s: a substring the length of which is specified by an argument
1292 integer.
1293 %Ns: likewise, but length specified as constant in the format string.
1294 Flag 'q': quote formatted text (must come immediately after '%').
1295 %Z: Requires two arguments - array of int, and len. Prints elements
1296 of the array.
1298 Arguments can be used sequentially, or through %N$ resp. *N$
1299 notation Nth argument after the format string. If %N$ / *N$
1300 notation is used, it must be used for all arguments, except %m, %%,
1301 %<, %>, %} and %', which may not have a number, as they do not consume
1302 an argument. When %M$.*N$s is used, M must be N + 1. (This may
1303 also be written %M$.*s, provided N is not otherwise used.) The
1304 format string must have conversion specifiers with argument numbers
1305 1 up to highest argument; each argument may only be used once.
1306 A format string can have at most 30 arguments. */
1308 /* Formatting phases 1 and 2: render TEXT->format_spec plus
1309 text->m_args_ptr into a series of chunks in pp_buffer (PP)->args[].
1310 Phase 3 is in pp_output_formatted_text.
1312 If URLIFIER is non-NULL, then use it to add URLs for quoted
1313 strings, so that e.g.
1314 "before %<quoted%> after"
1315 with a URLIFIER that has a URL for "quoted" might be emitted as:
1316 "before `BEGIN_URL(http://example.com)quotedEND_URL' after"
1317 This is handled here for message fragments that are:
1318 - quoted entirely in phase 1 (e.g. "%<this is quoted%>"), or
1319 - quoted entirely in phase 2 (e.g. "%qs"),
1320 Quoted fragments that use a mixture of both phases
1321 (e.g. "%<this is a mixture: %s %>")
1322 are stashed into the output_buffer's m_quotes for use in phase 3. */
1324 void
1325 pp_format (pretty_printer *pp,
1326 text_info *text,
1327 const urlifier *urlifier)
1329 output_buffer * const buffer = pp_buffer (pp);
1330 const char *p;
1331 const char **args;
1332 struct chunk_info *new_chunk_array;
1334 unsigned int curarg = 0, chunk = 0, argno;
1335 pp_wrapping_mode_t old_wrapping_mode;
1336 bool any_unnumbered = false, any_numbered = false;
1337 const char **formatters[PP_NL_ARGMAX];
1339 /* Allocate a new chunk structure. */
1340 new_chunk_array = XOBNEW (&buffer->chunk_obstack, struct chunk_info);
1342 new_chunk_array->prev = buffer->cur_chunk_array;
1343 new_chunk_array->m_quotes = nullptr;
1344 buffer->cur_chunk_array = new_chunk_array;
1345 args = new_chunk_array->args;
1347 /* Formatting phase 1: split up TEXT->format_spec into chunks in
1348 pp_buffer (PP)->args[]. Even-numbered chunks are to be output
1349 verbatim, odd-numbered chunks are format specifiers.
1350 %m, %%, %<, %>, %} and %' are replaced with the appropriate text at
1351 this point. */
1353 memset (formatters, 0, sizeof formatters);
1355 for (p = text->m_format_spec; *p; )
1357 while (*p != '\0' && *p != '%')
1359 obstack_1grow (&buffer->chunk_obstack, *p);
1360 p++;
1363 if (*p == '\0')
1364 break;
1366 switch (*++p)
1368 case '\0':
1369 gcc_unreachable ();
1371 case '%':
1372 obstack_1grow (&buffer->chunk_obstack, '%');
1373 p++;
1374 continue;
1376 case '<':
1378 obstack_grow (&buffer->chunk_obstack,
1379 open_quote, strlen (open_quote));
1380 const char *colorstr
1381 = colorize_start (pp_show_color (pp), "quote");
1382 obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
1383 p++;
1385 on_begin_quote (*buffer, chunk, urlifier);
1386 continue;
1389 case '>':
1391 on_end_quote (pp, *buffer, chunk, urlifier);
1393 const char *colorstr = colorize_stop (pp_show_color (pp));
1394 obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
1396 /* FALLTHRU */
1397 case '\'':
1398 obstack_grow (&buffer->chunk_obstack,
1399 close_quote, strlen (close_quote));
1400 p++;
1401 continue;
1403 case '}':
1405 const char *endurlstr = get_end_url_string (pp);
1406 obstack_grow (&buffer->chunk_obstack, endurlstr,
1407 strlen (endurlstr));
1409 p++;
1410 continue;
1412 case 'R':
1414 const char *colorstr = colorize_stop (pp_show_color (pp));
1415 obstack_grow (&buffer->chunk_obstack, colorstr,
1416 strlen (colorstr));
1417 p++;
1418 continue;
1421 case 'm':
1423 const char *errstr = xstrerror (text->m_err_no);
1424 obstack_grow (&buffer->chunk_obstack, errstr, strlen (errstr));
1426 p++;
1427 continue;
1429 default:
1430 /* Handled in phase 2. Terminate the plain chunk here. */
1431 obstack_1grow (&buffer->chunk_obstack, '\0');
1432 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1433 break;
1436 if (ISDIGIT (*p))
1438 char *end;
1439 argno = strtoul (p, &end, 10) - 1;
1440 p = end;
1441 gcc_assert (*p == '$');
1442 p++;
1444 any_numbered = true;
1445 gcc_assert (!any_unnumbered);
1447 else
1449 argno = curarg++;
1450 any_unnumbered = true;
1451 gcc_assert (!any_numbered);
1453 gcc_assert (argno < PP_NL_ARGMAX);
1454 gcc_assert (!formatters[argno]);
1455 formatters[argno] = &args[chunk];
1458 obstack_1grow (&buffer->chunk_obstack, *p);
1459 p++;
1461 while (strchr ("qwlzt+#", p[-1]));
1463 if (p[-1] == '.')
1465 /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
1466 (where M == N + 1). */
1467 if (ISDIGIT (*p))
1471 obstack_1grow (&buffer->chunk_obstack, *p);
1472 p++;
1474 while (ISDIGIT (p[-1]));
1475 gcc_assert (p[-1] == 's');
1477 else
1479 gcc_assert (*p == '*');
1480 obstack_1grow (&buffer->chunk_obstack, '*');
1481 p++;
1483 if (ISDIGIT (*p))
1485 char *end;
1486 unsigned int argno2 = strtoul (p, &end, 10) - 1;
1487 p = end;
1488 gcc_assert (argno2 == argno - 1);
1489 gcc_assert (!any_unnumbered);
1490 gcc_assert (*p == '$');
1492 p++;
1493 formatters[argno2] = formatters[argno];
1495 else
1497 gcc_assert (!any_numbered);
1498 formatters[argno+1] = formatters[argno];
1499 curarg++;
1501 gcc_assert (*p == 's');
1502 obstack_1grow (&buffer->chunk_obstack, 's');
1503 p++;
1506 if (*p == '\0')
1507 break;
1509 obstack_1grow (&buffer->chunk_obstack, '\0');
1510 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1511 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1514 obstack_1grow (&buffer->chunk_obstack, '\0');
1515 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1516 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1517 args[chunk] = 0;
1519 /* Set output to the argument obstack, and switch line-wrapping and
1520 prefixing off. */
1521 buffer->obstack = &buffer->chunk_obstack;
1522 const int old_line_length = buffer->line_length;
1523 old_wrapping_mode = pp_set_verbatim_wrapping (pp);
1525 /* Second phase. Replace each formatter with the formatted text it
1526 corresponds to. */
1528 for (argno = 0; formatters[argno]; argno++)
1530 int precision = 0;
1531 bool wide = false;
1532 bool plus = false;
1533 bool hash = false;
1534 bool quote = false;
1536 /* We do not attempt to enforce any ordering on the modifier
1537 characters. */
1539 for (p = *formatters[argno];; p++)
1541 switch (*p)
1543 case 'q':
1544 gcc_assert (!quote);
1545 quote = true;
1546 continue;
1548 case '+':
1549 gcc_assert (!plus);
1550 plus = true;
1551 continue;
1553 case '#':
1554 gcc_assert (!hash);
1555 hash = true;
1556 continue;
1558 case 'w':
1559 gcc_assert (!wide);
1560 wide = true;
1561 continue;
1563 case 'z':
1564 gcc_assert (!precision);
1565 precision = 3;
1566 continue;
1568 case 't':
1569 gcc_assert (!precision);
1570 precision = 4;
1571 continue;
1573 case 'l':
1574 /* We don't support precision beyond that of "long long". */
1575 gcc_assert (precision < 2);
1576 precision++;
1577 continue;
1579 break;
1582 gcc_assert (!wide || precision == 0);
1584 if (quote)
1586 pp_begin_quote (pp, pp_show_color (pp));
1587 on_begin_quote (*buffer, chunk, urlifier);
1590 switch (*p)
1592 case 'r':
1593 pp_string (pp, colorize_start (pp_show_color (pp),
1594 va_arg (*text->m_args_ptr,
1595 const char *)));
1596 break;
1598 case 'c':
1600 /* When quoting, print alphanumeric, punctuation, and the space
1601 character unchanged, and all others in hexadecimal with the
1602 "\x" prefix. Otherwise print them all unchanged. */
1603 int chr = va_arg (*text->m_args_ptr, int);
1604 if (ISPRINT (chr) || !quote)
1605 pp_character (pp, chr);
1606 else
1608 const char str [2] = { chr, '\0' };
1609 pp_quoted_string (pp, str, 1);
1611 break;
1614 case 'd':
1615 case 'i':
1616 if (wide)
1617 pp_wide_integer (pp, va_arg (*text->m_args_ptr, HOST_WIDE_INT));
1618 else
1619 pp_integer_with_precision (pp, *text->m_args_ptr, precision,
1620 int, "d");
1621 break;
1623 case 'o':
1624 if (wide)
1625 pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
1626 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1627 else
1628 pp_integer_with_precision (pp, *text->m_args_ptr, precision,
1629 unsigned, "o");
1630 break;
1632 case 's':
1633 if (quote)
1634 pp_quoted_string (pp, va_arg (*text->m_args_ptr, const char *));
1635 else
1636 pp_string (pp, va_arg (*text->m_args_ptr, const char *));
1637 break;
1639 case 'p':
1640 pp_pointer (pp, va_arg (*text->m_args_ptr, void *));
1641 break;
1643 case 'u':
1644 if (wide)
1645 pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
1646 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1647 else
1648 pp_integer_with_precision (pp, *text->m_args_ptr, precision,
1649 unsigned, "u");
1650 break;
1652 case 'f':
1653 pp_double (pp, va_arg (*text->m_args_ptr, double));
1654 break;
1656 case 'Z':
1658 int *v = va_arg (*text->m_args_ptr, int *);
1659 unsigned len = va_arg (*text->m_args_ptr, unsigned);
1661 for (unsigned i = 0; i < len; ++i)
1663 pp_scalar (pp, "%i", v[i]);
1664 if (i < len - 1)
1666 pp_comma (pp);
1667 pp_space (pp);
1670 break;
1673 case 'x':
1674 if (wide)
1675 pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
1676 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1677 else
1678 pp_integer_with_precision (pp, *text->m_args_ptr, precision,
1679 unsigned, "x");
1680 break;
1682 case '.':
1684 int n;
1685 const char *s;
1687 /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
1688 (where M == N + 1). The format string should be verified
1689 already from the first phase. */
1690 p++;
1691 if (ISDIGIT (*p))
1693 char *end;
1694 n = strtoul (p, &end, 10);
1695 p = end;
1696 gcc_assert (*p == 's');
1698 else
1700 gcc_assert (*p == '*');
1701 p++;
1702 gcc_assert (*p == 's');
1703 n = va_arg (*text->m_args_ptr, int);
1705 /* This consumes a second entry in the formatters array. */
1706 gcc_assert (formatters[argno] == formatters[argno+1]);
1707 argno++;
1710 s = va_arg (*text->m_args_ptr, const char *);
1712 /* Append the lesser of precision and strlen (s) characters
1713 from the array (which need not be a nul-terminated string).
1714 Negative precision is treated as if it were omitted. */
1715 size_t len = n < 0 ? strlen (s) : strnlen (s, n);
1717 pp_append_text (pp, s, s + len);
1719 break;
1721 case '@':
1723 /* diagnostic_event_id_t *. */
1724 diagnostic_event_id_ptr event_id
1725 = va_arg (*text->m_args_ptr, diagnostic_event_id_ptr);
1726 gcc_assert (event_id->known_p ());
1728 pp_string (pp, colorize_start (pp_show_color (pp), "path"));
1729 pp_character (pp, '(');
1730 pp_decimal_int (pp, event_id->one_based ());
1731 pp_character (pp, ')');
1732 pp_string (pp, colorize_stop (pp_show_color (pp)));
1734 break;
1736 case '{':
1737 pp_begin_url (pp, va_arg (*text->m_args_ptr, const char *));
1738 break;
1740 default:
1742 bool ok;
1744 /* Call the format decoder.
1745 Pass the address of "quote" so that format decoders can
1746 potentially disable printing of the closing quote
1747 (e.g. when printing "'TYPEDEF' aka 'TYPE'" in the C family
1748 of frontends). */
1749 gcc_assert (pp_format_decoder (pp));
1750 ok = pp_format_decoder (pp) (pp, text, p,
1751 precision, wide, plus, hash, &quote,
1752 formatters[argno]);
1753 gcc_assert (ok);
1757 if (quote)
1759 on_end_quote (pp, *buffer, chunk, urlifier);
1760 pp_end_quote (pp, pp_show_color (pp));
1763 obstack_1grow (&buffer->chunk_obstack, '\0');
1764 *formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *);
1767 if (CHECKING_P)
1768 for (; argno < PP_NL_ARGMAX; argno++)
1769 gcc_assert (!formatters[argno]);
1771 /* If the client supplied a postprocessing object, call its "handle"
1772 hook here. */
1773 if (pp->m_format_postprocessor)
1774 pp->m_format_postprocessor->handle (pp);
1776 /* Revert to normal obstack and wrapping mode. */
1777 buffer->obstack = &buffer->formatted_obstack;
1778 buffer->line_length = old_line_length;
1779 pp_wrapping_mode (pp) = old_wrapping_mode;
1780 pp_clear_state (pp);
1783 struct auto_obstack
1785 auto_obstack ()
1787 obstack_init (&m_obstack);
1790 ~auto_obstack ()
1792 obstack_free (&m_obstack, NULL);
1795 void grow (const void *src, size_t length)
1797 obstack_grow (&m_obstack, src, length);
1800 void *object_base () const
1802 return m_obstack.object_base;
1805 size_t object_size () const
1807 return obstack_object_size (&m_obstack);
1810 obstack m_obstack;
1813 /* Subroutine of pp_output_formatted_text for the awkward case where
1814 quoted text straddles multiple chunks.
1816 Flush PP's buffer's chunks to PP's output buffer, whilst inserting
1817 URLs for any quoted text that should be URLified.
1819 For example, given:
1820 | pp_format (pp,
1821 | "unrecognized option %qs; did you mean %<-%s%>",
1822 | "foo", "foption");
1823 we would have these chunks:
1824 | chunk 0: "unrecognized option "
1825 | chunk 1: "`foo'" (already checked for urlification)
1826 | chunk 2: "; did you mean `-"
1827 | ^*
1828 | chunk 3: "foption"
1829 | *******
1830 | chunk 4: "'"
1832 and this quoting_info would have recorded the open quote near the end
1833 of chunk 2 and close quote at the start of chunk 4; this function would
1834 check the combination of the end of chunk 2 and all of chunk 3 ("-foption")
1835 for urlification. */
1837 void
1838 quoting_info::handle_phase_3 (pretty_printer *pp,
1839 const urlifier &urlifier)
1841 unsigned int chunk;
1842 output_buffer * const buffer = pp_buffer (pp);
1843 struct chunk_info *chunk_array = buffer->cur_chunk_array;
1844 const char **args = chunk_array->args;
1846 /* We need to construct the string into an intermediate buffer
1847 for this case, since using pp_string can introduce prefixes
1848 and line-wrapping, and omit whitespace at the start of lines. */
1849 auto_obstack combined_buf;
1851 /* Iterate simultaneously through both
1852 - the chunks and
1853 - the runs of quoted characters
1854 Accumulate text from the chunks into combined_buf, and handle
1855 runs of quoted characters when handling the chunks they
1856 correspond to. */
1857 size_t start_of_run_byte_offset = 0;
1858 std::vector<quoting_info::run>::const_iterator iter_run
1859 = buffer->cur_chunk_array->m_quotes->m_phase_3_quotes.begin ();
1860 std::vector<quoting_info::run>::const_iterator end_runs
1861 = buffer->cur_chunk_array->m_quotes->m_phase_3_quotes.end ();
1862 for (chunk = 0; args[chunk]; chunk++)
1864 size_t start_of_chunk_idx = combined_buf.object_size ();
1866 combined_buf.grow (args[chunk], strlen (args[chunk]));
1868 if (iter_run != end_runs
1869 && chunk == iter_run->m_end.m_chunk_idx)
1871 /* A run is ending; consider for it urlification. */
1872 const size_t end_of_run_byte_offset
1873 = start_of_chunk_idx + iter_run->m_end.m_byte_offset;
1874 const size_t end_offset
1875 = urlify_quoted_string (pp,
1876 &combined_buf.m_obstack,
1877 &urlifier,
1878 start_of_run_byte_offset,
1879 end_of_run_byte_offset);
1881 /* If URLification occurred it will have grown the buffer.
1882 We need to update start_of_chunk_idx so that offsets
1883 relative to it are still correct, for the case where
1884 we have a chunk that both ends a quoted run and starts
1885 another quoted run. */
1886 gcc_assert (end_offset >= end_of_run_byte_offset);
1887 start_of_chunk_idx += end_offset - end_of_run_byte_offset;
1889 iter_run++;
1891 if (iter_run != end_runs
1892 && chunk == iter_run->m_start.m_chunk_idx)
1894 /* Note where the run starts w.r.t. the composed buffer. */
1895 start_of_run_byte_offset
1896 = start_of_chunk_idx + iter_run->m_start.m_byte_offset;
1900 /* Now print to PP. */
1901 const char *start
1902 = static_cast <const char *> (combined_buf.object_base ());
1903 pp_maybe_wrap_text (pp, start, start + combined_buf.object_size ());
1906 /* Format of a message pointed to by TEXT.
1907 If URLIFIER is non-null then use it on any quoted text that was not
1908 handled in phases 1 or 2 to potentially add URLs. */
1910 void
1911 pp_output_formatted_text (pretty_printer *pp,
1912 const urlifier *urlifier)
1914 unsigned int chunk;
1915 output_buffer * const buffer = pp_buffer (pp);
1916 struct chunk_info *chunk_array = buffer->cur_chunk_array;
1917 const char **args = chunk_array->args;
1919 gcc_assert (buffer->obstack == &buffer->formatted_obstack);
1921 /* This is a third phase, first 2 phases done in pp_format_args.
1922 Now we actually print it. */
1924 /* If we have any deferred urlification, handle it now. */
1925 if (urlifier
1926 && pp->url_format != URL_FORMAT_NONE
1927 && buffer->cur_chunk_array->m_quotes
1928 && buffer->cur_chunk_array->m_quotes->has_phase_3_quotes_p ())
1929 buffer->cur_chunk_array->m_quotes->handle_phase_3 (pp, *urlifier);
1930 else
1931 for (chunk = 0; args[chunk]; chunk++)
1932 pp_string (pp, args[chunk]);
1934 /* Deallocate the chunk structure and everything after it (i.e. the
1935 associated series of formatted strings). */
1936 delete buffer->cur_chunk_array->m_quotes;
1937 buffer->cur_chunk_array = chunk_array->prev;
1938 obstack_free (&buffer->chunk_obstack, chunk_array);
1941 /* Helper subroutine of output_verbatim and verbatim. Do the appropriate
1942 settings needed by BUFFER for a verbatim formatting. */
1943 void
1944 pp_format_verbatim (pretty_printer *pp, text_info *text)
1946 /* Set verbatim mode. */
1947 pp_wrapping_mode_t oldmode = pp_set_verbatim_wrapping (pp);
1949 /* Do the actual formatting. */
1950 pp_format (pp, text);
1951 pp_output_formatted_text (pp);
1953 /* Restore previous settings. */
1954 pp_wrapping_mode (pp) = oldmode;
1957 /* Flush the content of BUFFER onto the attached stream. This
1958 function does nothing unless pp->output_buffer->flush_p. */
1959 void
1960 pp_flush (pretty_printer *pp)
1962 pp_clear_state (pp);
1963 if (!pp->buffer->flush_p)
1964 return;
1965 pp_write_text_to_stream (pp);
1966 fflush (pp_buffer (pp)->stream);
1969 /* Flush the content of BUFFER onto the attached stream independently
1970 of the value of pp->output_buffer->flush_p. */
1971 void
1972 pp_really_flush (pretty_printer *pp)
1974 pp_clear_state (pp);
1975 pp_write_text_to_stream (pp);
1976 fflush (pp_buffer (pp)->stream);
1979 /* Sets the number of maximum characters per line PRETTY-PRINTER can
1980 output in line-wrapping mode. A LENGTH value 0 suppresses
1981 line-wrapping. */
1982 void
1983 pp_set_line_maximum_length (pretty_printer *pp, int length)
1985 pp_line_cutoff (pp) = length;
1986 pp_set_real_maximum_length (pp);
1989 /* Clear PRETTY-PRINTER output area text info. */
1990 void
1991 pp_clear_output_area (pretty_printer *pp)
1993 obstack_free (pp_buffer (pp)->obstack,
1994 obstack_base (pp_buffer (pp)->obstack));
1995 pp_buffer (pp)->line_length = 0;
1998 /* Set PREFIX for PRETTY-PRINTER, taking ownership of PREFIX, which
1999 will eventually be free-ed. */
2001 void
2002 pp_set_prefix (pretty_printer *pp, char *prefix)
2004 free (pp->prefix);
2005 pp->prefix = prefix;
2006 pp_set_real_maximum_length (pp);
2007 pp->emitted_prefix = false;
2008 pp_indentation (pp) = 0;
2011 /* Take ownership of PP's prefix, setting it to NULL.
2012 This allows clients to save, override, and then restore an existing
2013 prefix, without it being free-ed. */
2015 char *
2016 pp_take_prefix (pretty_printer *pp)
2018 char *result = pp->prefix;
2019 pp->prefix = NULL;
2020 return result;
2023 /* Free PRETTY-PRINTER's prefix, a previously malloc()'d string. */
2024 void
2025 pp_destroy_prefix (pretty_printer *pp)
2027 if (pp->prefix != NULL)
2029 free (pp->prefix);
2030 pp->prefix = NULL;
2034 /* Write out PRETTY-PRINTER's prefix. */
2035 void
2036 pp_emit_prefix (pretty_printer *pp)
2038 if (pp->prefix != NULL)
2040 switch (pp_prefixing_rule (pp))
2042 default:
2043 case DIAGNOSTICS_SHOW_PREFIX_NEVER:
2044 break;
2046 case DIAGNOSTICS_SHOW_PREFIX_ONCE:
2047 if (pp->emitted_prefix)
2049 pp_indent (pp);
2050 break;
2052 pp_indentation (pp) += 3;
2053 /* Fall through. */
2055 case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE:
2057 int prefix_length = strlen (pp->prefix);
2058 pp_append_r (pp, pp->prefix, prefix_length);
2059 pp->emitted_prefix = true;
2061 break;
2066 /* Construct a PRETTY-PRINTER of MAXIMUM_LENGTH characters per line. */
2068 pretty_printer::pretty_printer (int maximum_length)
2069 : buffer (new (XCNEW (output_buffer)) output_buffer ()),
2070 prefix (),
2071 padding (pp_none),
2072 maximum_length (),
2073 indent_skip (),
2074 wrapping (),
2075 format_decoder (),
2076 m_format_postprocessor (NULL),
2077 emitted_prefix (),
2078 need_newline (),
2079 translate_identifiers (true),
2080 show_color (),
2081 url_format (URL_FORMAT_NONE),
2082 m_skipping_null_url (false)
2084 pp_line_cutoff (this) = maximum_length;
2085 /* By default, we emit prefixes once per message. */
2086 pp_prefixing_rule (this) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
2087 pp_set_prefix (this, NULL);
2090 /* Copy constructor for pretty_printer. */
2092 pretty_printer::pretty_printer (const pretty_printer &other)
2093 : buffer (new (XCNEW (output_buffer)) output_buffer ()),
2094 prefix (),
2095 padding (other.padding),
2096 maximum_length (other.maximum_length),
2097 indent_skip (other.indent_skip),
2098 wrapping (other.wrapping),
2099 format_decoder (other.format_decoder),
2100 m_format_postprocessor (NULL),
2101 emitted_prefix (other.emitted_prefix),
2102 need_newline (other.need_newline),
2103 translate_identifiers (other.translate_identifiers),
2104 show_color (other.show_color),
2105 url_format (other.url_format),
2106 m_skipping_null_url (false)
2108 pp_line_cutoff (this) = maximum_length;
2109 /* By default, we emit prefixes once per message. */
2110 pp_prefixing_rule (this) = pp_prefixing_rule (&other);
2111 pp_set_prefix (this, NULL);
2113 if (other.m_format_postprocessor)
2114 m_format_postprocessor = other.m_format_postprocessor->clone ();
2117 pretty_printer::~pretty_printer ()
2119 if (m_format_postprocessor)
2120 delete m_format_postprocessor;
2121 buffer->~output_buffer ();
2122 XDELETE (buffer);
2123 free (prefix);
2126 /* Base class implementation of pretty_printer::clone vfunc. */
2128 pretty_printer *
2129 pretty_printer::clone () const
2131 return new pretty_printer (*this);
2134 /* Append a string delimited by START and END to the output area of
2135 PRETTY-PRINTER. No line wrapping is done. However, if beginning a
2136 new line then emit PRETTY-PRINTER's prefix and skip any leading
2137 whitespace if appropriate. The caller must ensure that it is
2138 safe to do so. */
2139 void
2140 pp_append_text (pretty_printer *pp, const char *start, const char *end)
2142 /* Emit prefix and skip whitespace if we're starting a new line. */
2143 if (pp_buffer (pp)->line_length == 0)
2145 pp_emit_prefix (pp);
2146 if (pp_is_wrapping_line (pp))
2147 while (start != end && *start == ' ')
2148 ++start;
2150 pp_append_r (pp, start, end - start);
2153 /* Finishes constructing a NULL-terminated character string representing
2154 the PRETTY-PRINTED text. */
2155 const char *
2156 pp_formatted_text (pretty_printer *pp)
2158 return output_buffer_formatted_text (pp_buffer (pp));
2161 /* Return a pointer to the last character emitted in PRETTY-PRINTER's
2162 output area. A NULL pointer means no character available. */
2163 const char *
2164 pp_last_position_in_text (const pretty_printer *pp)
2166 return output_buffer_last_position_in_text (pp_buffer (pp));
2169 /* Return the amount of characters PRETTY-PRINTER can accept to
2170 make a full line. Meaningful only in line-wrapping mode. */
2172 pp_remaining_character_count_for_line (pretty_printer *pp)
2174 return pp->maximum_length - pp_buffer (pp)->line_length;
2178 /* Format a message into BUFFER a la printf. */
2179 void
2180 pp_printf (pretty_printer *pp, const char *msg, ...)
2182 va_list ap;
2184 va_start (ap, msg);
2185 text_info text (msg, &ap, errno);
2186 pp_format (pp, &text);
2187 pp_output_formatted_text (pp);
2188 va_end (ap);
2192 /* Output MESSAGE verbatim into BUFFER. */
2193 void
2194 pp_verbatim (pretty_printer *pp, const char *msg, ...)
2196 va_list ap;
2198 va_start (ap, msg);
2199 text_info text (msg, &ap, errno);
2200 pp_format_verbatim (pp, &text);
2201 va_end (ap);
2206 /* Have PRETTY-PRINTER start a new line. */
2207 void
2208 pp_newline (pretty_printer *pp)
2210 obstack_1grow (pp_buffer (pp)->obstack, '\n');
2211 pp_needs_newline (pp) = false;
2212 pp_buffer (pp)->line_length = 0;
2215 /* Have PRETTY-PRINTER add a CHARACTER. */
2216 void
2217 pp_character (pretty_printer *pp, int c)
2219 if (pp_is_wrapping_line (pp)
2220 /* If printing UTF-8, don't wrap in the middle of a sequence. */
2221 && (((unsigned int) c) & 0xC0) != 0x80
2222 && pp_remaining_character_count_for_line (pp) <= 0)
2224 pp_newline (pp);
2225 if (ISSPACE (c))
2226 return;
2228 obstack_1grow (pp_buffer (pp)->obstack, c);
2229 ++pp_buffer (pp)->line_length;
2232 /* Append a STRING to the output area of PRETTY-PRINTER; the STRING may
2233 be line-wrapped if in appropriate mode. */
2234 void
2235 pp_string (pretty_printer *pp, const char *str)
2237 gcc_checking_assert (str);
2238 pp_maybe_wrap_text (pp, str, str + strlen (str));
2241 /* Append code point C to the output area of PRETTY-PRINTER, encoding it
2242 as UTF-8. */
2244 void
2245 pp_unicode_character (pretty_printer *pp, unsigned c)
2247 static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
2248 static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
2249 size_t nbytes;
2250 uchar buf[6], *p = &buf[6];
2252 nbytes = 1;
2253 if (c < 0x80)
2254 *--p = c;
2255 else
2259 *--p = ((c & 0x3F) | 0x80);
2260 c >>= 6;
2261 nbytes++;
2263 while (c >= 0x3F || (c & limits[nbytes-1]));
2264 *--p = (c | masks[nbytes-1]);
2267 pp_append_r (pp, (const char *)p, nbytes);
2270 /* Append the leading N characters of STRING to the output area of
2271 PRETTY-PRINTER, quoting in hexadecimal non-printable characters.
2272 Setting N = -1 is as if N were set to strlen (STRING). The STRING
2273 may be line-wrapped if in appropriate mode. */
2274 static void
2275 pp_quoted_string (pretty_printer *pp, const char *str, size_t n /* = -1 */)
2277 gcc_checking_assert (str);
2279 const char *last = str;
2280 const char *ps;
2282 /* Compute the length if not specified. */
2283 if (n == (size_t) -1)
2284 n = strlen (str);
2286 for (ps = str; n; ++ps, --n)
2288 if (ISPRINT (*ps))
2289 continue;
2291 /* Don't escape a valid UTF-8 extended char. */
2292 const unsigned char *ups = (const unsigned char *) ps;
2293 if (*ups & 0x80)
2295 unsigned int extended_char;
2296 const int valid_utf8_len = decode_utf8_char (ups, n, &extended_char);
2297 if (valid_utf8_len > 0)
2299 ps += valid_utf8_len - 1;
2300 n -= valid_utf8_len - 1;
2301 continue;
2305 if (last < ps)
2306 pp_maybe_wrap_text (pp, last, ps);
2308 /* Append the hexadecimal value of the character. Allocate a buffer
2309 that's large enough for a 32-bit char plus the hex prefix. */
2310 char buf [11];
2311 int n = sprintf (buf, "\\x%02x", (unsigned char)*ps);
2312 pp_maybe_wrap_text (pp, buf, buf + n);
2313 last = ps + 1;
2316 pp_maybe_wrap_text (pp, last, ps);
2319 /* Maybe print out a whitespace if needed. */
2321 void
2322 pp_maybe_space (pretty_printer *pp)
2324 if (pp->padding != pp_none)
2326 pp_space (pp);
2327 pp->padding = pp_none;
2331 // Add a newline to the pretty printer PP and flush formatted text.
2333 void
2334 pp_newline_and_flush (pretty_printer *pp)
2336 pp_newline (pp);
2337 pp_flush (pp);
2338 pp_needs_newline (pp) = false;
2341 // Add a newline to the pretty printer PP, followed by indentation.
2343 void
2344 pp_newline_and_indent (pretty_printer *pp, int n)
2346 pp_indentation (pp) += n;
2347 pp_newline (pp);
2348 pp_indent (pp);
2349 pp_needs_newline (pp) = false;
2352 // Add separator C, followed by a single whitespace.
2354 void
2355 pp_separate_with (pretty_printer *pp, char c)
2357 pp_character (pp, c);
2358 pp_space (pp);
2361 /* Add a localized open quote, and if SHOW_COLOR is true, begin colorizing
2362 using the "quote" color. */
2364 void
2365 pp_begin_quote (pretty_printer *pp, bool show_color)
2367 pp_string (pp, open_quote);
2368 pp_string (pp, colorize_start (show_color, "quote"));
2371 /* If SHOW_COLOR is true, stop colorizing.
2372 Add a localized close quote. */
2374 void
2375 pp_end_quote (pretty_printer *pp, bool show_color)
2377 pp_string (pp, colorize_stop (show_color));
2378 pp_string (pp, close_quote);
2382 /* The string starting at P has LEN (at least 1) bytes left; if they
2383 start with a valid UTF-8 sequence, return the length of that
2384 sequence and set *VALUE to the value of that sequence, and
2385 otherwise return 0 and set *VALUE to (unsigned int) -1. */
2387 static int
2388 decode_utf8_char (const unsigned char *p, size_t len, unsigned int *value)
2390 unsigned int t = *p;
2392 if (len == 0)
2393 abort ();
2394 if (t & 0x80)
2396 size_t utf8_len = 0;
2397 unsigned int ch;
2398 size_t i;
2399 for (t = *p; t & 0x80; t <<= 1)
2400 utf8_len++;
2402 if (utf8_len > len || utf8_len < 2 || utf8_len > 6)
2404 *value = (unsigned int) -1;
2405 return 0;
2407 ch = *p & ((1 << (7 - utf8_len)) - 1);
2408 for (i = 1; i < utf8_len; i++)
2410 unsigned int u = p[i];
2411 if ((u & 0xC0) != 0x80)
2413 *value = (unsigned int) -1;
2414 return 0;
2416 ch = (ch << 6) | (u & 0x3F);
2418 if ( (ch <= 0x7F && utf8_len > 1)
2419 || (ch <= 0x7FF && utf8_len > 2)
2420 || (ch <= 0xFFFF && utf8_len > 3)
2421 || (ch <= 0x1FFFFF && utf8_len > 4)
2422 || (ch <= 0x3FFFFFF && utf8_len > 5)
2423 || (ch >= 0xD800 && ch <= 0xDFFF))
2425 *value = (unsigned int) -1;
2426 return 0;
2428 *value = ch;
2429 return utf8_len;
2431 else
2433 *value = t;
2434 return 1;
2438 /* Allocator for identifier_to_locale and corresponding function to
2439 free memory. */
2441 void *(*identifier_to_locale_alloc) (size_t) = xmalloc;
2442 void (*identifier_to_locale_free) (void *) = free;
2444 /* Given IDENT, an identifier in the internal encoding, return a
2445 version of IDENT suitable for diagnostics in the locale character
2446 set: either IDENT itself, or a string, allocated using
2447 identifier_to_locale_alloc, converted to the locale character set
2448 and using escape sequences if not representable in the locale
2449 character set or containing control characters or invalid byte
2450 sequences. Existing backslashes in IDENT are not doubled, so the
2451 result may not uniquely specify the contents of an arbitrary byte
2452 sequence identifier. */
2454 const char *
2455 identifier_to_locale (const char *ident)
2457 const unsigned char *uid = (const unsigned char *) ident;
2458 size_t idlen = strlen (ident);
2459 bool valid_printable_utf8 = true;
2460 bool all_ascii = true;
2461 size_t i;
2463 for (i = 0; i < idlen;)
2465 unsigned int c;
2466 size_t utf8_len = decode_utf8_char (&uid[i], idlen - i, &c);
2467 if (utf8_len == 0 || c <= 0x1F || (c >= 0x7F && c <= 0x9F))
2469 valid_printable_utf8 = false;
2470 break;
2472 if (utf8_len > 1)
2473 all_ascii = false;
2474 i += utf8_len;
2477 /* If IDENT contains invalid UTF-8 sequences (which may occur with
2478 attributes putting arbitrary byte sequences in identifiers), or
2479 control characters, we use octal escape sequences for all bytes
2480 outside printable ASCII. */
2481 if (!valid_printable_utf8)
2483 char *ret = (char *) identifier_to_locale_alloc (4 * idlen + 1);
2484 char *p = ret;
2485 for (i = 0; i < idlen; i++)
2487 if (uid[i] > 0x1F && uid[i] < 0x7F)
2488 *p++ = uid[i];
2489 else
2491 sprintf (p, "\\%03o", uid[i]);
2492 p += 4;
2495 *p = 0;
2496 return ret;
2499 /* Otherwise, if it is valid printable ASCII, or printable UTF-8
2500 with the locale character set being UTF-8, IDENT is used. */
2501 if (all_ascii || locale_utf8)
2502 return ident;
2504 /* Otherwise IDENT is converted to the locale character set if
2505 possible. */
2506 #if defined ENABLE_NLS && defined HAVE_LANGINFO_CODESET && HAVE_ICONV
2507 if (locale_encoding != NULL)
2509 iconv_t cd = iconv_open (locale_encoding, "UTF-8");
2510 bool conversion_ok = true;
2511 char *ret = NULL;
2512 if (cd != (iconv_t) -1)
2514 size_t ret_alloc = 4 * idlen + 1;
2515 for (;;)
2517 /* Repeat the whole conversion process as needed with
2518 larger buffers so non-reversible transformations can
2519 always be detected. */
2520 ICONV_CONST char *inbuf = CONST_CAST (char *, ident);
2521 char *outbuf;
2522 size_t inbytesleft = idlen;
2523 size_t outbytesleft = ret_alloc - 1;
2524 size_t iconv_ret;
2526 ret = (char *) identifier_to_locale_alloc (ret_alloc);
2527 outbuf = ret;
2529 if (iconv (cd, 0, 0, 0, 0) == (size_t) -1)
2531 conversion_ok = false;
2532 break;
2535 iconv_ret = iconv (cd, &inbuf, &inbytesleft,
2536 &outbuf, &outbytesleft);
2537 if (iconv_ret == (size_t) -1 || inbytesleft != 0)
2539 if (errno == E2BIG)
2541 ret_alloc *= 2;
2542 identifier_to_locale_free (ret);
2543 ret = NULL;
2544 continue;
2546 else
2548 conversion_ok = false;
2549 break;
2552 else if (iconv_ret != 0)
2554 conversion_ok = false;
2555 break;
2557 /* Return to initial shift state. */
2558 if (iconv (cd, 0, 0, &outbuf, &outbytesleft) == (size_t) -1)
2560 if (errno == E2BIG)
2562 ret_alloc *= 2;
2563 identifier_to_locale_free (ret);
2564 ret = NULL;
2565 continue;
2567 else
2569 conversion_ok = false;
2570 break;
2573 *outbuf = 0;
2574 break;
2576 iconv_close (cd);
2577 if (conversion_ok)
2578 return ret;
2581 #endif
2583 /* Otherwise, convert non-ASCII characters in IDENT to UCNs. */
2585 char *ret = (char *) identifier_to_locale_alloc (10 * idlen + 1);
2586 char *p = ret;
2587 for (i = 0; i < idlen;)
2589 unsigned int c;
2590 size_t utf8_len = decode_utf8_char (&uid[i], idlen - i, &c);
2591 if (utf8_len == 1)
2592 *p++ = uid[i];
2593 else
2595 sprintf (p, "\\U%08x", c);
2596 p += 10;
2598 i += utf8_len;
2600 *p = 0;
2601 return ret;
2605 /* Support for encoding URLs.
2606 See egmontkob/Hyperlinks_in_Terminal_Emulators.md
2607 ( https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda ).
2609 > A hyperlink is opened upon encountering an OSC 8 escape sequence with
2610 > the target URI. The syntax is
2612 > OSC 8 ; params ; URI ST
2614 > A hyperlink is closed with the same escape sequence, omitting the
2615 > parameters and the URI but keeping the separators:
2617 > OSC 8 ; ; ST
2619 > OSC (operating system command) is typically ESC ].
2621 Use BEL instead of ST, as that is currently rendered better in some
2622 terminal emulators that don't support OSC 8, like konsole. */
2624 /* If URL-printing is enabled, write an "open URL" escape sequence to PP
2625 for the given URL. */
2627 void
2628 pp_begin_url (pretty_printer *pp, const char *url)
2630 if (!url)
2632 /* Handle null URL by skipping all output here,
2633 and in the next pp_end_url. */
2634 pp->m_skipping_null_url = true;
2635 return;
2637 switch (pp->url_format)
2639 case URL_FORMAT_NONE:
2640 break;
2641 case URL_FORMAT_ST:
2642 pp_string (pp, "\33]8;;");
2643 pp_string (pp, url);
2644 pp_string (pp, "\33\\");
2645 break;
2646 case URL_FORMAT_BEL:
2647 pp_string (pp, "\33]8;;");
2648 pp_string (pp, url);
2649 pp_string (pp, "\a");
2650 break;
2651 default:
2652 gcc_unreachable ();
2656 /* Helper function for pp_end_url and pp_format, return the "close URL" escape
2657 sequence string. */
2659 static const char *
2660 get_end_url_string (pretty_printer *pp)
2662 switch (pp->url_format)
2664 case URL_FORMAT_NONE:
2665 return "";
2666 case URL_FORMAT_ST:
2667 return "\33]8;;\33\\";
2668 case URL_FORMAT_BEL:
2669 return "\33]8;;\a";
2670 default:
2671 gcc_unreachable ();
2675 /* If URL-printing is enabled, write a "close URL" escape sequence to PP. */
2677 void
2678 pp_end_url (pretty_printer *pp)
2680 if (pp->m_skipping_null_url)
2682 /* We gracefully handle pp_begin_url (NULL) by omitting output for
2683 both begin and end. Here we handle the latter. */
2684 pp->m_skipping_null_url = false;
2685 return;
2687 if (pp->url_format != URL_FORMAT_NONE)
2688 pp_string (pp, get_end_url_string (pp));
2691 #if CHECKING_P
2693 namespace selftest {
2695 /* Smoketest for pretty_printer. */
2697 static void
2698 test_basic_printing ()
2700 pretty_printer pp;
2701 pp_string (&pp, "hello");
2702 pp_space (&pp);
2703 pp_string (&pp, "world");
2705 ASSERT_STREQ ("hello world", pp_formatted_text (&pp));
2708 /* Helper function for testing pp_format.
2709 Verify that pp_format (FMT, ...) followed by pp_output_formatted_text
2710 prints EXPECTED, assuming that pp_show_color is SHOW_COLOR. */
2712 static void
2713 assert_pp_format_va (const location &loc, const char *expected,
2714 bool show_color, const char *fmt, va_list *ap)
2716 pretty_printer pp;
2717 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
2719 text_info ti (fmt, ap, 0, nullptr, &rich_loc);
2721 pp_show_color (&pp) = show_color;
2722 pp_format (&pp, &ti);
2723 pp_output_formatted_text (&pp);
2724 ASSERT_STREQ_AT (loc, expected, pp_formatted_text (&pp));
2727 /* Verify that pp_format (FMT, ...) followed by pp_output_formatted_text
2728 prints EXPECTED, with show_color disabled. */
2730 static void
2731 assert_pp_format (const location &loc, const char *expected,
2732 const char *fmt, ...)
2734 va_list ap;
2736 va_start (ap, fmt);
2737 assert_pp_format_va (loc, expected, false, fmt, &ap);
2738 va_end (ap);
2741 /* As above, but with colorization enabled. */
2743 static void
2744 assert_pp_format_colored (const location &loc, const char *expected,
2745 const char *fmt, ...)
2747 /* The tests of colorization assume the default color scheme.
2748 If GCC_COLORS is set, then the colors have potentially been
2749 overridden; skip the test. */
2750 if (getenv ("GCC_COLORS"))
2751 return;
2753 va_list ap;
2755 va_start (ap, fmt);
2756 assert_pp_format_va (loc, expected, true, fmt, &ap);
2757 va_end (ap);
2760 /* Helper function for calling testing pp_format,
2761 by calling assert_pp_format with various numbers of arguments.
2762 These exist mostly to avoid having to write SELFTEST_LOCATION
2763 throughout test_pp_format. */
2765 #define ASSERT_PP_FORMAT_1(EXPECTED, FMT, ARG1) \
2766 SELFTEST_BEGIN_STMT \
2767 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2768 (ARG1)); \
2769 SELFTEST_END_STMT
2771 #define ASSERT_PP_FORMAT_2(EXPECTED, FMT, ARG1, ARG2) \
2772 SELFTEST_BEGIN_STMT \
2773 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2774 (ARG1), (ARG2)); \
2775 SELFTEST_END_STMT
2777 #define ASSERT_PP_FORMAT_3(EXPECTED, FMT, ARG1, ARG2, ARG3) \
2778 SELFTEST_BEGIN_STMT \
2779 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2780 (ARG1), (ARG2), (ARG3)); \
2781 SELFTEST_END_STMT
2783 /* Verify that pp_format works, for various format codes. */
2785 static void
2786 test_pp_format ()
2788 /* Avoid introducing locale-specific differences in the results
2789 by hardcoding open_quote and close_quote. */
2790 auto_fix_quotes fix_quotes;
2792 /* Verify that plain text is passed through unchanged. */
2793 assert_pp_format (SELFTEST_LOCATION, "unformatted", "unformatted");
2795 /* Verify various individual format codes, in the order listed in the
2796 comment for pp_format above. For each code, we append a second
2797 argument with a known bit pattern (0x12345678), to ensure that we
2798 are consuming arguments correctly. */
2799 ASSERT_PP_FORMAT_2 ("-27 12345678", "%d %x", -27, 0x12345678);
2800 ASSERT_PP_FORMAT_2 ("-5 12345678", "%i %x", -5, 0x12345678);
2801 ASSERT_PP_FORMAT_2 ("10 12345678", "%u %x", 10, 0x12345678);
2802 ASSERT_PP_FORMAT_2 ("17 12345678", "%o %x", 15, 0x12345678);
2803 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%x %x", 0xcafebabe, 0x12345678);
2804 ASSERT_PP_FORMAT_2 ("-27 12345678", "%ld %x", (long)-27, 0x12345678);
2805 ASSERT_PP_FORMAT_2 ("-5 12345678", "%li %x", (long)-5, 0x12345678);
2806 ASSERT_PP_FORMAT_2 ("10 12345678", "%lu %x", (long)10, 0x12345678);
2807 ASSERT_PP_FORMAT_2 ("17 12345678", "%lo %x", (long)15, 0x12345678);
2808 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%lx %x", (long)0xcafebabe,
2809 0x12345678);
2810 ASSERT_PP_FORMAT_2 ("-27 12345678", "%lld %x", (long long)-27, 0x12345678);
2811 ASSERT_PP_FORMAT_2 ("-5 12345678", "%lli %x", (long long)-5, 0x12345678);
2812 ASSERT_PP_FORMAT_2 ("10 12345678", "%llu %x", (long long)10, 0x12345678);
2813 ASSERT_PP_FORMAT_2 ("17 12345678", "%llo %x", (long long)15, 0x12345678);
2814 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%llx %x", (long long)0xcafebabe,
2815 0x12345678);
2816 ASSERT_PP_FORMAT_2 ("-27 12345678", "%wd %x", HOST_WIDE_INT_C (-27),
2817 0x12345678);
2818 ASSERT_PP_FORMAT_2 ("-5 12345678", "%wi %x", HOST_WIDE_INT_C (-5),
2819 0x12345678);
2820 ASSERT_PP_FORMAT_2 ("10 12345678", "%wu %x", HOST_WIDE_INT_UC (10),
2821 0x12345678);
2822 ASSERT_PP_FORMAT_2 ("17 12345678", "%wo %x", HOST_WIDE_INT_C (15),
2823 0x12345678);
2824 ASSERT_PP_FORMAT_2 ("0xcafebabe 12345678", "%wx %x",
2825 HOST_WIDE_INT_C (0xcafebabe), 0x12345678);
2826 ASSERT_PP_FORMAT_2 ("-27 12345678", "%zd %x", (ssize_t)-27, 0x12345678);
2827 ASSERT_PP_FORMAT_2 ("-5 12345678", "%zi %x", (ssize_t)-5, 0x12345678);
2828 ASSERT_PP_FORMAT_2 ("10 12345678", "%zu %x", (size_t)10, 0x12345678);
2829 ASSERT_PP_FORMAT_2 ("17 12345678", "%zo %x", (size_t)15, 0x12345678);
2830 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%zx %x", (size_t)0xcafebabe,
2831 0x12345678);
2832 ASSERT_PP_FORMAT_2 ("-27 12345678", "%td %x", (ptrdiff_t)-27, 0x12345678);
2833 ASSERT_PP_FORMAT_2 ("-5 12345678", "%ti %x", (ptrdiff_t)-5, 0x12345678);
2834 ASSERT_PP_FORMAT_2 ("10 12345678", "%tu %x", (ptrdiff_t)10, 0x12345678);
2835 ASSERT_PP_FORMAT_2 ("17 12345678", "%to %x", (ptrdiff_t)15, 0x12345678);
2836 ASSERT_PP_FORMAT_2 ("1afebabe 12345678", "%tx %x", (ptrdiff_t)0x1afebabe,
2837 0x12345678);
2838 ASSERT_PP_FORMAT_2 ("1.000000 12345678", "%f %x", 1.0, 0x12345678);
2839 ASSERT_PP_FORMAT_2 ("A 12345678", "%c %x", 'A', 0x12345678);
2840 ASSERT_PP_FORMAT_2 ("hello world 12345678", "%s %x", "hello world",
2841 0x12345678);
2843 /* Not nul-terminated. */
2844 char arr[5] = { '1', '2', '3', '4', '5' };
2845 ASSERT_PP_FORMAT_3 ("123 12345678", "%.*s %x", 3, arr, 0x12345678);
2846 ASSERT_PP_FORMAT_3 ("1234 12345678", "%.*s %x", -1, "1234", 0x12345678);
2847 ASSERT_PP_FORMAT_3 ("12345 12345678", "%.*s %x", 7, "12345", 0x12345678);
2849 /* We can't test for %p; the pointer is printed in an implementation-defined
2850 manner. */
2851 ASSERT_PP_FORMAT_2 ("normal colored normal 12345678",
2852 "normal %rcolored%R normal %x",
2853 "error", 0x12345678);
2854 assert_pp_format_colored
2855 (SELFTEST_LOCATION,
2856 "normal \33[01;31m\33[Kcolored\33[m\33[K normal 12345678",
2857 "normal %rcolored%R normal %x", "error", 0x12345678);
2858 /* TODO:
2859 %m: strerror(text->err_no) - does not consume a value from args_ptr. */
2860 ASSERT_PP_FORMAT_1 ("% 12345678", "%% %x", 0x12345678);
2861 ASSERT_PP_FORMAT_1 ("` 12345678", "%< %x", 0x12345678);
2862 ASSERT_PP_FORMAT_1 ("' 12345678", "%> %x", 0x12345678);
2863 ASSERT_PP_FORMAT_1 ("' 12345678", "%' %x", 0x12345678);
2864 ASSERT_PP_FORMAT_3 ("abc 12345678", "%.*s %x", 3, "abcdef", 0x12345678);
2865 ASSERT_PP_FORMAT_2 ("abc 12345678", "%.3s %x", "abcdef", 0x12345678);
2867 /* Verify flag 'q'. */
2868 ASSERT_PP_FORMAT_2 ("`foo' 12345678", "%qs %x", "foo", 0x12345678);
2869 assert_pp_format_colored (SELFTEST_LOCATION,
2870 "`\33[01m\33[Kfoo\33[m\33[K' 12345678", "%qs %x",
2871 "foo", 0x12345678);
2872 /* Verify "%@". */
2874 diagnostic_event_id_t first (2);
2875 diagnostic_event_id_t second (7);
2877 ASSERT_PP_FORMAT_2 ("first `free' at (3); second `free' at (8)",
2878 "first %<free%> at %@; second %<free%> at %@",
2879 &first, &second);
2880 assert_pp_format_colored
2881 (SELFTEST_LOCATION,
2882 "first `\e[01m\e[Kfree\e[m\e[K' at \e[01;36m\e[K(3)\e[m\e[K;"
2883 " second `\e[01m\e[Kfree\e[m\e[K' at \e[01;36m\e[K(8)\e[m\e[K",
2884 "first %<free%> at %@; second %<free%> at %@",
2885 &first, &second);
2888 /* Verify %Z. */
2889 int v[] = { 1, 2, 3 };
2890 ASSERT_PP_FORMAT_3 ("1, 2, 3 12345678", "%Z %x", v, 3, 0x12345678);
2892 int v2[] = { 0 };
2893 ASSERT_PP_FORMAT_3 ("0 12345678", "%Z %x", v2, 1, 0x12345678);
2895 /* Verify that combinations work, along with unformatted text. */
2896 assert_pp_format (SELFTEST_LOCATION,
2897 "the quick brown fox jumps over the lazy dog",
2898 "the %s %s %s jumps over the %s %s",
2899 "quick", "brown", "fox", "lazy", "dog");
2900 assert_pp_format (SELFTEST_LOCATION, "item 3 of 7", "item %i of %i", 3, 7);
2901 assert_pp_format (SELFTEST_LOCATION, "problem with `bar' at line 10",
2902 "problem with %qs at line %i", "bar", 10);
2904 /* Verified numbered args. */
2905 assert_pp_format (SELFTEST_LOCATION,
2906 "foo: second bar: first",
2907 "foo: %2$s bar: %1$s",
2908 "first", "second");
2909 assert_pp_format (SELFTEST_LOCATION,
2910 "foo: 1066 bar: 1776",
2911 "foo: %2$i bar: %1$i",
2912 1776, 1066);
2913 assert_pp_format (SELFTEST_LOCATION,
2914 "foo: second bar: 1776",
2915 "foo: %2$s bar: %1$i",
2916 1776, "second");
2919 /* A subclass of pretty_printer for use by test_prefixes_and_wrapping. */
2921 class test_pretty_printer : public pretty_printer
2923 public:
2924 test_pretty_printer (enum diagnostic_prefixing_rule_t rule,
2925 int max_line_length)
2927 pp_set_prefix (this, xstrdup ("PREFIX: "));
2928 wrapping.rule = rule;
2929 pp_set_line_maximum_length (this, max_line_length);
2933 /* Verify that the various values of enum diagnostic_prefixing_rule_t work
2934 as expected, with and without line wrapping. */
2936 static void
2937 test_prefixes_and_wrapping ()
2939 /* Tests of the various prefixing rules, without wrapping.
2940 Newlines embedded in pp_string don't affect it; we have to
2941 explicitly call pp_newline. */
2943 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_ONCE, 0);
2944 pp_string (&pp, "the quick brown fox");
2945 pp_newline (&pp);
2946 pp_string (&pp, "jumps over the lazy dog");
2947 pp_newline (&pp);
2948 ASSERT_STREQ (pp_formatted_text (&pp),
2949 "PREFIX: the quick brown fox\n"
2950 " jumps over the lazy dog\n");
2953 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_NEVER, 0);
2954 pp_string (&pp, "the quick brown fox");
2955 pp_newline (&pp);
2956 pp_string (&pp, "jumps over the lazy dog");
2957 pp_newline (&pp);
2958 ASSERT_STREQ (pp_formatted_text (&pp),
2959 "the quick brown fox\n"
2960 "jumps over the lazy dog\n");
2963 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE, 0);
2964 pp_string (&pp, "the quick brown fox");
2965 pp_newline (&pp);
2966 pp_string (&pp, "jumps over the lazy dog");
2967 pp_newline (&pp);
2968 ASSERT_STREQ (pp_formatted_text (&pp),
2969 "PREFIX: the quick brown fox\n"
2970 "PREFIX: jumps over the lazy dog\n");
2973 /* Tests of the various prefixing rules, with wrapping. */
2975 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_ONCE, 20);
2976 pp_string (&pp, "the quick brown fox jumps over the lazy dog");
2977 pp_newline (&pp);
2978 pp_string (&pp, "able was I ere I saw elba");
2979 pp_newline (&pp);
2980 ASSERT_STREQ (pp_formatted_text (&pp),
2981 "PREFIX: the quick \n"
2982 " brown fox jumps \n"
2983 " over the lazy \n"
2984 " dog\n"
2985 " able was I ere I \n"
2986 " saw elba\n");
2989 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_NEVER, 20);
2990 pp_string (&pp, "the quick brown fox jumps over the lazy dog");
2991 pp_newline (&pp);
2992 pp_string (&pp, "able was I ere I saw elba");
2993 pp_newline (&pp);
2994 ASSERT_STREQ (pp_formatted_text (&pp),
2995 "the quick brown fox \n"
2996 "jumps over the lazy \n"
2997 "dog\n"
2998 "able was I ere I \n"
2999 "saw elba\n");
3002 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE, 20);
3003 pp_string (&pp, "the quick brown fox jumps over the lazy dog");
3004 pp_newline (&pp);
3005 pp_string (&pp, "able was I ere I saw elba");
3006 pp_newline (&pp);
3007 ASSERT_STREQ (pp_formatted_text (&pp),
3008 "PREFIX: the quick brown fox jumps over the lazy dog\n"
3009 "PREFIX: able was I ere I saw elba\n");
3014 /* Verify that URL-printing works as expected. */
3016 void
3017 test_urls ()
3020 pretty_printer pp;
3021 pp.url_format = URL_FORMAT_NONE;
3022 pp_begin_url (&pp, "http://example.com");
3023 pp_string (&pp, "This is a link");
3024 pp_end_url (&pp);
3025 ASSERT_STREQ ("This is a link",
3026 pp_formatted_text (&pp));
3030 pretty_printer pp;
3031 pp.url_format = URL_FORMAT_ST;
3032 pp_begin_url (&pp, "http://example.com");
3033 pp_string (&pp, "This is a link");
3034 pp_end_url (&pp);
3035 ASSERT_STREQ ("\33]8;;http://example.com\33\\This is a link\33]8;;\33\\",
3036 pp_formatted_text (&pp));
3040 pretty_printer pp;
3041 pp.url_format = URL_FORMAT_BEL;
3042 pp_begin_url (&pp, "http://example.com");
3043 pp_string (&pp, "This is a link");
3044 pp_end_url (&pp);
3045 ASSERT_STREQ ("\33]8;;http://example.com\aThis is a link\33]8;;\a",
3046 pp_formatted_text (&pp));
3050 /* Verify that we gracefully reject null URLs. */
3052 void
3053 test_null_urls ()
3056 pretty_printer pp;
3057 pp.url_format = URL_FORMAT_NONE;
3058 pp_begin_url (&pp, nullptr);
3059 pp_string (&pp, "This isn't a link");
3060 pp_end_url (&pp);
3061 ASSERT_STREQ ("This isn't a link",
3062 pp_formatted_text (&pp));
3066 pretty_printer pp;
3067 pp.url_format = URL_FORMAT_ST;
3068 pp_begin_url (&pp, nullptr);
3069 pp_string (&pp, "This isn't a link");
3070 pp_end_url (&pp);
3071 ASSERT_STREQ ("This isn't a link",
3072 pp_formatted_text (&pp));
3076 pretty_printer pp;
3077 pp.url_format = URL_FORMAT_BEL;
3078 pp_begin_url (&pp, nullptr);
3079 pp_string (&pp, "This isn't a link");
3080 pp_end_url (&pp);
3081 ASSERT_STREQ ("This isn't a link",
3082 pp_formatted_text (&pp));
3086 /* Verify that URLification works as expected. */
3088 static void
3089 pp_printf_with_urlifier (pretty_printer *pp,
3090 const urlifier *urlifier,
3091 const char *msg, ...)
3093 va_list ap;
3095 va_start (ap, msg);
3096 text_info text (msg, &ap, errno);
3097 pp_format (pp, &text, urlifier);
3098 pp_output_formatted_text (pp, urlifier);
3099 va_end (ap);
3103 void
3104 test_urlification ()
3106 class test_urlifier : public urlifier
3108 public:
3109 char *
3110 get_url_for_quoted_text (const char *p, size_t sz) const final override
3112 if (!strncmp (p, "-foption", sz))
3113 return xstrdup ("http://example.com");
3114 return nullptr;
3118 auto_fix_quotes fix_quotes;
3119 const test_urlifier urlifier;
3121 /* Uses of "%<" and "%>". */
3124 pretty_printer pp;
3125 pp.url_format = URL_FORMAT_NONE;
3126 pp_printf_with_urlifier (&pp, &urlifier,
3127 "foo %<-foption%> %<unrecognized%> bar");
3128 ASSERT_STREQ ("foo `-foption' `unrecognized' bar",
3129 pp_formatted_text (&pp));
3132 pretty_printer pp;
3133 pp.url_format = URL_FORMAT_ST;
3134 pp_printf_with_urlifier (&pp, &urlifier,
3135 "foo %<-foption%> %<unrecognized%> bar");
3136 ASSERT_STREQ
3137 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
3138 " `unrecognized' bar",
3139 pp_formatted_text (&pp));
3142 pretty_printer pp;
3143 pp.url_format = URL_FORMAT_BEL;
3144 pp_printf_with_urlifier (&pp, &urlifier,
3145 "foo %<-foption%> %<unrecognized%> bar");
3146 ASSERT_STREQ
3147 ("foo `\33]8;;http://example.com\a-foption\33]8;;\a'"
3148 " `unrecognized' bar",
3149 pp_formatted_text (&pp));
3153 /* Use of "%qs". */
3155 pretty_printer pp;
3156 pp.url_format = URL_FORMAT_ST;
3157 pp_printf_with_urlifier (&pp, &urlifier,
3158 "foo %qs %qs bar",
3159 "-foption", "unrecognized");
3160 ASSERT_STREQ
3161 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
3162 " `unrecognized' bar",
3163 pp_formatted_text (&pp));
3166 /* Mixed usage of %< and %s, where the quoted string is built between
3167 a mixture of phase 1 and phase 2. */
3169 pretty_printer pp;
3170 pp.url_format = URL_FORMAT_ST;
3171 pp_printf_with_urlifier (&pp, &urlifier,
3172 "foo %<-f%s%> bar",
3173 "option");
3174 ASSERT_STREQ
3175 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3176 pp_formatted_text (&pp));
3179 /* Likewise, where there is trailing phase 1 content within the
3180 quoted region. */
3182 pretty_printer pp;
3183 pp.url_format = URL_FORMAT_ST;
3184 pp_printf_with_urlifier (&pp, &urlifier,
3185 "foo %<-f%sion%> bar %<-f%sion%> baz",
3186 "opt", "opt");
3187 ASSERT_STREQ
3188 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' baz",
3189 pp_formatted_text (&pp));
3192 /* Likewise. */
3194 pretty_printer pp;
3195 pp.url_format = URL_FORMAT_ST;
3196 pp_printf_with_urlifier (&pp, &urlifier,
3197 "foo %<%sption%> bar %<-f%sion%> baz",
3198 "-fo", "opt");
3199 ASSERT_STREQ
3200 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' baz",
3201 pp_formatted_text (&pp));
3204 /* Another mixed usage of %< and %s, where the quoted string is built
3205 between a mixture of phase 1 and multiple phase 2. */
3207 pretty_printer pp;
3208 pp.url_format = URL_FORMAT_ST;
3209 pp_printf_with_urlifier (&pp, &urlifier,
3210 "foo %<-f%s%s%> bar",
3211 "opt", "ion");
3212 ASSERT_STREQ
3213 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3214 pp_formatted_text (&pp));
3217 /* Mixed usage of %< and %s with a prefix. */
3219 pretty_printer pp;
3220 pp.url_format = URL_FORMAT_ST;
3221 pp_set_prefix (&pp, xstrdup ("PREFIX"));
3222 pp_printf_with_urlifier (&pp, &urlifier,
3223 "foo %<-f%s%> bar",
3224 "option");
3225 ASSERT_STREQ
3226 ("PREFIXfoo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3227 pp_formatted_text (&pp));
3230 /* Example of mixed %< and %s with numbered args. */
3232 pretty_printer pp;
3233 pp.url_format = URL_FORMAT_ST;
3234 pp_printf_with_urlifier (&pp, &urlifier,
3235 "foo %<-f%2$st%1$sn%> bar",
3236 "io", "op");
3237 ASSERT_STREQ
3238 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
3239 pp_formatted_text (&pp));
3243 /* Test multibyte awareness. */
3244 static void test_utf8 ()
3247 /* Check that pp_quoted_string leaves valid UTF-8 alone. */
3249 pretty_printer pp;
3250 const char *s = "\xf0\x9f\x98\x82";
3251 pp_quoted_string (&pp, s);
3252 ASSERT_STREQ (pp_formatted_text (&pp), s);
3255 /* Check that pp_quoted_string escapes non-UTF-8 nonprintable bytes. */
3257 pretty_printer pp;
3258 pp_quoted_string (&pp, "\xf0!\x9f\x98\x82");
3259 ASSERT_STREQ (pp_formatted_text (&pp),
3260 "\\xf0!\\x9f\\x98\\x82");
3263 /* Check that pp_character will line-wrap at the beginning of a UTF-8
3264 sequence, but not in the middle. */
3266 pretty_printer pp (3);
3267 const char s[] = "---\xf0\x9f\x98\x82";
3268 for (int i = 0; i != sizeof (s) - 1; ++i)
3269 pp_character (&pp, s[i]);
3270 pp_newline (&pp);
3271 for (int i = 1; i != sizeof (s) - 1; ++i)
3272 pp_character (&pp, s[i]);
3273 pp_character (&pp, '-');
3274 ASSERT_STREQ (pp_formatted_text (&pp),
3275 "---\n"
3276 "\xf0\x9f\x98\x82\n"
3277 "--\xf0\x9f\x98\x82\n"
3278 "-");
3283 /* Run all of the selftests within this file. */
3285 void
3286 pretty_print_cc_tests ()
3288 test_basic_printing ();
3289 test_pp_format ();
3290 test_prefixes_and_wrapping ();
3291 test_urls ();
3292 test_null_urls ();
3293 test_urlification ();
3294 test_utf8 ();
3297 } // namespace selftest
3299 #endif /* CHECKING_P */