1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "nstackx_getopt.h"
17 #include "nstackx_error.h"
18 #include "nstackx_log.h"
19 
20 #define TAG "nStackXGetOpt"
21 #define NSTACK_GETOPT_MAX_ARGC 100
22 
NstackInitGetOptMsg(NstackGetOptMsg * optMsg)23 int32_t NstackInitGetOptMsg(NstackGetOptMsg *optMsg)
24 {
25     if (optMsg == NULL) {
26         LOGE(TAG, "optMsg is NULL");
27         return NSTACKX_EFAILED;
28     }
29     optMsg->argvIdx = 1;
30     optMsg->argvOffset = 1;
31     optMsg->attachArg = NULL;
32     return NSTACKX_EOK;
33 }
34 
GetOptCheckInputArg(NstackGetOptMsg * optMsg,int argc,const char * const * argv)35 static int32_t GetOptCheckInputArg(NstackGetOptMsg *optMsg, int argc, const char *const *argv)
36 {
37     if (optMsg->argvIdx >= argc || argv[optMsg->argvIdx][0] != '-' || argv[optMsg->argvIdx][1] == '\0') {
38         return NSTACKX_EFAILED;
39     } else if (!strcmp(argv[optMsg->argvIdx], "--")) {
40         optMsg->argvIdx++;
41         return NSTACKX_EFAILED;
42     }
43     return NSTACKX_EOK;
44 }
45 
GetOptCheckCurrentOpt(NstackGetOptMsg * optMsg,int32_t currentOpt,char * currentOptIdxInOpts,char nextChar)46 static int32_t GetOptCheckCurrentOpt(NstackGetOptMsg *optMsg, int32_t currentOpt,
47     char *currentOptIdxInOpts, char nextChar)
48 {
49     if (currentOpt == ':' || currentOptIdxInOpts == NULL) {
50         LOGE(TAG, ": illegal option -- %c", currentOpt);
51         optMsg->argvOffset++;
52         if (nextChar == '\0') {
53             optMsg->argvIdx++;
54             optMsg->argvOffset = 1;
55         }
56         return NSTACKX_EFAILED;
57     }
58     return NSTACKX_EOK;
59 }
60 
GetOptParseAttachArg(NstackGetOptMsg * optMsg,int32_t argc,const char * const * argv,char currentOpt,const char * currentOptIdxInOpts)61 static int32_t GetOptParseAttachArg(NstackGetOptMsg *optMsg, int32_t argc, const char *const *argv,
62     char currentOpt, const char *currentOptIdxInOpts)
63 {
64     if (*(currentOptIdxInOpts + 1) == ':') {
65         if (argv[optMsg->argvIdx][optMsg->argvOffset + 1] != '\0') {
66             optMsg->attachArg = &argv[optMsg->argvIdx++][optMsg->argvOffset + 1];
67         } else if (++optMsg->argvIdx >= argc) {
68             LOGE(TAG, ": option requires an argument -- %c", currentOpt);
69             optMsg->argvOffset = 1;
70             return NSTACKX_EFAILED;
71         } else {
72             optMsg->attachArg = argv[optMsg->argvIdx++];
73         }
74         optMsg->argvOffset = 1;
75     } else {
76         if (argv[optMsg->argvIdx][++(optMsg->argvOffset)] == '\0') {
77             optMsg->argvOffset = 1;
78             optMsg->argvIdx++;
79         }
80         optMsg->attachArg = NULL;
81     }
82     return NSTACKX_EOK;
83 }
84 
NstackCheckArg(const NstackGetOptMsg * optMsg,int32_t argc,const char * const * argv)85 static int32_t NstackCheckArg(const NstackGetOptMsg *optMsg, int32_t argc, const char *const *argv)
86 {
87     if (optMsg == NULL) {
88         LOGE(TAG, "optMsg is NULL");
89         return NSTACKX_EFAILED;
90     }
91     if (argc <= 1 || argc > NSTACK_GETOPT_MAX_ARGC) {
92         LOGE(TAG, "argc is invalid %u", argc);
93         return NSTACKX_EFAILED;
94     }
95     if (argv == NULL) {
96         LOGE(TAG, "argv is NULL");
97         return NSTACKX_EFAILED;
98     }
99     int32_t i;
100     for (i = 0; i < argc; i++) {
101         if (argv[i] == NULL) {
102             LOGE(TAG, "argv[%d] is NULL", i);
103             return NSTACKX_EFAILED;
104         }
105     }
106     return NSTACKX_EOK;
107 }
108 
NstackGetOpt(NstackGetOptMsg * optMsg,int32_t argc,const char * const * argv,const char * opts)109 int32_t NstackGetOpt(NstackGetOptMsg *optMsg, int32_t argc, const char *const *argv, const char *opts)
110 {
111     if (NstackCheckArg(optMsg, argc, argv) != NSTACKX_EOK) {
112         return NSTACK_GETOPT_END_OF_STR;
113     }
114     int32_t currentOpt;
115     if (optMsg->argvOffset == 1 && GetOptCheckInputArg(optMsg, argc, argv) != NSTACKX_EOK) {
116         return NSTACK_GETOPT_END_OF_STR;
117     }
118     currentOpt = argv[optMsg->argvIdx][optMsg->argvOffset];
119     char *currentOptIdxInOpts = strchr(opts, currentOpt);
120     if (GetOptCheckCurrentOpt(optMsg, currentOpt, currentOptIdxInOpts,
121         argv[optMsg->argvIdx][optMsg->argvOffset + 1]) != NSTACKX_EOK) {
122         return NSTACK_GETOPT_UNKNOW_OPT;
123     }
124     if (GetOptParseAttachArg(optMsg, argc, argv, currentOpt, currentOptIdxInOpts) != NSTACKX_EOK) {
125         return NSTACK_GETOPT_UNKNOW_OPT;
126     }
127     return currentOpt;
128 }
129 
NstackGetOptArgs(const NstackGetOptMsg * optMsg)130 const char *NstackGetOptArgs(const NstackGetOptMsg *optMsg)
131 {
132     if (optMsg == NULL) {
133         LOGE(TAG, "optMsg is NULL");
134         return NULL;
135     }
136     return optMsg->attachArg;
137 }
138 
139