Coverage Report

Created: 2023-12-13 20:08

/src/php-src/main/getopt.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright (c) The PHP Group                                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to version 3.01 of the PHP license,      |
6
   | that is bundled with this package in the file LICENSE, and is        |
7
   | available through the world-wide-web at the following url:           |
8
   | https://www.php.net/license/3_01.txt                                 |
9
   | If you did not receive a copy of the PHP license and are unable to   |
10
   | obtain it through the world-wide-web, please send a note to          |
11
   | license@php.net so we can mail you a copy immediately.               |
12
   +----------------------------------------------------------------------+
13
   | Author: Marcus Boerger <helly@php.net>                               |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#include <stdio.h>
18
#include <string.h>
19
#include <assert.h>
20
#include <stdlib.h>
21
#include "php_getopt.h"
22
23
0
#define OPTERRCOLON (1)
24
0
#define OPTERRNF (2)
25
0
#define OPTERRARG (3)
26
27
// Print error message to stderr and return -2 to distinguish it from '?' command line option.
28
static int php_opt_error(int argc, char * const *argv, int optint, int optchr, int err, int show_err) /* {{{ */
29
0
{
30
0
  if (show_err)
31
0
  {
32
0
    fprintf(stderr, "Error in argument %d, char %d: ", optint, optchr+1);
33
0
    switch(err)
34
0
    {
35
0
    case OPTERRCOLON:
36
0
      fprintf(stderr, ": in flags\n");
37
0
      break;
38
0
    case OPTERRNF:
39
0
      fprintf(stderr, "option not found %c\n", argv[optint][optchr]);
40
0
      break;
41
0
    case OPTERRARG:
42
0
      fprintf(stderr, "no argument for option %c\n", argv[optint][optchr]);
43
0
      break;
44
0
    default:
45
0
      fprintf(stderr, "unknown\n");
46
0
      break;
47
0
    }
48
0
  }
49
0
  return PHP_GETOPT_INVALID_ARG;
50
0
}
51
/* }}} */
52
53
PHPAPI int php_optidx = -1;
54
55
PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start) /* {{{ */
56
0
{
57
0
  static int optchr = 0;
58
0
  static int dash = 0; /* have already seen the - */
59
0
  static char **prev_optarg = NULL;
60
61
0
  php_optidx = -1;
62
63
0
  if(prev_optarg && prev_optarg != optarg) {
64
    /* reset the state */
65
0
    optchr = 0;
66
0
    dash = 0;
67
0
  }
68
0
  prev_optarg = optarg;
69
70
0
  if (*optind >= argc) {
71
0
    return(EOF);
72
0
  }
73
0
  if (!dash) {
74
0
    if ((argv[*optind][0] !=  '-')) {
75
0
      return(EOF);
76
0
    } else {
77
0
      if (!argv[*optind][1])
78
0
      {
79
        /*
80
        * use to specify stdin. Need to let pgm process this and
81
        * the following args
82
        */
83
0
        return(EOF);
84
0
      }
85
0
    }
86
0
  }
87
0
  if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-')) {
88
0
    const char *pos;
89
0
    size_t arg_end = strlen(argv[*optind])-1;
90
91
    /* '--' indicates end of args if not followed by a known long option name */
92
0
    if (argv[*optind][2] == '\0') {
93
0
      (*optind)++;
94
0
      return(EOF);
95
0
    }
96
97
0
    arg_start = 2;
98
99
    /* Check for <arg>=<val> */
100
0
    if ((pos = php_memnstr(&argv[*optind][arg_start], "=", 1, argv[*optind]+arg_end)) != NULL) {
101
0
      arg_end = pos-&argv[*optind][arg_start];
102
0
      arg_start++;
103
0
    } else {
104
0
      arg_end--;
105
0
    }
106
107
0
    while (1) {
108
0
      php_optidx++;
109
0
      if (opts[php_optidx].opt_char == '-') {
110
0
        (*optind)++;
111
0
        return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
112
0
      } else if (opts[php_optidx].opt_name && !strncmp(&argv[*optind][2], opts[php_optidx].opt_name, arg_end) && arg_end == strlen(opts[php_optidx].opt_name)) {
113
0
        break;
114
0
      }
115
0
    }
116
117
0
    optchr = 0;
118
0
    dash = 0;
119
0
    arg_start += (int)strlen(opts[php_optidx].opt_name);
120
0
  } else {
121
0
    if (!dash) {
122
0
      dash = 1;
123
0
      optchr = 1;
124
0
    }
125
    /* Check if the guy tries to do a -: kind of flag */
126
0
    if (argv[*optind][optchr] == ':') {
127
0
      dash = 0;
128
0
      (*optind)++;
129
0
      return (php_opt_error(argc, argv, *optind-1, optchr, OPTERRCOLON, show_err));
130
0
    }
131
0
    arg_start = 1 + optchr;
132
0
  }
133
0
  if (php_optidx < 0) {
134
0
    while (1) {
135
0
      php_optidx++;
136
0
      if (opts[php_optidx].opt_char == '-') {
137
0
        int errind = *optind;
138
0
        int errchr = optchr;
139
140
0
        if (!argv[*optind][optchr+1]) {
141
0
          dash = 0;
142
0
          (*optind)++;
143
0
        } else {
144
0
          optchr++;
145
0
          arg_start++;
146
0
        }
147
0
        return(php_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
148
0
      } else if (argv[*optind][optchr] == opts[php_optidx].opt_char) {
149
0
        break;
150
0
      }
151
0
    }
152
0
  }
153
0
  if (opts[php_optidx].need_param) {
154
    /* Check for cases where the value of the argument
155
    is in the form -<arg> <val>, -<arg>=<varl> or -<arg><val> */
156
0
    dash = 0;
157
0
    if (!argv[*optind][arg_start]) {
158
0
      (*optind)++;
159
0
      if (*optind == argc) {
160
        /* Was the value required or is it optional? */
161
0
        if (opts[php_optidx].need_param == 1) {
162
0
          return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
163
0
        }
164
      /* Optional value is not supported with -<arg> <val> style */
165
0
      } else if (opts[php_optidx].need_param == 1) {
166
0
        *optarg = argv[(*optind)++];
167
0
      }
168
0
    } else if (argv[*optind][arg_start] == '=') {
169
0
      arg_start++;
170
0
      *optarg = &argv[*optind][arg_start];
171
0
      (*optind)++;
172
0
    } else {
173
0
      *optarg = &argv[*optind][arg_start];
174
0
      (*optind)++;
175
0
    }
176
0
    return opts[php_optidx].opt_char;
177
0
  } else {
178
    /* multiple options specified as one (exclude long opts) */
179
0
    if (arg_start >= 2 && !((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))) {
180
0
      if (!argv[*optind][optchr+1])
181
0
      {
182
0
        dash = 0;
183
0
        (*optind)++;
184
0
      } else {
185
0
        optchr++;
186
0
      }
187
0
    } else {
188
0
      (*optind)++;
189
0
    }
190
0
    return opts[php_optidx].opt_char;
191
0
  }
192
0
  assert(0);
193
0
  return(0); /* never reached */
194
0
}
195
/* }}} */