1 /*
2  * This file is part of libmodulemd
3  * Copyright (C) 2017-2020 Stephen Gallagher
4  *
5  * Fedora-License-Identifier: MIT
6  * SPDX-2.0-License-Identifier: MIT
7  * SPDX-3.0-License-Identifier: MIT
8  *
9  * This program is free software.
10  * For more information on the license, see COPYING.
11  * For more information on free software, see <https://www.gnu.org/philosophy/free-sw.en.html>.
12  */
13 
14 #pragma once
15 
16 #include <glib.h>
17 #include <yaml.h>
18 
19 #include "modulemd-errors.h"
20 #include "modulemd-service-level.h"
21 #include "modulemd-subdocument-info.h"
22 #include "private/modulemd-util.h"
23 
24 G_BEGIN_DECLS
25 
26 
27 /**
28  * SECTION: modulemd-yaml
29  * @title: YAML Manipulation Tools
30  * @stability: private
31  * @short_description: Provides private YAML utilities for internal use.
32  */
33 
34 
35 /**
36  * ModulemdYamlDocumentTypeEnum:
37  * @MODULEMD_YAML_DOC_UNKNOWN: Represents an unknown YAML document type.
38  * @MODULEMD_YAML_DOC_MODULESTREAM: Represents a `modulemd` (see
39  * #ModulemdModuleStream) YAML document type.
40  * @MODULEMD_YAML_DOC_DEFAULTS: Represents a `modulemd-defaults` (see
41  * #ModulemdDefaultsV1) YAML document type.
42  * @MODULEMD_YAML_DOC_TRANSLATIONS: Represents a `modulemd-translations` (see
43  * #ModulemdTranslation) YAML document type.
44  * @MODULEMD_YAML_DOC_PACKAGER: Represents a `modulemd-packager` document.
45  * V2 is a subset of #ModulemdModuleStreamV2 containing only the attributes that a
46  * package maintainer should modify. V3 (see #ModulemdPackagerV3) is a new YAML
47  * document type. Since: 2.9
48  * @MODULEMD_YAML_DOC_OBSOLETES: Represents a `modulemd-obsoletes` document (see
49  * #ModulemdObsoletes) YAML document type. Since: 2.10
50  *
51  * Since: 2.0
52  */
53 typedef enum
54 {
55   MODULEMD_YAML_DOC_UNKNOWN = 0,
56   MODULEMD_YAML_DOC_MODULESTREAM,
57   MODULEMD_YAML_DOC_DEFAULTS,
58   MODULEMD_YAML_DOC_TRANSLATIONS,
59   MODULEMD_YAML_DOC_PACKAGER,
60   MODULEMD_YAML_DOC_OBSOLETES
61 } ModulemdYamlDocumentTypeEnum;
62 
63 /**
64  * modulemd_yaml_string:
65  * @str: A pointer to a block of memory containing YAML.
66  * @len: The number of bytes currently in use in @str.
67  *
68  * #modulemd_yaml_string is an internal representation of an arbitrary length
69  * YAML string.
70  *
71  * Since: 2.0
72  */
73 typedef struct _modulemd_yaml_string
74 {
75   char *str;
76   size_t len;
77 } modulemd_yaml_string;
78 
79 /**
80  * write_yaml_string:
81  * @data: (inout): A void pointer to a #modulemd_yaml_string object.
82  * @buffer: (in): YAML text to append to @data.
83  * @size: (in): The number of bytes from @buffer to append to @data.
84  *
85  * Additionally memory for @data is automatically allocated if necessary.
86  *
87  * Since: 2.0
88  */
89 int
90 write_yaml_string (void *data, unsigned char *buffer, size_t size);
91 
92 /**
93  * modulemd_yaml_string_free:
94  * @yaml_string: (inout): A pointer to a #modulemd_yaml_string to be freed.
95  *
96  * Since: 2.0
97  */
98 void
99 modulemd_yaml_string_free (modulemd_yaml_string *yaml_string);
100 
101 G_DEFINE_AUTOPTR_CLEANUP_FUNC (FILE, fclose);
102 
103 G_DEFINE_AUTOPTR_CLEANUP_FUNC (modulemd_yaml_string,
104                                modulemd_yaml_string_free);
105 
106 G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (yaml_event_t, yaml_event_delete);
107 
108 G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (yaml_parser_t, yaml_parser_delete);
109 
110 G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (yaml_emitter_t, yaml_emitter_delete);
111 
112 /**
113  * mmd_yaml_get_event_name:
114  * @type: (in): A libyaml event type.
115  *
116  * Returns: The string representation for @type.
117  *
118  * Since: 2.0
119  */
120 const gchar *
121 mmd_yaml_get_event_name (yaml_event_type_t type);
122 
123 /**
124  * MMD_INIT_YAML_PARSER:
125  * @_parser: (out): A variable name to use for the new parser object.
126  *
127  * This convenience macro allocates and initializes a new libyaml parser object
128  * named @_parser.
129  *
130  * Since: 2.0
131  */
132 #define MMD_INIT_YAML_PARSER(_parser)                                         \
133   g_auto (yaml_parser_t) _parser;                                             \
134   yaml_parser_initialize (&_parser)
135 
136 /**
137  * MMD_INIT_YAML_EMITTER:
138  * @_emitter: (out): A variable name to use for the new emitter object.
139  *
140  * This convenience macro allocates and initializes a new libyaml emitter
141  * object named @_emitter.
142  *
143  * Since: 2.0
144  */
145 #define MMD_INIT_YAML_EMITTER(_emitter)                                       \
146   g_auto (yaml_emitter_t) _emitter;                                           \
147   yaml_emitter_initialize (&_emitter)
148 
149 /**
150  * MMD_INIT_YAML_EVENT:
151  * @_event: (out): A variable name to use for the new event object.
152  *
153  * This convenience macro allocates and initializes a new libyaml event object
154  * named @_event.
155  *
156  * Since: 2.0
157  */
158 #define MMD_INIT_YAML_EVENT(_event)                                           \
159   g_auto (yaml_event_t) _event;                                               \
160   memset (&(_event), 0, sizeof (yaml_event_t))
161 
162 /**
163  * MMD_INIT_YAML_STRING:
164  * @_emitter: (inout): A libyaml emitter object.
165  * @_string: (out): A variable name to use for the new yaml string object.
166  *
167  * This convenience macro allocates and initializes a new yaml string object
168  * named @_string and associates it as the output target for the libyaml
169  * emitter object @_emitter.
170  *
171  * Since: 2.0
172  */
173 #define MMD_INIT_YAML_STRING(_emitter, _string)                               \
174   g_autoptr (modulemd_yaml_string) _string =                                  \
175     g_malloc0_n (1, sizeof (modulemd_yaml_string));                           \
176   yaml_emitter_set_output (_emitter, write_yaml_string, (void *)_string)
177 
178 /**
179  * MMD_REINIT_YAML_STRING:
180  * @_emitter: (inout): A libyaml emitter object to reinitialize.
181  * @_string: (inout): A variable name to reinitialize with a new yaml string
182  * object.
183  *
184  * This convenience macro deletes then initializes a new libyaml emitter named
185  * @_emitter, then deletes, reallocates, and initializes a new yaml string
186  * object named @_string and associates it as the output target for @_emitter.
187  *
188  * Since: 2.0
189  */
190 #define MMD_REINIT_YAML_STRING(_emitter, _string)                             \
191   yaml_emitter_delete (_emitter);                                             \
192   yaml_emitter_initialize (_emitter);                                         \
193   g_clear_pointer (&_string, modulemd_yaml_string_free);                      \
194   _string = g_malloc0_n (1, sizeof (modulemd_yaml_string));                   \
195   yaml_emitter_set_output (_emitter, write_yaml_string, (void *)_string)
196 
197 /**
198  * YAML_PARSER_PARSE_WITH_EXIT_FULL:
199  * @_parser: (inout): A libyaml parser object positioned at the beginning of an
200  * event.
201  * @_returnval: (in): The value to return in case of a parsing error.
202  * @_event: (out): Returns the libyaml event that was parsed.
203  * @_error: (out): A #GError that will return the reason for a parsing or
204  * validation error.
205  *
206  * DIRECT USE OF THIS MACRO SHOULD BE AVOIDED. This is the internal
207  * implementation for %YAML_PARSER_PARSE_WITH_EXIT_BOOL,
208  * %YAML_PARSER_PARSE_WITH_EXIT_INT, and %YAML_PARSER_PARSE_WITH_EXIT which
209  * should be used instead.
210  *
211  * Returns: Continues on if parsing of the event was successful. Returns
212  * @_returnval if a parse error occurred and sets @_error appropriately.
213  *
214  * Since: 2.0
215  */
216 #define YAML_PARSER_PARSE_WITH_EXIT_FULL(_parser, _returnval, _event, _error) \
217   do                                                                          \
218     {                                                                         \
219       if (!yaml_parser_parse (_parser, _event))                               \
220         {                                                                     \
221           g_debug ("Parser error");                                           \
222           g_set_error_literal (_error,                                        \
223                                MODULEMD_YAML_ERROR,                           \
224                                MMD_YAML_ERROR_UNPARSEABLE,                    \
225                                "Parser error");                               \
226           return _returnval;                                                  \
227         }                                                                     \
228       if ((_event)->type == YAML_SCALAR_EVENT)                                \
229         g_debug ("Parser event: %s: %s",                                      \
230                  mmd_yaml_get_event_name ((_event)->type),                    \
231                  (const gchar *)event.data.scalar.value);                     \
232       else                                                                    \
233         {                                                                     \
234           g_debug ("Parser event: %s",                                        \
235                    mmd_yaml_get_event_name ((_event)->type));                 \
236         }                                                                     \
237     }                                                                         \
238   while (0)
239 
240 /**
241  * YAML_PARSER_PARSE_WITH_EXIT_BOOL:
242  * @_parser: (inout): A libyaml parser object positioned at the beginning of an
243  * event.
244  * @_event: (out): Returns the libyaml event that was parsed.
245  * @_error: (out): A #GError that will return the reason for a parsing or
246  * validation error.
247  *
248  * Returns: Continues on if parsing of the event was successful. Returns
249  * FALSE if a parse error occurred and sets @_error appropriately.
250  *
251  * Since: 2.0
252  */
253 #define YAML_PARSER_PARSE_WITH_EXIT_BOOL(_parser, _event, _error)             \
254   YAML_PARSER_PARSE_WITH_EXIT_FULL (_parser, FALSE, _event, _error)
255 
256 /**
257  * YAML_PARSER_PARSE_WITH_EXIT_INT:
258  * @_parser: (inout): A libyaml parser object positioned at the beginning of an
259  * event.
260  * @_event: (out): Returns the libyaml event that was parsed.
261  * @_error: (out): A #GError that will return the reason for a parsing or
262  * validation error.
263  *
264  * Returns: Continues on if parsing of the event was successful. Returns
265  * 0 if a parse error occurred and sets @_error appropriately.
266  *
267  * Since: 2.0
268  */
269 #define YAML_PARSER_PARSE_WITH_EXIT_INT(_parser, _event, _error)              \
270   YAML_PARSER_PARSE_WITH_EXIT_FULL (_parser, 0, _event, _error)
271 
272 /**
273  * YAML_PARSER_PARSE_WITH_EXIT:
274  * @_parser: (inout): A libyaml parser object positioned at the beginning of an
275  * event.
276  * @_event: (out): Returns the libyaml event that was parsed.
277  * @_error: (out): A #GError that will return the reason for a parsing or
278  * validation error.
279  *
280  * Returns: Continues on if parsing of the event was successful. Returns
281  * NULL if a parse error occurred and sets @_error appropriately.
282  *
283  * Since: 2.0
284  */
285 #define YAML_PARSER_PARSE_WITH_EXIT(_parser, _event, _error)                  \
286   YAML_PARSER_PARSE_WITH_EXIT_FULL (_parser, NULL, _event, _error)
287 
288 
289 /**
290  * MMD_EMIT_WITH_EXIT_FULL:
291  * @_emitter: (inout): A libyaml emitter object positioned where @_event
292  * belongs in the YAML document.
293  * @_returnval: (in): The value to return in case of an output error.
294  * @_event: (in): The libyaml event to be emitted.
295  * @_error: (out): A #GError that will return the reason for an output error.
296  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
297  * @_error in case of failure.
298  *
299  * DIRECT USE OF THIS MACRO SHOULD BE AVOIDED. This is the internal
300  * implementation for %MMD_EMIT_WITH_EXIT and %MMD_EMIT_WITH_EXIT_PTR which
301  * should be used instead.
302  *
303  * Returns: Continues on if emitting of the event was successful. Returns
304  * @_returnval if an output error occurred and sets @_error appropriately.
305  *
306  * Since: 2.0
307  */
308 #define MMD_EMIT_WITH_EXIT_FULL(_emitter, _returnval, _event, _error, ...)    \
309   do                                                                          \
310     {                                                                         \
311       int _ret;                                                               \
312       g_debug ("Emitter event: %s",                                           \
313                mmd_yaml_get_event_name ((_event)->type));                     \
314       _ret = yaml_emitter_emit (_emitter, _event);                            \
315       (_event)->type = 0;                                                     \
316       if (!_ret)                                                              \
317         {                                                                     \
318           g_debug (__VA_ARGS__);                                              \
319           g_set_error (                                                       \
320             _error, MODULEMD_YAML_ERROR, MMD_YAML_ERROR_EMIT, __VA_ARGS__);   \
321           return _returnval;                                                  \
322         }                                                                     \
323     }                                                                         \
324   while (0)
325 
326 /**
327  * MMD_EMIT_WITH_EXIT:
328  * @_emitter: (inout): A libyaml emitter object positioned where @_event
329  * belongs in the YAML document.
330  * @_event: (in): The libyaml event to be emitted.
331  * @_error: (out): A #GError that will return the reason for an output error.
332  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
333  * @_error in case of failure.
334  *
335  * Returns: Continues on if emitting of the event was successful. Returns
336  * FALSE if an output error occurred and sets @_error appropriately.
337  *
338  * Since: 2.0
339  */
340 #define MMD_EMIT_WITH_EXIT(_emitter, _event, _error, ...)                     \
341   MMD_EMIT_WITH_EXIT_FULL (_emitter, FALSE, _event, _error, __VA_ARGS__)
342 
343 /**
344  * MMD_EMIT_WITH_EXIT_PTR:
345  * @_emitter: (inout): A libyaml emitter object positioned where @_event
346  * belongs in the YAML document.
347  * @_event: (in): The libyaml event to be emitted.
348  * @_error: (out): A #GError that will return the reason for an output error.
349  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
350  * @_error in case of failure.
351  *
352  * Returns: Continues on if emitting of the event was successful. Returns
353  * NULL if an output error occurred and sets @_error appropriately.
354  *
355  * Since: 2.0
356  */
357 #define MMD_EMIT_WITH_EXIT_PTR(_emitter, _event, _error, ...)                 \
358   MMD_EMIT_WITH_EXIT_FULL (_emitter, NULL, _event, _error, __VA_ARGS__)
359 
360 /**
361  * MMD_YAML_ERROR_EVENT_EXIT_FULL:
362  * @_error: (out): A #GError that will return the reason for the error.
363  * @_errorcode: (in): The exact error code that should be set on @_error.
364  * @_event: (in): The libyaml event for which an error is to be reported.
365  * @_returnval: (in): The error value to return.
366  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
367  * @_error.
368  *
369  * DIRECT USE OF THIS MACRO SHOULD BE AVOIDED. This is the internal
370  * implementation for %MMD_YAML_ERROR_EVENT_EXIT,
371  * %MMD_YAML_ERROR_EVENT_EXIT_BOOL, and %MMD_YAML_ERROR_EVENT_EXIT_INT which
372  * should be used instead.
373  *
374  * Returns: Returns @_returnval and sets @_error appropriately.
375  *
376  * Since: 2.0
377  */
378 #define MMD_YAML_ERROR_EVENT_EXIT_FULL(                                       \
379   _error, _errorcode, _event, _returnval, ...)                                \
380   do                                                                          \
381     {                                                                         \
382       g_autofree gchar *formatted = g_strdup_printf (__VA_ARGS__);            \
383       g_autofree gchar *formatted2 =                                          \
384         g_strdup_printf ("%s [line %zu col %zu]",                             \
385                          formatted,                                           \
386                          _event.start_mark.line + 1,                          \
387                          _event.start_mark.column + 1);                       \
388       g_debug ("%s", formatted2);                                             \
389       g_set_error (                                                           \
390         _error, MODULEMD_YAML_ERROR, _errorcode, "%s", formatted2);           \
391       return _returnval;                                                      \
392     }                                                                         \
393   while (0)
394 
395 /**
396  * MMD_YAML_ERROR_EVENT_EXIT:
397  * @_error: (out): A #GError that will return the reason for the error.
398  * @_event: (in): The libyaml event for which an error is to be reported.
399  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
400  * @_error.
401  *
402  * Returns: Returns NULL and sets @_error appropriately.
403  *
404  * Since: 2.0
405  */
406 #define MMD_YAML_ERROR_EVENT_EXIT(_error, _event, ...)                        \
407   MMD_YAML_ERROR_EVENT_EXIT_FULL (                                            \
408     _error, MMD_YAML_ERROR_PARSE, _event, NULL, __VA_ARGS__)
409 
410 /**
411  * MMD_YAML_ERROR_EVENT_EXIT_BOOL:
412  * @_error: (out): A #GError that will return the reason for the error.
413  * @_event: (in): The libyaml event for which an error is to be reported.
414  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
415  * @_error.
416  *
417  * Returns: Returns FALSE and sets @_error appropriately.
418  *
419  * Since: 2.0
420  */
421 #define MMD_YAML_ERROR_EVENT_EXIT_BOOL(_error, _event, ...)                   \
422   MMD_YAML_ERROR_EVENT_EXIT_FULL (                                            \
423     _error, MMD_YAML_ERROR_PARSE, _event, FALSE, __VA_ARGS__)
424 
425 /**
426  * MMD_YAML_ERROR_EVENT_EXIT_INT:
427  * @_error: (out): A #GError that will return the reason for the error.
428  * @_event: (in): The libyaml event for which an error is to be reported.
429  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
430  * @_error.
431  *
432  * Returns: Returns 0 and sets @_error appropriately.
433  *
434  * Since: 2.0
435  */
436 #define MMD_YAML_ERROR_EVENT_EXIT_INT(_error, _event, ...)                    \
437   MMD_YAML_ERROR_EVENT_EXIT_FULL (                                            \
438     _error, MMD_YAML_ERROR_PARSE, _event, 0, __VA_ARGS__)
439 
440 /**
441  * MMD_SET_PARSED_YAML_STRING:
442  * @_parser: (inout): A libyaml parser object positioned at the beginning of an
443  * expected string event.
444  * @_error: (out): A #GError that will return the reason for a parsing or
445  * validation error.
446  * @_fn: (in): A setter method for a property of object @_obj to be called with
447  * the successfully parsed string.
448  * @_obj: (inout): The object that is to store the parsed string via its @_fn
449  * setter method.
450  *
451  * This convenience macro can be used when a YAML string (scalar) event is
452  * expected, and that string is to be stored in a property of libmodulemd
453  * object @_obj via setter method @_fn.
454  *
455  * Returns: Continues on if parsing of the event was successful. Returns
456  * NULL if a parse error occurred and sets @_error appropriately.
457  *
458  * Since: 2.0
459  */
460 #define MMD_SET_PARSED_YAML_STRING(_parser, _error, _fn, _obj)                \
461   do                                                                          \
462     {                                                                         \
463       GError *_nested_error = NULL;                                           \
464       g_autofree gchar *_scalar =                                             \
465         modulemd_yaml_parse_string (_parser, &_nested_error);                 \
466       if (!_scalar)                                                           \
467         {                                                                     \
468           g_propagate_error (_error, _nested_error);                          \
469           return NULL;                                                        \
470         }                                                                     \
471       _fn (_obj, _scalar);                                                    \
472       g_clear_pointer (&_scalar, g_free);                                     \
473     }                                                                         \
474   while (0)
475 
476 /**
477  * mmd_emitter_start_stream:
478  * @emitter: (inout): A libyaml emitter object that will be positioned at the
479  * beginning of a new YAML output stream.
480  * @error: (out): A #GError that will return the reason for any error.
481  *
482  * Returns: TRUE if the YAML stream was started successfully. Returns FALSE if
483  * an error occurred and sets @error appropriately.
484  *
485  * Since: 2.0
486  */
487 gboolean
488 mmd_emitter_start_stream (yaml_emitter_t *emitter, GError **error);
489 
490 /**
491  * mmd_emitter_end_stream:
492  * @emitter: (inout): A libyaml emitter object that is positioned at the end of
493  * a YAML output stream to be closed.
494  * @error: (out): A #GError that will return the reason for any error.
495  *
496  * Returns: TRUE if the YAML stream was closed successfully. Returns FALSE if
497  * an error occurred and sets @error appropriately.
498  *
499  * Since: 2.0
500  */
501 gboolean
502 mmd_emitter_end_stream (yaml_emitter_t *emitter, GError **error);
503 
504 
505 /**
506  * mmd_emitter_start_document:
507  * @emitter: (inout): A libyaml emitter object that is positioned at the start
508  * of where a new YAML document will be written.
509  * @error: (out): A #GError that will return the reason for any error.
510  *
511  * Emits a YAML document start header line.
512  *
513  * Returns: TRUE if the YAML document was started successfully. Returns FALSE
514  * if an error occurred and sets @error appropriately.
515  *
516  * Since: 2.0
517  */
518 gboolean
519 mmd_emitter_start_document (yaml_emitter_t *emitter, GError **error);
520 
521 /**
522  * mmd_emitter_end_document:
523  * @emitter: (inout): A libyaml emitter object that is positioned at the start
524  * of where a YAML document terminator will be written.
525  * @error: (out): A #GError that will return the reason for any error.
526  *
527  * Emits a YAML document termination line.
528  *
529  * Returns: TRUE if the YAML document was terminated successfully. Returns
530  * FALSE if an error occurred and sets @error appropriately.
531  *
532  * Since: 2.0
533  */
534 gboolean
535 mmd_emitter_end_document (yaml_emitter_t *emitter, GError **error);
536 
537 
538 /**
539  * mmd_emitter_start_mapping:
540  * @emitter: (inout): A libyaml emitter object that is positioned at the start
541  * of where a new mapping will be written.
542  * @style: (in): The YAML mapping style for the output.
543  * @error: (out): A #GError that will return the reason for any error.
544  *
545  * Returns: TRUE if the YAML mapping was started successfully. Returns FALSE if
546  * an error occurred and sets @error appropriately.
547  *
548  * Since: 2.0
549  */
550 gboolean
551 mmd_emitter_start_mapping (yaml_emitter_t *emitter,
552                            yaml_mapping_style_t style,
553                            GError **error);
554 
555 /**
556  * mmd_emitter_end_mapping:
557  * @emitter: (inout): A libyaml emitter object that is positioned at the start
558  * of where a mapping ending will be written.
559  * @error: (out): A #GError that will return the reason for any error.
560  *
561  * Returns: TRUE if the YAML mapping was ended successfully. Returns FALSE if
562  * an error occurred and sets @error appropriately.
563  *
564  * Since: 2.0
565  */
566 gboolean
567 mmd_emitter_end_mapping (yaml_emitter_t *emitter, GError **error);
568 
569 
570 /**
571  * mmd_emitter_start_sequence:
572  * @emitter: (inout): A libyaml emitter object that is positioned at the start
573  * of where a new sequence will be written.
574  * @style: (in): The YAML sequence style for the output.
575  * @error: (out): A #GError that will return the reason for any error.
576  *
577  * Returns: TRUE if the YAML sequence was started successfully. Returns FALSE
578  * if an error occurred and sets @error appropriately.
579  *
580  * Since: 2.0
581  */
582 gboolean
583 mmd_emitter_start_sequence (yaml_emitter_t *emitter,
584                             yaml_sequence_style_t style,
585                             GError **error);
586 
587 /**
588  * mmd_emitter_end_sequence:
589  * @emitter: (inout): A libyaml emitter object that is positioned at the start
590  * of where a sequence ending will be written.
591  * @error: (out): A #GError that will return the reason for any error.
592  *
593  * Returns: TRUE if the YAML sequence was ended successfully. Returns FALSE if
594  * an error occurred and sets @error appropriately.
595  *
596  * Since: 2.0
597  */
598 gboolean
599 mmd_emitter_end_sequence (yaml_emitter_t *emitter, GError **error);
600 
601 
602 /**
603  * mmd_emitter_scalar:
604  * @emitter: (inout): A libyaml emitter object that is positioned at the start
605  * of where a scalar will be written.
606  * @scalar: (in): The scalar (string) to be written.
607  * @style: (in): The YAML scalar style for the output.
608  * @error: (out): A #GError that will return the reason for any error.
609  *
610  * Returns: TRUE if the YAML scalar was written successfully. Returns FALSE if
611  * an error occurred and sets @error appropriately.
612  *
613  * Since: 2.0
614  */
615 gboolean
616 mmd_emitter_scalar (yaml_emitter_t *emitter,
617                     const gchar *scalar,
618                     yaml_scalar_style_t style,
619                     GError **error);
620 
621 
622 /**
623  * mmd_emitter_strv:
624  * @emitter: (inout): A libyaml emitter object positioned at the start of where
625  * a string sequence will be written.
626  * @seq_style: (in): The YAML sequence style for the output.
627  * @list: (in): A list that will be emitted to the YAML emitter.
628  * @error: (out): A #GError that will return the reason for an emitting error.
629  *
630  * Returns: TRUE if the sequence emitted successfully. FALSE if an error was
631  * encountered and sets @error appropriately.
632  *
633  * Since: 2.0
634  */
635 gboolean
636 mmd_emitter_strv (yaml_emitter_t *emitter,
637                   yaml_sequence_style_t seq_style,
638                   GStrv list,
639                   GError **error);
640 
641 
642 /**
643  * modulemd_yaml_parse_date:
644  * @parser: (inout): A libyaml parser object positioned at the beginning of a
645  * date (YYYY-MM-DD) scalar entry.
646  * @error: (out): A #GError that will return the reason for a parsing or
647  * validation error.
648  *
649  * Returns: (transfer full): A newly-allocated #GDate representing the parsed
650  * value. NULL if a parse or validation error occurred and sets @error
651  * appropriately.
652  *
653  * Since: 2.0
654  */
655 GDate *
656 modulemd_yaml_parse_date (yaml_parser_t *parser, GError **error);
657 
658 
659 /**
660  * modulemd_yaml_parse_string:
661  * @parser: (inout): A libyaml parser object positioned at the beginning of a
662  * string scalar entry.
663  * @error: (out): A #GError that will return the reason for a parsing or
664  * validation error.
665  *
666  * Returns: (transfer full): A newly-allocated `gchar *` representing the
667  * parsed value. NULL if a parse error occurred and sets @error appropriately.
668  *
669  * Since: 2.0
670  */
671 gchar *
672 modulemd_yaml_parse_string (yaml_parser_t *parser, GError **error);
673 
674 
675 /**
676  * modulemd_yaml_parse_bool:
677  * @parser: (inout): A libyaml parser object positioned at the beginning of a
678  * boolean scalar entry.
679  * @error: (out): A #GError that will return the reason for a parsing or
680  * validation error.
681  *
682  * Returns: A boolean representing the parsed value. Returns FALSE if a parse
683  * error occurred and sets @error appropriately.
684  *
685  * Since: 2.2
686  */
687 gboolean
688 modulemd_yaml_parse_bool (yaml_parser_t *parser, GError **error);
689 
690 
691 /**
692  * modulemd_yaml_parse_int64:
693  * @parser: (inout): A libyaml parser object positioned at the beginning of a
694  * int64 scalar entry.
695  * @error: (out): A #GError that will return the reason for a parsing or
696  * validation error.
697  *
698  * Returns: (transfer full): A 64-bit signed integer representing the parsed
699  * value. Returns 0 if a parse error occurred and sets @error appropriately.
700  *
701  * Since: 2.0
702  */
703 gint64
704 modulemd_yaml_parse_int64 (yaml_parser_t *parser, GError **error);
705 
706 
707 /**
708  * modulemd_yaml_parse_uint64:
709  * @parser: (inout): A libyaml parser object positioned at the beginning of a
710  * uint64 scalar entry.
711  * @error: (out): A #GError that will return the reason for a parsing or
712  * validation error.
713  *
714  * Returns: (transfer full): A 64-bit unsigned integer representing the parsed
715  * value. Returns 0 if a parse error occurred and sets @error appropriately.
716  *
717  * Since: 2.0
718  */
719 guint64
720 modulemd_yaml_parse_uint64 (yaml_parser_t *parser, GError **error);
721 
722 
723 /**
724  * modulemd_yaml_parse_string_set:
725  * @parser: (inout): A libyaml parser object positioned at the beginning of a
726  * sequence with string scalars.
727  * @error: (out): A #GError that will return the reason for a parsing or
728  * validation error.
729  *
730  * Returns: (transfer full): A newly-allocated #GHashTable * representing the
731  * parsed value. All parsed sequence entries are added as keys in the
732  * hashtable. NULL if a parse error occurred and sets @error appropriately.
733  *
734  * Since: 2.0
735  */
736 GHashTable *
737 modulemd_yaml_parse_string_set (yaml_parser_t *parser, GError **error);
738 
739 
740 /**
741  * modulemd_yaml_parse_string_set_from_map:
742  * @parser: (inout): A libyaml parser object positioned at the beginning of a
743  * map containing a single key which is a sequence with string scalars.
744  * @key: (in): The key in a single-key mapping whose contents should be
745  * returned as a string set.
746  * @strict: (in): Whether the parser should return failure if it encounters an
747  * unknown mapping key or if it should ignore it.
748  * @error: (out): A #GError that will return the reason for a parsing or
749  * validation error.
750  *
751  * Function for retrieving a string set from a single-key map such as
752  * data.artifacts, data.api or data.filter from a module stream document.
753  *
754  * Returns: (transfer full): A newly-allocated #GHashTable * representing the
755  * parsed values. All parsed sequence entries are added as keys in the
756  * hashtable. NULL if a parse error occurred and sets @error appropriately.
757  *
758  * Since: 2.0
759  */
760 GHashTable *
761 modulemd_yaml_parse_string_set_from_map (yaml_parser_t *parser,
762                                          const gchar *key,
763                                          gboolean strict,
764                                          GError **error);
765 
766 
767 /**
768  * modulemd_yaml_parse_string_string_map:
769  * @parser: (inout): A libyaml parser object positioned at the beginning of a
770  * map containing a scalar/scalar key/value pairs.
771  * @error: (out): A #GError that will return the reason for a parsing or
772  * validation error.
773  *
774  * Function for retrieving a hash table from a str/str map such as
775  * data.dependencies in ModuleStreamV1.
776  *
777  * Returns: (transfer full): A newly-allocated #GHashTable * representing the
778  * parsed values. NULL if a parse error occurred and sets @error appropriately.
779  *
780  * Since: 2.0
781  */
782 GHashTable *
783 modulemd_yaml_parse_string_string_map (yaml_parser_t *parser, GError **error);
784 
785 
786 /**
787  * modulemd_yaml_parse_nested_set:
788  * @parser: (inout): A libyaml parser object positioned at the beginning of a
789  * map containing scalar keys with string set values.
790  * @error: (out): A #GError that will return the reason for a parsing or
791  * validation error.
792  *
793  * Function for retrieving a hash table from a str/string-set map such as
794  * data.dependencies in #ModulemdModuleStreamV2.
795  *
796  * Returns: (transfer full): A newly-allocated #GHashTable * representing the
797  * parsed values. NULL if a parse error occurred and sets @error appropriately.
798  *
799  * Since: 2.10
800  */
801 GHashTable *
802 modulemd_yaml_parse_nested_set (yaml_parser_t *parser, GError **error);
803 
804 /**
805  * modulemd_yaml_emit_nested_set:
806  * @emitter: (inout): A libyaml emitter object that is positioned where a nested
807  * set (a map containing scalar keys with string set values) should occur.
808  * @table: (in): The nested set to emit.
809  * @error: (out): A #GError that will return the reason for failing to emit.
810  *
811  * Returns: TRUE if the nested set emitted successfully. FALSE if an error was
812  * encountered and sets @error appropriately.
813  *
814  * Since: 2.10
815  */
816 gboolean
817 modulemd_yaml_emit_nested_set (yaml_emitter_t *emitter,
818                                GHashTable *table,
819                                GError **error);
820 
821 /**
822  * modulemd_yaml_parse_document_type:
823  * @parser: (inout): A libyaml parser object positioned at the beginning of a
824  * yaml subdocument immediately prior to a `YAML_DOCUMENT_START_EVENT`.
825  *
826  * Reads through a YAML subdocument to retrieve the document type, metadata
827  * version and the data section.
828  *
829  * Returns: (transfer full): A #ModulemdSubdocumentInfo with information on
830  * the parse results.
831  *
832  * Since: 2.0
833  */
834 ModulemdSubdocumentInfo *
835 modulemd_yaml_parse_document_type (yaml_parser_t *parser);
836 
837 
838 /**
839  * modulemd_yaml_emit_document_headers:
840  * @emitter: (inout): A libyaml emitter object that is positioned where the
841  * `YAML_DOCUMENT_START_EVENT` should occur (so this must be after either a
842  * `YAML_STREAM_START_EVENT` or `YAML_DOCUMENT_END_EVENT`).
843  * @doctype: (in): The document type (see #ModulemdYamlDocumentTypeEnum)
844  * @mdversion: (in): The metadata version for this document
845  * @error: (out): A #GError that will return the reason for failing to emit.
846  *
847  * Creates the YAML header and returns @emitter positioned just before the
848  * `YAML_MAPPING_START` for the "data:" section.
849  *
850  * Returns: TRUE if the document emitted successfully. FALSE if an error was
851  * encountered and sets @error appropriately.
852  *
853  * Since: 2.0
854  */
855 gboolean
856 modulemd_yaml_emit_document_headers (yaml_emitter_t *emitter,
857                                      ModulemdYamlDocumentTypeEnum doctype,
858                                      guint64 mdversion,
859                                      GError **error);
860 
861 
862 /**
863  * modulemd_yaml_emit_variant:
864  * @emitter: (inout): A libyaml emitter object that is positioned where the
865  * variant should occur.
866  * @variant: (in): The variant to emit. It must be either a boolean, string,
867  * array or dictionary.
868  * @error: (out): A #GError that will return the reason for failing to emit.
869  *
870  * Returns: TRUE if the variant emitted successfully. FALSE if an error was
871  * encountered and sets @error appropriately.
872  *
873  * Since: 2.0
874  */
875 gboolean
876 modulemd_yaml_emit_variant (yaml_emitter_t *emitter,
877                             GVariant *variant,
878                             GError **error);
879 
880 
881 /**
882  * mmd_variant_from_scalar:
883  * @scalar: (in): A string or boolean value to read into a #GVariant
884  *
885  * Returns: (transfer full): A new, floating #GVariant representing a string
886  * or boolean value matching the scalar passed in.
887  *
888  * Since: 2.0
889  */
890 GVariant *
891 mmd_variant_from_scalar (const gchar *scalar);
892 
893 
894 /**
895  * mmd_variant_from_mapping:
896  * @parser: (inout): A YAML parser positioned just after a `MAPPING_START`
897  * @error: (out): A #GError that will return the reason for failing to parse.
898  *
899  * Returns: (transfer full): A new, floating #GVariant representing a hash
900  * table with string keys and #GVariant values.
901  *
902  * Since: 2.0
903  */
904 GVariant *
905 mmd_variant_from_mapping (yaml_parser_t *parser, GError **error);
906 
907 
908 /**
909  * mmd_variant_from_sequence:
910  * @parser: (inout): A YAML parser positioned just after a `SEQUENCE_START`
911  * @error: (out): A #GError that will return the reason for failing to parse.
912  *
913  * Returns: (transfer full): A new, floating #GVariant representing a list of
914  * #GVariant values.
915  *
916  * Since: 2.0
917  */
918 GVariant *
919 mmd_variant_from_sequence (yaml_parser_t *parser, GError **error);
920 
921 
922 /**
923  * mmd_parse_xmd:
924  * @parser: (inout): A YAML parser positioned just after an 'xmd' mapping key.
925  * @error: (out): A #GError that will return the reason for failing to parse.
926  *
927  * Returns: (transfer full): A new, floating #GVariant representing the parsed
928  * XMD (eXtensible MetaData).
929  *
930  * Since: 2.10
931  */
932 GVariant *
933 mmd_parse_xmd (yaml_parser_t *parser, GError **error);
934 
935 
936 /**
937  * skip_unknown_yaml:
938  * @parser: (inout): A YAML parser positioned just after an unexpected map key.
939  * @error: (out): A #GError that will return the reason for failing to parse.
940  *
941  * This function is used to skip a section of YAML that contains unknown keys.
942  * The intent here is that it will allow libmodulemd to be forward-compatible
943  * with new, backwards-compatible changes in the metadata format. This function
944  * will advance @parser to just before the next key in the map.
945  *
946  * Returns: TRUE if the parser was able to skip the unknown values safely.
947  * FALSE and sets @error appropriately if the document was malformed YAML.
948  */
949 gboolean
950 skip_unknown_yaml (yaml_parser_t *parser, GError **error);
951 
952 
953 /**
954  * SKIP_UNKNOWN:
955  * @_parser: (inout): A YAML parser positioned just after an unexpected map key.
956  * @_returnval: (in): The error value to return.
957  * @...: (in): Additional argument(s) to pass to g_set_error() when setting
958  * `error`.
959  *
960  * This convenience macro is a wrapper around skip_unknown_yaml() used to skip
961  * a section of YAML that contains unknown keys.
962  *
963  * NOTE: Local variables `strict` and `error` are expected to be present in the
964  * code from which this macro is used.
965  *
966  * Returns: If `strict` is TRUE or skip_unknown_yaml() fails, @_returnval is
967  * returned and `error` is set appropriately.
968  *
969  * Since: 2.0
970  */
971 #define SKIP_UNKNOWN(_parser, _returnval, ...)                                \
972   do                                                                          \
973     {                                                                         \
974       g_debug (__VA_ARGS__);                                                  \
975       if (strict)                                                             \
976         {                                                                     \
977           MMD_YAML_ERROR_EVENT_EXIT_FULL (error,                              \
978                                           MMD_YAML_ERROR_UNKNOWN_ATTR,        \
979                                           event,                              \
980                                           _returnval,                         \
981                                           __VA_ARGS__);                       \
982         }                                                                     \
983                                                                               \
984       if (!skip_unknown_yaml (_parser, error))                                \
985         return _returnval;                                                    \
986       break;                                                                  \
987     }                                                                         \
988   while (0)
989 
990 
991 /* A set of macros for simple emitting of common elements */
992 /**
993  * NON_EMPTY_TABLE:
994  * @table: A #GHashTable.
995  *
996  * Returns: FALSE if @table is empty, otherwise TRUE.
997  *
998  * Since: 2.0
999  */
1000 #define NON_EMPTY_TABLE(table) (g_hash_table_size (table) != 0)
1001 
1002 /**
1003  * NON_EMPTY_ARRAY:
1004  * @array: A #GPtrArray.
1005  *
1006  * Returns: FALSE if @array is empty, otherwise TRUE.
1007  *
1008  * Since: 2.0
1009  */
1010 #define NON_EMPTY_ARRAY(array) (array->len != 0)
1011 
1012 /**
1013  * EMIT_SCALAR_FULL:
1014  * @emitter: (inout): A libyaml emitter object positioned where a scalar
1015  * belongs in the YAML document.
1016  * @error: (out): A #GError that will return the reason for an output error.
1017  * @value: (in): The scalar (string) to be written.
1018  * @style: (in): The YAML scalar style for the output.
1019  *
1020  * Emits scalar @value using style @style.
1021  *
1022  * Returns: Continues on if the YAML scalar was written successfully. Returns
1023  * FALSE if an error occurred and sets @error appropriately.
1024  *
1025  * Since: 2.1
1026  */
1027 #define EMIT_SCALAR_FULL(emitter, error, value, style)                        \
1028   do                                                                          \
1029     {                                                                         \
1030       if (!mmd_emitter_scalar (emitter, value, style, error))                 \
1031         return FALSE;                                                         \
1032     }                                                                         \
1033   while (0)
1034 
1035 /**
1036  * EMIT_SCALAR:
1037  * @emitter: (inout): A libyaml emitter object positioned where a scalar
1038  * belongs in the YAML document.
1039  * @error: (out): A #GError that will return the reason for an output error.
1040  * @value: (in): The scalar (string) to be written.
1041  *
1042  * Emits scalar @value using style `YAML_PLAIN_SCALAR_STYLE`.
1043  *
1044  * Returns: Continues on if the YAML scalar was written successfully. Returns
1045  * FALSE if an error occurred and sets @error appropriately.
1046  *
1047  * Since: 2.0
1048  */
1049 #define EMIT_SCALAR(emitter, error, value)                                    \
1050   EMIT_SCALAR_FULL (emitter, error, value, YAML_PLAIN_SCALAR_STYLE)
1051 
1052 /**
1053  * EMIT_KEY_VALUE_FULL:
1054  * @emitter: (inout): A libyaml emitter object positioned where a scalar
1055  * belongs in the YAML document.
1056  * @error: (out): A #GError that will return the reason for an output error.
1057  * @key: (in): The key (string) to be written.
1058  * @value: (in): The scalar (string) to be written.
1059  * @style: (in): The YAML scalar style for the output.
1060  *
1061  * Emits key/value pair (@key: @value) using style @style.
1062  *
1063  * NOTE: This macro outputs both a key and a value for that key, thus it must
1064  * only be used from within a YAML mapping.
1065  *
1066  * Returns: Continues on if the YAML key/value pair was written successfully.
1067  * Returns FALSE if an error occurred and sets @error appropriately.
1068  *
1069  * Since: 2.1
1070  */
1071 #define EMIT_KEY_VALUE_FULL(emitter, error, key, value, style)                \
1072   do                                                                          \
1073     {                                                                         \
1074       if (value == NULL)                                                      \
1075         {                                                                     \
1076           g_set_error (error,                                                 \
1077                        MODULEMD_YAML_ERROR,                                   \
1078                        MMD_YAML_ERROR_EMIT,                                   \
1079                        "Value for key %s was NULL on emit",                   \
1080                        key);                                                  \
1081           return FALSE;                                                       \
1082         }                                                                     \
1083       EMIT_SCALAR (emitter, error, key);                                      \
1084       EMIT_SCALAR_FULL (emitter, error, value, style);                        \
1085     }                                                                         \
1086   while (0)
1087 
1088 /**
1089  * EMIT_KEY_VALUE:
1090  * @emitter: (inout): A libyaml emitter object positioned where a scalar
1091  * belongs in the YAML document.
1092  * @error: (out): A #GError that will return the reason for an output error.
1093  * @key: (in): The key (string) to be written.
1094  * @value: (in): The scalar (string) to be written.
1095  *
1096  * Emits key/value pair (@key: @value) using style `YAML_PLAIN_SCALAR_STYLE`.
1097  *
1098  * NOTE: This macro outputs both a key and a value for that key, thus it must
1099  * only be used from within a YAML mapping.
1100  *
1101  * Returns: Continues on if the YAML key/value pair was written successfully.
1102  * Returns FALSE if an error occurred and sets @error appropriately.
1103  *
1104  * Since: 2.0
1105  */
1106 #define EMIT_KEY_VALUE(emitter, error, key, value)                            \
1107   EMIT_KEY_VALUE_FULL (emitter, error, key, value, YAML_PLAIN_SCALAR_STYLE)
1108 
1109 
1110 /**
1111  * EMIT_KEY_VALUE_IF_SET:
1112  * @emitter: (inout): A libyaml emitter object positioned where a scalar
1113  * belongs in the YAML document.
1114  * @error: (out): A #GError that will return the reason for an output error.
1115  * @key: (in): The key (string) to be written.
1116  * @value: (in): The scalar (string) to be written.
1117  *
1118  * Emits key/value pair (@key: @value) only if @value is not NULL.
1119  *
1120  * NOTE: This macro outputs both a key and a value for that key, thus it must
1121  * only be used from within a YAML mapping.
1122  *
1123  * Returns: Continues on if @value is NULL or the YAML key/value pair was
1124  * written successfully. Returns FALSE if an error occurred and sets @error
1125  * appropriately.
1126  *
1127  * Since: 2.0
1128  */
1129 #define EMIT_KEY_VALUE_IF_SET(emitter, error, key, value)                     \
1130   do                                                                          \
1131     {                                                                         \
1132       if (value != NULL)                                                      \
1133         {                                                                     \
1134           EMIT_KEY_VALUE (emitter, error, key, value);                        \
1135         }                                                                     \
1136     }                                                                         \
1137   while (0)
1138 
1139 /**
1140  * EMIT_MAPPING_START_WITH_STYLE:
1141  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1142  * of where a new mapping will be written.
1143  * @error: (out): A #GError that will return the reason for any error.
1144  * @style: (in): The YAML mapping style for the output.
1145  *
1146  * Returns: Continues on if the YAML mapping was started successfully. Returns
1147  * FALSE if an error occurred and sets @error appropriately.
1148  *
1149  * Since: 2.0
1150  */
1151 #define EMIT_MAPPING_START_WITH_STYLE(emitter, error, style)                  \
1152   do                                                                          \
1153     {                                                                         \
1154       if (!mmd_emitter_start_mapping (emitter, style, error))                 \
1155         return FALSE;                                                         \
1156     }                                                                         \
1157   while (0)
1158 
1159 /**
1160  * EMIT_MAPPING_START:
1161  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1162  * of where a new mapping will be written.
1163  * @error: (out): A #GError that will return the reason for any error.
1164  *
1165  * Returns: Continues on if the YAML mapping was started successfully using
1166  * style `YAML_BLOCK_MAPPING_STYLE`. Returns FALSE if an error occurred and
1167  * sets @error appropriately.
1168  *
1169  * Since: 2.0
1170  */
1171 #define EMIT_MAPPING_START(emitter, error)                                    \
1172   EMIT_MAPPING_START_WITH_STYLE (emitter, error, YAML_BLOCK_MAPPING_STYLE)
1173 
1174 /**
1175  * EMIT_MAPPING_END:
1176  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1177  * of where a mapping ending will be written.
1178  * @error: (out): A #GError that will return the reason for any error.
1179  *
1180  * Returns: Continues on if the YAML mapping was ended successfully. Returns
1181  * FALSE if an error occurred and sets @error appropriately.
1182  *
1183  * Since: 2.0
1184  */
1185 #define EMIT_MAPPING_END(emitter, error)                                      \
1186   do                                                                          \
1187     {                                                                         \
1188       if (!mmd_emitter_end_mapping (emitter, error))                          \
1189         return FALSE;                                                         \
1190     }                                                                         \
1191   while (0)
1192 
1193 /**
1194  * EMIT_SEQUENCE_START_WITH_STYLE:
1195  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1196  * of where a new sequence will be written.
1197  * @error: (out): A #GError that will return the reason for any error.
1198  * @style: (in): The YAML sequence style for the output.
1199  *
1200  * Returns: Continues on if the YAML sequence was started successfully. Returns
1201  * FALSE if an error occurred and sets @error appropriately.
1202  *
1203  * Since: 2.0
1204  */
1205 #define EMIT_SEQUENCE_START_WITH_STYLE(emitter, error, style)                 \
1206   do                                                                          \
1207     {                                                                         \
1208       if (!mmd_emitter_start_sequence (emitter, style, error))                \
1209         return FALSE;                                                         \
1210     }                                                                         \
1211   while (0)
1212 
1213 /**
1214  * EMIT_SEQUENCE_START:
1215  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1216  * of where a new sequence will be written.
1217  * @error: (out): A #GError that will return the reason for any error.
1218  *
1219  * Returns: Continues on if the YAML sequence was started successfully using
1220  * style `YAML_BLOCK_SEQUENCE_STYLE`. Returns FALSE if an error occurred and
1221  * sets @error appropriately.
1222  *
1223  * Since: 2.0
1224  */
1225 #define EMIT_SEQUENCE_START(emitter, error)                                   \
1226   EMIT_SEQUENCE_START_WITH_STYLE (emitter, error, YAML_BLOCK_SEQUENCE_STYLE)
1227 
1228 /**
1229  * EMIT_SEQUENCE_END:
1230  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1231  * of where a sequence ending will be written.
1232  * @error: (out): A #GError that will return the reason for any error.
1233  *
1234  * Returns: Continues on if the YAML sequence was ended successfully. Returns
1235  * FALSE if an error occurred and sets @error appropriately.
1236  *
1237  * Since: 2.0
1238  */
1239 #define EMIT_SEQUENCE_END(emitter, error)                                     \
1240   do                                                                          \
1241     {                                                                         \
1242       if (!mmd_emitter_end_sequence (emitter, error))                         \
1243         return FALSE;                                                         \
1244     }                                                                         \
1245   while (0)
1246 
1247 /**
1248  * EMIT_HASHTABLE_VALUES_IF_NON_EMPTY:
1249  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1250  * of where a new mapping will be written.
1251  * @error: (out): A #GError that will return the reason for any error.
1252  * @key: (in): The name to be used as the identifier for the output mapping.
1253  * @table: (in): The #GHashTable that is to be output.
1254  * @emitfn: (in): A function used to emit each of the hash table values.
1255  *
1256  * Does nothing if the hash table @table is empty. Otherwise, calls @emitfn
1257  * to emit each of the values from @table identified as @key.
1258  *
1259  * NOTE: This macro outputs both a key and a sub-mapping value for that key,
1260  * thus it must only be used from within a YAML mapping.
1261  *
1262  * Returns: Continues on if the YAML mapping was output successfully. Returns
1263  * FALSE if an error occurred and sets @error appropriately.
1264  *
1265  * Since: 2.0
1266  */
1267 #define EMIT_HASHTABLE_VALUES_IF_NON_EMPTY(                                   \
1268   emitter, error, key, table, emitfn)                                         \
1269   do                                                                          \
1270     {                                                                         \
1271       if (NON_EMPTY_TABLE (table))                                            \
1272         {                                                                     \
1273           EMIT_SCALAR (emitter, error, key);                                  \
1274           EMIT_MAPPING_START (emitter, error);                                \
1275           gsize i;                                                            \
1276           g_autoptr (GPtrArray) keys =                                        \
1277             modulemd_ordered_str_keys (table, modulemd_strcmp_sort);          \
1278           for (i = 0; i < keys->len; i++)                                     \
1279             {                                                                 \
1280               if (!emitfn (                                                   \
1281                     g_hash_table_lookup (table, g_ptr_array_index (keys, i)), \
1282                     emitter,                                                  \
1283                     error))                                                   \
1284                 return FALSE;                                                 \
1285             }                                                                 \
1286           EMIT_MAPPING_END (emitter, error);                                  \
1287         }                                                                     \
1288     }                                                                         \
1289   while (0)
1290 
1291 /**
1292  * EMIT_HASHTABLE_KEY_VALUES_IF_NON_EMPTY:
1293  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1294  * of where a new mapping will be written.
1295  * @error: (out): A #GError that will return the reason for any error.
1296  * @key: (in): The name to be used as the identifier for the output mapping.
1297  * @table: (in): The #GHashTable that is to be output. Both the keys and values
1298  * must be strings.
1299  *
1300  * Does nothing if the hash table @table is empty. Otherwise, outputs a YAML
1301  * mapping with the key/value pairs from @table identified as @key.
1302  *
1303  * NOTE: This macro outputs both a key and a sub-mapping value for that key,
1304  * thus it must only be used from within a YAML mapping.
1305  *
1306  * Returns: Continues on if the YAML mapping was output successfully. Returns
1307  * FALSE if an error occurred and sets @error appropriately.
1308  *
1309  * Since: 2.0
1310  */
1311 #define EMIT_HASHTABLE_KEY_VALUES_IF_NON_EMPTY(emitter, error, key, table)    \
1312   do                                                                          \
1313     {                                                                         \
1314       if (NON_EMPTY_TABLE (table))                                            \
1315         {                                                                     \
1316           EMIT_SCALAR (emitter, error, key);                                  \
1317           EMIT_MAPPING_START (emitter, error);                                \
1318           gsize i;                                                            \
1319           g_autoptr (GPtrArray) keys =                                        \
1320             modulemd_ordered_str_keys (table, modulemd_strcmp_sort);          \
1321           for (i = 0; i < keys->len; i++)                                     \
1322             {                                                                 \
1323               EMIT_SCALAR (emitter, error, g_ptr_array_index (keys, i));      \
1324               EMIT_SCALAR (                                                   \
1325                 emitter,                                                      \
1326                 error,                                                        \
1327                 g_hash_table_lookup (table, g_ptr_array_index (keys, i)));    \
1328             }                                                                 \
1329           EMIT_MAPPING_END (emitter, error);                                  \
1330         }                                                                     \
1331     }                                                                         \
1332   while (0)
1333 
1334 /**
1335  * EMIT_STRING_SET:
1336  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1337  * of where a new sequence will be written.
1338  * @error: (out): A #GError that will return the reason for any error.
1339  * @key: (in): The name to be used as the identifier for the output sequence.
1340  * @table: (in): The #GHashTable that is to be output. The keys are expected to
1341  * be a set() of strings.
1342  *
1343  * Raises an error if the hash table @table is empty. Otherwise, outputs a YAML
1344  * sequence using style `YAML_BLOCK_SEQUENCE_STYLE` with the keys from @table
1345  * identified as @key.
1346  *
1347  * NOTE: This macro outputs both a key and an array value for that key, thus it
1348  * must only be used from within a YAML mapping.
1349  *
1350  * Returns: Continues on if the YAML sequence was output successfully. Returns
1351  * FALSE if an error occurred and sets @error appropriately.
1352  *
1353  * Since: 2.0
1354  */
1355 #define EMIT_STRING_SET(emitter, error, key, table)                           \
1356   do                                                                          \
1357     {                                                                         \
1358       if (!NON_EMPTY_TABLE (table))                                           \
1359         {                                                                     \
1360           g_set_error (error,                                                 \
1361                        MODULEMD_YAML_ERROR,                                   \
1362                        MMD_YAML_ERROR_EMIT,                                   \
1363                        "String set for key %s was empty on emit",             \
1364                        key);                                                  \
1365           return FALSE;                                                       \
1366         }                                                                     \
1367       EMIT_STRING_SET_FULL (                                                  \
1368         emitter, error, key, table, YAML_BLOCK_SEQUENCE_STYLE);               \
1369     }                                                                         \
1370   while (0)
1371 
1372 /**
1373  * EMIT_STRING_SET_IF_NON_EMPTY:
1374  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1375  * of where a new sequence will be written.
1376  * @error: (out): A #GError that will return the reason for any error.
1377  * @key: (in): The name to be used as the identifier for the output sequence.
1378  * @table: (in): The #GHashTable that is to be output. The keys are expected to
1379  * be a set() of strings.
1380  *
1381  * Does nothing if the hash table @table is empty. Otherwise, outputs a YAML
1382  * sequence using style `YAML_BLOCK_SEQUENCE_STYLE` with the keys from @table
1383  * identified as @key.
1384  *
1385  * NOTE: This macro outputs both a key and an array value for that key, thus it
1386  * must only be used from within a YAML mapping.
1387  *
1388  * Returns: Continues on if the YAML sequence was output successfully. Returns
1389  * FALSE if an error occurred and sets @error appropriately.
1390  *
1391  * Since: 2.0
1392  */
1393 #define EMIT_STRING_SET_IF_NON_EMPTY(emitter, error, key, table)              \
1394   do                                                                          \
1395     {                                                                         \
1396       if (NON_EMPTY_TABLE (table))                                            \
1397         {                                                                     \
1398           EMIT_STRING_SET (emitter, error, key, table);                       \
1399         }                                                                     \
1400     }                                                                         \
1401   while (0)
1402 
1403 /**
1404  * EMIT_STRING_SET_FULL:
1405  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1406  * of where a new sequence will be written.
1407  * @error: (out): A #GError that will return the reason for any error.
1408  * @key: (in): The name to be used as the identifier for the output sequence.
1409  * @table: (in): The #GHashTable that is to be output. The keys are expected to
1410  * be a set() of strings.
1411  * @sequence_style: (in): The YAML sequence style for the output.
1412  *
1413  * Outputs a YAML sequence with the keys from @table identified as @key.
1414  *
1415  * NOTE: This macro outputs both a key and an array value for that key, thus it
1416  * must only be used from within a YAML mapping.
1417  *
1418  * Returns: Continues on if the YAML sequence was output successfully. Returns
1419  * FALSE if an error occurred and sets @error appropriately.
1420  *
1421  * Since: 2.1
1422  */
1423 #define EMIT_STRING_SET_FULL(emitter, error, key, table, sequence_style)      \
1424   do                                                                          \
1425     {                                                                         \
1426       EMIT_SCALAR (emitter, error, key);                                      \
1427       EMIT_SEQUENCE_START_WITH_STYLE (emitter, error, sequence_style);        \
1428       gsize i;                                                                \
1429       g_autoptr (GPtrArray) keys =                                            \
1430         modulemd_ordered_str_keys (table, modulemd_strcmp_sort);              \
1431       for (i = 0; i < keys->len; i++)                                         \
1432         {                                                                     \
1433           EMIT_SCALAR (emitter, error, g_ptr_array_index (keys, i));          \
1434         }                                                                     \
1435       EMIT_SEQUENCE_END (emitter, error);                                     \
1436     }                                                                         \
1437   while (0)
1438 
1439 /**
1440  * EMIT_ARRAY_VALUES:
1441  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1442  * of where a new sequence will be written.
1443  * @error: (out): A #GError that will return the reason for any error.
1444  * @key: (in): The name to be used as the identifier for the output sequence.
1445  * @array: (in): The #GPtrArray that is to be output.
1446  * @emitfn: (in): A function used to emit each of the array values.
1447  *
1448  * Raises an error if the array @array is empty. Otherwise, calls @emitfn
1449  * to emit each of the values from @array identified as @key.
1450  *
1451  * NOTE: This macro outputs both a key and an array value for that key, thus it
1452  * must only be used from within a YAML mapping.
1453  *
1454  * Returns: Continues on if the YAML sequence was output successfully. Returns
1455  * FALSE if an error occurred and sets @error appropriately.
1456  *
1457  * Since: 2.0
1458  */
1459 #define EMIT_ARRAY_VALUES(emitter, error, key, array, emitfn)                 \
1460   do                                                                          \
1461     {                                                                         \
1462       if (!NON_EMPTY_ARRAY (array))                                           \
1463         {                                                                     \
1464           g_set_error (error,                                                 \
1465                        MODULEMD_YAML_ERROR,                                   \
1466                        MMD_YAML_ERROR_EMIT,                                   \
1467                        "Array for key %s was empty on emit",                  \
1468                        key);                                                  \
1469           return FALSE;                                                       \
1470         }                                                                     \
1471       EMIT_SCALAR (emitter, error, key);                                      \
1472       EMIT_SEQUENCE_START (emitter, error);                                   \
1473       gsize i;                                                                \
1474       for (i = 0; i < array->len; i++)                                        \
1475         {                                                                     \
1476           if (!emitfn (g_ptr_array_index (array, i), emitter, error))         \
1477             return FALSE;                                                     \
1478         }                                                                     \
1479       EMIT_SEQUENCE_END (emitter, error);                                     \
1480     }                                                                         \
1481   while (0)
1482 
1483 /**
1484  * EMIT_ARRAY_VALUES_IF_NON_EMPTY:
1485  * @emitter: (inout): A libyaml emitter object that is positioned at the start
1486  * of where a new sequence will be written.
1487  * @error: (out): A #GError that will return the reason for any error.
1488  * @key: (in): The name to be used as the identifier for the output sequence.
1489  * @array: (in): The #GPtrArray that is to be output.
1490  * @emitfn: (in): A function used to emit each of the array values.
1491  *
1492  * Does nothing if the array @array is empty. Otherwise, calls @emitfn to emit
1493  * each of the values from @array identified as @key.
1494  *
1495  * NOTE: This macro outputs both a key and an array value for that key, thus it
1496  * must only be used from within a YAML mapping.
1497  *
1498  * Returns: Continues on if the YAML sequence was output successfully. Returns
1499  * FALSE if an error occurred and sets @error appropriately.
1500  *
1501  * Since: 2.0
1502  */
1503 #define EMIT_ARRAY_VALUES_IF_NON_EMPTY(emitter, error, key, array, emitfn)    \
1504   do                                                                          \
1505     {                                                                         \
1506       if (NON_EMPTY_ARRAY (array))                                            \
1507         {                                                                     \
1508           EMIT_ARRAY_VALUES (emitter, error, key, array, emitfn);             \
1509         }                                                                     \
1510     }                                                                         \
1511   while (0)
1512 
1513 G_END_DECLS
1514