]>
Commit | Line | Data |
---|---|---|
507116e3 A |
1 | /* |
2 | * Copyright (c) 2018 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | /*! | |
25 | * @header | |
26 | * Interfaces to implement subcommand-style command line utilities (e.g. | |
27 | * launchctl(1)) and automatically generate usage output. The usage generated by | |
28 | * these interfaces assumes a long option convention (cf. getopt_long(3)) and is | |
29 | * loosely based on the docopt convention described at | |
30 | * | |
31 | * http://docopt.org | |
32 | * | |
33 | * The user may define each subcommand taken by the utility as: | |
34 | * | |
e1ee4b85 A |
35 | * static const struct option _template_opts[] = { |
36 | * [0] = { | |
37 | * .name = "bar", | |
38 | * .has_arg = required_argument, | |
39 | * .flag = NULL, | |
40 | * .val = 'f', | |
41 | * }, { | |
42 | * .name = "baz", | |
43 | * .has_arg = optional_argument, | |
44 | * .flag = NULL, | |
45 | * .val = 'b', | |
46 | * }, { | |
47 | * .name = NULL, | |
48 | * .has_arg = 0, | |
49 | * .flag = NULL, | |
50 | * .val = 0, | |
51 | * }, | |
507116e3 | 52 | * }; |
507116e3 | 53 | * |
e1ee4b85 A |
54 | * static const os_subcommand_option_t _template_required[] = { |
55 | * [0] = { | |
56 | * .osco_template = OS_SUBCOMMAND_OPTION_VERSION, | |
57 | * .osco_flags = 0, | |
58 | * .osco_option = &_template_opts[0], | |
59 | * .osco_argument_usage = "thing-to-bar", | |
60 | * .osco_argument_human = "The thing to bar. May be specified as a " | |
61 | * "bar that has a baz. This baz should have a shnaz.", | |
62 | * }, | |
63 | * OS_SUBCOMMAND_OPTION_TERMINATOR, | |
507116e3 | 64 | * }; |
507116e3 | 65 | * |
e1ee4b85 A |
66 | * static const os_subcommand_option_t _template_optional[] = { |
67 | * [0] = { | |
68 | * .osco_template = OS_SUBCOMMAND_OPTION_VERSION, | |
69 | * .osco_flags = 0, | |
70 | * .osco_option = &_template_opts[1], | |
71 | * .osco_argument_usage = "thing-to-baz", | |
72 | * .osco_argument_human = "The baz of which to propagate a foo.", | |
73 | * }, | |
74 | * OS_SUBCOMMAND_OPTION_TERMINATOR, | |
75 | * }; | |
76 | * | |
77 | * static const os_subcommand_option_t _template_positional[] = { | |
78 | * [0] = { | |
79 | * .osco_template = OS_SUBCOMMAND_OPTION_VERSION, | |
80 | * .osco_flags = 0, | |
81 | * .osco_option = NULL, | |
82 | * .osco_argument_usage = "positional-baz", | |
83 | * .osco_argument_human = "A baz specified by position.", | |
84 | * }, | |
85 | * OS_SUBCOMMAND_OPTION_TERMINATOR, | |
86 | * }; | |
87 | * | |
88 | * static const os_subcommand_t _template_cmd = { | |
89 | * .osc_template = OS_SUBCOMMAND_VERSION, | |
90 | * .osc_flags = 0, | |
91 | * .osc_name = "foo", | |
92 | * .osc_desc = "foo a bar or maybe baz", | |
93 | * .osc_optstring = "f:b:", | |
94 | * .osc_options = _foo_opts, | |
95 | * .osc_required = _foo_required, | |
96 | * .osc_optional = _foo_optional, | |
97 | * .osc_positional = _template_positional, | |
98 | * .osc_invoke = &_foo_invoke, | |
507116e3 | 99 | * } |
e1ee4b85 A |
100 | * OS_SUBCOMMAND_REGISTER(_foo_cmd); |
101 | * }; | |
507116e3 A |
102 | * |
103 | * When {@link os_subcommand_main} is called, the tool's "help" subcommand will | |
104 | * display approximately the following: | |
105 | * | |
106 | * $ tool help | |
e1ee4b85 | 107 | * usage: tool <subcommand> |
507116e3 A |
108 | * |
109 | * subcommands: | |
e1ee4b85 A |
110 | * foo foo a bar or maybe baz |
111 | * help Prints helpful information | |
507116e3 A |
112 | * |
113 | * $ tool help foo | |
e1ee4b85 A |
114 | * usage: tool foo [options] --bar=<thing-to-bar> <positional-baz> |
115 | * | |
116 | * required options: | |
117 | * --bar=<thing-to-bar> The thing to bar. May be specified as a bar that | |
118 | * has a baz. This baz should have a shnaz. | |
119 | * | |
120 | * positional-baz A baz specified by position. | |
121 | * | |
122 | * optional options: | |
123 | * --baz[=thing-to-baz] The baz of which to propagate a foo. | |
507116e3 A |
124 | */ |
125 | #ifndef __DARWIN_CTL_H | |
126 | #define __DARWIN_CTL_H | |
127 | ||
128 | #include <os/base.h> | |
129 | #include <os/api.h> | |
507116e3 | 130 | #include <os/linker_set.h> |
507116e3 A |
131 | #include <sys/cdefs.h> |
132 | #include <stdio.h> | |
133 | #include <getopt.h> | |
134 | ||
e1ee4b85 A |
135 | #if DARWIN_TAPI |
136 | #include "tapi.h" | |
137 | #endif | |
138 | ||
507116e3 A |
139 | __BEGIN_DECLS; |
140 | ||
141 | /*! | |
142 | * @define OS_SUBCOMMAND_REGISTER | |
143 | * Registers a {@link os_subcommand_t} with the runtime. Subcommands may only be | |
144 | * declared as part of the main executable image -- subcommands declared in | |
145 | * dynamic libraries or bundles will not be recognized. | |
146 | */ | |
147 | #define OS_SUBCOMMAND_REGISTER(_subcommand) \ | |
148 | LINKER_SET_ENTRY(__subcommands, _subcommand) | |
149 | ||
150 | /*! | |
151 | * @typedef os_subcommand_t | |
152 | * The formal type name for the _os_subcommand structure. | |
153 | */ | |
154 | DARWIN_API_AVAILABLE_20181020 | |
155 | typedef struct _os_subcommand os_subcommand_t; | |
156 | ||
157 | /*! | |
158 | * @const OS_SUBCOMMAND_OPTION_VERSION | |
159 | * The maximum version of the {@link os_subcommand_option_t} structure supported | |
160 | * by the implementation. | |
161 | */ | |
162 | #define OS_SUBCOMMAND_OPTION_VERSION ((os_struct_version_t)0) | |
163 | ||
507116e3 A |
164 | /*! |
165 | * @typedef os_subcommand_option_flags_t | |
166 | * Flags describing an option for a subcommand. | |
167 | * | |
168 | * @const OS_SUBCOMMAND_OPTION_FLAG_INIT | |
169 | * No flags set. This value is suitable for initialization purposes. | |
170 | * | |
e1ee4b85 A |
171 | * @const OS_SUBCOMMAND_OPTION_FLAG_TERMINATOR |
172 | * The option terminates an array of {@link os_subcommand_option_t} structures | |
173 | * and does not contain any useful information. | |
174 | * | |
175 | * @const OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS | |
176 | * The option is a positional option (that is, not identified by a long or short | |
177 | * flag) and is not required for the subcommand to execute successfully. | |
a9aaacca A |
178 | * |
179 | * @const OS_SUBCOMMAND_OPTION_FLAG_ENUM | |
180 | * The option has an explicitly-defined list of valid inputs that are enumerated | |
181 | * in the option's {@link osco_argument_usage} field. When printing usage | |
182 | * information for this option, the implementation will not transform the string | |
183 | * in this field in any way. | |
184 | * | |
185 | * For example, an option named "--stream" might have three valid inputs: | |
186 | * "stdin", "stdout", and "stderr", and the usage string may be specified as | |
187 | * | |
188 | * "stdin|stdout|stderr" | |
189 | * | |
190 | * Without this flag, the implementation would print this string as a parameter | |
191 | * name, i.e. in all caps: | |
192 | * | |
193 | * "<STDIN|STDOUT|STDERR>" | |
194 | * | |
195 | * With this flag, the string will be printed as it is given. | |
507116e3 A |
196 | */ |
197 | DARWIN_API_AVAILABLE_20181020 | |
198 | OS_CLOSED_ENUM(os_subcommand_option_flags, uint64_t, | |
199 | OS_SUBCOMMAND_OPTION_FLAG_INIT = 0, | |
e1ee4b85 A |
200 | OS_SUBCOMMAND_OPTION_FLAG_TERMINATOR = (1 << 0), |
201 | OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS = (1 << 1), | |
a9aaacca | 202 | OS_SUBCOMMAND_OPTION_FLAG_ENUM = (1 << 2), |
507116e3 A |
203 | ); |
204 | ||
205 | /*! | |
206 | * @typedef os_subcommand_option_t | |
207 | * A structure describing human-readable information about a particular option | |
208 | * taken by a subcommand. This structure is to be returned when the | |
e1ee4b85 A |
209 | * implementation invokes a {@link os_subcommand_option_info_t} function to |
210 | * query about a command's options individually. This is done when the | |
211 | * implementation is synthesizing a usage string. | |
507116e3 A |
212 | * |
213 | * @field osco_version | |
214 | * The version of the structure. Initialize to | |
215 | * {@link OS_SUBCOMMAND_OPTION_VERSION}. | |
216 | * | |
217 | * @field osco_flags | |
e1ee4b85 A |
218 | * A set of flags describing information about the option. |
219 | * | |
220 | * @field osco_option | |
221 | * A pointer to the option structure ingested by getopt_long(3) which | |
222 | * corresponds to this option. | |
507116e3 | 223 | * |
e1ee4b85 A |
224 | * @field osco_argument_usage |
225 | * The short-form name of the argument given to the option, appropriate for | |
226 | * display in a usage specifier. For example, if the subcommand takes a "--file" | |
227 | * option with a required argument, this might be the string "FILE-PATH", and | |
228 | * the resulting usage specifier would be | |
229 | * | |
230 | * --file=<FILE-PATH> | |
231 | * | |
232 | * @field osco_argument_human | |
233 | * The long-form description of the argument given to the option. Extending the | |
234 | * above example, this might be the string "The path to a file to take as input. | |
235 | * This path must be absolute; relative paths are not supported." and the | |
236 | * resulting usage specifier would be | |
237 | * | |
238 | * --file=<FILE-PATH> The path to a file to take as input. This path must be | |
239 | * absolute; relative paths are not supported. | |
507116e3 | 240 | */ |
e1ee4b85 | 241 | DARWIN_API_AVAILABLE_20191015 |
507116e3 A |
242 | typedef struct _os_subcommand_option { |
243 | const os_struct_version_t osco_version; | |
244 | os_subcommand_option_flags_t osco_flags; | |
e1ee4b85 A |
245 | const struct option *osco_option; |
246 | const char *osco_argument_usage; | |
247 | const char *osco_argument_human; | |
507116e3 A |
248 | } os_subcommand_option_t; |
249 | ||
250 | /*! | |
e1ee4b85 A |
251 | * @const OS_SUBCOMMAND_OPTION_TERMINATOR |
252 | * A convenience terminator for an array of {@link os_subcommand_option_t} | |
253 | * structures. | |
507116e3 | 254 | */ |
e1ee4b85 A |
255 | #define OS_SUBCOMMAND_OPTION_TERMINATOR (os_subcommand_option_t){ \ |
256 | .osco_version = OS_SUBCOMMAND_OPTION_VERSION, \ | |
257 | .osco_flags = OS_SUBCOMMAND_OPTION_FLAG_TERMINATOR, \ | |
258 | .osco_option = NULL, \ | |
259 | .osco_argument_usage = NULL, \ | |
260 | .osco_argument_human = NULL, \ | |
261 | } | |
262 | ||
263 | /*! | |
264 | * @const OS_SUBCOMMAND_GETOPT_TERMINATOR | |
265 | * A convenience terminator for an array of getopt(3) option structures. | |
266 | */ | |
267 | #define OS_SUBCOMMAND_GETOPT_TERMINATOR (struct option){ \ | |
268 | .name = NULL, \ | |
269 | .has_arg = 0, \ | |
270 | .flag = NULL, \ | |
271 | .val = 0, \ | |
272 | } | |
507116e3 A |
273 | |
274 | /*! | |
275 | * @const OS_SUBCOMMAND_VERSION | |
276 | * The maximum version of the {@link os_subcommand_t} structure supported by the | |
277 | * implementation. | |
278 | */ | |
279 | #define OS_SUBCOMMAND_VERSION ((os_struct_version_t)0) | |
280 | ||
281 | /*! | |
282 | * @enum os_subcommand_flags_t | |
283 | * A type describing flags associated with a subcommand for a command line | |
284 | * utility. | |
285 | * | |
286 | * @const OS_SUBCOMMAND_FLAG_INIT | |
287 | * No flags set. This value is suitable for initialization purposes. | |
288 | * | |
289 | * @const OS_SUBCOMMAND_FLAG_REQUIRE_ROOT | |
290 | * This subcommand requires the user to be root. If the user is not root, the | |
291 | * {@link os_subcommand_dispatch} routine will return {@EX_PERM}. | |
292 | * | |
293 | * @const OS_SUBCOMMAND_FLAG_TTYONLY | |
294 | * This subcommand may only be invoked via a terminal interface, i.e. it should | |
295 | * not be invoked by scripts. Use this option to emphasize that a command's | |
296 | * output is human-readably only and should not be parsed. | |
297 | * | |
298 | * @const OS_SUBCOMMAND_FLAG_HIDDEN | |
299 | * This subcommand should not be displayed in the list of subcommands. | |
e1ee4b85 A |
300 | * |
301 | * @const OS_SUBCOMMAND_FLAG_MAIN | |
302 | * This subcommand is the "main" subcommand. Designating a main subcommand | |
303 | * allows the program to specify and parse global options using an | |
304 | * {@link os_subcommand_t} object and {@link os_subcommand_main}. | |
305 | * | |
306 | * This flag implies the behavior of {@link OS_SUBCOMMAND_FLAG_HIDDEN}. | |
307 | * | |
308 | * If the program specifies a main subcommand, that subcommand's invocation | |
309 | * routine is unconditionally called before calling the subcommand invocation, | |
310 | * if the user provided a subcommand. The invocation function for the main | |
311 | * subcommand should not exit on success and should instead return 0. | |
312 | * | |
313 | * If multiple subcommands in the same program set | |
314 | * {@link OS_SUBCOMMAND_FLAG_MAIN}, the implementation's behavior is undefined. | |
a9aaacca A |
315 | * |
316 | * @const OS_SUBCOMMAND_FLAG_HELPFUL | |
317 | * When invoked with no arguments, this subcommand will print usage information | |
318 | * to stdout and exit with status zero. | |
319 | * | |
320 | * @const OS_SUBCOMMAND_FLAG_HELPFUL_FIRST_OPTION | |
321 | * Allow the implementation to detect whether the user is attempting to print | |
322 | * usage information for the given subcommand. If the implementation concludes | |
323 | * that the user is seeking help, it will print the subcommand's usage | |
324 | * information to stdout and exit with status 0. | |
325 | * | |
326 | * The implementation will conclude that the user is seeking help if | |
327 | * | |
328 | * - only one argument is provided to the subcommand, and | |
329 | * | |
330 | * any of the following | |
331 | * | |
332 | * - the argument is "-h" | |
333 | * - the argument is "-help" | |
334 | * - the argument is "--help" | |
335 | * - the argument is "help" | |
507116e3 A |
336 | */ |
337 | DARWIN_API_AVAILABLE_20181020 | |
338 | OS_CLOSED_OPTIONS(os_subcommand_flags, uint64_t, | |
339 | OS_SUBCOMMAND_FLAG_INIT, | |
340 | OS_SUBCOMMAND_FLAG_REQUIRE_ROOT = (1 << 0), | |
341 | OS_SUBCOMMAND_FLAG_TTYONLY = (1 << 1), | |
342 | OS_SUBCOMMAND_FLAG_HIDDEN = (1 << 2), | |
e1ee4b85 | 343 | OS_SUBCOMMAND_FLAG_MAIN = (1 << 3), |
a9aaacca A |
344 | OS_SUBCOMMAND_FLAG_HELPFUL = (1 << 4), |
345 | OS_SUBCOMMAND_FLAG_HELPFUL_FIRST_OPTION = (1 << 5), | |
507116e3 A |
346 | ); |
347 | ||
348 | /*! | |
349 | * @typedef os_subcommand_invoke_t | |
350 | * An type describing the invocation function for a subcommand. | |
351 | * | |
352 | * @param osc | |
353 | * The descriptor for the command being invoked. | |
354 | * | |
355 | * @param argc | |
356 | * The argument vector count. | |
357 | * | |
358 | * @param argv | |
359 | * The argument vector. The first element of this array is the name of the | |
360 | * subcommand. | |
361 | * | |
362 | * @result | |
e1ee4b85 A |
363 | * An exit code, preferably from sysexits(3). Do not return a POSIX error code |
364 | * directly from this routine. | |
507116e3 A |
365 | * |
366 | * @discussion | |
e1ee4b85 A |
367 | * You may exit directly on success or failure from this routine if desired. If |
368 | * the routine is the invocation for a main subcommand, then on success, the | |
369 | * routine should return zero to the caller rather than exiting so that the | |
370 | * implementation may continue parsing the command line arguments. | |
507116e3 A |
371 | */ |
372 | DARWIN_API_AVAILABLE_20181020 | |
373 | typedef int (*os_subcommand_invoke_t)( | |
e1ee4b85 A |
374 | const os_subcommand_t *osc, |
375 | int argc, | |
376 | const char *argv[] | |
377 | ); | |
507116e3 A |
378 | |
379 | /*! | |
380 | * @struct os_subcommand_t | |
381 | * A type describing a subcommand for a command line tool. | |
382 | * | |
383 | * @field osc_version | |
384 | * The version of the structure. Initialize to {@link OS_SUBCOMMAND_VERSION}. | |
385 | * | |
386 | * @field osc_flags | |
387 | * The flags for the subcommand. | |
388 | * | |
389 | * @field osc_name | |
390 | * The name of the subcommand. The second argument of user input will be matched | |
391 | * against this name. | |
392 | * | |
393 | * @field osc_desc | |
394 | * A brief description of the subcommand. This description will be displayed | |
395 | * next to the subcommand when the user lists all subcommands. | |
396 | * | |
a9aaacca A |
397 | * @field osc_long_desc |
398 | * A long description of the subcommand. This description will be displayed | |
399 | * when the user invokes help on the subcommand. If it's NULL the brief | |
400 | * description from osc_desc will be displayed. | |
401 | * | |
507116e3 A |
402 | * @field osc_optstring |
403 | * The option string associated with the subcommand. The implementation does not | |
404 | * recognize this string directly; the intent of storing it here is to provide a | |
405 | * convenient place to access the string for the implementation function. | |
406 | * Combined with the {@link osc_options} field, this enables the following | |
407 | * pattern: | |
408 | * | |
409 | * int ch = 0; | |
410 | * while ((ch = getopt_long(argc, argv, cmd->osc_optstring, | |
411 | * cmd->osc_options, NULL)) != -1) { | |
412 | * switch (ch) { | |
413 | * // process option | |
414 | * } | |
415 | * } | |
416 | * | |
417 | * This pattern keeps the option string and option structs co-located in code. | |
418 | * | |
419 | * @field osc_options | |
420 | * A pointer to an array of option structures describing the long options | |
e1ee4b85 A |
421 | * recognized by the subcommand. This array must be terminated by a NULL entry |
422 | * as expected by getopt_long(3). | |
423 | * | |
424 | * @field osc_required | |
425 | * A pointer to an array of subcommand option descriptors. The options described | |
426 | * in this array are required for the subcommand to execute successfully. This | |
427 | * array should be terminated with {@link OS_SUBCOMMAND_OPTION_TERMINATOR}. | |
428 | * | |
429 | * This array is consulted when printing usage information. | |
430 | * | |
431 | * @field osc_optional | |
432 | * A pointer to an array of subcommand option descriptors. The options described | |
433 | * in this array are parsed by the subcommand but not required for it to execute | |
434 | * successfully. This array should be terminated with | |
435 | * {@link OS_SUBCOMMAND_OPTION_TERMINATOR}. | |
436 | * | |
437 | * This array is consulted when printing usage information. | |
438 | * | |
439 | * @field osc_positional | |
440 | * A pointer to an array of subcommand option descriptors. The options described | |
441 | * in this array are expected to follow the required and optional arguments in | |
442 | * the command line invocation, in the order given in this array. This array | |
443 | * should be terminated with {@link OS_SUBCOMMAND_OPTION_TERMINATOR}. | |
444 | * | |
445 | * These options are expected to have their {@link osco_option} fields set to | |
446 | * NULL. | |
447 | * | |
448 | * This array is consulted when printing usage information. | |
507116e3 A |
449 | * |
450 | * @field osc_info | |
451 | * A pointer to a function which returns information about the subcommand's | |
452 | * individual options. | |
453 | * | |
454 | * @field osc_invoke | |
455 | * The implementation for the subcommand. | |
456 | */ | |
a9aaacca | 457 | DARWIN_API_AVAILABLE_20200401 |
507116e3 A |
458 | struct _os_subcommand { |
459 | const os_struct_version_t osc_version; | |
460 | const os_subcommand_flags_t osc_flags; | |
461 | const char *const osc_name; | |
462 | const char *const osc_desc; | |
463 | const char *osc_optstring; | |
464 | const struct option *osc_options; | |
e1ee4b85 A |
465 | const os_subcommand_option_t *osc_required; |
466 | const os_subcommand_option_t *osc_optional; | |
467 | const os_subcommand_option_t *osc_positional; | |
507116e3 | 468 | const os_subcommand_invoke_t osc_invoke; |
a9aaacca | 469 | const char *const osc_long_desc; |
507116e3 A |
470 | }; |
471 | ||
e1ee4b85 A |
472 | /*! |
473 | * @typedef os_subcommand_main_flags_t | |
474 | * Flags modifying the behavior of {@link os_subcommand_main}. | |
475 | * | |
476 | * @const OS_SUBCOMMAND_MAIN_FLAG_INIT | |
477 | * No flags set. This value is suitable for initialization purposes. | |
478 | */ | |
479 | OS_CLOSED_OPTIONS(os_subcommand_main_flags, uint64_t, | |
480 | OS_SUBCOMMAND_MAIN_FLAG_INIT, | |
481 | ); | |
482 | ||
507116e3 A |
483 | /*! |
484 | * @function os_subcommand_main | |
485 | * Dispatches the subcommand appropriate for the given arguments. All | |
486 | * subcommands will be implicitly discovered by virtue of their delcarations | |
487 | * with the OS_SUBCOMMAND_REGISTER attribute. | |
488 | * | |
489 | * @param argc | |
490 | * The argument count supplied to main(). | |
491 | * | |
492 | * @param argv | |
493 | * The argument vector supplied to main(). | |
494 | * | |
e1ee4b85 A |
495 | * @param flags |
496 | * Flags modifying the behavior of the implementation. | |
497 | * | |
507116e3 A |
498 | * @result |
499 | * The exit status from the subcommand's invocation function or an exit status | |
500 | * from the implementation indicating that the subcommand could not be | |
501 | * dispatched. Exit codes that can be returned by the implementation are: | |
502 | * | |
503 | * [EX_USAGE] The subcommand was invoked with improper syntax. Usage | |
504 | * has been printed to stderr. | |
505 | * [EX_USAGE] The subcommand specified is not recognized. | |
506 | * [EX_PERM] The command required root privileges, and the caller is | |
507 | * not running as root. | |
508 | * [EX_UNAVAILABLE] The command specified that it may only run within | |
509 | * the context of a tty(3), and either stdin or stdout are | |
510 | * not a tty(3). | |
511 | * | |
512 | * @discussion | |
513 | * In general, the code returned by this routine should immediately be passed to | |
514 | * exit(3). The reason this routine does not implicitly exit is to allow for the | |
515 | * caller to process multiple subcommand invocations as a batch. | |
516 | * | |
517 | * The caller should not print anything after this routine has returned -- the | |
518 | * expectation is that all relevant information has already been conveyed to the | |
519 | * user either by the implementation or from one of the subcommand invocation | |
520 | * routines. | |
521 | * | |
522 | * This routine implicitly implements a "help" subcommand. | |
523 | */ | |
e1ee4b85 | 524 | DARWIN_API_AVAILABLE_20191015 |
507116e3 A |
525 | OS_EXPORT OS_WARN_RESULT OS_NONNULL2 |
526 | int | |
e1ee4b85 A |
527 | os_subcommand_main(int argc, const char *argv[], |
528 | os_subcommand_main_flags_t flags); | |
529 | ||
530 | /*! | |
531 | * @function os_subcommand_fprintf | |
532 | * Prints a message in the context of a subcommand to the given output stream. | |
533 | * | |
534 | * @param osc | |
535 | * The subcommand which represents the context of the message. | |
536 | * | |
537 | * @param f | |
538 | * The stream to which the message shall be printed. If NULL, will be printed to | |
539 | * stderr(4). | |
540 | * | |
541 | * @param fmt | |
542 | * A printf(3)-style format string. | |
543 | * | |
544 | * @param ... | |
545 | * The arguments corresponding to {@link fmt}. | |
546 | * | |
547 | * @discussion | |
548 | * This routine provides a uniform method for printing messages in the context | |
549 | * of a subcommand. It will ensure that the message is prefixed appropriately | |
550 | * (e.g. with the program name and/or subcommand name). | |
551 | * | |
552 | * This routine should be used for printing messages intended for humans to | |
553 | * read; the implementation makes no guarantees about the output format's | |
554 | * stability. If any output is intended to be machine-parseable, it should be | |
555 | * written with fprintf(3) et al. | |
556 | */ | |
557 | DARWIN_API_AVAILABLE_20191015 | |
558 | OS_EXPORT OS_NONNULL3 OS_FORMAT_PRINTF(3, 4) | |
559 | void | |
560 | os_subcommand_fprintf(const os_subcommand_t *osc, FILE *f, | |
561 | const char *fmt, ...); | |
562 | ||
563 | /*! | |
564 | * @function os_subcommand_vfprintf | |
565 | * Prints a message in the context of a subcommand to the given output stream. | |
566 | * | |
567 | * @param osc | |
568 | * The subcommand which represents the context of the message. | |
569 | * | |
570 | * @param f | |
571 | * The stream to which the message shall be printed. If NULL, will be printed to | |
572 | * stderr(4). | |
573 | * | |
574 | * @param fmt | |
575 | * A printf(3)-style format string. | |
576 | * | |
577 | * @param ap | |
578 | * The argument list corresponding to {@link fmt}. | |
579 | * | |
580 | * @discussion | |
581 | * See discussion for {@link os_subcommand_fprintf}. | |
582 | */ | |
583 | DARWIN_API_AVAILABLE_20191015 | |
584 | OS_EXPORT OS_NONNULL3 | |
585 | void | |
586 | os_subcommand_vfprintf(const os_subcommand_t *osc, FILE *f, | |
587 | const char *fmt, va_list ap); | |
507116e3 A |
588 | |
589 | __END_DECLS; | |
590 | ||
591 | #endif // __DARWIN_CTL_H |