core_parser.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <stdlib.h> | ||
| 2 | #include <string.h> | ||
| 3 | |||
| 4 | #include "ap_internal.h" | ||
| 5 | |||
| 6 | 576 | static bool action_takes_no_value(ap_action action) { | |
| 7 |
3/4✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 448 times.
✓ Branch 3 taken 86 times.
|
534 | return action == AP_ACTION_STORE_TRUE || action == AP_ACTION_STORE_FALSE || |
| 8 |
4/4✓ Branch 0 taken 534 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 444 times.
|
1110 | action == AP_ACTION_COUNT || action == AP_ACTION_STORE_CONST; |
| 9 | } | ||
| 10 | |||
| 11 | 178 | static bool action_allows_multiple_occurrences(ap_action action) { | |
| 12 |
5/6✓ Branch 0 taken 78 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 74 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
178 | return action == AP_ACTION_APPEND || action == AP_ACTION_COUNT || |
| 13 | action == AP_ACTION_STORE_CONST; | ||
| 14 | } | ||
| 15 | |||
| 16 | static int push_value(ap_parsed_arg *parsed, int def_index, const char *token, | ||
| 17 | ap_error *err); | ||
| 18 | static int push_token(ap_parsed_arg *parsed, int def_index, const char *token, | ||
| 19 | ap_error *err); | ||
| 20 | static void free_parsed_storage(const ap_parser *parser, ap_parsed_arg *parsed); | ||
| 21 | |||
| 22 | 1684 | static int find_flag_index(const ap_parser *parser, const char *token) { | |
| 23 | int i; | ||
| 24 | int j; | ||
| 25 | 1684 | int abbrev_match = -1; | |
| 26 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1678 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
1684 | bool consider_abbrev = parser && parser->allow_abbrev && token && |
| 27 |
3/6✓ Branch 0 taken 1684 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
3374 | token[0] != '\0' && token[1] != '\0' && |
| 28 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | token[0] == token[1]; |
| 29 |
2/2✓ Branch 0 taken 5732 times.
✓ Branch 1 taken 1174 times.
|
6906 | for (i = 0; i < parser->defs_count; i++) { |
| 30 | 5732 | const ap_arg_def *def = &parser->defs[i]; | |
| 31 |
2/2✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 4664 times.
|
5732 | if (!def->is_optional) { |
| 32 | 1068 | continue; | |
| 33 | } | ||
| 34 |
2/2✓ Branch 0 taken 8268 times.
✓ Branch 1 taken 4154 times.
|
12422 | for (j = 0; j < def->flags_count; j++) { |
| 35 |
2/2✓ Branch 0 taken 508 times.
✓ Branch 1 taken 7760 times.
|
8268 | if (strcmp(def->flags[j], token) == 0) { |
| 36 | 508 | return i; | |
| 37 | } | ||
| 38 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7746 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
7760 | if (consider_abbrev && def->flags[j][0] == token[0] && |
| 39 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
|
14 | def->flags[j][1] == token[0] && |
| 40 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | strncmp(def->flags[j], token, strlen(token)) == 0) { |
| 41 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
6 | if (abbrev_match >= 0 && abbrev_match != i) { |
| 42 | 2 | return -2; | |
| 43 | } | ||
| 44 | 4 | abbrev_match = i; | |
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | 1174 | return abbrev_match >= 0 ? abbrev_match : -1; | |
| 49 | } | ||
| 50 | |||
| 51 | 20 | static int find_flag_index_n(const ap_parser *parser, const char *token, | |
| 52 | size_t token_len) { | ||
| 53 | int i; | ||
| 54 | int j; | ||
| 55 | 20 | int abbrev_match = -1; | |
| 56 |
4/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
20 | bool consider_abbrev = parser && parser->allow_abbrev && token && |
| 57 |
2/4✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
40 | token_len >= 2 && token[0] == token[1]; |
| 58 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 8 times.
|
68 | for (i = 0; i < parser->defs_count; i++) { |
| 59 | 60 | const ap_arg_def *def = &parser->defs[i]; | |
| 60 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 52 times.
|
60 | if (!def->is_optional) { |
| 61 | 8 | continue; | |
| 62 | } | ||
| 63 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 40 times.
|
132 | for (j = 0; j < def->flags_count; j++) { |
| 64 | 92 | const char *flag = def->flags[j]; | |
| 65 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 12 times.
|
92 | if (strlen(flag) == token_len && strncmp(flag, token, token_len) == 0) { |
| 66 | 10 | return i; | |
| 67 | } | ||
| 68 |
5/6✓ Branch 0 taken 8 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
82 | if (consider_abbrev && strlen(flag) >= token_len && flag[0] == token[0] && |
| 69 |
3/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
|
6 | flag[1] == token[0] && strncmp(flag, token, token_len) == 0) { |
| 70 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | if (abbrev_match >= 0 && abbrev_match != i) { |
| 71 | 2 | return -2; | |
| 72 | } | ||
| 73 | 2 | abbrev_match = i; | |
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | 8 | return abbrev_match >= 0 ? abbrev_match : -1; | |
| 78 | } | ||
| 79 | |||
| 80 | 924 | static int parse_short_cluster(const ap_parser *parser, const char *token, | |
| 81 | bool allow_unknown, ap_parsed_arg *parsed, | ||
| 82 | ap_error *err) { | ||
| 83 | size_t i; | ||
| 84 | char short_flag[3]; | ||
| 85 | char prefix; | ||
| 86 | |||
| 87 |
4/6✓ Branch 0 taken 924 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 924 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 152 times.
✓ Branch 6 taken 772 times.
|
924 | if (!token || !ap_token_has_prefix(parser, token) || token[2] == '\0') { |
| 88 | 152 | return 1; | |
| 89 | } | ||
| 90 | 772 | prefix = token[0]; | |
| 91 |
2/2✓ Branch 0 taken 754 times.
✓ Branch 1 taken 18 times.
|
772 | if (token[1] == prefix) { |
| 92 | 754 | return 1; | |
| 93 | } | ||
| 94 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
|
18 | if (strchr(token, '=') != NULL) { |
| 95 | 2 | return 1; | |
| 96 | } | ||
| 97 | |||
| 98 | 16 | short_flag[0] = prefix; | |
| 99 | 16 | short_flag[2] = '\0'; | |
| 100 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 4 times.
|
34 | for (i = 1; token[i] != '\0'; i++) { |
| 101 | int def_index; | ||
| 102 | 30 | short_flag[1] = token[i]; | |
| 103 | 30 | def_index = find_flag_index(parser, short_flag); | |
| 104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (def_index == -2) { |
| 105 | ✗ | ap_error_set(err, AP_ERR_DUPLICATE_OPTION, short_flag, | |
| 106 | "ambiguous option '%s'", short_flag); | ||
| 107 | ✗ | return -1; | |
| 108 | } | ||
| 109 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 26 times.
|
30 | if (def_index < 0) { |
| 110 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (!allow_unknown) { |
| 111 | 2 | ap_error_set(err, AP_ERR_UNKNOWN_OPTION, short_flag, | |
| 112 | "unknown option '%s'", short_flag); | ||
| 113 | } | ||
| 114 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | return allow_unknown ? 1 : -1; |
| 115 | } | ||
| 116 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14 times.
|
26 | if (parser->defs[def_index].opts.action != AP_ACTION_STORE_TRUE && |
| 117 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | parser->defs[def_index].opts.action != AP_ACTION_STORE_FALSE && |
| 118 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | parser->defs[def_index].opts.action != AP_ACTION_COUNT) { |
| 119 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (allow_unknown) { |
| 120 | 2 | return 1; | |
| 121 | } | ||
| 122 | 4 | ap_error_set(err, AP_ERR_INVALID_NARGS, short_flag, | |
| 123 | "option '%s' cannot be used in a short option cluster", | ||
| 124 | short_flag); | ||
| 125 | 4 | return -1; | |
| 126 | } | ||
| 127 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
|
26 | if (parsed[def_index].seen && !action_allows_multiple_occurrences( |
| 128 | 6 | parser->defs[def_index].opts.action)) { | |
| 129 | 2 | ap_error_set(err, AP_ERR_DUPLICATE_OPTION, short_flag, | |
| 130 | "duplicate option '%s'", short_flag); | ||
| 131 | 2 | return -1; | |
| 132 | } | ||
| 133 | 18 | parsed[def_index].seen = true; | |
| 134 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
|
18 | if (push_token(parsed, def_index, token, err) != 0) { |
| 135 | ✗ | return -1; | |
| 136 | } | ||
| 137 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
24 | if (parser->defs[def_index].opts.action == AP_ACTION_COUNT && |
| 138 | 6 | push_value(parsed, def_index, "1", err) != 0) { | |
| 139 | ✗ | return -1; | |
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | 4 | return 0; | |
| 144 | } | ||
| 145 | |||
| 146 | 108 | static int positional_min_required(const ap_arg_def *def) { | |
| 147 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
|
108 | if (action_takes_no_value(def->opts.action)) { |
| 148 | ✗ | return 0; | |
| 149 | } | ||
| 150 |
3/4✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
108 | switch (def->opts.nargs) { |
| 151 | 92 | case AP_NARGS_ONE: | |
| 152 | 92 | return 1; | |
| 153 | 4 | case AP_NARGS_ONE_OR_MORE: | |
| 154 | 4 | return 1; | |
| 155 | 12 | case AP_NARGS_FIXED: | |
| 156 | 12 | return def->opts.nargs_count; | |
| 157 | ✗ | case AP_NARGS_OPTIONAL: | |
| 158 | case AP_NARGS_ZERO_OR_MORE: | ||
| 159 | default: | ||
| 160 | ✗ | return 0; | |
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | 214 | static int remaining_min_required(const ap_parser *parser, | |
| 165 | const int *positional_defs, | ||
| 166 | int positional_count, int from_index) { | ||
| 167 | 214 | int min_required = 0; | |
| 168 | int i; | ||
| 169 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 214 times.
|
322 | for (i = from_index; i < positional_count; i++) { |
| 170 | 108 | min_required += positional_min_required(&parser->defs[positional_defs[i]]); | |
| 171 | } | ||
| 172 | 214 | return min_required; | |
| 173 | } | ||
| 174 | |||
| 175 | 362 | static int collect_positional_def_indexes(const ap_parser *parser, | |
| 176 | int **out_defs, int *out_count) { | ||
| 177 | 362 | int *positional_defs = NULL; | |
| 178 | 362 | int positional_count = 0; | |
| 179 | int i; | ||
| 180 | |||
| 181 |
3/6✓ Branch 0 taken 362 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 362 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 362 times.
|
362 | if (!parser || !out_defs || !out_count) { |
| 182 | ✗ | return -1; | |
| 183 | } | ||
| 184 | |||
| 185 |
2/2✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 362 times.
|
1444 | for (i = 0; i < parser->defs_count; i++) { |
| 186 |
2/2✓ Branch 0 taken 236 times.
✓ Branch 1 taken 846 times.
|
1082 | if (!parser->defs[i].is_optional) { |
| 187 | 236 | positional_count++; | |
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 |
2/2✓ Branch 0 taken 152 times.
✓ Branch 1 taken 210 times.
|
362 | if (positional_count > 0) { |
| 192 | 152 | positional_defs = malloc(sizeof(int) * (size_t)positional_count); | |
| 193 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 150 times.
|
152 | if (!positional_defs) { |
| 194 | 2 | return -1; | |
| 195 | } | ||
| 196 | 150 | positional_count = 0; | |
| 197 |
2/2✓ Branch 0 taken 586 times.
✓ Branch 1 taken 150 times.
|
736 | for (i = 0; i < parser->defs_count; i++) { |
| 198 |
2/2✓ Branch 0 taken 234 times.
✓ Branch 1 taken 352 times.
|
586 | if (!parser->defs[i].is_optional) { |
| 199 | 234 | positional_defs[positional_count++] = i; | |
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | 360 | *out_defs = positional_defs; | |
| 205 | 360 | *out_count = positional_count; | |
| 206 | 360 | return 0; | |
| 207 | } | ||
| 208 | |||
| 209 | 40 | const ap_arg_def *ap_next_positional_def(const ap_parser *parser, | |
| 210 | int consumed_positionals) { | ||
| 211 | 40 | int *positional_defs = NULL; | |
| 212 | 40 | int positional_defs_count = 0; | |
| 213 | 40 | int positional_cursor = 0; | |
| 214 | 40 | int next_slot = consumed_positionals + 1; | |
| 215 | 40 | const ap_arg_def *result = NULL; | |
| 216 | int i; | ||
| 217 | |||
| 218 |
4/4✓ Branch 0 taken 38 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 36 times.
|
40 | if (!parser || consumed_positionals < 0) { |
| 219 | 4 | return NULL; | |
| 220 | } | ||
| 221 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
|
36 | if (collect_positional_def_indexes(parser, &positional_defs, |
| 222 | &positional_defs_count) != 0) { | ||
| 223 | ✗ | return NULL; | |
| 224 | } | ||
| 225 | |||
| 226 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 14 times.
|
52 | for (i = 0; i < positional_defs_count; i++) { |
| 227 | 38 | const ap_arg_def *def = &parser->defs[positional_defs[i]]; | |
| 228 | 38 | int values_left = next_slot - positional_cursor; | |
| 229 | 38 | int min_after = remaining_min_required(parser, positional_defs, | |
| 230 | positional_defs_count, i + 1); | ||
| 231 | 38 | int take = 0; | |
| 232 | |||
| 233 |
5/6✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
38 | switch (def->opts.nargs) { |
| 234 | 24 | case AP_NARGS_ONE: | |
| 235 | 24 | take = values_left > 0 ? 1 : 0; | |
| 236 | 24 | break; | |
| 237 | 2 | case AP_NARGS_OPTIONAL: | |
| 238 | 2 | take = values_left > min_after ? 1 : 0; | |
| 239 | 2 | break; | |
| 240 | 4 | case AP_NARGS_ZERO_OR_MORE: | |
| 241 | 4 | take = values_left - min_after; | |
| 242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (take < 0) { |
| 243 | ✗ | take = 0; | |
| 244 | } | ||
| 245 | 4 | break; | |
| 246 | 2 | case AP_NARGS_ONE_OR_MORE: | |
| 247 | 2 | take = values_left - min_after; | |
| 248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (take < 1) { |
| 249 | ✗ | take = 1; | |
| 250 | } | ||
| 251 | 2 | break; | |
| 252 | 6 | case AP_NARGS_FIXED: | |
| 253 | 6 | take = def->opts.nargs_count; | |
| 254 | 6 | break; | |
| 255 | } | ||
| 256 | |||
| 257 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | if (positional_cursor < next_slot && |
| 258 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 16 times.
|
38 | positional_cursor + take >= next_slot) { |
| 259 | 22 | result = def; | |
| 260 | 22 | break; | |
| 261 | } | ||
| 262 | 16 | positional_cursor += take; | |
| 263 | } | ||
| 264 | |||
| 265 | 36 | free(positional_defs); | |
| 266 | 36 | return result; | |
| 267 | } | ||
| 268 | |||
| 269 | 776 | static int push_value(ap_parsed_arg *parsed, int def_index, const char *token, | |
| 270 | ap_error *err) { | ||
| 271 | 776 | char *copy = ap_strdup(token); | |
| 272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 776 times.
|
776 | if (!copy) { |
| 273 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 274 | ✗ | return -1; | |
| 275 | } | ||
| 276 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 776 times.
|
776 | if (ap_strvec_push(&parsed[def_index].values, copy) != 0) { |
| 277 | ✗ | free(copy); | |
| 278 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 279 | ✗ | return -1; | |
| 280 | } | ||
| 281 | 776 | return 0; | |
| 282 | } | ||
| 283 | |||
| 284 | 838 | static int push_token(ap_parsed_arg *parsed, int def_index, const char *token, | |
| 285 | ap_error *err) { | ||
| 286 | 838 | char *copy = ap_strdup(token); | |
| 287 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 836 times.
|
838 | if (!copy) { |
| 288 | 2 | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 289 | 2 | return -1; | |
| 290 | } | ||
| 291 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 836 times.
|
836 | if (ap_strvec_push(&parsed[def_index].tokens, copy) != 0) { |
| 292 | ✗ | free(copy); | |
| 293 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 294 | ✗ | return -1; | |
| 295 | } | ||
| 296 | 836 | return 0; | |
| 297 | } | ||
| 298 | |||
| 299 | 56 | static void free_parsed_storage(const ap_parser *parser, | |
| 300 | ap_parsed_arg *parsed) { | ||
| 301 | int i; | ||
| 302 |
2/4✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
|
56 | if (!parser || !parsed) { |
| 303 | ✗ | return; | |
| 304 | } | ||
| 305 |
2/2✓ Branch 0 taken 146 times.
✓ Branch 1 taken 56 times.
|
202 | for (i = 0; i < parser->defs_count; i++) { |
| 306 | 146 | ap_strvec_free(&parsed[i].tokens); | |
| 307 | 146 | ap_strvec_free(&parsed[i].values); | |
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | 468 | static int consume_optional_values(const ap_parser *parser, int argc, | |
| 312 | char **argv, int *idx, int def_index, | ||
| 313 | const char *inline_value, | ||
| 314 | ap_parsed_arg *parsed, ap_error *err) { | ||
| 315 | 468 | const ap_arg_def *def = &parser->defs[def_index]; | |
| 316 | 468 | int start = *idx; | |
| 317 | |||
| 318 |
2/2✓ Branch 1 taken 132 times.
✓ Branch 2 taken 336 times.
|
468 | if (action_takes_no_value(def->opts.action)) { |
| 319 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 126 times.
|
132 | if (inline_value) { |
| 320 | 6 | ap_error_set(err, AP_ERR_INVALID_NARGS, def->flags[0], | |
| 321 | 6 | "option '%s' does not take a value", def->flags[0]); | |
| 322 | 6 | return -1; | |
| 323 | } | ||
| 324 |
3/4✓ Branch 0 taken 84 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
|
210 | if (def->opts.action == AP_ACTION_COUNT && |
| 325 | 84 | push_value(parsed, def_index, "1", err) != 0) { | |
| 326 | ✗ | return -1; | |
| 327 | } | ||
| 328 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
128 | if (def->opts.action == AP_ACTION_STORE_CONST && |
| 329 | 2 | push_value(parsed, def_index, def->opts.const_value, err) != 0) { | |
| 330 | ✗ | return -1; | |
| 331 | } | ||
| 332 | 126 | return 0; | |
| 333 | } | ||
| 334 | |||
| 335 |
2/2✓ Branch 0 taken 312 times.
✓ Branch 1 taken 24 times.
|
336 | if (def->opts.nargs == AP_NARGS_ONE) { |
| 336 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 308 times.
|
312 | if (inline_value) { |
| 337 | 4 | return push_value(parsed, def_index, inline_value, err); | |
| 338 | } | ||
| 339 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
|
308 | if (start + 1 >= argc) { |
| 340 | ✗ | ap_error_set(err, AP_ERR_MISSING_VALUE, def->flags[0], | |
| 341 | ✗ | "option '%s' requires a value", def->flags[0]); | |
| 342 | ✗ | return -1; | |
| 343 | } | ||
| 344 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 306 times.
|
308 | if (find_flag_index(parser, argv[start + 1]) >= 0) { |
| 345 | 2 | ap_error_set(err, AP_ERR_MISSING_VALUE, def->flags[0], | |
| 346 | 2 | "option '%s' requires a value", def->flags[0]); | |
| 347 | 2 | return -1; | |
| 348 | } | ||
| 349 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 306 times.
|
306 | if (push_value(parsed, def_index, argv[start + 1], err) != 0) { |
| 350 | ✗ | return -1; | |
| 351 | } | ||
| 352 | 306 | *idx = start + 1; | |
| 353 | 306 | return 0; | |
| 354 | } | ||
| 355 | |||
| 356 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
|
24 | if (def->opts.nargs == AP_NARGS_OPTIONAL) { |
| 357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (inline_value) { |
| 358 | ✗ | return push_value(parsed, def_index, inline_value, err); | |
| 359 | } | ||
| 360 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (start + 1 < argc) { |
| 361 | 16 | int next_flag_idx = find_flag_index(parser, argv[start + 1]); | |
| 362 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | if (next_flag_idx < 0) { |
| 363 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
14 | if (push_value(parsed, def_index, argv[start + 1], err) != 0) { |
| 364 | ✗ | return -1; | |
| 365 | } | ||
| 366 | 14 | *idx = start + 1; | |
| 367 | } | ||
| 368 | } | ||
| 369 | 16 | return 0; | |
| 370 | } | ||
| 371 | |||
| 372 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (def->opts.nargs == AP_NARGS_FIXED) { |
| 373 | 4 | int need = def->opts.nargs_count; | |
| 374 | 4 | int consumed = 0; | |
| 375 | 4 | int j = start + 1; | |
| 376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (inline_value) { |
| 377 | ✗ | if (push_value(parsed, def_index, inline_value, err) != 0) { | |
| 378 | ✗ | return -1; | |
| 379 | } | ||
| 380 | ✗ | consumed++; | |
| 381 | } | ||
| 382 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
|
10 | while (consumed < need) { |
| 383 |
4/6✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
14 | if (j >= argc || strcmp(argv[j], "--") == 0 || |
| 384 | 6 | find_flag_index(parser, argv[j]) >= 0) { | |
| 385 | 2 | ap_error_set(err, AP_ERR_INVALID_NARGS, def->flags[0], | |
| 386 | 2 | "option '%s' requires exactly %d values", def->flags[0], | |
| 387 | 2 | def->opts.nargs_count); | |
| 388 | 2 | return -1; | |
| 389 | } | ||
| 390 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if (push_value(parsed, def_index, argv[j], err) != 0) { |
| 391 | ✗ | return -1; | |
| 392 | } | ||
| 393 | 6 | consumed++; | |
| 394 | 6 | j++; | |
| 395 | } | ||
| 396 | 2 | *idx = j - 1; | |
| 397 | 2 | return 0; | |
| 398 | } | ||
| 399 | |||
| 400 | { | ||
| 401 | 4 | int j = start + 1; | |
| 402 | 4 | int consumed = 0; | |
| 403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (inline_value) { |
| 404 | ✗ | if (push_value(parsed, def_index, inline_value, err) != 0) { | |
| 405 | ✗ | return -1; | |
| 406 | } | ||
| 407 | ✗ | consumed = 1; | |
| 408 | } | ||
| 409 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | while (j < argc) { |
| 410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (strcmp(argv[j], "--") == 0) { |
| 411 | ✗ | break; | |
| 412 | } | ||
| 413 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (find_flag_index(parser, argv[j]) >= 0) { |
| 414 | ✗ | break; | |
| 415 | } | ||
| 416 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (push_value(parsed, def_index, argv[j], err) != 0) { |
| 417 | ✗ | return -1; | |
| 418 | } | ||
| 419 | 4 | consumed++; | |
| 420 | 4 | j++; | |
| 421 | } | ||
| 422 |
3/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
|
4 | if (def->opts.nargs == AP_NARGS_ONE_OR_MORE && consumed == 0) { |
| 423 | 2 | ap_error_set(err, AP_ERR_INVALID_NARGS, def->flags[0], | |
| 424 | 2 | "option '%s' requires at least one value", def->flags[0]); | |
| 425 | 2 | return -1; | |
| 426 | } | ||
| 427 | 2 | *idx = j - 1; | |
| 428 | 2 | return 0; | |
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 432 | 326 | int ap_parser_parse(const ap_parser *parser, int argc, char **argv, | |
| 433 | bool allow_unknown, ap_parsed_arg **out_parsed, | ||
| 434 | ap_strvec *positionals, ap_strvec *unknown_args, | ||
| 435 | ap_error *err) { | ||
| 436 | ap_parsed_arg *parsed; | ||
| 437 | 326 | int positional_defs_count = 0; | |
| 438 | 326 | int *positional_defs = NULL; | |
| 439 | int i; | ||
| 440 | 326 | int positional_cursor = 0; | |
| 441 | 326 | int token_index = 1; | |
| 442 | 326 | bool positional_only = false; | |
| 443 | |||
| 444 | 326 | parsed = calloc((size_t)parser->defs_count, sizeof(ap_parsed_arg)); | |
| 445 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 326 times.
|
326 | if (!parsed) { |
| 446 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 447 | ✗ | return -1; | |
| 448 | } | ||
| 449 | |||
| 450 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 324 times.
|
326 | if (collect_positional_def_indexes(parser, &positional_defs, |
| 451 | &positional_defs_count) != 0) { | ||
| 452 | 2 | free(parsed); | |
| 453 | 2 | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 454 | 2 | return -1; | |
| 455 | } | ||
| 456 | |||
| 457 |
2/2✓ Branch 0 taken 1374 times.
✓ Branch 1 taken 276 times.
|
1650 | while (token_index < argc) { |
| 458 | 1374 | const char *token = argv[token_index]; | |
| 459 | |||
| 460 |
4/4✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 1262 times.
|
1374 | if (!positional_only && strcmp(token, "--") == 0) { |
| 461 |
3/4✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
34 | if (allow_unknown && unknown_args) { |
| 462 | int j; | ||
| 463 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 16 times.
|
174 | for (j = token_index + 1; j < argc; j++) { |
| 464 | 158 | char *copy = ap_strdup(argv[j]); | |
| 465 |
2/4✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 158 times.
|
158 | if (!copy || ap_strvec_push(unknown_args, copy) != 0) { |
| 466 | ✗ | free(copy); | |
| 467 | ✗ | free(positional_defs); | |
| 468 | ✗ | free(parsed); | |
| 469 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 470 | ✗ | return -1; | |
| 471 | } | ||
| 472 | } | ||
| 473 | 16 | token_index = argc; | |
| 474 | 16 | break; | |
| 475 | } | ||
| 476 | 18 | positional_only = true; | |
| 477 | 18 | token_index++; | |
| 478 | 18 | continue; | |
| 479 | } | ||
| 480 | |||
| 481 |
4/4✓ Branch 0 taken 1262 times.
✓ Branch 1 taken 78 times.
✓ Branch 3 taken 924 times.
✓ Branch 4 taken 338 times.
|
1340 | if (!positional_only && ap_token_has_prefix(parser, token)) { |
| 482 | int cluster_rc = | ||
| 483 | 924 | parse_short_cluster(parser, token, allow_unknown, parsed, err); | |
| 484 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 920 times.
|
924 | if (cluster_rc == 0) { |
| 485 | 4 | token_index++; | |
| 486 | 4 | continue; | |
| 487 | } | ||
| 488 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 912 times.
|
920 | if (cluster_rc < 0) { |
| 489 | 8 | free_parsed_storage(parser, parsed); | |
| 490 | 8 | free(positional_defs); | |
| 491 | 8 | free(parsed); | |
| 492 | 8 | return -1; | |
| 493 | } | ||
| 494 | |||
| 495 | 912 | const char *eq = strchr(token, '='); | |
| 496 | 912 | const char *inline_value = NULL; | |
| 497 | 912 | int def_index = -1; | |
| 498 |
3/4✓ Branch 0 taken 20 times.
✓ Branch 1 taken 892 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
912 | if (eq && eq != token) { |
| 499 | 20 | def_index = find_flag_index_n(parser, token, (size_t)(eq - token)); | |
| 500 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | if (def_index >= 0) { |
| 501 | 10 | inline_value = eq + 1; | |
| 502 | } | ||
| 503 | } else { | ||
| 504 | 892 | def_index = find_flag_index(parser, token); | |
| 505 | } | ||
| 506 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 908 times.
|
912 | if (def_index == -2) { |
| 507 | 4 | ap_error_set(err, AP_ERR_DUPLICATE_OPTION, token, | |
| 508 | "ambiguous option '%s'", token); | ||
| 509 | 4 | goto fail; | |
| 510 | } | ||
| 511 |
2/2✓ Branch 0 taken 436 times.
✓ Branch 1 taken 472 times.
|
908 | if (def_index < 0) { |
| 512 |
2/2✓ Branch 0 taken 432 times.
✓ Branch 1 taken 4 times.
|
436 | if (allow_unknown) { |
| 513 | 432 | char *copy = ap_strdup(token); | |
| 514 |
3/6✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 432 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 432 times.
|
864 | if (!copy || !unknown_args || |
| 515 | 432 | ap_strvec_push(unknown_args, copy) != 0) { | |
| 516 | ✗ | free(copy); | |
| 517 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, token, "out of memory"); | |
| 518 | ✗ | goto fail; | |
| 519 | } | ||
| 520 |
2/2✓ Branch 0 taken 428 times.
✓ Branch 1 taken 4 times.
|
432 | if (token_index + 1 < argc && |
| 521 |
3/4✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 18 times.
|
856 | strcmp(argv[token_index + 1], "--") != 0 && |
| 522 | 428 | find_flag_index(parser, argv[token_index + 1]) < 0 && | |
| 523 |
2/2✓ Branch 1 taken 140 times.
✓ Branch 2 taken 270 times.
|
410 | !ap_token_has_prefix(parser, argv[token_index + 1])) { |
| 524 | 140 | char *next_copy = ap_strdup(argv[token_index + 1]); | |
| 525 |
2/4✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 140 times.
|
140 | if (!next_copy || ap_strvec_push(unknown_args, next_copy) != 0) { |
| 526 | ✗ | free(next_copy); | |
| 527 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, token, "out of memory"); | |
| 528 | ✗ | goto fail; | |
| 529 | } | ||
| 530 | 140 | token_index += 2; | |
| 531 | 140 | continue; | |
| 532 | } | ||
| 533 | 292 | token_index++; | |
| 534 | 292 | continue; | |
| 535 | } | ||
| 536 | 4 | ap_error_set(err, AP_ERR_UNKNOWN_OPTION, token, "unknown option '%s'", | |
| 537 | token); | ||
| 538 | 4 | goto fail; | |
| 539 | } | ||
| 540 |
4/4✓ Branch 0 taken 172 times.
✓ Branch 1 taken 300 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 170 times.
|
644 | if (parsed[def_index].seen && !action_allows_multiple_occurrences( |
| 541 | 172 | parser->defs[def_index].opts.action)) { | |
| 542 | 2 | ap_error_set(err, AP_ERR_DUPLICATE_OPTION, token, | |
| 543 | "duplicate option '%s'", token); | ||
| 544 | 2 | goto fail; | |
| 545 | } | ||
| 546 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 468 times.
|
470 | if (push_token(parsed, def_index, token, err) != 0) { |
| 547 | 2 | goto fail; | |
| 548 | } | ||
| 549 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 456 times.
|
468 | if (consume_optional_values(parser, argc, argv, &token_index, def_index, |
| 550 | inline_value, parsed, err) != 0) { | ||
| 551 | 12 | free_parsed_storage(parser, parsed); | |
| 552 | 12 | free(positional_defs); | |
| 553 | 12 | free(parsed); | |
| 554 | 12 | return -1; | |
| 555 | } | ||
| 556 | 456 | parsed[def_index].seen = true; | |
| 557 | 456 | token_index++; | |
| 558 | 456 | continue; | |
| 559 | } | ||
| 560 | |||
| 561 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 416 times.
|
416 | if (ap_strvec_push(positionals, ap_strdup(token)) != 0) { |
| 562 | ✗ | free_parsed_storage(parser, parsed); | |
| 563 | ✗ | free(positional_defs); | |
| 564 | ✗ | free(parsed); | |
| 565 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, token, "out of memory"); | |
| 566 | ✗ | return -1; | |
| 567 | } | ||
| 568 | 416 | token_index++; | |
| 569 | } | ||
| 570 | |||
| 571 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 286 times.
|
462 | for (i = 0; i < positional_defs_count; i++) { |
| 572 | 176 | const ap_arg_def *def = &parser->defs[positional_defs[i]]; | |
| 573 | 176 | int values_left = positionals->count - positional_cursor; | |
| 574 | 176 | int min_after = remaining_min_required(parser, positional_defs, | |
| 575 | positional_defs_count, i + 1); | ||
| 576 | 176 | int take = 0; | |
| 577 | |||
| 578 |
4/6✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
176 | switch (def->opts.nargs) { |
| 579 | 132 | case AP_NARGS_ONE: | |
| 580 | 132 | take = values_left > 0 ? 1 : 0; | |
| 581 | 132 | break; | |
| 582 | ✗ | case AP_NARGS_OPTIONAL: | |
| 583 | ✗ | take = values_left > min_after ? 1 : 0; | |
| 584 | ✗ | break; | |
| 585 | 24 | case AP_NARGS_ZERO_OR_MORE: | |
| 586 | 24 | take = values_left - min_after; | |
| 587 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
|
24 | if (take < 0) { |
| 588 | 2 | take = 0; | |
| 589 | } | ||
| 590 | 24 | break; | |
| 591 | 2 | case AP_NARGS_ONE_OR_MORE: | |
| 592 | 2 | take = values_left - min_after; | |
| 593 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (take < 1) { |
| 594 | char label[96]; | ||
| 595 | 2 | ap_error_label_for_arg(def, label, sizeof(label)); | |
| 596 | 2 | ap_error_set(err, AP_ERR_INVALID_NARGS, ap_error_argument_name(def), | |
| 597 | "%s requires at least one value", label); | ||
| 598 | 2 | goto fail; | |
| 599 | } | ||
| 600 | ✗ | break; | |
| 601 | 18 | case AP_NARGS_FIXED: | |
| 602 | 18 | take = def->opts.nargs_count; | |
| 603 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (values_left < take) { |
| 604 | char label[96]; | ||
| 605 | 4 | ap_error_label_for_arg(def, label, sizeof(label)); | |
| 606 | 4 | ap_error_set(err, AP_ERR_INVALID_NARGS, ap_error_argument_name(def), | |
| 607 | "%s requires exactly %d values", label, | ||
| 608 | 4 | def->opts.nargs_count); | |
| 609 | 4 | goto fail; | |
| 610 | } | ||
| 611 | 14 | break; | |
| 612 | } | ||
| 613 | |||
| 614 |
3/4✓ Branch 0 taken 350 times.
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 350 times.
✗ Branch 3 not taken.
|
520 | while (take-- > 0 && positional_cursor < positionals->count) { |
| 615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
|
350 | if (push_token(parsed, positional_defs[i], |
| 616 | 350 | positionals->items[positional_cursor], err) != 0) { | |
| 617 | ✗ | goto fail; | |
| 618 | } | ||
| 619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
|
350 | if (push_value(parsed, positional_defs[i], |
| 620 | 350 | positionals->items[positional_cursor], err) != 0) { | |
| 621 | ✗ | goto fail; | |
| 622 | } | ||
| 623 | 350 | positional_cursor++; | |
| 624 | } | ||
| 625 | } | ||
| 626 | |||
| 627 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 264 times.
|
286 | if (positional_cursor < positionals->count) { |
| 628 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
22 | if (allow_unknown && unknown_args) { |
| 629 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | while (positional_cursor < positionals->count) { |
| 630 | 6 | char *extra = ap_strdup(positionals->items[positional_cursor]); | |
| 631 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
|
6 | if (!extra || ap_strvec_push(unknown_args, extra) != 0) { |
| 632 | ✗ | free(extra); | |
| 633 | ✗ | ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory"); | |
| 634 | ✗ | goto fail; | |
| 635 | } | ||
| 636 | 6 | positional_cursor++; | |
| 637 | } | ||
| 638 | 4 | free(positional_defs); | |
| 639 | 4 | *out_parsed = parsed; | |
| 640 | 4 | return 0; | |
| 641 | } | ||
| 642 | 18 | ap_error_set(err, AP_ERR_UNEXPECTED_POSITIONAL, | |
| 643 | 18 | positionals->items[positional_cursor], | |
| 644 | "unexpected positional argument '%s'", | ||
| 645 | 18 | positionals->items[positional_cursor]); | |
| 646 | 18 | goto fail; | |
| 647 | } | ||
| 648 | |||
| 649 | 264 | free(positional_defs); | |
| 650 | 264 | *out_parsed = parsed; | |
| 651 | 264 | return 0; | |
| 652 | |||
| 653 | 36 | fail: { | |
| 654 | 36 | free_parsed_storage(parser, parsed); | |
| 655 | 36 | free(positional_defs); | |
| 656 | 36 | free(parsed); | |
| 657 | 36 | return -1; | |
| 658 | } | ||
| 659 | } | ||
| 660 |