1 /*
2  * GetOpt functions
3  *
4  * Copyright (C) 2011-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <narrow_string.h>
24 #include <system_string.h>
25 #include <types.h>
26 #include <wide_string.h>
27 
28 #if defined( HAVE_STDLIB_H ) || defined( WINAPI )
29 #include <stdlib.h>
30 #endif
31 
32 #include "evt_test_getopt.h"
33 #include "evt_test_libcnotify.h"
34 
35 #if !defined( HAVE_GETOPT )
36 
37 /* The option index
38  * Start with argument 1 (argument 0 is the program name)
39  */
40 int optind = 1;
41 
42 /* The current option argument
43  */
44 system_character_t *optarg = NULL;
45 
46 /* Value to indicate the current option
47  */
48 system_integer_t optopt = 0;
49 
50 /* The next option in a group
51  */
52 system_character_t *next_option = NULL;
53 
54 /* Get the program options
55  * Function for platforms that do not have the getopt function
56  * Returns the option character processed, or -1 on error,
57  * ? if the option was not in the options string, : if the option argument was missing
58  */
evt_test_getopt(int argument_count,system_character_t * const argument_values[],const system_character_t * options_string)59 system_integer_t evt_test_getopt(
60                   int argument_count,
61                   system_character_t * const argument_values[],
62                   const system_character_t *options_string )
63 {
64 	system_character_t *argument_value = NULL;
65 	system_character_t *option_value   = NULL;
66 	static char *function              = "evt_test_getopt";
67 	size_t options_string_length       = 0;
68 
69 	if( next_option != NULL )
70 	{
71 		argument_value = next_option;
72 		next_option    = NULL;
73 	}
74 	else if( optind >= argument_count )
75 	{
76 		return( (system_integer_t) -1 );
77 	}
78 	else
79 	{
80 		argument_value = argument_values[ optind ];
81 
82 		/* Check if the argument value is not an empty string
83 		 */
84 		if( *argument_value == (system_character_t) '\0' )
85 		{
86 			return( (system_integer_t) -1 );
87 		}
88 		/* Check if the first character is a option marker '-'
89 		 */
90 		if( *argument_value != (system_character_t) '-' )
91 		{
92 			return( (system_integer_t) -1 );
93 		}
94 		argument_value++;
95 
96 		/* Check if long options are provided '--'
97 		 */
98 		if( *argument_value == (system_character_t) '-' )
99 		{
100 			optind++;
101 
102 			return( (system_integer_t) -1 );
103 		}
104 	}
105 	options_string_length = system_string_length(
106 	                         options_string );
107 
108 	optopt       = *argument_value;
109 	option_value = system_string_search_character(
110 	                options_string,
111 	                optopt,
112 	                options_string_length );
113 
114 	argument_value++;
115 
116 	/* Check if an argument was specified or that the option was not found
117 	 * in the option string
118 	 */
119 	if( ( optopt == (system_integer_t) ':' )
120 	 || ( option_value == NULL ) )
121 	{
122 		if( *argument_value == (system_character_t) '\0' )
123 		{
124 			optind++;
125 		}
126 		if( ( *options_string != (system_character_t) ':' )
127 		 && ( optopt != (system_integer_t) '?' ) )
128 		{
129 			libcnotify_printf(
130 			 "%s: no such option: %" PRIc_SYSTEM ".\n",
131 			 function,
132 			 optopt );
133 		}
134 		return( (system_integer_t) '?' );
135 	}
136 	option_value++;
137 
138 	/* Check if no option argument is required
139 	 */
140 	if( *option_value != (system_character_t) ':' )
141 	{
142 		optarg = NULL;
143 
144 		if( *argument_value == (system_character_t) '\0' )
145 		{
146 			optind++;
147 		}
148 		else
149 		{
150 			/* Multiple options are grouped
151 			 */
152 			next_option = argument_value;
153 		}
154 	}
155 	/* Check if the argument is right after the option flag with no space in between
156 	 */
157 	else if( *argument_value != (system_character_t) '\0' )
158 	{
159 		optarg = argument_value;
160 
161 		optind++;
162 	}
163 	else
164 	{
165 		optind++;
166 
167 		/* Check if the argument was provided as the next argument value
168 		 */
169 		if( argument_count <= optind )
170 		{
171 			if( *option_value == ':' )
172 			{
173 				return( (system_integer_t) ':' );
174 			}
175 			libcnotify_printf(
176 			 "%s: option: %" PRIc_SYSTEM " requires an argument.\n",
177 			 function,
178 			 optopt );
179 
180 			return( (system_integer_t) '?' );
181 		}
182 		optarg = argument_values[ optind ];
183 
184 		optind++;
185 	}
186 	return( optopt );
187 }
188 
189 #endif /* !defined( HAVE_GETOPT ) */
190 
191