aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/aws-c-common/source/command_line_parser.c
blob: bf2db81e0a0fdd7c5d46e269f30d10fde0a45b9a (plain) (blame)
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
/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */
#include <aws/common/byte_buf.h>
#include <aws/common/command_line_parser.h>

#include <ctype.h>

int aws_cli_optind = 1;
int aws_cli_opterr = -1;
int aws_cli_optopt = 0;
bool aws_cli_on_arg = false;

const char *aws_cli_optarg = NULL;
const char *aws_cli_positional_arg = NULL;

static const struct aws_cli_option *s_find_option_from_char(
    const struct aws_cli_option *longopts,
    char search_for,
    int *longindex) {
    int index = 0;
    const struct aws_cli_option *option = &longopts[index];

    while (option->val != 0 || option->name) {
        if (option->val == search_for) {
            if (longindex) {
                *longindex = index;
            }
            return option;
        }

        option = &longopts[++index];
    }

    return NULL;
}

AWS_COMMON_API void aws_cli_reset_state(void) {
    aws_cli_optind = 1;
    aws_cli_opterr = -1;
    aws_cli_optopt = 0;
    aws_cli_on_arg = false;

    aws_cli_optarg = NULL;
    aws_cli_positional_arg = NULL;
}

static const struct aws_cli_option *s_find_option_from_c_str(
    const struct aws_cli_option *longopts,
    const char *search_for,
    int *longindex) {
    int index = 0;
    const struct aws_cli_option *option = &longopts[index];

    while (option->name || option->val != 0) {
        if (option->name) {
            if (option->name && !strcmp(search_for, option->name)) {
                if (longindex) {
                    *longindex = index;
                }
                return option;
            }
        }

        option = &longopts[++index];
    }

    return NULL;
}

int aws_cli_getopt_long(
    int argc,
    char *const argv[],
    const char *optstring,
    const struct aws_cli_option *longopts,
    int *longindex) {
    aws_cli_optarg = NULL;

    if (aws_cli_optind >= argc) {
        return -1;
    }

    char first_char = argv[aws_cli_optind][0];
    char second_char = argv[aws_cli_optind][1];
    char *option_start = NULL;
    const struct aws_cli_option *option = NULL;
    bool positional_arg_encountered = false;

    if (first_char == '-' && second_char != '-') {
        aws_cli_on_arg = true;
        positional_arg_encountered = false;
        option_start = &argv[aws_cli_optind][1];
        option = s_find_option_from_char(longopts, *option_start, longindex);
    } else if (first_char == '-' && second_char == '-') {
        aws_cli_on_arg = true;
        positional_arg_encountered = false;
        option_start = &argv[aws_cli_optind][2];
        option = s_find_option_from_c_str(longopts, option_start, longindex);
    } else {
        if (!aws_cli_on_arg) {
            aws_cli_positional_arg = argv[aws_cli_optind];
            positional_arg_encountered = true;
        } else {
            aws_cli_on_arg = false;
            aws_cli_positional_arg = NULL;
        }
    }

    aws_cli_optind++;
    if (option) {
        bool has_arg = false;
        aws_cli_on_arg = false;
        aws_cli_positional_arg = NULL;

        char *opt_value = memchr(optstring, option->val, strlen(optstring) + 1);
        if (!opt_value) {
            return '?';
        }

        if (opt_value[1] == ':') {
            has_arg = true;
        }

        if (has_arg) {
            if (aws_cli_optind >= argc) {
                return '?';
            }

            aws_cli_optarg = argv[aws_cli_optind++];
        }

        return option->val;
    }

    /* start of text to indicate we just have a text argument. */
    return positional_arg_encountered ? 0x02 : '?';
}

int aws_cli_dispatch_on_subcommand(
    int argc,
    char *const argv[],
    struct aws_cli_subcommand_dispatch *dispatch_table,
    int table_length,
    void *user_data) {
    if (argc >= 2) {
        struct aws_byte_cursor arg_name = aws_byte_cursor_from_c_str(argv[1]);
        for (int i = 0; i < table_length; ++i) {
            struct aws_byte_cursor cmd_name = aws_byte_cursor_from_c_str(dispatch_table[i].command_name);

            if (aws_byte_cursor_eq_ignore_case(&arg_name, &cmd_name)) {
                return dispatch_table[i].subcommand_fn(argc - 1, &argv[1], (const char *)arg_name.ptr, user_data);
            }
        }

        return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
    }

    return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}