File: util_fmt.h

package info (click to toggle)
s390-tools 2.35.0-3
  • links: PTS
  • area: main
  • in suites: forky
  • size: 12,248 kB
  • sloc: ansic: 184,236; sh: 12,152; cpp: 4,954; makefile: 2,763; perl: 2,519; asm: 1,085; python: 697; xml: 29
file content (235 lines) | stat: -rw-r--r-- 8,327 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
 * util_fmt - Format structured key-value data as JSON, text pairs, or CSV
 *
 * Copyright IBM Corp. 2024
 *
 * s390-tools is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 *
 * This module provides helper functions for converting structured key-value
 * data into different output formats.
 *
 * Benefits:
 * - Output format can be dynamically configured at run-time
 * - Callers do not need to add extra code for each output format
 * - Some format-specific requirements such as quoting, indentation, and
 *   comma-placement are automated
 *
 * Basic API calling sequence:
 *
 * util_fmt_init()      => Select output format
 * util_fmt_obj_start() => Start a new object or list
 * util_fmt_pair()      => Emit a key-value pair
 * util_fmt_obj_end()   => End the latest object or list
 * util_fmt_exit()      => Cleanup
 *
 * Note:
 * - Supported data elements are objects, lists and key-value pairs (mappings)
 * - Scalars are only supported as part of a mapping
 * - For CSV output and key filtering, mapping keys must be unique - this can
 *   be achieved either by choosing unique key names or by including object
 *   names via the FMT_PREFIX flag
 * - For CSV output, at least one object or list with the FMT_ROW flag must be
 *   emitted
 * - Common tool-specific meta-information such as API-level, tool version,
 *   etc. is automatically added to the output
 */

#ifndef LIB_UTIL_FMT_H
#define LIB_UTIL_FMT_H

#include <stdbool.h>
#include <stdio.h>

/* Flag value for default behavior (all flag types). */
#define FMT_DEFAULT	0

/* Names of supported output format types. */
#define FMT_TYPE_NAMES	"json json-seq pairs csv"

/**
 * enum util_fmt_t - Output format types.
 * @FMT_JSON:    JavaScript Object Notation output data structure
 * @FMT_JSONSEQ: Sequence of JSON data structures according to RFC7464
 * @FMT_PAIRS:   Textual key=value pairs
 * @FMT_CSV:     Comma-separated-values output
 *
 * Use these types with util_fmt_init() to control the output format.
 */
enum util_fmt_t {
	FMT_JSON,
	FMT_JSONSEQ,
	FMT_PAIRS,
	FMT_CSV,
};

/**
 * enum util_fmt_flags_t - Format control flags.
 * @FMT_NOPREFIX:  (pairs) Remove object hierarchy prefix from keys
 * @FMT_KEEPINVAL: (all)   Print mappings even if value is marked as invalid
 *                         Values will be replaced with null (JSON) or an empty
 *                         string
 * @FMT_QUOTEALL:  (all)   Add quotes to all mapping values
 * @FMT_FILTER:    (all)   Ignore keys not announced via util_fmt_add_key()
 * @FMT_HANDLEINT: (json)  Ensure correct JSON closure when interrupted
 * @FMT_NOMETA:    (all)   Do not emit tool meta-data
 * @FMT_WARN:      (all)   Warn about incorrect API usage
 *
 * Use these flags with util_fmt_init() to control generic aspects.
 */
enum util_fmt_flags_t {
	FMT_NOPREFIX  = (1 << 0),
	FMT_KEEPINVAL = (1 << 1),
	FMT_QUOTEALL  = (1 << 2),
	FMT_FILTER    = (1 << 3),
	FMT_HANDLEINT = (1 << 4),
	FMT_NOMETA    = (1 << 5),
	FMT_WARN      = (1 << 6),
};

/**
 * enum util_fmt_oflags_t - Object flags.
 * @FMT_LIST:   (all) Object is a list
 * @FMT_ROW:    (csv) Start a new CSV row with this object
 * @FMT_PREFIX: (all) Include object name in key prefix for CSV headings
 *                    and filter keys
 *
 * Use these flags with util_fmt_obj_start() to control object related
 * aspects.
 */
enum util_fmt_oflags_t {
	FMT_LIST   = (1 << 0),
	FMT_ROW    = (1 << 1),
	FMT_PREFIX = (1 << 2),
};

/**
 * enum util_fmt_mflags_t - Mapping flags.
 * @FMT_QUOTE:   (all) Quote value
 * @FMT_INVAL:   (all) Mark value as invalid
 * @FMT_PERSIST: (csv) Keep value across CSV rows until overwritten
 *
 * Use these flags with util_fmt_pair() to control mapping related aspects.
 */
enum util_fmt_mflags_t {
	FMT_QUOTE   = (1 << 0),
	FMT_INVAL   = (1 << 1),
	FMT_PERSIST = (1 << 2),
};

/**
 * util_fmt_init() - Initialize output formatter.
 * @fd   : Output file descriptor
 * @type : Output format type
 * @flags: Formatting parameters
 * @api_level: Output format level indicator
 *
 * Prepare for writing formatted output with the given @type to @fd. Additional
 * @flags can be specified to control certain output aspects (see &enum
 * util_fmt_flags_t).
 *
 * @api_level represents an application-specific output format version number:
 * this number starts at 1 and must be increased whenever an incompatible format
 * change is introduced, e.g. when a non-optional object or mapping is removed
 * or used for different data.
 */
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
		   int api_level);

/**
 * util_fmt_exit() - Release resources used by output formatter.
 *
 * Release all resources currently in use by the output formatter.
 */
void util_fmt_exit(void);

/**
 * util_fmt_name_to_type() - Convert format name to type identifier.
 * @name: Format name
 * @type: Pointer to resulting format type identifier
 *
 * Search supported output format types for a type with associated @name. If
 * found, store resulting type identifier in @type.
 *
 * Return: %true if type is found, %false otherwise.
 */
bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type);

/**
 * util_fmt_set_indent() - Set indentation parameters.
 * @base    : Base indentation level to apply to all output lines (default 0)
 * @width   : Number of indentation characters per intendation level (default 2)
 * @ind_char: Indentation characters to use (default space).
 */
void util_fmt_set_indent(unsigned int base, unsigned int width, char ind_char);

/**
 * util_fmt_add_key() - Register expected mapping keys.
 * @fmt: Format string to generate key
 *
 * Register a mapping key before the associated key-value pair is emitted.
 *
 * Use this function together with format control flag @FMT_FILTER to ignore all
 * key-value pairs for which the key has not been registered. This can be
 * useful to allow for dynamically configured filtering of output based on
 * a static list of emitted mappings.
 *
 * When creating CSV output, use this function to register all column keys
 * in advance to enable a stable column list in case of rows that do not
 * provide data for all columns.
 */
void util_fmt_add_key(const char *fmt, ...);

/**
 * util_fmt_obj_start() - Start a new data object.
 * @oflags: Flags controlling aspects of this object.
 * @fmt   : Format string for generating an object name or %NULL.
 *
 * Use this function to start a new object in output data. Depending on
 * @oflags, the new object represents either a normal object or a list. @oflags
 * can also be used to indicated that an object corresponds to a new row of
 * CSV data. If @fmt is non-%NULL, the resulting name is used in a format
 * type specified way:
 *
 * Pairs:
 *   - Object names are reflected as dot-separated component in the mapping
 *     prefix, e.g. 'a.b.key=value'
 *   - An index is generated for mappings and objects that are part of list,
 *     e.g. 'a.b[1].key=value'
 * JSON:
 *   - Object names are reflected as key-object mappings, e.g.
 *     <name>: { }
 *   - Required commas between objects and mappings are automatically generated
 * CSV:
 *   - Object names and the list type flag have no effect
 *   - When flag @FMT_ROW is specified, a CSV row will be emitted when
 *     util_fmt_obj_end() is called for the associated object
 */
void util_fmt_obj_start(unsigned int oflags, const char *fmt, ...);

/**
 * util_fmt_obj_end() - Announce the end of the latest data object started.
 *
 * Each object started with util_fmt_obj_start() must be ended with an
 * associated util_fmt_obj_end() call.
 */
void util_fmt_obj_end(void);

/**
 * util_fmt_pair() - Emit a key-value pair.
 * @mflags: Flags controlling this pair.
 * @key   : Key for this pair, excluding prefix.
 * @fmt   : Format string used to generated the pair value.
 *
 * Emit a key-value pair with the specified @key and the value that results
 * from format string @fmt.
 *
 * Notes:
 * - For JSON, a mapping can only occur after util_fmt_obj_start()
 * - For CSV, each @key must be unique, either by choosing unique key names
 *   or by including object names as prefix via the use of FMT_PREFIX in
 *   parent objects
 */
void util_fmt_pair(unsigned int mflags, const char *key, const char *fmt, ...);

#endif /* LIB_UTIL_FMT_H */