Tutorial part 8: message buffers

In previous examples, we finished a diagnostic with a call to diagnostic_finish(), which takes a format string and arguments to determine the text message of the diagnostic.

Sometimes this approach is inconvenient, such as where you might want to build up a message programatically from a series of components. Additionally, you might have existing code that uses fprintf, whereas diagnostic_finish() has its own formatting conventions which are not the same as printf.

For this reason libgdiagnostics (from LIBGDIAGNOSTICS_ABI_3 onwards) supports diagnostic_message_buffer, which can be used to accumulate a message before using it.

You create a diagnostic_message_buffer using diagnostic_message_buffer_new().

There are various API entrypoints for accumulating text into the buffer.

For example:

  diagnostic *d = diagnostic_begin (diag_mgr,
				    DIAGNOSTIC_LEVEL_ERROR);

  diagnostic_message_buffer *msg_buf = diagnostic_message_buffer_new ();

  /* Add a null-terminated string.  */
  diagnostic_message_buffer_append_str (msg_buf, "this is a string; ");

  /* Add a length-specified string.  */
  diagnostic_message_buffer_append_text (msg_buf, "foobar", 3);

  /* "printf"-formatting.  */
  diagnostic_message_buffer_append_printf (msg_buf,
					   "; int: %i str: %s; ",
					   42, "mostly harmless");

  /* Adding a URL.  */
  diagnostic_message_buffer_begin_url (msg_buf, "https://example.com/");
  diagnostic_message_buffer_append_str (msg_buf, "this is a link");  
  diagnostic_message_buffer_end_url (msg_buf);

  diagnostic_message_buffer_append_str (msg_buf, " ");  

  /* Add quoted text.  */
  diagnostic_message_buffer_begin_quote (msg_buf);
  diagnostic_message_buffer_append_str (msg_buf, "this is quoted");  
  diagnostic_message_buffer_end_quote (msg_buf);
  
  diagnostic_message_buffer_append_str (msg_buf, " ");  

  /* Add colorized text.  */
  diagnostic_message_buffer_begin_color (msg_buf, "highlight-a");
  diagnostic_message_buffer_append_str (msg_buf, "highlight A");  
  diagnostic_message_buffer_end_color (msg_buf);

  diagnostic_message_buffer_append_str (msg_buf, " ");
  
  diagnostic_message_buffer_begin_color (msg_buf, "highlight-b");
  diagnostic_message_buffer_append_str (msg_buf, "highlight B");  
  diagnostic_message_buffer_end_color (msg_buf);
  
  diagnostic_message_buffer_append_str (msg_buf, " ");

  /* Add an event ID.  This will be printed as "(1)".  */
  diagnostic_message_buffer_append_event_id (msg_buf, event_id);
  
  /* Add an ASCII char.  */
  diagnostic_message_buffer_append_byte (msg_buf, '.');

  diagnostic_finish_via_msg_buf (d, msg_buf);

Running this will produce this text output:

.. code-block:: console

$ ./test-message-buffer.c.exe ./test-message-buffer.c.exe: error: this is a string; foo; int: 42 str: mostly harmless; this is a link ‘this is quoted’ highlight A highlight B (1).

where in a suitably-capable terminal if a text sink is directly connected to a tty:

  • the this is a link will be a clickable hyperlink (and the URL will be captured in SARIF output).

  • the quoted text will be in bold

  • the highlight A and highlight B text will be colorized

  • the event ID will be colorized (and will be a URL in SARIF output if used within a diagnostic_execution_path).

Moving on

That’s the end of the tutorial. For more information on libgdiagnostics, see the topic guide.