ReactOS 0.4.16-dev-853-g88d9285
argv_wildcards.cpp
Go to the documentation of this file.
1/***
2*wild.c - wildcard expander
3*
4* Copyright (c) Microsoft Corporation. All rights reserved.
5*
6*Purpose:
7* expands wildcards in argv
8*
9* handles '*' (none or more of any char) and '?' (exactly one char)
10*
11*
12*******************************************************************************/
13
14#include <corecrt_internal.h>
15#include <ctype.h>
17#include <limits.h>
18#include <mbstring.h>
19#include <stddef.h>
20#include <stdlib.h>
21#include <string.h>
23
24
25
26namespace
27{
28 template <typename Character>
30 {
31 public:
32
33 argument_list() throw() : _first(nullptr), _last(nullptr), _end(nullptr) { }
34
35 size_t size() const throw() { return _last - _first; }
36 Character** begin() const throw() { return _first; }
37 Character** end() const throw() { return _last; }
38
39 errno_t append(Character* const element) throw()
40 {
41 errno_t const expand_status = expand_if_necessary();
42 if (expand_status != 0)
43 {
45 return expand_status;
46 }
47
48 *_last++ = element;
49 return 0;
50 }
51
52 Character** detach() throw()
53 {
54 _last = nullptr;
55 _end = nullptr;
56
57 Character** const first = _first;
58 _first = nullptr;
59 return first;
60 }
61
63 {
64 for (auto it = _first; it != _last; ++it)
65 _free_crt(*it);
66
67 _free_crt(_first);
68 }
69
70 private:
71
72 argument_list(argument_list const&) throw(); // not implemented
73 argument_list& operator=(argument_list const&) throw(); // not implemented
74
76 {
77 // If there is already room for more elements, just return:
78 if (_last != _end)
79 {
80 return 0;
81 }
82 // If the list has not yet had an array allocated for it, allocate one:
83 if (!_first)
84 {
85 size_t const initial_count = 4;
86
87 _first = _calloc_crt_t(Character*, initial_count).detach();
88 if (!_first)
89 return ENOMEM;
90
91 _last = _first;
92 _end = _first + initial_count;
93 return 0;
94 }
95 // Otherwise, double the size of the array:
96 else
97 {
98 size_t const old_count = _end - _first;
99 if (old_count > SIZE_MAX / 2)
100 return ENOMEM;
101
102 size_t const new_count = old_count * 2;
103 __crt_unique_heap_ptr<Character*> new_array(_recalloc_crt_t(Character*, _first, new_count));
104 if (!new_array)
105 return ENOMEM;
106
107 _first = new_array.detach();
108 _last = _first + old_count;
109 _end = _first + new_count;
110 return 0;
111 }
112 }
113
114 Character** _first;
115 Character** _last;
116 Character** _end;
117 };
118}
119
121static char*
123 _In_z_ char* const current) throw()
124{
125 return reinterpret_cast<char*>(_mbsdec(
126 reinterpret_cast<unsigned char*>(first),
127 reinterpret_cast<unsigned char*>(current)));
128}
129
130static wchar_t* previous_character(_In_reads_(0) wchar_t*, _In_reads_(0) wchar_t* const current) throw()
131{
132 return current - 1;
133}
134
135
136
137template <typename Character>
139 _In_z_ Character const* const file_name,
140 _In_z_ Character const* const directory,
141 size_t const directory_length,
142 argument_list<Character>& buffer
143 ) throw()
144{
145 typedef __crt_char_traits<Character> traits;
146
147 size_t const file_name_count = traits::tcslen(file_name) + 1;
148 if (file_name_count > SIZE_MAX - directory_length)
149 return ENOMEM;
150
151 size_t const required_count = directory_length + file_name_count + 1;
152 __crt_unique_heap_ptr<Character> argument_buffer(_calloc_crt_t(Character, required_count));
153
154 if (directory_length > 0)
155 {
156 _ERRCHECK(traits::tcsncpy_s(argument_buffer.get(), required_count, directory, directory_length));
157 }
158
159 _ERRCHECK(traits::tcsncpy_s(
160 argument_buffer.get() + directory_length,
161 required_count - directory_length,
162 file_name,
163 file_name_count));
164
165 return buffer.append(argument_buffer.detach());
166}
167
168
169static wchar_t * get_wide(__crt_internal_win32_buffer<wchar_t> * const dest, char * const source)
170{
172 source,
173 *dest,
175 );
176
177 if (cvt1 != 0)
178 {
179 return nullptr;
180 }
181
182 return dest->data();
183};
184
185static wchar_t * get_wide(__crt_internal_win32_buffer<wchar_t> *, wchar_t * const source)
186{
187 return source;
188}
189
190static char * get_file_name(__crt_internal_win32_buffer<char> * const dest, wchar_t * const source)
191{
193 source,
194 *dest,
196 );
197
198 if (cvt != 0)
199 {
200 return nullptr;
201 }
202
203 return dest->data();
204}
205
207{
208 return source;
209}
210
211template <typename Character>
213 Character* const argument,
214 Character* const wildcard,
215 argument_list<Character>& buffer
216 ) throw()
217{
218 typedef __crt_char_traits<Character> traits;
219 typedef typename traits::win32_find_data_type find_data_type;
220
221 auto const is_directory_separator = [](Character const c) { return c == '/' || c == '\\' || c == ':'; };
222
223 // Find the first slash or colon before the wildcard:
224 Character* it = wildcard;
225 while (it != argument && !is_directory_separator(*it))
226 {
227 it = previous_character(argument, it);
228 }
229
230 // If we found a colon that can't form a drive name (e.g. it can't be 'D:'),
231 // then just add the argument as-is (we don't know how to expand it):
232 if (*it == ':' && it != argument + 1)
233 {
234 return copy_and_add_argument_to_buffer(argument, static_cast<Character*>(nullptr), 0, buffer);
235 }
236
237 size_t const directory_length = is_directory_separator(*it)
238 ? it - argument + 1 // it points to the separator, so add 1 to include it.
239 : 0;
240
241 // Try to begin the find operation:
242 WIN32_FIND_DATAW findFileDataW;
244
245 __crt_findfile_handle const find_handle(::FindFirstFileExW(
246 get_wide(&wide_file_name, argument),
248 &findFileDataW,
250 nullptr,
251 0));
252
253 // If the find operation failed, there was no match, so just add the argument:
255 {
256 return copy_and_add_argument_to_buffer(argument, static_cast<Character*>(nullptr), 0, buffer);
257 }
258
259 size_t const old_argument_count = buffer.size();
260
261 do
262 {
264 Character* const file_name = get_file_name(&character_buffer, findFileDataW.cFileName);
265 // Skip . and ..:
266 if (file_name[0] == '.' && file_name[1] == '\0')
267 {
268 continue;
269 }
270
271 if (file_name[0] == '.' && file_name[1] == '.' && file_name[2] == '\0')
272 {
273 continue;
274 }
275
276 errno_t const add_status = copy_and_add_argument_to_buffer(file_name, argument, directory_length, buffer);
277 if (add_status != 0)
278 {
279 return add_status;
280 }
281 }
282 while (::FindNextFileW(find_handle.get(), &findFileDataW));
283
284 // If we didn't add any arguments to the buffer, then we're done:
285 size_t const new_argument_count = buffer.size();
286 if (old_argument_count == new_argument_count)
287 {
288 return 0;
289 }
290
291 // If we did add new arguments, let's helpfully sort them:
292 qsort(
293 buffer.begin() + old_argument_count,
294 new_argument_count - old_argument_count,
295 sizeof(Character*),
296 [](void const* lhs, void const* rhs) -> int
297 {
298 if (lhs < rhs) { return -1; }
299 if (lhs > rhs) { return 1; }
300 return 0;
301 });
302
303 return 0;
304}
305
306
307template <typename Character>
308static errno_t common_expand_argv_wildcards(Character** const argv, Character*** const result) throw()
309{
310 typedef __crt_char_traits<Character> traits;
311
313 *result = nullptr;
314
315 argument_list<Character> expansion_buffer;
316 for (Character** it = argv; *it != nullptr; ++it)
317 {
318 Character const wildcard_characters[] = { '*', '?', '\0' };
319 Character* const wildcard = traits::tcspbrk(*it, wildcard_characters);
320
321 // If no wildcard characters were found in the argument string, just
322 // append it to the list and continue on. Otherwise, do the expansion:
323 if (!wildcard)
324 {
325 errno_t const append_status = copy_and_add_argument_to_buffer(
326 *it,
327 static_cast<Character*>(nullptr),
328 0,
329 expansion_buffer);
330
331 if (append_status != 0)
332 return append_status;
333 }
334 else
335 {
336 errno_t const expand_status = expand_argument_wildcards(*it, wildcard, expansion_buffer);
337 if (expand_status != 0)
338 return expand_status;
339 }
340 }
341
342 // Now that we've accumulated the expanded arguments into the expansion
343 // buffer, we want to re-pack them in the form used by the argv parser,
344 // in a single array, with everything "concatenated" together.
345 size_t const argument_count = expansion_buffer.size() + 1;
346 size_t character_count = 0;
347 for (auto it = expansion_buffer.begin(); it != expansion_buffer.end(); ++it)
348 character_count += traits::tcslen(*it) + 1;
349
350 __crt_unique_heap_ptr<unsigned char> expanded_argv(__acrt_allocate_buffer_for_argv(
351 argument_count,
353 sizeof(Character)));
354
355 if (!expanded_argv)
356 return -1;
357
358 Character** const argument_first = reinterpret_cast<Character**>(expanded_argv.get());
359 Character* const character_first = reinterpret_cast<Character*>(
360 expanded_argv.get() +
361 argument_count * sizeof(Character*));
362
363 Character** argument_it = argument_first;
364 Character* character_it = character_first;
365 for (auto it = expansion_buffer.begin(); it != expansion_buffer.end(); ++it)
366 {
367 size_t const count = traits::tcslen(*it) + 1;
368
369 _ERRCHECK(traits::tcsncpy_s(
370 character_it,
371 character_count - (character_it - character_first),
372 *it,
373 count));
374
375 *argument_it++ = character_it;
376 character_it += count;
377 }
378
379 *result = reinterpret_cast<Character**>(expanded_argv.detach());
380 return 0;
381}
382
383extern "C" errno_t __acrt_expand_narrow_argv_wildcards(char** const argv, char*** const result)
384{
386}
387
388extern "C" errno_t __acrt_expand_wide_argv_wildcards(wchar_t** const argv, wchar_t*** const result)
389{
391}
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
unsigned char *__cdecl __acrt_allocate_buffer_for_argv(size_t const argument_count, size_t const character_count, size_t const character_size)
static errno_t expand_argument_wildcards(Character *const argument, Character *const wildcard, argument_list< Character > &buffer)
static errno_t copy_and_add_argument_to_buffer(_In_z_ Character const *const file_name, _In_z_ Character const *const directory, size_t const directory_length, argument_list< Character > &buffer)
static _Check_return_ char * previous_character(_In_reads_z_(current - first+1) char *const first, _In_z_ char *const current)
static wchar_t * get_wide(__crt_internal_win32_buffer< wchar_t > *const dest, char *const source)
static errno_t common_expand_argv_wildcards(Character **const argv, Character ***const result)
errno_t __acrt_expand_wide_argv_wildcards(wchar_t **const argv, wchar_t ***const result)
errno_t __acrt_expand_narrow_argv_wildcards(char **const argv, char ***const result)
argument_list & operator=(argument_list const &)
_In_ size_t character_count
#define _ERRCHECK(e)
errno_t __acrt_mbs_to_wcs_cp(char const *const null_terminated_input_string, __crt_win32_buffer< wchar_t, ResizePolicy > &win32_buffer, unsigned int const code_page)
errno_t __acrt_wcs_to_mbs_cp(wchar_t const *const null_terminated_input_string, __crt_win32_buffer< char, ResizePolicy > &win32_buffer, unsigned int const code_page)
unsigned int __acrt_get_utf8_acp_compatibility_codepage()
void __cdecl qsort(_Inout_updates_bytes_(_NumOfElements *_SizeOfElements) void *_Base, _In_ size_t _NumOfElements, _In_ size_t _SizeOfElements, _In_ int(__cdecl *_PtFuncCompare)(const void *, const void *))
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const _In_ bool const _Inout_ __crt_cached_ptd_host &ptd throw()
Definition: cvt.cpp:119
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
HANDLE WINAPI FindFirstFileExW(IN LPCWSTR lpFileName, IN FINDEX_INFO_LEVELS fInfoLevelId, OUT LPVOID lpFindFileData, IN FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, IN DWORD dwAdditionalFlags)
Definition: find.c:649
static char * cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag)
Definition: fcvtbuf.c:45
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
const GLint * first
Definition: glext.h:5794
GLuint64EXT * result
Definition: glext.h:11304
_Check_return_ _CRTIMP unsigned char *__cdecl _mbsdec(_In_reads_z_(_Pos-_Start+1) const unsigned char *_Start, _In_z_ const unsigned char *_Pos)
#define _free_crt
#define _VALIDATE_RETURN_ERRCODE(expr, errorcode)
#define c
Definition: ke_i.h:80
if(dx< 0)
Definition: linetemp.h:194
struct task_struct * current
Definition: linux.c:32
static char * dest
Definition: rtl.c:135
static LPCWSTR file_name
Definition: protocol.c:147
#define argv
Definition: mplay32.c:18
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _In_z_
Definition: no_sal2.h:164
#define _Check_return_
Definition: no_sal2.h:60
#define _In_reads_z_(s)
Definition: no_sal2.h:172
#define get_file_name
Definition: regproc.h:51
#define SIZE_MAX
Definition: compat.h:66
errno_t const cvt1
Definition: strftime.cpp:139
int errno_t
Definition: corecrt.h:615
@ FindExSearchNameMatch
Definition: winbase.h:1159
@ FindExInfoStandard
Definition: winbase.h:1153