1/* Various declarations for language-independent pretty-print subroutines.
2 Copyright (C) 2003-2023 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "intl.h"
25#include "pretty-print.h"
26#include "pretty-print-urlifier.h"
27#include "diagnostic-color.h"
28#include "diagnostic-event-id.h"
29#include "selftest.h"
30
31#if HAVE_ICONV
32#include <iconv.h>
33#endif
34
35#ifdef __MINGW32__
36
37/* Replacement for fputs() that handles ANSI escape codes on Windows NT.
38 Contributed by: Liu Hao (lh_mouse at 126 dot com)
39
40 XXX: This file is compiled into libcommon.a that will be self-contained.
41 It looks like that these functions can be put nowhere else. */
42
43#include <io.h>
44#define WIN32_LEAN_AND_MEAN 1
45#include <windows.h>
46
47/* Write all bytes in [s,s+n) into the specified stream.
48 Errors are ignored. */
49static void
50write_all (HANDLE h, const char *s, size_t n)
51{
52 size_t rem = n;
53 DWORD step;
54
55 while (rem != 0)
56 {
57 if (rem <= UINT_MAX)
58 step = rem;
59 else
60 step = UINT_MAX;
61 if (!WriteFile (h, s + n - rem, step, &step, NULL))
62 break;
63 rem -= step;
64 }
65}
66
67/* Find the beginning of an escape sequence.
68 There are two cases:
69 1. If the sequence begins with an ESC character (0x1B) and a second
70 character X in [0x40,0x5F], returns X and stores a pointer to
71 the third character into *head.
72 2. If the sequence begins with a character X in [0x80,0x9F], returns
73 (X-0x40) and stores a pointer to the second character into *head.
74 Stores the number of ESC character(s) in *prefix_len.
75 Returns 0 if no such sequence can be found. */
76static int
77find_esc_head (int *prefix_len, const char **head, const char *str)
78{
79 int c;
80 const char *r = str;
81 int escaped = 0;
82
83 for (;;)
84 {
85 c = (unsigned char) *r;
86 if (c == 0)
87 {
88 /* Not found. */
89 return 0;
90 }
91 if (escaped && 0x40 <= c && c <= 0x5F)
92 {
93 /* Found (case 1). */
94 *prefix_len = 2;
95 *head = r + 1;
96 return c;
97 }
98 if (0x80 <= c && c <= 0x9F)
99 {
100 /* Found (case 2). */
101 *prefix_len = 1;
102 *head = r + 1;
103 return c - 0x40;
104 }
105 ++r;
106 escaped = c == 0x1B;
107 }
108}
109
110/* Find the terminator of an escape sequence.
111 str should be the value stored in *head by a previous successful
112 call to find_esc_head().
113 Returns 0 if no such sequence can be found. */
114static int
115find_esc_terminator (const char **term, const char *str)
116{
117 int c;
118 const char *r = str;
119
120 for (;;)
121 {
122 c = (unsigned char) *r;
123 if (c == 0)
124 {
125 /* Not found. */
126 return 0;
127 }
128 if (0x40 <= c && c <= 0x7E)
129 {
130 /* Found. */
131 *term = r;
132 return c;
133 }
134 ++r;
135 }
136}
137
138/* Handle a sequence of codes. Sequences that are invalid, reserved,
139 unrecognized or unimplemented are ignored silently.
140 There isn't much we can do because of lameness of Windows consoles. */
141static void
142eat_esc_sequence (HANDLE h, int esc_code,
143 const char *esc_head, const char *esc_term)
144{
145 /* Numbers in an escape sequence cannot be negative, because
146 a minus sign in the middle of it would have terminated it. */
147 long n1, n2;
148 char *eptr, *delim;
149 CONSOLE_SCREEN_BUFFER_INFO sb;
150 COORD cr;
151 /* ED and EL parameters. */
152 DWORD cnt, step;
153 long rows;
154 /* SGR parameters. */
155 WORD attrib_add, attrib_rm;
156 const char *param;
157
158 switch (MAKEWORD (esc_code, *esc_term))
159 {
160 /* ESC [ n1 'A'
161 Move the cursor up by n1 characters. */
162 case MAKEWORD ('[', 'A'):
163 if (esc_head == esc_term)
164 n1 = 1;
165 else
166 {
167 n1 = strtol (esc_head, &eptr, 10);
168 if (eptr != esc_term)
169 break;
170 }
171
172 if (GetConsoleScreenBufferInfo (h, &sb))
173 {
174 cr = sb.dwCursorPosition;
175 /* Stop at the topmost boundary. */
176 if (cr.Y > n1)
177 cr.Y -= n1;
178 else
179 cr.Y = 0;
180 SetConsoleCursorPosition (h, cr);
181 }
182 break;
183
184 /* ESC [ n1 'B'
185 Move the cursor down by n1 characters. */
186 case MAKEWORD ('[', 'B'):
187 if (esc_head == esc_term)
188 n1 = 1;
189 else
190 {
191 n1 = strtol (esc_head, &eptr, 10);
192 if (eptr != esc_term)
193 break;
194 }
195
196 if (GetConsoleScreenBufferInfo (h, &sb))
197 {
198 cr = sb.dwCursorPosition;
199 /* Stop at the bottommost boundary. */
200 if (sb.dwSize.Y - cr.Y > n1)
201 cr.Y += n1;
202 else
203 cr.Y = sb.dwSize.Y;
204 SetConsoleCursorPosition (h, cr);
205 }
206 break;
207
208 /* ESC [ n1 'C'
209 Move the cursor right by n1 characters. */
210 case MAKEWORD ('[', 'C'):
211 if (esc_head == esc_term)
212 n1 = 1;
213 else
214 {
215 n1 = strtol (esc_head, &eptr, 10);
216 if (eptr != esc_term)
217 break;
218 }
219
220 if (GetConsoleScreenBufferInfo (h, &sb))
221 {
222 cr = sb.dwCursorPosition;
223 /* Stop at the rightmost boundary. */
224 if (sb.dwSize.X - cr.X > n1)
225 cr.X += n1;
226 else
227 cr.X = sb.dwSize.X;
228 SetConsoleCursorPosition (h, cr);
229 }
230 break;
231
232 /* ESC [ n1 'D'
233 Move the cursor left by n1 characters. */
234 case MAKEWORD ('[', 'D'):
235 if (esc_head == esc_term)
236 n1 = 1;
237 else
238 {
239 n1 = strtol (esc_head, &eptr, 10);
240 if (eptr != esc_term)
241 break;
242 }
243
244 if (GetConsoleScreenBufferInfo (h, &sb))
245 {
246 cr = sb.dwCursorPosition;
247 /* Stop at the leftmost boundary. */
248 if (cr.X > n1)
249 cr.X -= n1;
250 else
251 cr.X = 0;
252 SetConsoleCursorPosition (h, cr);
253 }
254 break;
255
256 /* ESC [ n1 'E'
257 Move the cursor to the beginning of the n1-th line downwards. */
258 case MAKEWORD ('[', 'E'):
259 if (esc_head == esc_term)
260 n1 = 1;
261 else
262 {
263 n1 = strtol (esc_head, &eptr, 10);
264 if (eptr != esc_term)
265 break;
266 }
267
268 if (GetConsoleScreenBufferInfo (h, &sb))
269 {
270 cr = sb.dwCursorPosition;
271 cr.X = 0;
272 /* Stop at the bottommost boundary. */
273 if (sb.dwSize.Y - cr.Y > n1)
274 cr.Y += n1;
275 else
276 cr.Y = sb.dwSize.Y;
277 SetConsoleCursorPosition (h, cr);
278 }
279 break;
280
281 /* ESC [ n1 'F'
282 Move the cursor to the beginning of the n1-th line upwards. */
283 case MAKEWORD ('[', 'F'):
284 if (esc_head == esc_term)
285 n1 = 1;
286 else
287 {
288 n1 = strtol (esc_head, &eptr, 10);
289 if (eptr != esc_term)
290 break;
291 }
292
293 if (GetConsoleScreenBufferInfo (h, &sb))
294 {
295 cr = sb.dwCursorPosition;
296 cr.X = 0;
297 /* Stop at the topmost boundary. */
298 if (cr.Y > n1)
299 cr.Y -= n1;
300 else
301 cr.Y = 0;
302 SetConsoleCursorPosition (h, cr);
303 }
304 break;
305
306 /* ESC [ n1 'G'
307 Move the cursor to the (1-based) n1-th column. */
308 case MAKEWORD ('[', 'G'):
309 if (esc_head == esc_term)
310 n1 = 1;
311 else
312 {
313 n1 = strtol (esc_head, &eptr, 10);
314 if (eptr != esc_term)
315 break;
316 }
317
318 if (GetConsoleScreenBufferInfo (h, &sb))
319 {
320 cr = sb.dwCursorPosition;
321 n1 -= 1;
322 /* Stop at the leftmost or rightmost boundary. */
323 if (n1 < 0)
324 cr.X = 0;
325 else if (n1 > sb.dwSize.X)
326 cr.X = sb.dwSize.X;
327 else
328 cr.X = n1;
329 SetConsoleCursorPosition (h, cr);
330 }
331 break;
332
333 /* ESC [ n1 ';' n2 'H'
334 ESC [ n1 ';' n2 'f'
335 Move the cursor to the (1-based) n1-th row and
336 (also 1-based) n2-th column. */
337 case MAKEWORD ('[', 'H'):
338 case MAKEWORD ('[', 'f'):
339 if (esc_head == esc_term)
340 {
341 /* Both parameters are omitted and set to 1 by default. */
342 n1 = 1;
343 n2 = 1;
344 }
345 else if (!(delim = (char *) memchr (esc_head, ';',
346 esc_term - esc_head)))
347 {
348 /* Only the first parameter is given. The second one is
349 set to 1 by default. */
350 n1 = strtol (esc_head, &eptr, 10);
351 if (eptr != esc_term)
352 break;
353 n2 = 1;
354 }
355 else
356 {
357 /* Both parameters are given. The first one shall be
358 terminated by the semicolon. */
359 n1 = strtol (esc_head, &eptr, 10);
360 if (eptr != delim)
361 break;
362 n2 = strtol (delim + 1, &eptr, 10);
363 if (eptr != esc_term)
364 break;
365 }
366
367 if (GetConsoleScreenBufferInfo (h, &sb))
368 {
369 cr = sb.dwCursorPosition;
370 n1 -= 1;
371 n2 -= 1;
372 /* The cursor position shall be relative to the view coord of
373 the console window, which is usually smaller than the actual
374 buffer. FWIW, the 'appropriate' solution will be shrinking
375 the buffer to match the size of the console window,
376 destroying scrollback in the process. */
377 n1 += sb.srWindow.Top;
378 n2 += sb.srWindow.Left;
379 /* Stop at the topmost or bottommost boundary. */
380 if (n1 < 0)
381 cr.Y = 0;
382 else if (n1 > sb.dwSize.Y)
383 cr.Y = sb.dwSize.Y;
384 else
385 cr.Y = n1;
386 /* Stop at the leftmost or rightmost boundary. */
387 if (n2 < 0)
388 cr.X = 0;
389 else if (n2 > sb.dwSize.X)
390 cr.X = sb.dwSize.X;
391 else
392 cr.X = n2;
393 SetConsoleCursorPosition (h, cr);
394 }
395 break;
396
397 /* ESC [ n1 'J'
398 Erase display. */
399 case MAKEWORD ('[', 'J'):
400 if (esc_head == esc_term)
401 /* This is one of the very few codes whose parameters have
402 a default value of zero. */
403 n1 = 0;
404 else
405 {
406 n1 = strtol (esc_head, &eptr, 10);
407 if (eptr != esc_term)
408 break;
409 }
410
411 if (GetConsoleScreenBufferInfo (h, &sb))
412 {
413 /* The cursor is not necessarily in the console window, which
414 makes the behavior of this code harder to define. */
415 switch (n1)
416 {
417 case 0:
418 /* If the cursor is in or above the window, erase from
419 it to the bottom of the window; otherwise, do nothing. */
420 cr = sb.dwCursorPosition;
421 cnt = sb.dwSize.X - sb.dwCursorPosition.X;
422 rows = sb.srWindow.Bottom - sb.dwCursorPosition.Y;
423 break;
424 case 1:
425 /* If the cursor is in or under the window, erase from
426 it to the top of the window; otherwise, do nothing. */
427 cr.X = 0;
428 cr.Y = sb.srWindow.Top;
429 cnt = sb.dwCursorPosition.X + 1;
430 rows = sb.dwCursorPosition.Y - sb.srWindow.Top;
431 break;
432 case 2:
433 /* Erase the entire window. */
434 cr.X = sb.srWindow.Left;
435 cr.Y = sb.srWindow.Top;
436 cnt = 0;
437 rows = sb.srWindow.Bottom - sb.srWindow.Top + 1;
438 break;
439 default:
440 /* Erase the entire buffer. */
441 cr.X = 0;
442 cr.Y = 0;
443 cnt = 0;
444 rows = sb.dwSize.Y;
445 break;
446 }
447 if (rows < 0)
448 break;
449 cnt += rows * sb.dwSize.X;
450 FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
451 FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
452 }
453 break;
454
455 /* ESC [ n1 'K'
456 Erase line. */
457 case MAKEWORD ('[', 'K'):
458 if (esc_head == esc_term)
459 /* This is one of the very few codes whose parameters have
460 a default value of zero. */
461 n1 = 0;
462 else
463 {
464 n1 = strtol (esc_head, &eptr, 10);
465 if (eptr != esc_term)
466 break;
467 }
468
469 if (GetConsoleScreenBufferInfo (h, &sb))
470 {
471 switch (n1)
472 {
473 case 0:
474 /* Erase from the cursor to the end. */
475 cr = sb.dwCursorPosition;
476 cnt = sb.dwSize.X - sb.dwCursorPosition.X;
477 break;
478 case 1:
479 /* Erase from the cursor to the beginning. */
480 cr = sb.dwCursorPosition;
481 cr.X = 0;
482 cnt = sb.dwCursorPosition.X + 1;
483 break;
484 default:
485 /* Erase the entire line. */
486 cr = sb.dwCursorPosition;
487 cr.X = 0;
488 cnt = sb.dwSize.X;
489 break;
490 }
491 FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
492 FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
493 }
494 break;
495
496 /* ESC [ n1 ';' n2 'm'
497 Set SGR parameters. Zero or more parameters will follow. */
498 case MAKEWORD ('[', 'm'):
499 attrib_add = 0;
500 attrib_rm = 0;
501 if (esc_head == esc_term)
502 {
503 /* When no parameter is given, reset the console. */
504 attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
505 | FOREGROUND_BLUE);
506 attrib_rm = -1; /* Removes everything. */
507 goto sgr_set_it;
508 }
509 param = esc_head;
510 do
511 {
512 /* Parse a parameter. */
513 n1 = strtol (param, &eptr, 10);
514 if (*eptr != ';' && eptr != esc_term)
515 goto sgr_set_it;
516
517 switch (n1)
518 {
519 case 0:
520 /* Reset. */
521 attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
522 | FOREGROUND_BLUE);
523 attrib_rm = -1; /* Removes everything. */
524 break;
525 case 1:
526 /* Bold. */
527 attrib_add |= FOREGROUND_INTENSITY;
528 break;
529 case 4:
530 /* Underline. */
531 attrib_add |= COMMON_LVB_UNDERSCORE;
532 break;
533 case 5:
534 /* Blink. */
535 /* XXX: It is not BLINKING at all! */
536 attrib_add |= BACKGROUND_INTENSITY;
537 break;
538 case 7:
539 /* Reverse. */
540 attrib_add |= COMMON_LVB_REVERSE_VIDEO;
541 break;
542 case 22:
543 /* No bold. */
544 attrib_add &= ~FOREGROUND_INTENSITY;
545 attrib_rm |= FOREGROUND_INTENSITY;
546 break;
547 case 24:
548 /* No underline. */
549 attrib_add &= ~COMMON_LVB_UNDERSCORE;
550 attrib_rm |= COMMON_LVB_UNDERSCORE;
551 break;
552 case 25:
553 /* No blink. */
554 /* XXX: It is not BLINKING at all! */
555 attrib_add &= ~BACKGROUND_INTENSITY;
556 attrib_rm |= BACKGROUND_INTENSITY;
557 break;
558 case 27:
559 /* No reverse. */
560 attrib_add &= ~COMMON_LVB_REVERSE_VIDEO;
561 attrib_rm |= COMMON_LVB_REVERSE_VIDEO;
562 break;
563 case 30:
564 case 31:
565 case 32:
566 case 33:
567 case 34:
568 case 35:
569 case 36:
570 case 37:
571 /* Foreground color. */
572 attrib_add &= ~(FOREGROUND_RED | FOREGROUND_GREEN
573 | FOREGROUND_BLUE);
574 n1 -= 30;
575 if (n1 & 1)
576 attrib_add |= FOREGROUND_RED;
577 if (n1 & 2)
578 attrib_add |= FOREGROUND_GREEN;
579 if (n1 & 4)
580 attrib_add |= FOREGROUND_BLUE;
581 attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
582 | FOREGROUND_BLUE);
583 break;
584 case 38:
585 /* Reserved for extended foreground color.
586 Don't know how to handle parameters remaining.
587 Bail out. */
588 goto sgr_set_it;
589 case 39:
590 /* Reset foreground color. */
591 /* Set to grey. */
592 attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
593 | FOREGROUND_BLUE);
594 attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
595 | FOREGROUND_BLUE);
596 break;
597 case 40:
598 case 41:
599 case 42:
600 case 43:
601 case 44:
602 case 45:
603 case 46:
604 case 47:
605 /* Background color. */
606 attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
607 | BACKGROUND_BLUE);
608 n1 -= 40;
609 if (n1 & 1)
610 attrib_add |= BACKGROUND_RED;
611 if (n1 & 2)
612 attrib_add |= BACKGROUND_GREEN;
613 if (n1 & 4)
614 attrib_add |= BACKGROUND_BLUE;
615 attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
616 | BACKGROUND_BLUE);
617 break;
618 case 48:
619 /* Reserved for extended background color.
620 Don't know how to handle parameters remaining.
621 Bail out. */
622 goto sgr_set_it;
623 case 49:
624 /* Reset background color. */
625 /* Set to black. */
626 attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
627 | BACKGROUND_BLUE);
628 attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
629 | BACKGROUND_BLUE);
630 break;
631 }
632
633 /* Prepare the next parameter. */
634 param = eptr + 1;
635 }
636 while (param != esc_term);
637
638sgr_set_it:
639 /* 0xFFFF removes everything. If it is not the case,
640 care must be taken to preserve old attributes. */
641 if (attrib_rm != 0xFFFF && GetConsoleScreenBufferInfo (h, &sb))
642 {
643 attrib_add |= sb.wAttributes & ~attrib_rm;
644 }
645 if (attrib_add & COMMON_LVB_REVERSE_VIDEO)
646 {
647 /* COMMON_LVB_REVERSE_VIDEO is only effective for DBCS.
648 * Swap foreground and background colors by hand.
649 */
650 attrib_add = (attrib_add & 0xFF00)
651 | ((attrib_add & 0x00F0) >> 4)
652 | ((attrib_add & 0x000F) << 4);
653 attrib_add &= ~COMMON_LVB_REVERSE_VIDEO;
654 }
655 SetConsoleTextAttribute (h, attrib_add);
656 break;
657 }
658}
659
660int
661mingw_ansi_fputs (const char *str, FILE *fp)
662{
663 const char *read = str;
664 HANDLE h;
665 DWORD mode;
666 int esc_code, prefix_len;
667 const char *esc_head, *esc_term;
668
669 h = (HANDLE) _get_osfhandle (_fileno (fp));
670 if (h == INVALID_HANDLE_VALUE)
671 return EOF;
672
673 /* Don't mess up stdio functions with Windows APIs. */
674 fflush (fp);
675
676 if (GetConsoleMode (h, &mode))
677 /* If it is a console, translate ANSI escape codes as needed. */
678 for (;;)
679 {
680 if ((esc_code = find_esc_head (&prefix_len, &esc_head, read)) == 0)
681 {
682 /* Write all remaining characters, then exit. */
683 write_all (h, read, strlen (read));
684 break;
685 }
686 if (find_esc_terminator (&esc_term, esc_head) == 0)
687 /* Ignore incomplete escape sequences at the moment.
688 FIXME: The escape state shall be cached for further calls
689 to this function. */
690 break;
691 write_all (h, read, esc_head - prefix_len - read);
692 eat_esc_sequence (h, esc_code, esc_head, esc_term);
693 read = esc_term + 1;
694 }
695 else
696 /* If it is not a console, write everything as-is. */
697 write_all (h, read, strlen (read));
698
699 return 1;
700}
701
702#endif /* __MINGW32__ */
703
704static int
705decode_utf8_char (const unsigned char *, size_t len, unsigned int *);
706static void pp_quoted_string (pretty_printer *, const char *, size_t = -1);
707
708/* Overwrite the given location/range within this text_info's rich_location.
709 For use e.g. when implementing "+" in client format decoders. */
710
711void
712text_info::set_location (unsigned int idx, location_t loc,
713 enum range_display_kind range_display_kind)
714{
715 gcc_checking_assert (m_richloc);
716 m_richloc->set_range (idx, loc, range_display_kind);
717}
718
719location_t
720text_info::get_location (unsigned int index_of_location) const
721{
722 gcc_checking_assert (m_richloc);
723
724 if (index_of_location == 0)
725 return m_richloc->get_loc ();
726 else
727 return UNKNOWN_LOCATION;
728}
729
730// Default construct an output buffer.
731
732output_buffer::output_buffer ()
733 : formatted_obstack (),
734 chunk_obstack (),
735 obstack (&formatted_obstack),
736 cur_chunk_array (),
737 stream (stderr),
738 line_length (),
739 digit_buffer (),
740 flush_p (true)
741{
742 obstack_init (&formatted_obstack);
743 obstack_init (&chunk_obstack);
744}
745
746// Release resources owned by an output buffer at the end of lifetime.
747
748output_buffer::~output_buffer ()
749{
750 obstack_free (&chunk_obstack, NULL);
751 obstack_free (&formatted_obstack, NULL);
752}
753
754
755/* Format an integer given by va_arg (ARG, type-specifier T) where
756 type-specifier is a precision modifier as indicated by PREC. F is
757 a string used to construct the appropriate format-specifier. */
758#define pp_integer_with_precision(PP, ARG, PREC, T, F) \
759 do \
760 switch (PREC) \
761 { \
762 case 0: \
763 pp_scalar (PP, "%" F, va_arg (ARG, T)); \
764 break; \
765 \
766 case 1: \
767 pp_scalar (PP, "%l" F, va_arg (ARG, long T)); \
768 break; \
769 \
770 case 2: \
771 pp_scalar (PP, "%" HOST_LONG_LONG_FORMAT F, va_arg (ARG, long long T)); \
772 break; \
773 \
774 default: \
775 break; \
776 } \
777 while (0)
778
779
780/* Subroutine of pp_set_maximum_length. Set up PRETTY-PRINTER's
781 internal maximum characters per line. */
782static void
783pp_set_real_maximum_length (pretty_printer *pp)
784{
785 /* If we're told not to wrap lines then do the obvious thing. In case
786 we'll emit prefix only once per message, it is appropriate
787 not to increase unnecessarily the line-length cut-off. */
788 if (!pp_is_wrapping_line (pp)
789 || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ONCE
790 || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
791 pp->maximum_length = pp_line_cutoff (pp);
792 else
793 {
794 int prefix_length = pp->prefix ? strlen (s: pp->prefix) : 0;
795 /* If the prefix is ridiculously too long, output at least
796 32 characters. */
797 if (pp_line_cutoff (pp) - prefix_length < 32)
798 pp->maximum_length = pp_line_cutoff (pp) + 32;
799 else
800 pp->maximum_length = pp_line_cutoff (pp);
801 }
802}
803
804/* Clear PRETTY-PRINTER's output state. */
805static inline void
806pp_clear_state (pretty_printer *pp)
807{
808 pp->emitted_prefix = false;
809 pp_indentation (pp) = 0;
810}
811
812/* Print X to PP in decimal. */
813template<unsigned int N, typename T>
814void
815pp_wide_integer (pretty_printer *pp, const poly_int<N, T> &x)
816{
817 if (x.is_constant ())
818 pp_wide_integer (pp, x.coeffs[0]);
819 else
820 {
821 pp_left_bracket (pp);
822 for (unsigned int i = 0; i < N; ++i)
823 {
824 if (i != 0)
825 pp_comma (pp);
826 pp_wide_integer (pp, x.coeffs[i]);
827 }
828 pp_right_bracket (pp);
829 }
830}
831
832template void pp_wide_integer (pretty_printer *, const poly_uint16 &);
833template void pp_wide_integer (pretty_printer *, const poly_int64 &);
834template void pp_wide_integer (pretty_printer *, const poly_uint64 &);
835
836/* Flush the formatted text of PRETTY-PRINTER onto the attached stream. */
837void
838pp_write_text_to_stream (pretty_printer *pp)
839{
840 const char *text = pp_formatted_text (pp);
841#ifdef __MINGW32__
842 mingw_ansi_fputs (text, pp_buffer (pp)->stream);
843#else
844 fputs (s: text, pp_buffer (pp)->stream);
845#endif
846 pp_clear_output_area (pp);
847}
848
849/* As pp_write_text_to_stream, but for GraphViz label output.
850
851 Flush the formatted text of pretty-printer PP onto the attached stream.
852 Replace characters in PPF that have special meaning in a GraphViz .dot
853 file.
854
855 This routine is not very fast, but it doesn't have to be as this is only
856 be used by routines dumping intermediate representations in graph form. */
857
858void
859pp_write_text_as_dot_label_to_stream (pretty_printer *pp, bool for_record)
860{
861 const char *text = pp_formatted_text (pp);
862 const char *p = text;
863 FILE *fp = pp_buffer (pp)->stream;
864
865 for (;*p; p++)
866 {
867 bool escape_char;
868 switch (*p)
869 {
870 /* Print newlines as a left-aligned newline. */
871 case '\n':
872 fputs (s: "\\l", stream: fp);
873 escape_char = true;
874 break;
875
876 /* The following characters are only special for record-shape nodes. */
877 case '|':
878 case '{':
879 case '}':
880 case '<':
881 case '>':
882 case ' ':
883 escape_char = for_record;
884 break;
885
886 /* The following characters always have to be escaped
887 for use in labels. */
888 case '\\':
889 /* There is a bug in some (f.i. 2.36.0) versions of graphiz
890 ( http://www.graphviz.org/mantisbt/view.php?id=2524 ) related to
891 backslash as last char in label. Let's avoid triggering it. */
892 gcc_assert (*(p + 1) != '\0');
893 /* Fall through. */
894 case '"':
895 escape_char = true;
896 break;
897
898 default:
899 escape_char = false;
900 break;
901 }
902
903 if (escape_char)
904 fputc (c: '\\', stream: fp);
905
906 fputc (c: *p, stream: fp);
907 }
908
909 pp_clear_output_area (pp);
910}
911
912/* As pp_write_text_to_stream, but for GraphViz HTML-like strings.
913
914 Flush the formatted text of pretty-printer PP onto the attached stream,
915 escaping these characters
916 " & < >
917 using XML escape sequences.
918
919 http://www.graphviz.org/doc/info/lang.html#html states:
920 special XML escape sequences for ", &, <, and > may be necessary in
921 order to embed these characters in attribute values or raw text
922 This doesn't list "'" (which would normally be escaped in XML
923 as "&apos;" or in HTML as "&#39;");.
924
925 Experiments show that escaping "'" doesn't seem to be necessary. */
926
927void
928pp_write_text_as_html_like_dot_to_stream (pretty_printer *pp)
929{
930 const char *text = pp_formatted_text (pp);
931 const char *p = text;
932 FILE *fp = pp_buffer (pp)->stream;
933
934 for (;*p; p++)
935 {
936 switch (*p)
937 {
938 case '"':
939 fputs (s: "&quot;", stream: fp);
940 break;
941 case '&':
942 fputs (s: "&amp;", stream: fp);
943 break;
944 case '<':
945 fputs (s: "&lt;", stream: fp);
946 break;
947 case '>':
948 fputs (s: "&gt;",stream: fp);
949 break;
950
951 default:
952 fputc (c: *p, stream: fp);
953 break;
954 }
955 }
956
957 pp_clear_output_area (pp);
958}
959
960/* Wrap a text delimited by START and END into PRETTY-PRINTER. */
961static void
962pp_wrap_text (pretty_printer *pp, const char *start, const char *end)
963{
964 bool wrapping_line = pp_is_wrapping_line (pp);
965
966 while (start != end)
967 {
968 /* Dump anything bordered by whitespaces. */
969 {
970 const char *p = start;
971 while (p != end && !ISBLANK (*p) && *p != '\n')
972 ++p;
973 if (wrapping_line
974 && p - start >= pp_remaining_character_count_for_line (pp))
975 pp_newline (pp);
976 pp_append_text (pp, start, p);
977 start = p;
978 }
979
980 if (start != end && ISBLANK (*start))
981 {
982 pp_space (pp);
983 ++start;
984 }
985 if (start != end && *start == '\n')
986 {
987 pp_newline (pp);
988 ++start;
989 }
990 }
991}
992
993/* Same as pp_wrap_text but wrap text only when in line-wrapping mode. */
994static inline void
995pp_maybe_wrap_text (pretty_printer *pp, const char *start, const char *end)
996{
997 if (pp_is_wrapping_line (pp))
998 pp_wrap_text (pp, start, end);
999 else
1000 pp_append_text (pp, start, end);
1001}
1002
1003/* Append to the output area of PRETTY-PRINTER a string specified by its
1004 STARTing character and LENGTH. */
1005static inline void
1006pp_append_r (pretty_printer *pp, const char *start, int length)
1007{
1008 output_buffer_append_r (pp_buffer (pp), start, length);
1009}
1010
1011/* Insert enough spaces into the output area of PRETTY-PRINTER to bring
1012 the column position to the current indentation level, assuming that a
1013 newline has just been written to the buffer. */
1014void
1015pp_indent (pretty_printer *pp)
1016{
1017 int n = pp_indentation (pp);
1018 int i;
1019
1020 for (i = 0; i < n; ++i)
1021 pp_space (pp);
1022}
1023
1024static const char *get_end_url_string (pretty_printer *);
1025
1026/* Append STR to OSTACK, without a null-terminator. */
1027
1028static void
1029obstack_append_string (obstack *ostack, const char *str)
1030{
1031 obstack_grow (ostack, str, strlen (str));
1032}
1033
1034/* Given quoted text starting at QUOTED_TEXT_START_IDX within PP's buffer,
1035 potentially use URLIFIER (if non-null) to see if there's a URL for the
1036 quoted text.
1037
1038 If so, replace the quoted part of the text in the buffer with a URLified
1039 version of the text, using PP's settings.
1040
1041 For example, given this is the buffer:
1042 "this is a test `hello world"
1043 .................^~~~~~~~~~~
1044 with the quoted text starting at the 'h' of "hello world", the buffer
1045 becomes:
1046 "this is a test `BEGIN_URL(URL)hello worldEND(URL)"
1047 .................^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1048 .................-----------replacement-----------
1049*/
1050
1051static void
1052urlify_quoted_string (pretty_printer *pp,
1053 const urlifier *urlifier,
1054 size_t quoted_text_start_idx)
1055{
1056 if (pp->url_format == URL_FORMAT_NONE)
1057 return;
1058 if (!urlifier)
1059 return;
1060
1061 output_buffer * const buffer = pp_buffer (pp);
1062
1063 /* Get end of quoted string. */
1064 const size_t close_quote_idx
1065 = obstack_object_size (&buffer->chunk_obstack);
1066 gcc_assert (close_quote_idx >= quoted_text_start_idx);
1067 if (close_quote_idx == quoted_text_start_idx)
1068 /* Empty quoted string; do nothing. */
1069 return;
1070 const size_t len = close_quote_idx - quoted_text_start_idx;
1071 const char *start = (buffer->chunk_obstack.object_base
1072 + quoted_text_start_idx);
1073 char *url = urlifier->get_url_for_quoted_text (p: start, sz: len);
1074 if (!url)
1075 /* No URL for this quoted text; do nothing. */
1076 return;
1077
1078 /* Stash a copy of the quoted text. */
1079 char *text = xstrndup (start, len);
1080
1081 /* Replace quoted text... */
1082 buffer->chunk_obstack.next_free -= len;
1083
1084 /* ...with URLified version of the text. */
1085 /* Begin URL. */
1086 switch (pp->url_format)
1087 {
1088 default:
1089 case URL_FORMAT_NONE:
1090 gcc_unreachable ();
1091 case URL_FORMAT_ST:
1092 obstack_append_string (ostack: &buffer->chunk_obstack,
1093 str: "\33]8;;");
1094 obstack_append_string (ostack: &buffer->chunk_obstack, str: url);
1095 obstack_append_string (ostack: &buffer->chunk_obstack,
1096 str: "\33\\");
1097 break;
1098 case URL_FORMAT_BEL:
1099 obstack_append_string (ostack: &buffer->chunk_obstack,
1100 str: "\33]8;;");
1101 obstack_append_string (ostack: &buffer->chunk_obstack, str: url);
1102 obstack_append_string (ostack: &buffer->chunk_obstack,
1103 str: "\a");
1104 break;
1105 }
1106 /* Add the text back. */
1107 obstack_append_string (ostack: &buffer->chunk_obstack, str: text);
1108 /* End URL. */
1109 obstack_append_string (ostack: &buffer->chunk_obstack,
1110 str: get_end_url_string (pp));
1111 free (ptr: text);
1112 free (ptr: url);
1113}
1114
1115/* The following format specifiers are recognized as being client independent:
1116 %d, %i: (signed) integer in base ten.
1117 %u: unsigned integer in base ten.
1118 %o: unsigned integer in base eight.
1119 %x: unsigned integer in base sixteen.
1120 %ld, %li, %lo, %lu, %lx: long versions of the above.
1121 %lld, %lli, %llo, %llu, %llx: long long versions.
1122 %wd, %wi, %wo, %wu, %wx: HOST_WIDE_INT versions.
1123 %f: double
1124 %c: character.
1125 %s: string.
1126 %p: pointer (printed in a host-dependent manner).
1127 %r: if pp_show_color(pp), switch to color identified by const char *.
1128 %R: if pp_show_color(pp), reset color.
1129 %m: strerror(text->err_no) - does not consume a value from args_ptr.
1130 %%: '%'.
1131 %<: opening quote.
1132 %>: closing quote.
1133 %{: URL start. Consumes a const char * argument for the URL.
1134 %}: URL end. Does not consume any arguments.
1135 %': apostrophe (should only be used in untranslated messages;
1136 translations should use appropriate punctuation directly).
1137 %@: diagnostic_event_id_ptr, for which event_id->known_p () must be true.
1138 %.*s: a substring the length of which is specified by an argument
1139 integer.
1140 %Ns: likewise, but length specified as constant in the format string.
1141 Flag 'q': quote formatted text (must come immediately after '%').
1142 %Z: Requires two arguments - array of int, and len. Prints elements
1143 of the array.
1144
1145 Arguments can be used sequentially, or through %N$ resp. *N$
1146 notation Nth argument after the format string. If %N$ / *N$
1147 notation is used, it must be used for all arguments, except %m, %%,
1148 %<, %>, %} and %', which may not have a number, as they do not consume
1149 an argument. When %M$.*N$s is used, M must be N + 1. (This may
1150 also be written %M$.*s, provided N is not otherwise used.) The
1151 format string must have conversion specifiers with argument numbers
1152 1 up to highest argument; each argument may only be used once.
1153 A format string can have at most 30 arguments. */
1154
1155/* Formatting phases 1 and 2: render TEXT->format_spec plus
1156 text->m_args_ptr into a series of chunks in pp_buffer (PP)->args[].
1157 Phase 3 is in pp_output_formatted_text.
1158
1159 If URLIFIER is non-NULL, then use it to add URLs for quoted
1160 strings, so that e.g.
1161 "before %<quoted%> after"
1162 with a URLIFIER that has a URL for "quoted" might be emitted as:
1163 "before `BEGIN_URL(http://example.com)quotedEND_URL' after"
1164 This only works for message fragments that are:
1165 - quoted entirely in phase 1 (e.g. "%<this is quoted%>"), or
1166 - quoted entirely in phase 2 (e.g. "%qs"),
1167 but *not* in strings that use a mixture of both phases
1168 (e.g. "%<this is a mixture: %s %>"). */
1169
1170void
1171pp_format (pretty_printer *pp,
1172 text_info *text,
1173 const urlifier *urlifier)
1174{
1175 output_buffer * const buffer = pp_buffer (pp);
1176 const char *p;
1177 const char **args;
1178 struct chunk_info *new_chunk_array;
1179
1180 unsigned int curarg = 0, chunk = 0, argno;
1181 pp_wrapping_mode_t old_wrapping_mode;
1182 bool any_unnumbered = false, any_numbered = false;
1183 const char **formatters[PP_NL_ARGMAX];
1184
1185 /* Keep track of location of last "%", if any. */
1186 size_t quoted_text_start_idx = 0;
1187
1188 /* Allocate a new chunk structure. */
1189 new_chunk_array = XOBNEW (&buffer->chunk_obstack, struct chunk_info);
1190 new_chunk_array->prev = buffer->cur_chunk_array;
1191 buffer->cur_chunk_array = new_chunk_array;
1192 args = new_chunk_array->args;
1193
1194 /* Formatting phase 1: split up TEXT->format_spec into chunks in
1195 pp_buffer (PP)->args[]. Even-numbered chunks are to be output
1196 verbatim, odd-numbered chunks are format specifiers.
1197 %m, %%, %<, %>, %} and %' are replaced with the appropriate text at
1198 this point. */
1199
1200 memset (s: formatters, c: 0, n: sizeof formatters);
1201
1202 for (p = text->m_format_spec; *p; )
1203 {
1204 while (*p != '\0' && *p != '%')
1205 {
1206 obstack_1grow (&buffer->chunk_obstack, *p);
1207 p++;
1208 }
1209
1210 if (*p == '\0')
1211 break;
1212
1213 switch (*++p)
1214 {
1215 case '\0':
1216 gcc_unreachable ();
1217
1218 case '%':
1219 obstack_1grow (&buffer->chunk_obstack, '%');
1220 p++;
1221 continue;
1222
1223 case '<':
1224 {
1225 obstack_grow (&buffer->chunk_obstack,
1226 open_quote, strlen (open_quote));
1227 const char *colorstr
1228 = colorize_start (pp_show_color (pp), name: "quote");
1229 obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
1230 p++;
1231
1232 /* Stash offset of start of quoted string. */
1233 quoted_text_start_idx
1234 = obstack_object_size (&buffer->chunk_obstack);
1235
1236 continue;
1237 }
1238
1239 case '>':
1240 {
1241 if (quoted_text_start_idx)
1242 {
1243 urlify_quoted_string (pp, urlifier, quoted_text_start_idx);
1244 quoted_text_start_idx = 0;
1245 }
1246 const char *colorstr = colorize_stop (pp_show_color (pp));
1247 obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
1248 }
1249 /* FALLTHRU */
1250 case '\'':
1251 obstack_grow (&buffer->chunk_obstack,
1252 close_quote, strlen (close_quote));
1253 p++;
1254 continue;
1255
1256 case '}':
1257 {
1258 const char *endurlstr = get_end_url_string (pp);
1259 obstack_grow (&buffer->chunk_obstack, endurlstr,
1260 strlen (endurlstr));
1261 }
1262 p++;
1263 continue;
1264
1265 case 'R':
1266 {
1267 const char *colorstr = colorize_stop (pp_show_color (pp));
1268 obstack_grow (&buffer->chunk_obstack, colorstr,
1269 strlen (colorstr));
1270 p++;
1271 continue;
1272 }
1273
1274 case 'm':
1275 {
1276 const char *errstr = xstrerror (text->m_err_no);
1277 obstack_grow (&buffer->chunk_obstack, errstr, strlen (errstr));
1278 }
1279 p++;
1280 continue;
1281
1282 default:
1283 /* Handled in phase 2. Terminate the plain chunk here. */
1284 obstack_1grow (&buffer->chunk_obstack, '\0');
1285 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1286 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1287 /* We can't yet handle urlifying quoted strings that use
1288 a combination of phase 1 and phase 2 e.g.
1289 "did you mean %<-%s%>".
1290 Stop any phase 1 quoted text if there are going to be any
1291 phase 2 quoted chunks. */
1292 quoted_text_start_idx = 0;
1293 break;
1294 }
1295
1296 if (ISDIGIT (*p))
1297 {
1298 char *end;
1299 argno = strtoul (nptr: p, endptr: &end, base: 10) - 1;
1300 p = end;
1301 gcc_assert (*p == '$');
1302 p++;
1303
1304 any_numbered = true;
1305 gcc_assert (!any_unnumbered);
1306 }
1307 else
1308 {
1309 argno = curarg++;
1310 any_unnumbered = true;
1311 gcc_assert (!any_numbered);
1312 }
1313 gcc_assert (argno < PP_NL_ARGMAX);
1314 gcc_assert (!formatters[argno]);
1315 formatters[argno] = &args[chunk];
1316 do
1317 {
1318 obstack_1grow (&buffer->chunk_obstack, *p);
1319 p++;
1320 }
1321 while (strchr (s: "qwl+#", c: p[-1]));
1322
1323 if (p[-1] == '.')
1324 {
1325 /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
1326 (where M == N + 1). */
1327 if (ISDIGIT (*p))
1328 {
1329 do
1330 {
1331 obstack_1grow (&buffer->chunk_obstack, *p);
1332 p++;
1333 }
1334 while (ISDIGIT (p[-1]));
1335 gcc_assert (p[-1] == 's');
1336 }
1337 else
1338 {
1339 gcc_assert (*p == '*');
1340 obstack_1grow (&buffer->chunk_obstack, '*');
1341 p++;
1342
1343 if (ISDIGIT (*p))
1344 {
1345 char *end;
1346 unsigned int argno2 = strtoul (nptr: p, endptr: &end, base: 10) - 1;
1347 p = end;
1348 gcc_assert (argno2 == argno - 1);
1349 gcc_assert (!any_unnumbered);
1350 gcc_assert (*p == '$');
1351
1352 p++;
1353 formatters[argno2] = formatters[argno];
1354 }
1355 else
1356 {
1357 gcc_assert (!any_numbered);
1358 formatters[argno+1] = formatters[argno];
1359 curarg++;
1360 }
1361 gcc_assert (*p == 's');
1362 obstack_1grow (&buffer->chunk_obstack, 's');
1363 p++;
1364 }
1365 }
1366 if (*p == '\0')
1367 break;
1368
1369 obstack_1grow (&buffer->chunk_obstack, '\0');
1370 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1371 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1372 }
1373
1374 obstack_1grow (&buffer->chunk_obstack, '\0');
1375 gcc_assert (chunk < PP_NL_ARGMAX * 2);
1376 args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
1377 args[chunk] = 0;
1378
1379 /* Set output to the argument obstack, and switch line-wrapping and
1380 prefixing off. */
1381 buffer->obstack = &buffer->chunk_obstack;
1382 const int old_line_length = buffer->line_length;
1383 old_wrapping_mode = pp_set_verbatim_wrapping (pp);
1384
1385 /* Second phase. Replace each formatter with the formatted text it
1386 corresponds to. */
1387
1388 for (argno = 0; formatters[argno]; argno++)
1389 {
1390 int precision = 0;
1391 bool wide = false;
1392 bool plus = false;
1393 bool hash = false;
1394 bool quote = false;
1395 quoted_text_start_idx = 0;
1396
1397 /* We do not attempt to enforce any ordering on the modifier
1398 characters. */
1399
1400 for (p = *formatters[argno];; p++)
1401 {
1402 switch (*p)
1403 {
1404 case 'q':
1405 gcc_assert (!quote);
1406 quote = true;
1407 continue;
1408
1409 case '+':
1410 gcc_assert (!plus);
1411 plus = true;
1412 continue;
1413
1414 case '#':
1415 gcc_assert (!hash);
1416 hash = true;
1417 continue;
1418
1419 case 'w':
1420 gcc_assert (!wide);
1421 wide = true;
1422 continue;
1423
1424 case 'l':
1425 /* We don't support precision beyond that of "long long". */
1426 gcc_assert (precision < 2);
1427 precision++;
1428 continue;
1429 }
1430 break;
1431 }
1432
1433 gcc_assert (!wide || precision == 0);
1434
1435 if (quote)
1436 {
1437 pp_begin_quote (pp, pp_show_color (pp));
1438 quoted_text_start_idx
1439 = obstack_object_size (&buffer->chunk_obstack);
1440 }
1441
1442 switch (*p)
1443 {
1444 case 'r':
1445 pp_string (pp, colorize_start (pp_show_color (pp),
1446 va_arg (*text->m_args_ptr,
1447 const char *)));
1448 break;
1449
1450 case 'c':
1451 {
1452 /* When quoting, print alphanumeric, punctuation, and the space
1453 character unchanged, and all others in hexadecimal with the
1454 "\x" prefix. Otherwise print them all unchanged. */
1455 int chr = va_arg (*text->m_args_ptr, int);
1456 if (ISPRINT (chr) || !quote)
1457 pp_character (pp, chr);
1458 else
1459 {
1460 const char str [2] = { chr, '\0' };
1461 pp_quoted_string (pp, str, 1);
1462 }
1463 break;
1464 }
1465
1466 case 'd':
1467 case 'i':
1468 if (wide)
1469 pp_wide_integer (pp, va_arg (*text->m_args_ptr, HOST_WIDE_INT));
1470 else
1471 pp_integer_with_precision
1472 (pp, *text->m_args_ptr, precision, int, "d");
1473 break;
1474
1475 case 'o':
1476 if (wide)
1477 pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
1478 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1479 else
1480 pp_integer_with_precision
1481 (pp, *text->m_args_ptr, precision, unsigned, "o");
1482 break;
1483
1484 case 's':
1485 if (quote)
1486 pp_quoted_string (pp, va_arg (*text->m_args_ptr, const char *));
1487 else
1488 pp_string (pp, va_arg (*text->m_args_ptr, const char *));
1489 break;
1490
1491 case 'p':
1492 pp_pointer (pp, va_arg (*text->m_args_ptr, void *));
1493 break;
1494
1495 case 'u':
1496 if (wide)
1497 pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
1498 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1499 else
1500 pp_integer_with_precision
1501 (pp, *text->m_args_ptr, precision, unsigned, "u");
1502 break;
1503
1504 case 'f':
1505 pp_double (pp, va_arg (*text->m_args_ptr, double));
1506 break;
1507
1508 case 'Z':
1509 {
1510 int *v = va_arg (*text->m_args_ptr, int *);
1511 unsigned len = va_arg (*text->m_args_ptr, unsigned);
1512
1513 for (unsigned i = 0; i < len; ++i)
1514 {
1515 pp_scalar (pp, "%i", v[i]);
1516 if (i < len - 1)
1517 {
1518 pp_comma (pp);
1519 pp_space (pp);
1520 }
1521 }
1522 break;
1523 }
1524
1525 case 'x':
1526 if (wide)
1527 pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
1528 va_arg (*text->m_args_ptr, unsigned HOST_WIDE_INT));
1529 else
1530 pp_integer_with_precision
1531 (pp, *text->m_args_ptr, precision, unsigned, "x");
1532 break;
1533
1534 case '.':
1535 {
1536 int n;
1537 const char *s;
1538
1539 /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
1540 (where M == N + 1). The format string should be verified
1541 already from the first phase. */
1542 p++;
1543 if (ISDIGIT (*p))
1544 {
1545 char *end;
1546 n = strtoul (nptr: p, endptr: &end, base: 10);
1547 p = end;
1548 gcc_assert (*p == 's');
1549 }
1550 else
1551 {
1552 gcc_assert (*p == '*');
1553 p++;
1554 gcc_assert (*p == 's');
1555 n = va_arg (*text->m_args_ptr, int);
1556
1557 /* This consumes a second entry in the formatters array. */
1558 gcc_assert (formatters[argno] == formatters[argno+1]);
1559 argno++;
1560 }
1561
1562 s = va_arg (*text->m_args_ptr, const char *);
1563
1564 /* Append the lesser of precision and strlen (s) characters
1565 from the array (which need not be a nul-terminated string).
1566 Negative precision is treated as if it were omitted. */
1567 size_t len = n < 0 ? strlen (s: s) : strnlen (string: s, maxlen: n);
1568
1569 pp_append_text (pp, s, s + len);
1570 }
1571 break;
1572
1573 case '@':
1574 {
1575 /* diagnostic_event_id_t *. */
1576 diagnostic_event_id_ptr event_id
1577 = va_arg (*text->m_args_ptr, diagnostic_event_id_ptr);
1578 gcc_assert (event_id->known_p ());
1579
1580 pp_string (pp, colorize_start (pp_show_color (pp), name: "path"));
1581 pp_character (pp, '(');
1582 pp_decimal_int (pp, event_id->one_based ());
1583 pp_character (pp, ')');
1584 pp_string (pp, colorize_stop (pp_show_color (pp)));
1585 }
1586 break;
1587
1588 case '{':
1589 pp_begin_url (pp, va_arg (*text->m_args_ptr, const char *));
1590 break;
1591
1592 default:
1593 {
1594 bool ok;
1595
1596 /* Call the format decoder.
1597 Pass the address of "quote" so that format decoders can
1598 potentially disable printing of the closing quote
1599 (e.g. when printing "'TYPEDEF' aka 'TYPE'" in the C family
1600 of frontends). */
1601 gcc_assert (pp_format_decoder (pp));
1602 ok = pp_format_decoder (pp) (pp, text, p,
1603 precision, wide, plus, hash, &quote,
1604 formatters[argno]);
1605 gcc_assert (ok);
1606 }
1607 }
1608
1609 if (quote)
1610 {
1611 if (quoted_text_start_idx)
1612 {
1613 urlify_quoted_string (pp, urlifier, quoted_text_start_idx);
1614 quoted_text_start_idx = 0;
1615 }
1616 pp_end_quote (pp, pp_show_color (pp));
1617 }
1618
1619 obstack_1grow (&buffer->chunk_obstack, '\0');
1620 *formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *);
1621 }
1622
1623 if (CHECKING_P)
1624 for (; argno < PP_NL_ARGMAX; argno++)
1625 gcc_assert (!formatters[argno]);
1626
1627 /* If the client supplied a postprocessing object, call its "handle"
1628 hook here. */
1629 if (pp->m_format_postprocessor)
1630 pp->m_format_postprocessor->handle (pp);
1631
1632 /* Revert to normal obstack and wrapping mode. */
1633 buffer->obstack = &buffer->formatted_obstack;
1634 buffer->line_length = old_line_length;
1635 pp_wrapping_mode (pp) = old_wrapping_mode;
1636 pp_clear_state (pp);
1637}
1638
1639/* Format of a message pointed to by TEXT. */
1640void
1641pp_output_formatted_text (pretty_printer *pp)
1642{
1643 unsigned int chunk;
1644 output_buffer * const buffer = pp_buffer (pp);
1645 struct chunk_info *chunk_array = buffer->cur_chunk_array;
1646 const char **args = chunk_array->args;
1647
1648 gcc_assert (buffer->obstack == &buffer->formatted_obstack);
1649
1650 /* This is a third phase, first 2 phases done in pp_format_args.
1651 Now we actually print it. */
1652 for (chunk = 0; args[chunk]; chunk++)
1653 pp_string (pp, args[chunk]);
1654
1655 /* Deallocate the chunk structure and everything after it (i.e. the
1656 associated series of formatted strings). */
1657 buffer->cur_chunk_array = chunk_array->prev;
1658 obstack_free (&buffer->chunk_obstack, chunk_array);
1659}
1660
1661/* Helper subroutine of output_verbatim and verbatim. Do the appropriate
1662 settings needed by BUFFER for a verbatim formatting. */
1663void
1664pp_format_verbatim (pretty_printer *pp, text_info *text)
1665{
1666 /* Set verbatim mode. */
1667 pp_wrapping_mode_t oldmode = pp_set_verbatim_wrapping (pp);
1668
1669 /* Do the actual formatting. */
1670 pp_format (pp, text);
1671 pp_output_formatted_text (pp);
1672
1673 /* Restore previous settings. */
1674 pp_wrapping_mode (pp) = oldmode;
1675}
1676
1677/* Flush the content of BUFFER onto the attached stream. This
1678 function does nothing unless pp->output_buffer->flush_p. */
1679void
1680pp_flush (pretty_printer *pp)
1681{
1682 pp_clear_state (pp);
1683 if (!pp->buffer->flush_p)
1684 return;
1685 pp_write_text_to_stream (pp);
1686 fflush (pp_buffer (pp)->stream);
1687}
1688
1689/* Flush the content of BUFFER onto the attached stream independently
1690 of the value of pp->output_buffer->flush_p. */
1691void
1692pp_really_flush (pretty_printer *pp)
1693{
1694 pp_clear_state (pp);
1695 pp_write_text_to_stream (pp);
1696 fflush (pp_buffer (pp)->stream);
1697}
1698
1699/* Sets the number of maximum characters per line PRETTY-PRINTER can
1700 output in line-wrapping mode. A LENGTH value 0 suppresses
1701 line-wrapping. */
1702void
1703pp_set_line_maximum_length (pretty_printer *pp, int length)
1704{
1705 pp_line_cutoff (pp) = length;
1706 pp_set_real_maximum_length (pp);
1707}
1708
1709/* Clear PRETTY-PRINTER output area text info. */
1710void
1711pp_clear_output_area (pretty_printer *pp)
1712{
1713 obstack_free (pp_buffer (pp)->obstack,
1714 obstack_base (pp_buffer (pp)->obstack));
1715 pp_buffer (pp)->line_length = 0;
1716}
1717
1718/* Set PREFIX for PRETTY-PRINTER, taking ownership of PREFIX, which
1719 will eventually be free-ed. */
1720
1721void
1722pp_set_prefix (pretty_printer *pp, char *prefix)
1723{
1724 free (ptr: pp->prefix);
1725 pp->prefix = prefix;
1726 pp_set_real_maximum_length (pp);
1727 pp->emitted_prefix = false;
1728 pp_indentation (pp) = 0;
1729}
1730
1731/* Take ownership of PP's prefix, setting it to NULL.
1732 This allows clients to save, override, and then restore an existing
1733 prefix, without it being free-ed. */
1734
1735char *
1736pp_take_prefix (pretty_printer *pp)
1737{
1738 char *result = pp->prefix;
1739 pp->prefix = NULL;
1740 return result;
1741}
1742
1743/* Free PRETTY-PRINTER's prefix, a previously malloc()'d string. */
1744void
1745pp_destroy_prefix (pretty_printer *pp)
1746{
1747 if (pp->prefix != NULL)
1748 {
1749 free (ptr: pp->prefix);
1750 pp->prefix = NULL;
1751 }
1752}
1753
1754/* Write out PRETTY-PRINTER's prefix. */
1755void
1756pp_emit_prefix (pretty_printer *pp)
1757{
1758 if (pp->prefix != NULL)
1759 {
1760 switch (pp_prefixing_rule (pp))
1761 {
1762 default:
1763 case DIAGNOSTICS_SHOW_PREFIX_NEVER:
1764 break;
1765
1766 case DIAGNOSTICS_SHOW_PREFIX_ONCE:
1767 if (pp->emitted_prefix)
1768 {
1769 pp_indent (pp);
1770 break;
1771 }
1772 pp_indentation (pp) += 3;
1773 /* Fall through. */
1774
1775 case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE:
1776 {
1777 int prefix_length = strlen (s: pp->prefix);
1778 pp_append_r (pp, start: pp->prefix, length: prefix_length);
1779 pp->emitted_prefix = true;
1780 }
1781 break;
1782 }
1783 }
1784}
1785
1786/* Construct a PRETTY-PRINTER of MAXIMUM_LENGTH characters per line. */
1787
1788pretty_printer::pretty_printer (int maximum_length)
1789 : buffer (new (XCNEW (output_buffer)) output_buffer ()),
1790 prefix (),
1791 padding (pp_none),
1792 maximum_length (),
1793 indent_skip (),
1794 wrapping (),
1795 format_decoder (),
1796 m_format_postprocessor (NULL),
1797 emitted_prefix (),
1798 need_newline (),
1799 translate_identifiers (true),
1800 show_color (),
1801 url_format (URL_FORMAT_NONE),
1802 m_skipping_null_url (false)
1803{
1804 pp_line_cutoff (this) = maximum_length;
1805 /* By default, we emit prefixes once per message. */
1806 pp_prefixing_rule (this) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
1807 pp_set_prefix (pp: this, NULL);
1808}
1809
1810/* Copy constructor for pretty_printer. */
1811
1812pretty_printer::pretty_printer (const pretty_printer &other)
1813: buffer (new (XCNEW (output_buffer)) output_buffer ()),
1814 prefix (),
1815 padding (other.padding),
1816 maximum_length (other.maximum_length),
1817 indent_skip (other.indent_skip),
1818 wrapping (other.wrapping),
1819 format_decoder (other.format_decoder),
1820 m_format_postprocessor (NULL),
1821 emitted_prefix (other.emitted_prefix),
1822 need_newline (other.need_newline),
1823 translate_identifiers (other.translate_identifiers),
1824 show_color (other.show_color),
1825 url_format (other.url_format),
1826 m_skipping_null_url (false)
1827{
1828 pp_line_cutoff (this) = maximum_length;
1829 /* By default, we emit prefixes once per message. */
1830 pp_prefixing_rule (this) = pp_prefixing_rule (&other);
1831 pp_set_prefix (pp: this, NULL);
1832
1833 if (other.m_format_postprocessor)
1834 m_format_postprocessor = other.m_format_postprocessor->clone ();
1835}
1836
1837pretty_printer::~pretty_printer ()
1838{
1839 if (m_format_postprocessor)
1840 delete m_format_postprocessor;
1841 buffer->~output_buffer ();
1842 XDELETE (buffer);
1843 free (ptr: prefix);
1844}
1845
1846/* Base class implementation of pretty_printer::clone vfunc. */
1847
1848pretty_printer *
1849pretty_printer::clone () const
1850{
1851 return new pretty_printer (*this);
1852}
1853
1854/* Append a string delimited by START and END to the output area of
1855 PRETTY-PRINTER. No line wrapping is done. However, if beginning a
1856 new line then emit PRETTY-PRINTER's prefix and skip any leading
1857 whitespace if appropriate. The caller must ensure that it is
1858 safe to do so. */
1859void
1860pp_append_text (pretty_printer *pp, const char *start, const char *end)
1861{
1862 /* Emit prefix and skip whitespace if we're starting a new line. */
1863 if (pp_buffer (pp)->line_length == 0)
1864 {
1865 pp_emit_prefix (pp);
1866 if (pp_is_wrapping_line (pp))
1867 while (start != end && *start == ' ')
1868 ++start;
1869 }
1870 pp_append_r (pp, start, length: end - start);
1871}
1872
1873/* Finishes constructing a NULL-terminated character string representing
1874 the PRETTY-PRINTED text. */
1875const char *
1876pp_formatted_text (pretty_printer *pp)
1877{
1878 return output_buffer_formatted_text (pp_buffer (pp));
1879}
1880
1881/* Return a pointer to the last character emitted in PRETTY-PRINTER's
1882 output area. A NULL pointer means no character available. */
1883const char *
1884pp_last_position_in_text (const pretty_printer *pp)
1885{
1886 return output_buffer_last_position_in_text (pp_buffer (pp));
1887}
1888
1889/* Return the amount of characters PRETTY-PRINTER can accept to
1890 make a full line. Meaningful only in line-wrapping mode. */
1891int
1892pp_remaining_character_count_for_line (pretty_printer *pp)
1893{
1894 return pp->maximum_length - pp_buffer (pp)->line_length;
1895}
1896
1897
1898/* Format a message into BUFFER a la printf. */
1899void
1900pp_printf (pretty_printer *pp, const char *msg, ...)
1901{
1902 va_list ap;
1903
1904 va_start (ap, msg);
1905 text_info text (msg, &ap, errno);
1906 pp_format (pp, text: &text);
1907 pp_output_formatted_text (pp);
1908 va_end (ap);
1909}
1910
1911
1912/* Output MESSAGE verbatim into BUFFER. */
1913void
1914pp_verbatim (pretty_printer *pp, const char *msg, ...)
1915{
1916 va_list ap;
1917
1918 va_start (ap, msg);
1919 text_info text (msg, &ap, errno);
1920 pp_format_verbatim (pp, text: &text);
1921 va_end (ap);
1922}
1923
1924
1925
1926/* Have PRETTY-PRINTER start a new line. */
1927void
1928pp_newline (pretty_printer *pp)
1929{
1930 obstack_1grow (pp_buffer (pp)->obstack, '\n');
1931 pp_needs_newline (pp) = false;
1932 pp_buffer (pp)->line_length = 0;
1933}
1934
1935/* Have PRETTY-PRINTER add a CHARACTER. */
1936void
1937pp_character (pretty_printer *pp, int c)
1938{
1939 if (pp_is_wrapping_line (pp)
1940 /* If printing UTF-8, don't wrap in the middle of a sequence. */
1941 && (((unsigned int) c) & 0xC0) != 0x80
1942 && pp_remaining_character_count_for_line (pp) <= 0)
1943 {
1944 pp_newline (pp);
1945 if (ISSPACE (c))
1946 return;
1947 }
1948 obstack_1grow (pp_buffer (pp)->obstack, c);
1949 ++pp_buffer (pp)->line_length;
1950}
1951
1952/* Append a STRING to the output area of PRETTY-PRINTER; the STRING may
1953 be line-wrapped if in appropriate mode. */
1954void
1955pp_string (pretty_printer *pp, const char *str)
1956{
1957 gcc_checking_assert (str);
1958 pp_maybe_wrap_text (pp, start: str, end: str + strlen (s: str));
1959}
1960
1961/* Append code point C to the output area of PRETTY-PRINTER, encoding it
1962 as UTF-8. */
1963
1964void
1965pp_unicode_character (pretty_printer *pp, unsigned c)
1966{
1967 static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
1968 static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
1969 size_t nbytes;
1970 uchar buf[6], *p = &buf[6];
1971
1972 nbytes = 1;
1973 if (c < 0x80)
1974 *--p = c;
1975 else
1976 {
1977 do
1978 {
1979 *--p = ((c & 0x3F) | 0x80);
1980 c >>= 6;
1981 nbytes++;
1982 }
1983 while (c >= 0x3F || (c & limits[nbytes-1]));
1984 *--p = (c | masks[nbytes-1]);
1985 }
1986
1987 pp_append_r (pp, start: (const char *)p, length: nbytes);
1988}
1989
1990/* Append the leading N characters of STRING to the output area of
1991 PRETTY-PRINTER, quoting in hexadecimal non-printable characters.
1992 Setting N = -1 is as if N were set to strlen (STRING). The STRING
1993 may be line-wrapped if in appropriate mode. */
1994static void
1995pp_quoted_string (pretty_printer *pp, const char *str, size_t n /* = -1 */)
1996{
1997 gcc_checking_assert (str);
1998
1999 const char *last = str;
2000 const char *ps;
2001
2002 /* Compute the length if not specified. */
2003 if (n == (size_t) -1)
2004 n = strlen (s: str);
2005
2006 for (ps = str; n; ++ps, --n)
2007 {
2008 if (ISPRINT (*ps))
2009 continue;
2010
2011 /* Don't escape a valid UTF-8 extended char. */
2012 const unsigned char *ups = (const unsigned char *) ps;
2013 if (*ups & 0x80)
2014 {
2015 unsigned int extended_char;
2016 const int valid_utf8_len = decode_utf8_char (ups, len: n, &extended_char);
2017 if (valid_utf8_len > 0)
2018 {
2019 ps += valid_utf8_len - 1;
2020 n -= valid_utf8_len - 1;
2021 continue;
2022 }
2023 }
2024
2025 if (last < ps)
2026 pp_maybe_wrap_text (pp, start: last, end: ps);
2027
2028 /* Append the hexadecimal value of the character. Allocate a buffer
2029 that's large enough for a 32-bit char plus the hex prefix. */
2030 char buf [11];
2031 int n = sprintf (s: buf, format: "\\x%02x", (unsigned char)*ps);
2032 pp_maybe_wrap_text (pp, start: buf, end: buf + n);
2033 last = ps + 1;
2034 }
2035
2036 pp_maybe_wrap_text (pp, start: last, end: ps);
2037}
2038
2039/* Maybe print out a whitespace if needed. */
2040
2041void
2042pp_maybe_space (pretty_printer *pp)
2043{
2044 if (pp->padding != pp_none)
2045 {
2046 pp_space (pp);
2047 pp->padding = pp_none;
2048 }
2049}
2050
2051// Add a newline to the pretty printer PP and flush formatted text.
2052
2053void
2054pp_newline_and_flush (pretty_printer *pp)
2055{
2056 pp_newline (pp);
2057 pp_flush (pp);
2058 pp_needs_newline (pp) = false;
2059}
2060
2061// Add a newline to the pretty printer PP, followed by indentation.
2062
2063void
2064pp_newline_and_indent (pretty_printer *pp, int n)
2065{
2066 pp_indentation (pp) += n;
2067 pp_newline (pp);
2068 pp_indent (pp);
2069 pp_needs_newline (pp) = false;
2070}
2071
2072// Add separator C, followed by a single whitespace.
2073
2074void
2075pp_separate_with (pretty_printer *pp, char c)
2076{
2077 pp_character (pp, c);
2078 pp_space (pp);
2079}
2080
2081/* Add a localized open quote, and if SHOW_COLOR is true, begin colorizing
2082 using the "quote" color. */
2083
2084void
2085pp_begin_quote (pretty_printer *pp, bool show_color)
2086{
2087 pp_string (pp, str: open_quote);
2088 pp_string (pp, str: colorize_start (show_color, name: "quote"));
2089}
2090
2091/* If SHOW_COLOR is true, stop colorizing.
2092 Add a localized close quote. */
2093
2094void
2095pp_end_quote (pretty_printer *pp, bool show_color)
2096{
2097 pp_string (pp, str: colorize_stop (show_color));
2098 pp_string (pp, str: close_quote);
2099}
2100
2101
2102/* The string starting at P has LEN (at least 1) bytes left; if they
2103 start with a valid UTF-8 sequence, return the length of that
2104 sequence and set *VALUE to the value of that sequence, and
2105 otherwise return 0 and set *VALUE to (unsigned int) -1. */
2106
2107static int
2108decode_utf8_char (const unsigned char *p, size_t len, unsigned int *value)
2109{
2110 unsigned int t = *p;
2111
2112 if (len == 0)
2113 abort ();
2114 if (t & 0x80)
2115 {
2116 size_t utf8_len = 0;
2117 unsigned int ch;
2118 size_t i;
2119 for (t = *p; t & 0x80; t <<= 1)
2120 utf8_len++;
2121
2122 if (utf8_len > len || utf8_len < 2 || utf8_len > 6)
2123 {
2124 *value = (unsigned int) -1;
2125 return 0;
2126 }
2127 ch = *p & ((1 << (7 - utf8_len)) - 1);
2128 for (i = 1; i < utf8_len; i++)
2129 {
2130 unsigned int u = p[i];
2131 if ((u & 0xC0) != 0x80)
2132 {
2133 *value = (unsigned int) -1;
2134 return 0;
2135 }
2136 ch = (ch << 6) | (u & 0x3F);
2137 }
2138 if ( (ch <= 0x7F && utf8_len > 1)
2139 || (ch <= 0x7FF && utf8_len > 2)
2140 || (ch <= 0xFFFF && utf8_len > 3)
2141 || (ch <= 0x1FFFFF && utf8_len > 4)
2142 || (ch <= 0x3FFFFFF && utf8_len > 5)
2143 || (ch >= 0xD800 && ch <= 0xDFFF))
2144 {
2145 *value = (unsigned int) -1;
2146 return 0;
2147 }
2148 *value = ch;
2149 return utf8_len;
2150 }
2151 else
2152 {
2153 *value = t;
2154 return 1;
2155 }
2156}
2157
2158/* Allocator for identifier_to_locale and corresponding function to
2159 free memory. */
2160
2161void *(*identifier_to_locale_alloc) (size_t) = xmalloc;
2162void (*identifier_to_locale_free) (void *) = free;
2163
2164/* Given IDENT, an identifier in the internal encoding, return a
2165 version of IDENT suitable for diagnostics in the locale character
2166 set: either IDENT itself, or a string, allocated using
2167 identifier_to_locale_alloc, converted to the locale character set
2168 and using escape sequences if not representable in the locale
2169 character set or containing control characters or invalid byte
2170 sequences. Existing backslashes in IDENT are not doubled, so the
2171 result may not uniquely specify the contents of an arbitrary byte
2172 sequence identifier. */
2173
2174const char *
2175identifier_to_locale (const char *ident)
2176{
2177 const unsigned char *uid = (const unsigned char *) ident;
2178 size_t idlen = strlen (s: ident);
2179 bool valid_printable_utf8 = true;
2180 bool all_ascii = true;
2181 size_t i;
2182
2183 for (i = 0; i < idlen;)
2184 {
2185 unsigned int c;
2186 size_t utf8_len = decode_utf8_char (p: &uid[i], len: idlen - i, value: &c);
2187 if (utf8_len == 0 || c <= 0x1F || (c >= 0x7F && c <= 0x9F))
2188 {
2189 valid_printable_utf8 = false;
2190 break;
2191 }
2192 if (utf8_len > 1)
2193 all_ascii = false;
2194 i += utf8_len;
2195 }
2196
2197 /* If IDENT contains invalid UTF-8 sequences (which may occur with
2198 attributes putting arbitrary byte sequences in identifiers), or
2199 control characters, we use octal escape sequences for all bytes
2200 outside printable ASCII. */
2201 if (!valid_printable_utf8)
2202 {
2203 char *ret = (char *) identifier_to_locale_alloc (4 * idlen + 1);
2204 char *p = ret;
2205 for (i = 0; i < idlen; i++)
2206 {
2207 if (uid[i] > 0x1F && uid[i] < 0x7F)
2208 *p++ = uid[i];
2209 else
2210 {
2211 sprintf (s: p, format: "\\%03o", uid[i]);
2212 p += 4;
2213 }
2214 }
2215 *p = 0;
2216 return ret;
2217 }
2218
2219 /* Otherwise, if it is valid printable ASCII, or printable UTF-8
2220 with the locale character set being UTF-8, IDENT is used. */
2221 if (all_ascii || locale_utf8)
2222 return ident;
2223
2224 /* Otherwise IDENT is converted to the locale character set if
2225 possible. */
2226#if defined ENABLE_NLS && defined HAVE_LANGINFO_CODESET && HAVE_ICONV
2227 if (locale_encoding != NULL)
2228 {
2229 iconv_t cd = iconv_open (tocode: locale_encoding, fromcode: "UTF-8");
2230 bool conversion_ok = true;
2231 char *ret = NULL;
2232 if (cd != (iconv_t) -1)
2233 {
2234 size_t ret_alloc = 4 * idlen + 1;
2235 for (;;)
2236 {
2237 /* Repeat the whole conversion process as needed with
2238 larger buffers so non-reversible transformations can
2239 always be detected. */
2240 ICONV_CONST char *inbuf = CONST_CAST (char *, ident);
2241 char *outbuf;
2242 size_t inbytesleft = idlen;
2243 size_t outbytesleft = ret_alloc - 1;
2244 size_t iconv_ret;
2245
2246 ret = (char *) identifier_to_locale_alloc (ret_alloc);
2247 outbuf = ret;
2248
2249 if (iconv (cd: cd, inbuf: 0, inbytesleft: 0, outbuf: 0, outbytesleft: 0) == (size_t) -1)
2250 {
2251 conversion_ok = false;
2252 break;
2253 }
2254
2255 iconv_ret = iconv (cd: cd, inbuf: &inbuf, inbytesleft: &inbytesleft,
2256 outbuf: &outbuf, outbytesleft: &outbytesleft);
2257 if (iconv_ret == (size_t) -1 || inbytesleft != 0)
2258 {
2259 if (errno == E2BIG)
2260 {
2261 ret_alloc *= 2;
2262 identifier_to_locale_free (ret);
2263 ret = NULL;
2264 continue;
2265 }
2266 else
2267 {
2268 conversion_ok = false;
2269 break;
2270 }
2271 }
2272 else if (iconv_ret != 0)
2273 {
2274 conversion_ok = false;
2275 break;
2276 }
2277 /* Return to initial shift state. */
2278 if (iconv (cd: cd, inbuf: 0, inbytesleft: 0, outbuf: &outbuf, outbytesleft: &outbytesleft) == (size_t) -1)
2279 {
2280 if (errno == E2BIG)
2281 {
2282 ret_alloc *= 2;
2283 identifier_to_locale_free (ret);
2284 ret = NULL;
2285 continue;
2286 }
2287 else
2288 {
2289 conversion_ok = false;
2290 break;
2291 }
2292 }
2293 *outbuf = 0;
2294 break;
2295 }
2296 iconv_close (cd: cd);
2297 if (conversion_ok)
2298 return ret;
2299 }
2300 }
2301#endif
2302
2303 /* Otherwise, convert non-ASCII characters in IDENT to UCNs. */
2304 {
2305 char *ret = (char *) identifier_to_locale_alloc (10 * idlen + 1);
2306 char *p = ret;
2307 for (i = 0; i < idlen;)
2308 {
2309 unsigned int c;
2310 size_t utf8_len = decode_utf8_char (p: &uid[i], len: idlen - i, value: &c);
2311 if (utf8_len == 1)
2312 *p++ = uid[i];
2313 else
2314 {
2315 sprintf (s: p, format: "\\U%08x", c);
2316 p += 10;
2317 }
2318 i += utf8_len;
2319 }
2320 *p = 0;
2321 return ret;
2322 }
2323}
2324
2325/* Support for encoding URLs.
2326 See egmontkob/Hyperlinks_in_Terminal_Emulators.md
2327 ( https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda ).
2328
2329 > A hyperlink is opened upon encountering an OSC 8 escape sequence with
2330 > the target URI. The syntax is
2331 >
2332 > OSC 8 ; params ; URI ST
2333 >
2334 > A hyperlink is closed with the same escape sequence, omitting the
2335 > parameters and the URI but keeping the separators:
2336 >
2337 > OSC 8 ; ; ST
2338 >
2339 > OSC (operating system command) is typically ESC ].
2340
2341 Use BEL instead of ST, as that is currently rendered better in some
2342 terminal emulators that don't support OSC 8, like konsole. */
2343
2344/* If URL-printing is enabled, write an "open URL" escape sequence to PP
2345 for the given URL. */
2346
2347void
2348pp_begin_url (pretty_printer *pp, const char *url)
2349{
2350 if (!url)
2351 {
2352 /* Handle null URL by skipping all output here,
2353 and in the next pp_end_url. */
2354 pp->m_skipping_null_url = true;
2355 return;
2356 }
2357 switch (pp->url_format)
2358 {
2359 case URL_FORMAT_NONE:
2360 break;
2361 case URL_FORMAT_ST:
2362 pp_string (pp, str: "\33]8;;");
2363 pp_string (pp, str: url);
2364 pp_string (pp, str: "\33\\");
2365 break;
2366 case URL_FORMAT_BEL:
2367 pp_string (pp, str: "\33]8;;");
2368 pp_string (pp, str: url);
2369 pp_string (pp, str: "\a");
2370 break;
2371 default:
2372 gcc_unreachable ();
2373 }
2374}
2375
2376/* Helper function for pp_end_url and pp_format, return the "close URL" escape
2377 sequence string. */
2378
2379static const char *
2380get_end_url_string (pretty_printer *pp)
2381{
2382 switch (pp->url_format)
2383 {
2384 case URL_FORMAT_NONE:
2385 return "";
2386 case URL_FORMAT_ST:
2387 return "\33]8;;\33\\";
2388 case URL_FORMAT_BEL:
2389 return "\33]8;;\a";
2390 default:
2391 gcc_unreachable ();
2392 }
2393}
2394
2395/* If URL-printing is enabled, write a "close URL" escape sequence to PP. */
2396
2397void
2398pp_end_url (pretty_printer *pp)
2399{
2400 if (pp->m_skipping_null_url)
2401 {
2402 /* We gracefully handle pp_begin_url (NULL) by omitting output for
2403 both begin and end. Here we handle the latter. */
2404 pp->m_skipping_null_url = false;
2405 return;
2406 }
2407 if (pp->url_format != URL_FORMAT_NONE)
2408 pp_string (pp, str: get_end_url_string (pp));
2409}
2410
2411#if CHECKING_P
2412
2413namespace selftest {
2414
2415/* Smoketest for pretty_printer. */
2416
2417static void
2418test_basic_printing ()
2419{
2420 pretty_printer pp;
2421 pp_string (pp: &pp, str: "hello");
2422 pp_space (&pp);
2423 pp_string (pp: &pp, str: "world");
2424
2425 ASSERT_STREQ ("hello world", pp_formatted_text (&pp));
2426}
2427
2428/* Helper function for testing pp_format.
2429 Verify that pp_format (FMT, ...) followed by pp_output_formatted_text
2430 prints EXPECTED, assuming that pp_show_color is SHOW_COLOR. */
2431
2432static void
2433assert_pp_format_va (const location &loc, const char *expected,
2434 bool show_color, const char *fmt, va_list *ap)
2435{
2436 pretty_printer pp;
2437 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
2438
2439 text_info ti (fmt, ap, 0, nullptr, &rich_loc);
2440
2441 pp_show_color (&pp) = show_color;
2442 pp_format (pp: &pp, text: &ti);
2443 pp_output_formatted_text (pp: &pp);
2444 ASSERT_STREQ_AT (loc, expected, pp_formatted_text (&pp));
2445}
2446
2447/* Verify that pp_format (FMT, ...) followed by pp_output_formatted_text
2448 prints EXPECTED, with show_color disabled. */
2449
2450static void
2451assert_pp_format (const location &loc, const char *expected,
2452 const char *fmt, ...)
2453{
2454 va_list ap;
2455
2456 va_start (ap, fmt);
2457 assert_pp_format_va (loc, expected, show_color: false, fmt, ap: &ap);
2458 va_end (ap);
2459}
2460
2461/* As above, but with colorization enabled. */
2462
2463static void
2464assert_pp_format_colored (const location &loc, const char *expected,
2465 const char *fmt, ...)
2466{
2467 /* The tests of colorization assume the default color scheme.
2468 If GCC_COLORS is set, then the colors have potentially been
2469 overridden; skip the test. */
2470 if (getenv (name: "GCC_COLORS"))
2471 return;
2472
2473 va_list ap;
2474
2475 va_start (ap, fmt);
2476 assert_pp_format_va (loc, expected, show_color: true, fmt, ap: &ap);
2477 va_end (ap);
2478}
2479
2480/* Helper function for calling testing pp_format,
2481 by calling assert_pp_format with various numbers of arguments.
2482 These exist mostly to avoid having to write SELFTEST_LOCATION
2483 throughout test_pp_format. */
2484
2485#define ASSERT_PP_FORMAT_1(EXPECTED, FMT, ARG1) \
2486 SELFTEST_BEGIN_STMT \
2487 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2488 (ARG1)); \
2489 SELFTEST_END_STMT
2490
2491#define ASSERT_PP_FORMAT_2(EXPECTED, FMT, ARG1, ARG2) \
2492 SELFTEST_BEGIN_STMT \
2493 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2494 (ARG1), (ARG2)); \
2495 SELFTEST_END_STMT
2496
2497#define ASSERT_PP_FORMAT_3(EXPECTED, FMT, ARG1, ARG2, ARG3) \
2498 SELFTEST_BEGIN_STMT \
2499 assert_pp_format ((SELFTEST_LOCATION), (EXPECTED), (FMT), \
2500 (ARG1), (ARG2), (ARG3)); \
2501 SELFTEST_END_STMT
2502
2503/* Verify that pp_format works, for various format codes. */
2504
2505static void
2506test_pp_format ()
2507{
2508 /* Avoid introducing locale-specific differences in the results
2509 by hardcoding open_quote and close_quote. */
2510 auto_fix_quotes fix_quotes;
2511
2512 /* Verify that plain text is passed through unchanged. */
2513 assert_pp_format (SELFTEST_LOCATION, expected: "unformatted", fmt: "unformatted");
2514
2515 /* Verify various individual format codes, in the order listed in the
2516 comment for pp_format above. For each code, we append a second
2517 argument with a known bit pattern (0x12345678), to ensure that we
2518 are consuming arguments correctly. */
2519 ASSERT_PP_FORMAT_2 ("-27 12345678", "%d %x", -27, 0x12345678);
2520 ASSERT_PP_FORMAT_2 ("-5 12345678", "%i %x", -5, 0x12345678);
2521 ASSERT_PP_FORMAT_2 ("10 12345678", "%u %x", 10, 0x12345678);
2522 ASSERT_PP_FORMAT_2 ("17 12345678", "%o %x", 15, 0x12345678);
2523 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%x %x", 0xcafebabe, 0x12345678);
2524 ASSERT_PP_FORMAT_2 ("-27 12345678", "%ld %x", (long)-27, 0x12345678);
2525 ASSERT_PP_FORMAT_2 ("-5 12345678", "%li %x", (long)-5, 0x12345678);
2526 ASSERT_PP_FORMAT_2 ("10 12345678", "%lu %x", (long)10, 0x12345678);
2527 ASSERT_PP_FORMAT_2 ("17 12345678", "%lo %x", (long)15, 0x12345678);
2528 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%lx %x", (long)0xcafebabe,
2529 0x12345678);
2530 ASSERT_PP_FORMAT_2 ("-27 12345678", "%lld %x", (long long)-27, 0x12345678);
2531 ASSERT_PP_FORMAT_2 ("-5 12345678", "%lli %x", (long long)-5, 0x12345678);
2532 ASSERT_PP_FORMAT_2 ("10 12345678", "%llu %x", (long long)10, 0x12345678);
2533 ASSERT_PP_FORMAT_2 ("17 12345678", "%llo %x", (long long)15, 0x12345678);
2534 ASSERT_PP_FORMAT_2 ("cafebabe 12345678", "%llx %x", (long long)0xcafebabe,
2535 0x12345678);
2536 ASSERT_PP_FORMAT_2 ("-27 12345678", "%wd %x", (HOST_WIDE_INT)-27, 0x12345678);
2537 ASSERT_PP_FORMAT_2 ("-5 12345678", "%wi %x", (HOST_WIDE_INT)-5, 0x12345678);
2538 ASSERT_PP_FORMAT_2 ("10 12345678", "%wu %x", (unsigned HOST_WIDE_INT)10,
2539 0x12345678);
2540 ASSERT_PP_FORMAT_2 ("17 12345678", "%wo %x", (HOST_WIDE_INT)15, 0x12345678);
2541 ASSERT_PP_FORMAT_2 ("0xcafebabe 12345678", "%wx %x", (HOST_WIDE_INT)0xcafebabe,
2542 0x12345678);
2543 ASSERT_PP_FORMAT_2 ("1.000000 12345678", "%f %x", 1.0, 0x12345678);
2544 ASSERT_PP_FORMAT_2 ("A 12345678", "%c %x", 'A', 0x12345678);
2545 ASSERT_PP_FORMAT_2 ("hello world 12345678", "%s %x", "hello world",
2546 0x12345678);
2547
2548 /* Not nul-terminated. */
2549 char arr[5] = { '1', '2', '3', '4', '5' };
2550 ASSERT_PP_FORMAT_3 ("123 12345678", "%.*s %x", 3, arr, 0x12345678);
2551 ASSERT_PP_FORMAT_3 ("1234 12345678", "%.*s %x", -1, "1234", 0x12345678);
2552 ASSERT_PP_FORMAT_3 ("12345 12345678", "%.*s %x", 7, "12345", 0x12345678);
2553
2554 /* We can't test for %p; the pointer is printed in an implementation-defined
2555 manner. */
2556 ASSERT_PP_FORMAT_2 ("normal colored normal 12345678",
2557 "normal %rcolored%R normal %x",
2558 "error", 0x12345678);
2559 assert_pp_format_colored
2560 (SELFTEST_LOCATION,
2561 expected: "normal \33[01;31m\33[Kcolored\33[m\33[K normal 12345678",
2562 fmt: "normal %rcolored%R normal %x", "error", 0x12345678);
2563 /* TODO:
2564 %m: strerror(text->err_no) - does not consume a value from args_ptr. */
2565 ASSERT_PP_FORMAT_1 ("% 12345678", "%% %x", 0x12345678);
2566 ASSERT_PP_FORMAT_1 ("` 12345678", "%< %x", 0x12345678);
2567 ASSERT_PP_FORMAT_1 ("' 12345678", "%> %x", 0x12345678);
2568 ASSERT_PP_FORMAT_1 ("' 12345678", "%' %x", 0x12345678);
2569 ASSERT_PP_FORMAT_3 ("abc 12345678", "%.*s %x", 3, "abcdef", 0x12345678);
2570 ASSERT_PP_FORMAT_2 ("abc 12345678", "%.3s %x", "abcdef", 0x12345678);
2571
2572 /* Verify flag 'q'. */
2573 ASSERT_PP_FORMAT_2 ("`foo' 12345678", "%qs %x", "foo", 0x12345678);
2574 assert_pp_format_colored (SELFTEST_LOCATION,
2575 expected: "`\33[01m\33[Kfoo\33[m\33[K' 12345678", fmt: "%qs %x",
2576 "foo", 0x12345678);
2577 /* Verify "%@". */
2578 {
2579 diagnostic_event_id_t first (2);
2580 diagnostic_event_id_t second (7);
2581
2582 ASSERT_PP_FORMAT_2 ("first `free' at (3); second `free' at (8)",
2583 "first %<free%> at %@; second %<free%> at %@",
2584 &first, &second);
2585 assert_pp_format_colored
2586 (SELFTEST_LOCATION,
2587 expected: "first `free' at (3);"
2588 " second `free' at (8)",
2589 fmt: "first %<free%> at %@; second %<free%> at %@",
2590 &first, &second);
2591 }
2592
2593 /* Verify %Z. */
2594 int v[] = { 1, 2, 3 };
2595 ASSERT_PP_FORMAT_3 ("1, 2, 3 12345678", "%Z %x", v, 3, 0x12345678);
2596
2597 int v2[] = { 0 };
2598 ASSERT_PP_FORMAT_3 ("0 12345678", "%Z %x", v2, 1, 0x12345678);
2599
2600 /* Verify that combinations work, along with unformatted text. */
2601 assert_pp_format (SELFTEST_LOCATION,
2602 expected: "the quick brown fox jumps over the lazy dog",
2603 fmt: "the %s %s %s jumps over the %s %s",
2604 "quick", "brown", "fox", "lazy", "dog");
2605 assert_pp_format (SELFTEST_LOCATION, expected: "item 3 of 7", fmt: "item %i of %i", 3, 7);
2606 assert_pp_format (SELFTEST_LOCATION, expected: "problem with `bar' at line 10",
2607 fmt: "problem with %qs at line %i", "bar", 10);
2608}
2609
2610/* A subclass of pretty_printer for use by test_prefixes_and_wrapping. */
2611
2612class test_pretty_printer : public pretty_printer
2613{
2614 public:
2615 test_pretty_printer (enum diagnostic_prefixing_rule_t rule,
2616 int max_line_length)
2617 {
2618 pp_set_prefix (pp: this, prefix: xstrdup ("PREFIX: "));
2619 wrapping.rule = rule;
2620 pp_set_line_maximum_length (pp: this, length: max_line_length);
2621 }
2622};
2623
2624/* Verify that the various values of enum diagnostic_prefixing_rule_t work
2625 as expected, with and without line wrapping. */
2626
2627static void
2628test_prefixes_and_wrapping ()
2629{
2630 /* Tests of the various prefixing rules, without wrapping.
2631 Newlines embedded in pp_string don't affect it; we have to
2632 explicitly call pp_newline. */
2633 {
2634 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_ONCE, 0);
2635 pp_string (pp: &pp, str: "the quick brown fox");
2636 pp_newline (pp: &pp);
2637 pp_string (pp: &pp, str: "jumps over the lazy dog");
2638 pp_newline (pp: &pp);
2639 ASSERT_STREQ (pp_formatted_text (&pp),
2640 "PREFIX: the quick brown fox\n"
2641 " jumps over the lazy dog\n");
2642 }
2643 {
2644 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_NEVER, 0);
2645 pp_string (pp: &pp, str: "the quick brown fox");
2646 pp_newline (pp: &pp);
2647 pp_string (pp: &pp, str: "jumps over the lazy dog");
2648 pp_newline (pp: &pp);
2649 ASSERT_STREQ (pp_formatted_text (&pp),
2650 "the quick brown fox\n"
2651 "jumps over the lazy dog\n");
2652 }
2653 {
2654 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE, 0);
2655 pp_string (pp: &pp, str: "the quick brown fox");
2656 pp_newline (pp: &pp);
2657 pp_string (pp: &pp, str: "jumps over the lazy dog");
2658 pp_newline (pp: &pp);
2659 ASSERT_STREQ (pp_formatted_text (&pp),
2660 "PREFIX: the quick brown fox\n"
2661 "PREFIX: jumps over the lazy dog\n");
2662 }
2663
2664 /* Tests of the various prefixing rules, with wrapping. */
2665 {
2666 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_ONCE, 20);
2667 pp_string (pp: &pp, str: "the quick brown fox jumps over the lazy dog");
2668 pp_newline (pp: &pp);
2669 pp_string (pp: &pp, str: "able was I ere I saw elba");
2670 pp_newline (pp: &pp);
2671 ASSERT_STREQ (pp_formatted_text (&pp),
2672 "PREFIX: the quick \n"
2673 " brown fox jumps \n"
2674 " over the lazy \n"
2675 " dog\n"
2676 " able was I ere I \n"
2677 " saw elba\n");
2678 }
2679 {
2680 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_NEVER, 20);
2681 pp_string (pp: &pp, str: "the quick brown fox jumps over the lazy dog");
2682 pp_newline (pp: &pp);
2683 pp_string (pp: &pp, str: "able was I ere I saw elba");
2684 pp_newline (pp: &pp);
2685 ASSERT_STREQ (pp_formatted_text (&pp),
2686 "the quick brown fox \n"
2687 "jumps over the lazy \n"
2688 "dog\n"
2689 "able was I ere I \n"
2690 "saw elba\n");
2691 }
2692 {
2693 test_pretty_printer pp (DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE, 20);
2694 pp_string (pp: &pp, str: "the quick brown fox jumps over the lazy dog");
2695 pp_newline (pp: &pp);
2696 pp_string (pp: &pp, str: "able was I ere I saw elba");
2697 pp_newline (pp: &pp);
2698 ASSERT_STREQ (pp_formatted_text (&pp),
2699 "PREFIX: the quick brown fox jumps over the lazy dog\n"
2700 "PREFIX: able was I ere I saw elba\n");
2701 }
2702
2703}
2704
2705/* Verify that URL-printing works as expected. */
2706
2707void
2708test_urls ()
2709{
2710 {
2711 pretty_printer pp;
2712 pp.url_format = URL_FORMAT_NONE;
2713 pp_begin_url (pp: &pp, url: "http://example.com");
2714 pp_string (pp: &pp, str: "This is a link");
2715 pp_end_url (pp: &pp);
2716 ASSERT_STREQ ("This is a link",
2717 pp_formatted_text (&pp));
2718 }
2719
2720 {
2721 pretty_printer pp;
2722 pp.url_format = URL_FORMAT_ST;
2723 pp_begin_url (pp: &pp, url: "http://example.com");
2724 pp_string (pp: &pp, str: "This is a link");
2725 pp_end_url (pp: &pp);
2726 ASSERT_STREQ ("\33]8;;http://example.com\33\\This is a link\33]8;;\33\\",
2727 pp_formatted_text (&pp));
2728 }
2729
2730 {
2731 pretty_printer pp;
2732 pp.url_format = URL_FORMAT_BEL;
2733 pp_begin_url (pp: &pp, url: "http://example.com");
2734 pp_string (pp: &pp, str: "This is a link");
2735 pp_end_url (pp: &pp);
2736 ASSERT_STREQ ("\33]8;;http://example.com\aThis is a link\33]8;;\a",
2737 pp_formatted_text (&pp));
2738 }
2739}
2740
2741/* Verify that we gracefully reject null URLs. */
2742
2743void
2744test_null_urls ()
2745{
2746 {
2747 pretty_printer pp;
2748 pp.url_format = URL_FORMAT_NONE;
2749 pp_begin_url (pp: &pp, url: nullptr);
2750 pp_string (pp: &pp, str: "This isn't a link");
2751 pp_end_url (pp: &pp);
2752 ASSERT_STREQ ("This isn't a link",
2753 pp_formatted_text (&pp));
2754 }
2755
2756 {
2757 pretty_printer pp;
2758 pp.url_format = URL_FORMAT_ST;
2759 pp_begin_url (pp: &pp, url: nullptr);
2760 pp_string (pp: &pp, str: "This isn't a link");
2761 pp_end_url (pp: &pp);
2762 ASSERT_STREQ ("This isn't a link",
2763 pp_formatted_text (&pp));
2764 }
2765
2766 {
2767 pretty_printer pp;
2768 pp.url_format = URL_FORMAT_BEL;
2769 pp_begin_url (pp: &pp, url: nullptr);
2770 pp_string (pp: &pp, str: "This isn't a link");
2771 pp_end_url (pp: &pp);
2772 ASSERT_STREQ ("This isn't a link",
2773 pp_formatted_text (&pp));
2774 }
2775}
2776
2777/* Verify that URLification works as expected. */
2778
2779static void
2780pp_printf_with_urlifier (pretty_printer *pp,
2781 const urlifier *urlifier,
2782 const char *msg, ...)
2783{
2784 va_list ap;
2785
2786 va_start (ap, msg);
2787 text_info text (msg, &ap, errno);
2788 pp_format (pp, text: &text, urlifier);
2789 pp_output_formatted_text (pp);
2790 va_end (ap);
2791}
2792
2793
2794void
2795test_urlification ()
2796{
2797 class test_urlifier : public urlifier
2798 {
2799 public:
2800 char *
2801 get_url_for_quoted_text (const char *p, size_t sz) const final override
2802 {
2803 if (!strncmp (s1: p, s2: "-foption", n: sz))
2804 return xstrdup ("http://example.com");
2805 return nullptr;
2806 }
2807 };
2808
2809 auto_fix_quotes fix_quotes;
2810 const test_urlifier urlifier;
2811
2812 /* Uses of "%<" and "%>". */
2813 {
2814 {
2815 pretty_printer pp;
2816 pp.url_format = URL_FORMAT_NONE;
2817 pp_printf_with_urlifier (pp: &pp, urlifier: &urlifier,
2818 msg: "foo %<-foption%> %<unrecognized%> bar");
2819 ASSERT_STREQ ("foo `-foption' `unrecognized' bar",
2820 pp_formatted_text (&pp));
2821 }
2822 {
2823 pretty_printer pp;
2824 pp.url_format = URL_FORMAT_ST;
2825 pp_printf_with_urlifier (pp: &pp, urlifier: &urlifier,
2826 msg: "foo %<-foption%> %<unrecognized%> bar");
2827 ASSERT_STREQ
2828 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
2829 " `unrecognized' bar",
2830 pp_formatted_text (&pp));
2831 }
2832 {
2833 pretty_printer pp;
2834 pp.url_format = URL_FORMAT_BEL;
2835 pp_printf_with_urlifier (pp: &pp, urlifier: &urlifier,
2836 msg: "foo %<-foption%> %<unrecognized%> bar");
2837 ASSERT_STREQ
2838 ("foo `\33]8;;http://example.com\a-foption\33]8;;\a'"
2839 " `unrecognized' bar",
2840 pp_formatted_text (&pp));
2841 }
2842 }
2843
2844 /* Use of "%qs". */
2845 {
2846 pretty_printer pp;
2847 pp.url_format = URL_FORMAT_ST;
2848 pp_printf_with_urlifier (pp: &pp, urlifier: &urlifier,
2849 msg: "foo %qs %qs bar",
2850 "-foption", "unrecognized");
2851 ASSERT_STREQ
2852 ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
2853 " `unrecognized' bar",
2854 pp_formatted_text (&pp));
2855 }
2856
2857 /* Mixed usage of %< and %s, where the quoted string is built between
2858 a mixture of phase 1 and phase 2. */
2859 {
2860 pretty_printer pp;
2861 pp.url_format = URL_FORMAT_ST;
2862 pp_printf_with_urlifier (pp: &pp, urlifier: &urlifier,
2863 msg: "foo %<-f%s%> bar",
2864 "option");
2865 /* We don't support this, but make sure we don't crash. */
2866 ASSERT_STREQ
2867 ("foo `-foption' bar",
2868 pp_formatted_text (&pp));
2869 }
2870}
2871
2872/* Test multibyte awareness. */
2873static void test_utf8 ()
2874{
2875
2876 /* Check that pp_quoted_string leaves valid UTF-8 alone. */
2877 {
2878 pretty_printer pp;
2879 const char *s = "\xf0\x9f\x98\x82";
2880 pp_quoted_string (pp: &pp, str: s);
2881 ASSERT_STREQ (pp_formatted_text (&pp), s);
2882 }
2883
2884 /* Check that pp_quoted_string escapes non-UTF-8 nonprintable bytes. */
2885 {
2886 pretty_printer pp;
2887 pp_quoted_string (pp: &pp, str: "\xf0!\x9f\x98\x82");
2888 ASSERT_STREQ (pp_formatted_text (&pp),
2889 "\\xf0!\\x9f\\x98\\x82");
2890 }
2891
2892 /* Check that pp_character will line-wrap at the beginning of a UTF-8
2893 sequence, but not in the middle. */
2894 {
2895 pretty_printer pp (3);
2896 const char s[] = "---\xf0\x9f\x98\x82";
2897 for (int i = 0; i != sizeof (s) - 1; ++i)
2898 pp_character (pp: &pp, c: s[i]);
2899 pp_newline (pp: &pp);
2900 for (int i = 1; i != sizeof (s) - 1; ++i)
2901 pp_character (pp: &pp, c: s[i]);
2902 pp_character (pp: &pp, c: '-');
2903 ASSERT_STREQ (pp_formatted_text (&pp),
2904 "---\n"
2905 "\xf0\x9f\x98\x82\n"
2906 "--\xf0\x9f\x98\x82\n"
2907 "-");
2908 }
2909
2910}
2911
2912/* Run all of the selftests within this file. */
2913
2914void
2915pretty_print_cc_tests ()
2916{
2917 test_basic_printing ();
2918 test_pp_format ();
2919 test_prefixes_and_wrapping ();
2920 test_urls ();
2921 test_null_urls ();
2922 test_urlification ();
2923 test_utf8 ();
2924}
2925
2926} // namespace selftest
2927
2928#endif /* CHECKING_P */
2929

source code of gcc/pretty-print.cc