ReactOS 0.4.16-dev-1025-gd3456f5
getpath.cpp
Go to the documentation of this file.
1/***
2*getpath.c - extract a pathname from an environment variable
3*
4* Copyright (c) Microsoft Corporation. All rights reserved.
5*
6*Purpose:
7* Extract pathnames from a string of semicolon delimited pathnames
8* (generally the value of an environment variable such as PATH).
9*
10*******************************************************************************/
11
12#include <corecrt_internal.h>
13#include <stddef.h>
14
15/***
16*_getpath() - extract a pathname from a semicolon-delimited list of pathnames
17*
18*Purpose:
19* To extract the next pathname from a semicolon-delimited list of
20* pathnames (usually the value on an environment variable) and copy
21* it to a caller-specified buffer. No check is done to see if the path
22* is valid. The maximum number of characters copied to the buffer is
23* maxlen - 1 (and then a '\0' is appended).
24*
25*ifdef _HPFS_
26* If we hit a quoted string, then allow any characters inside.
27* For example, to put a semi-colon in a path, the user could have
28* an environment variable that looks like:
29*
30* PATH=C:\BIN;"D:\CRT\TOOLS;B1";C:\BINP
31*endif
32*
33* NOTE: Semi-colons in sequence are skipped over; pointers to 0-length
34* pathnames are NOT returned (this includes leading semi-colons).
35*
36* NOTE: If this routine is made user-callable, the near attribute
37* must be replaced by _LOAD_DS and the prototype moved from INTERNAL.H
38* to STDLIB.H. The source files MISC\SEARCHEN.C and EXEC\SPAWNVPE.C
39* will need to be recompiled, but should not require any changes.
40*
41*Entry:
42* src - Pointer to a string of 0 or more path specificiations,
43* delimited by semicolons (';'), and terminated by a null
44* character
45* dst - Pointer to the buffer where the next path specification is to
46* be copied
47* maxlen - Maximum number of characters to be copied, counting the
48* terminating null character. Note that a value of 0 is treated
49* as UINT_MAX + 1.
50*
51*Exit:
52* If a pathname is successfully extracted and copied, a pointer to the
53* first character of next pathname is returned (intervening semicolons
54* are skipped over). If the pathname is too long, as much as possible
55* is copied to the user-specified buffer and nullptr is returned.
56*
57* Note that the no check is made of the validity of the copied pathname.
58*
59*Exceptions:
60*
61*******************************************************************************/
62template <typename Character>
63_Success_(return != 0)
64static Character* __cdecl common_getpath(
65 _In_z_ Character const* const delimited_paths,
66 _Out_writes_z_(result_count) Character* const result,
67 size_t const result_count
69{
70 _VALIDATE_RETURN_NOEXC(result != nullptr, EINVAL, nullptr);
71
72 if (result_count > 0)
73 {
74 result[0] = '\0';
75 }
76
77 _VALIDATE_RETURN_NOEXC(result_count > 1, EINVAL, nullptr);
78
79 Character const* source_it = delimited_paths;
80
81 // Skip past any leading semicolons:
82 while (*source_it == ';')
83 {
84 ++source_it;
85 }
86
87 Character const* const source_first = source_it;
88
89 Character* result_it = result;
90 Character* const result_last = result + result_count - 1; // Leave room for \0
91
92#pragma warning(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_NULLTERMINATED) // 26018 Prefast is confused.
93 while (*source_it != '\0' && *source_it != ';')
94 {
95 if (*source_it == '"')
96 {
97 // We found a quote; copy all characters until we reach the matching
98 // end quote or the end of the string:
99 ++source_it; // Advance past opening quote
100
101 while (*source_it != '\0' && *source_it != '"')
102 {
103#pragma warning(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) // 26015 Prefast is confused.
104 *result_it++ = *source_it++;
105 if (result_it == result_last)
106 {
107 *result_it = '\0';
108 errno = ERANGE;
109 return nullptr;
110 }
111 }
112
113 if (*source_it != '\0')
114 {
115 ++source_it; // Advance past closing quote
116 }
117 }
118 else
119 {
120 *result_it++ = *source_it++;
121 if (result_it == result_last)
122 {
123 *result_it = '\0';
124 errno = ERANGE;
125 return nullptr;
126 }
127 }
128 }
129
130 // If we copied something and stopped because we reached a semicolon, skip
131 // any semicolons before returning:
132 while (*source_it == ';')
133 {
134 ++source_it;
135 }
136
137 *result_it = '\0';
138 return source_it == source_first
139 ? nullptr
140 : const_cast<Character*>(source_it);
141}
142
143extern "C" char* __cdecl __acrt_getpath(
144 char const* const delimited_paths,
145 char* const result,
146 size_t const result_count
147 )
148{
149 return common_getpath(delimited_paths, result, result_count);
150}
151
152extern "C" wchar_t* __cdecl __acrt_wgetpath(
153 wchar_t const* const delimited_paths,
154 wchar_t* const result,
155 size_t const result_count
156 )
157{
158 return common_getpath(delimited_paths, result, result_count);
159}
#define EINVAL
Definition: acclib.h:90
#define ERANGE
Definition: acclib.h:92
#define __cdecl
Definition: accygwin.h:79
return nullptr
Definition: expand.cpp:78
char *__cdecl __acrt_getpath(char const *const delimited_paths, char *const result, size_t const result_count)
Definition: getpath.cpp:143
size_t const result_count throw()
Definition: getpath.cpp:68
wchar_t *__cdecl __acrt_wgetpath(wchar_t const *const delimited_paths, wchar_t *const result, size_t const result_count)
Definition: getpath.cpp:152
GLuint64EXT * result
Definition: glext.h:11304
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
#define _Out_writes_z_(s)
Definition: no_sal2.h:180
#define _Success_(c)
Definition: no_sal2.h:84
#define _In_z_
Definition: no_sal2.h:164
#define errno
Definition: errno.h:18
#define const
Definition: zconf.h:233