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