[crt]
[reactos.git] / reactos / lib / sdk / crt / string / _tsplitpath_x.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * PURPOSE: CRT: implementation of __[w]splitpath[_s]
5 * PROGRAMMERS: Timo Kreuzer
6 */
7
8 #include <precomp.h>
9 #include <tchar.h>
10
11 #if IS_SECAPI
12 #define _FAILURE -1
13 #define _SUCCESS 0
14
15 _Check_return_wat_
16 _CRTIMP_ALTERNATIVE
17 errno_t
18 __cdecl
19 _tsplitpath_x(
20 _In_z_ const _TCHAR* path,
21 _Out_writes_opt_z_(drive_size) _TCHAR* drive,
22 _In_ size_t drive_size,
23 _Out_writes_opt_z_(dir_size) _TCHAR* dir,
24 _In_ size_t dir_size,
25 _Out_writes_opt_z_(fname_size) _TCHAR* fname,
26 _In_ size_t fname_size,
27 _Out_writes_opt_z_(ext_size) _TCHAR* ext,
28 _In_ size_t ext_size)
29 #else
30 #define _FAILURE
31 #define _SUCCESS
32
33 _CRT_INSECURE_DEPRECATE(_splitpath_s)
34 _CRTIMP
35 void
36 __cdecl
37 _tsplitpath_x(
38 _In_z_ const _TCHAR* path,
39 _Pre_maybenull_ _Post_z_ _TCHAR* drive,
40 _Pre_maybenull_ _Post_z_ _TCHAR* dir,
41 _Pre_maybenull_ _Post_z_ _TCHAR* fname,
42 _Pre_maybenull_ _Post_z_ _TCHAR* ext)
43 #endif
44 {
45 const _TCHAR *src, *dir_start, *file_start = 0, *ext_start = 0;
46 size_t count;
47 #if !IS_SECAPI
48 const size_t drive_size = INT_MAX, dir_size = INT_MAX,
49 fname_size = INT_MAX, ext_size = INT_MAX;
50 #endif
51
52 #if IS_SECAPI
53 /* Validate parameters */
54 if (MSVCRT_CHECK_PMT((path == NULL) ||
55 ((drive != NULL) && (drive_size == 0)) ||
56 ((dir != NULL) && (dir_size == 0)) ||
57 ((fname != NULL) && (fname_size == 0)) ||
58 ((ext != NULL) && (ext_size == 0))))
59 {
60 errno = EINVAL;
61 return -1;
62 }
63 #endif
64
65 /* Truncate all output strings */
66 if (drive) drive[0] = '\0';
67 if (dir) dir[0] = '\0';
68 if (fname) fname[0] = '\0';
69 if (ext) ext[0] = '\0';
70
71 #if WINVER >= 0x600
72 /* Check parameter */
73 if (!path)
74 {
75 #ifndef _LIBCNT_
76 _set_errno(EINVAL);
77 #endif
78 return _FAILURE;
79 }
80 #endif
81
82 _Analysis_assume_(path != 0);
83
84 #if WINVER == 0x600
85 /* Skip '\\?\' prefix */
86 if ((path[0] == '\\') && (path[1] == '\\') &&
87 (path[2] == '?') && (path[3] == '\\')) path += 4;
88 #endif
89
90 if (path[0] == '\0') return _FAILURE;
91
92 /* Check if we have a drive letter (only 1 char supported) */
93 if (path[1] == ':')
94 {
95 if (drive && (drive_size >= 3))
96 {
97 drive[0] = path[0];
98 drive[1] = ':';
99 drive[2] = '\0';
100 }
101 path += 2;
102 }
103
104 /* Scan the rest of the string */
105 dir_start = path;
106 while (*path != '\0')
107 {
108 /* Remember last path separator and last dot */
109 if ((*path == '\\') || (*path == '/')) file_start = path + 1;
110 if (*path == '.') ext_start = path;
111 path++;
112 }
113
114 /* Check if we got a file name / extension */
115 if (!file_start)
116 file_start = dir_start;
117 if (!ext_start || ext_start < file_start)
118 ext_start = path;
119
120 if (dir)
121 {
122 src = dir_start;
123 count = dir_size - 1;
124 while (src < file_start && count--) *dir++ = *src++;
125 *dir = '\0';
126 }
127
128 if (fname)
129 {
130 src = file_start;
131 count = fname_size - 1;
132 while (src < ext_start && count--) *fname++ = *src++;
133 *fname = '\0';
134 }
135
136 if (ext)
137 {
138 src = ext_start;
139 count = ext_size - 1;
140 while (*src != '\0' && count--) *ext++ = *src++;
141 *ext = '\0';
142 }
143
144 return _SUCCESS;
145 }
146