SLikeNet  0.1.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
linux_adapter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2019, SLikeSoft UG (haftungsbeschränkt)
3  *
4  * This source code is licensed under the MIT-style license found in the
5  * license.txt file in the root directory of this source tree.
6  *
7  *
8  * This file defines adapters for all MS-specific functions used throughout SLikeNet.
9  */
10 
11 #ifdef __linux__
12 #include "slikenet/linux_adapter.h"
13 
14 #include <algorithm> // for std::max, std::min
15 #include <cerrno> // for errno
16 #include <cstdio> // for FILE, fopen, vsnprintf
17 #include <cstdlib> // for mbstowcs
18 #include <cstring> // for strcat, strcpy, strerror, strncat, strncpy
19 #include <cstdarg> // for va_start, va_end, va_list
20 #include <ctime> // for localtime, time_t
21 #include <cwchar> // for wcscat, wcscpy, wcslen
22 
23 errno_t fopen_s(FILE **pfile, const char *filename, const char *mode)
24 {
25  if ((pfile == nullptr) || (filename == nullptr) || (mode == nullptr)) {
26  return 22; // error: EINVAL
27  }
28 
29  FILE *file = fopen(filename, mode);
30  if (file == nullptr) {
31  return errno;
32  }
33 
34  *pfile = file;
35  return 0;
36 }
37 
38 errno_t localtime_s(struct tm *_tm, const time_t *time)
39 {
40  // #med - should actually also check for _*time > _MAX_TIME64_T according to MSDN, but can't seem to find the
41  // definition of _MAX_TIME64_T
42  if ((_tm == nullptr) || (time == nullptr) || (*time == 0)) {
43  if (_tm != nullptr) {
44  _tm->tm_hour = -1;
45  _tm->tm_isdst = -1;
46  _tm->tm_mday = -1;
47  _tm->tm_min = -1;
48  _tm->tm_mon = -1;
49  _tm->tm_sec = -1;
50  _tm->tm_wday = -1;
51  _tm->tm_yday = -1;
52  _tm->tm_year = -1;
53  }
54  return 22; // error: EINVAL
55  }
56 
57  struct tm *curTime = localtime(time);
58  *_tm = *curTime;
59 
60  return 0;
61 }
62 
63 errno_t mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count)
64 {
65  if ((mbstr == nullptr) || ((wcstr == nullptr) && (sizeInWords > 0)) || ((wcstr != nullptr) && (sizeInWords != 0))) {
66  if (wcstr != nullptr) {
67  wcstr[0] = L'\0'; // ensure 0-termination
68  }
69  return 22; // error: EINVAL
70  }
71 
72  size_t numMaxChars = sizeInWords;
73  if (count != _TRUNCATE) {
74  numMaxChars = std::min(numMaxChars, count);
75  }
76 
77  size_t numCharsWritten = mbstowcs(wcstr, mbstr, numMaxChars);
78  if (numCharsWritten == (size_t)-1) {
79  // invalid multibyte character encountered
80  if (pReturnValue != nullptr) {
81  *pReturnValue = 0;
82  }
83  if (wcstr != nullptr) {
84  wcstr[0] = L'\0'; // ensure 0-termination
85  }
86  return 42; // error: EILSEQ
87  }
88 
89  if (numCharsWritten == numMaxChars) {
90  if (wcstr != nullptr) {
91  wcstr[0] = L'\0'; // ensure 0-termination
92  }
93  return 34; // error: ERANGE
94  }
95 
96  if (pReturnValue != nullptr) {
97  *pReturnValue = numCharsWritten + 1; // chars written, including terminating null character
98  }
99 
100  // ensure we write a terminating null character (in case there was none in the original converted string)
101  if (wcstr != nullptr) {
102  wcstr[numCharsWritten] = L'\0'; // ensure 0-termination
103  }
104 
105  return 0;
106 }
107 
108 int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...)
109 {
110  if ((buffer == nullptr) || (sizeOfBuffer == 0) || (format == nullptr)) {
111  return -1;
112  }
113 
114  va_list arglist;
115  va_start(arglist, format);
116  int numCharsWritten = vsnprintf(buffer, sizeOfBuffer, format, arglist);
117  va_end(arglist);
118 
119  if (numCharsWritten == -1) {
120  buffer[0] = '\0'; // error occurred ensure terminating \0-character
121  return -1;
122  }
123 
124  if (numCharsWritten >= sizeOfBuffer) {
125  buffer[0] = '\0'; // buffer too small, write empty string to ensure terminating \0-char
126  }
127 
128  return numCharsWritten;
129 }
130 
131 errno_t strcat_s(char *strDestination, size_t numberOfElements, const char *strSource)
132 {
133  if ((strDestination == nullptr) || (strSource == nullptr)) {
134  if (strDestination != nullptr) {
135  strDestination[0] = '\0'; // ensure trailing \0 is written
136  }
137  return 22; // error: EINVAL
138  }
139 
140  if (numberOfElements == 0) {
141  strDestination[0] = '\0'; // ensure trailing \0 is written
142  return 34; // error: ERANGE
143  }
144 
145  const size_t destLen = strlen(strDestination);
146  const size_t sourceLen = strlen(strSource);
147  if ((destLen > numberOfElements - 1) || ((sourceLen > 0) && (destLen == numberOfElements - 1)) || (sourceLen > numberOfElements - destLen - 1)) {
148  strDestination[0] = '\0'; // ensure trailing \0 is written
149  return 34; // error: ERANGE
150  }
151 
152  (void)strcat(strDestination, strSource);
153  return 0;
154 }
155 
156 errno_t strcpy_s(char* strDestination, size_t numberOfElements, const char *strSource)
157 {
158  if ((strDestination == nullptr) || (strSource == nullptr)) {
159  if (strDestination != nullptr) {
160  strDestination[0] = '\0'; // ensure trailing \0 is written
161  }
162  return 22; // error: EINVAL
163  }
164 
165  if ((numberOfElements == 0) || (strlen(strSource) >= numberOfElements)) {
166  strDestination[0] = '\0'; // ensure trailing \0 is written
167  return 34; // error: ERANGE
168  }
169 
170  (void)strcpy(strDestination, strSource);
171  return 0;
172 }
173 
174 errno_t strerror_s(char* buffer, size_t numberOfElements, int errnum)
175 {
176  // check valid parameters
177  if ((buffer == nullptr) || (numberOfElements == 0)) {
178  return 22; // error: EINVAL
179  }
180 
181  const char *errorMessage = strerror(errnum);
182  return strcpy_s(buffer, numberOfElements, errorMessage);
183 }
184 
185 errno_t strncat_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
186 {
187  // check valid parameters
188  if ((strDest == nullptr) || (strSource == nullptr)) {
189  return 22; // error: EINVAL
190  }
191 
192  if (numberOfElements == 0) {
193  return 34; // error: ERANGE
194  }
195 
196  size_t charsToWrite;
197  const size_t sourceLen = strlen(strSource);
198  if (count == _TRUNCATE) {
199  charsToWrite = sourceLen;
200  }
201  else {
202  charsToWrite = std::min(count, sourceLen);
203  }
204 
205  const size_t destLen = strlen(strDest);
206  const size_t sizeLeft = numberOfElements - destLen;
207 
208  if (((count != _TRUNCATE) && (charsToWrite > sizeLeft - 1)) || ((sourceLen > 0) && (destLen == numberOfElements - 1))) {
209  strDest[0] = '\0'; // ensure trailing \0 is written
210  return 34; // error: ERANGE
211  }
212 
213  (void)strncat(strDest, strSource, charsToWrite);
214  return 0;
215 }
216 
217 errno_t strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
218 {
219  // check valid parameters
220  if ((numberOfElements == 0) || (strDest == nullptr) || (strSource == nullptr)) {
221  if (strDest != nullptr) {
222  strDest[0] = '\0'; // ensure trailing \0 is written
223  }
224  return 22; // error: EINVAL
225  }
226 
227  size_t numChars;
228  bool truncated = false;
229  if (count == _TRUNCATE) {
230  // if count == _TRUNCATE use the length of the source string
231  numChars = strlen(strSource);
232 
233  // ensure we are not exceeding numberOfElements
234  if (numChars >= numberOfElements) {
235  numChars = numberOfElements - 1;
236  truncated = true; // we are going to truncate the copied string
237  }
238  }
239  else {
240  // otherwise we use count, but have to check that the destination buffer is of sufficient size
241  if ((count > numberOfElements) || ((count == numberOfElements) && (strSource[count] != '\0'))) {
242  strDest[0] = '\0'; // ensure trailing \0 is written
243  return 34; // error: ERANGE
244  }
245  numChars = count;
246  }
247 
248  (void)strncpy(strDest, strSource, numChars);
249 
250  // enforce the trailing \0
251  strDest[numChars] = '\0';
252 
253  return truncated ? 80 : 0; // STRUNCATE, if we truncated the string, 0 otherwise
254 }
255 
256 int vsnprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, va_list argptr)
257 {
258  if ((buffer == nullptr) || (format == nullptr) || (sizeOfBuffer == 0)) {
259  return -1;
260  }
261 
262  size_t maxChars = sizeOfBuffer;
263  if (count != _TRUNCATE) {
264  if (count >= sizeOfBuffer) {
265  buffer[0] = '\0'; // ensure trailing \0 is written
266  return -1;
267  }
268  maxChars = count;
269  }
270 
271  int numCharsWritten = vsnprintf(buffer, maxChars, format, argptr);
272  if (numCharsWritten >= maxChars) {
273  if (count != _TRUNCATE) {
274  buffer[0] = '\0'; // buffer set to empty string
275  return -1;
276  }
277 
278  // truncation occurred, add terminating \0
279  buffer[sizeOfBuffer] = '\0';
280  }
281 
282  return numCharsWritten;
283 }
284 
285 errno_t wcscat_s(wchar_t *strDestination, size_t numberOfElements, const wchar_t *strSource)
286 {
287  if ((strDestination == nullptr) || (strSource == nullptr)) {
288  if (strDestination != nullptr) {
289  strDestination[0] = L'\0'; // ensure trailing \0 is written
290  }
291  return 22; // error: EINVAL
292  }
293 
294  if (numberOfElements == 0) {
295  strDestination[0] = L'\0'; // ensure trailing \0 is written
296  return 34; // error: ERANGE
297  }
298 
299  const size_t destLen = wcslen(strDestination);
300  const size_t sourceLen = wcslen(strSource);
301  if ((destLen > numberOfElements - 1) || ((sourceLen > 0) && (destLen == numberOfElements)) || (sourceLen > numberOfElements - destLen - 1)) {
302  strDestination[0] = L'\0'; // ensure trailing \0 is written
303  return 34; // error: ERANGE
304  }
305 
306  (void)wcscat(strDestination, strSource);
307  return 0;
308 }
309 
310 errno_t wcscpy_s(wchar_t* strDestination, size_t numberOfElements, const wchar_t *strSource)
311 {
312  if ((strDestination == nullptr) || (strSource == nullptr)) {
313  if (strDestination != nullptr) {
314  strDestination[0] = L'\0'; // ensure trailing \0 is written
315  }
316  return 22; // error: EINVAL
317  }
318 
319  if ((numberOfElements == 0) || (wcslen(strSource) >= numberOfElements)) {
320  strDestination[0] = L'\0'; // ensure trailing \0 is written
321  return 34; // error: ERANGE
322  }
323 
324  (void)wcscpy(strDestination, strSource);
325  return 0;
326 }
327 
328 #endif