/src/util-linux/include/optutils.h
Line | Count | Source |
1 | | /* |
2 | | * No copyright is claimed. This code is in the public domain; do with |
3 | | * it what you wish. |
4 | | */ |
5 | | #ifndef UTIL_LINUX_OPTUTILS_H |
6 | | #define UTIL_LINUX_OPTUTILS_H |
7 | | |
8 | | #include <assert.h> |
9 | | |
10 | | #include "c.h" |
11 | | #include "nls.h" |
12 | | #include "cctype.h" |
13 | | |
14 | | /* |
15 | | * Converts the short option @c to the corresponding long option from @opts, or |
16 | | * returns NULL. |
17 | | */ |
18 | | static inline const char *ul_get_longopt(const struct option *opts, int c) |
19 | 0 | { |
20 | 0 | const struct option *o; |
21 | 0 |
|
22 | 0 | assert(!(opts == NULL)); |
23 | 0 | for (o = opts; o->name; o++) |
24 | 0 | if (o->val == c) |
25 | 0 | return o->name; |
26 | 0 | return NULL; |
27 | 0 | } |
28 | | |
29 | | /* |
30 | | * Converts the short options @c to "%c" or "0x<hex>" if not printable. |
31 | | */ |
32 | | static inline const char *ul_get_shortopt(char *buf, size_t bufsz, int c) |
33 | 0 | { |
34 | 0 | if (c_isgraph(c)) |
35 | 0 | snprintf(buf, bufsz, "%c", c); |
36 | 0 | else |
37 | 0 | snprintf(buf, bufsz, "<0x%02x>", c); /* should not happen */ |
38 | 0 |
|
39 | 0 | return buf; |
40 | 0 | } |
41 | | |
42 | | #ifndef OPTUTILS_EXIT_CODE |
43 | | # define OPTUTILS_EXIT_CODE EXIT_FAILURE |
44 | | #endif |
45 | | |
46 | | /* |
47 | | * Check collisions between options. |
48 | | * |
49 | | * The conflicts between options are described in ul_excl_t array. The |
50 | | * array contains groups of mutually exclusive options. For example |
51 | | * |
52 | | * static const ul_excl_t excl[] = { |
53 | | * { 'Z','b','c' }, // first group |
54 | | * { 'b','x' }, // second group |
55 | | * { 0 } |
56 | | * }; |
57 | | * |
58 | | * int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; |
59 | | * |
60 | | * while ((c = getopt_long(argc, argv, "Zbcx", longopts, NULL)) != -1) { |
61 | | * |
62 | | * err_exclusive_options(c, longopts, excl, excl_st); |
63 | | * |
64 | | * switch (c) { |
65 | | * case 'Z': |
66 | | * .... |
67 | | * } |
68 | | * } |
69 | | * |
70 | | * The array excl[] defines two groups of the mutually exclusive options. The |
71 | | * option '-b' is in the both groups. |
72 | | * |
73 | | * Note that the options in the group have to be in ASCII order (ABC..abc..) and |
74 | | * groups have to be also in ASCII order. |
75 | | * |
76 | | * The maximal number of the options in the group is 15 (size of the array is |
77 | | * 16, last is zero). |
78 | | * |
79 | | * The current status of options is stored in excl_st array. The size of the array |
80 | | * must be the same as number of the groups in the ul_excl_t array. |
81 | | * |
82 | | * If you're unsure then see sys-utils/mount.c or misc-utils/findmnt.c. |
83 | | */ |
84 | | #define UL_EXCL_STATUS_INIT { 0 } |
85 | | typedef int ul_excl_t[16]; |
86 | | |
87 | | static inline void err_exclusive_options( |
88 | | int c, |
89 | | const struct option *opts, |
90 | | const ul_excl_t *excl, |
91 | | int *status) |
92 | 0 | { |
93 | 0 | int e; |
94 | 0 |
|
95 | 0 | for (e = 0; excl[e][0] && excl[e][0] <= c; e++) { |
96 | 0 | const int *op = excl[e]; |
97 | 0 |
|
98 | 0 | for (; *op && *op <= c; op++) { |
99 | 0 | if (*op != c) |
100 | 0 | continue; |
101 | 0 | if (status[e] == 0) |
102 | 0 | status[e] = c; |
103 | 0 | else if (status[e] != c) { |
104 | 0 | const char *a = ul_get_longopt(opts, status[e]); |
105 | 0 | const char *b = ul_get_longopt(opts, c); |
106 | 0 | char buf[16]; /* short option in hex */ |
107 | 0 |
|
108 | 0 | errx(OPTUTILS_EXIT_CODE, |
109 | 0 | _("options %s%s and %s%s cannot be combined"), |
110 | 0 | a ? "--" : "-", |
111 | 0 | a ? a : ul_get_shortopt(buf, sizeof(buf), status[e]), |
112 | 0 | b ? "--" : "-", |
113 | 0 | b ? b : ul_get_shortopt(buf, sizeof(buf), c)); |
114 | 0 | } |
115 | 0 | break; |
116 | 0 | } |
117 | 0 | } |
118 | 0 | } |
119 | | |
120 | | #endif |