💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

929 lines
22 KiB

7 years ago
  1. /*
  2. * Dirent interface for Microsoft Visual Studio
  3. * Version 1.21
  4. *
  5. * Copyright (C) 2006-2012 Toni Ronkko
  6. * This file is part of dirent. Dirent may be freely distributed
  7. * under the MIT license. For all details and documentation, see
  8. * https://github.com/tronkko/dirent
  9. */
  10. #ifndef DIRENT_H
  11. #define DIRENT_H
  12. /*
  13. * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
  14. * Windows Sockets 2.0.
  15. */
  16. #ifndef WIN32_LEAN_AND_MEAN
  17. # define WIN32_LEAN_AND_MEAN
  18. #endif
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <stdarg.h>
  22. #include <wchar.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <malloc.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <errno.h>
  29. /* Indicates that d_type field is available in dirent structure */
  30. #define _DIRENT_HAVE_D_TYPE
  31. /* Indicates that d_namlen field is available in dirent structure */
  32. #define _DIRENT_HAVE_D_NAMLEN
  33. /* Entries missing from MSVC 6.0 */
  34. #if !defined(FILE_ATTRIBUTE_DEVICE)
  35. # define FILE_ATTRIBUTE_DEVICE 0x40
  36. #endif
  37. /* File type and permission flags for stat(), general mask */
  38. #if !defined(S_IFMT)
  39. # define S_IFMT _S_IFMT
  40. #endif
  41. /* Directory bit */
  42. #if !defined(S_IFDIR)
  43. # define S_IFDIR _S_IFDIR
  44. #endif
  45. /* Character device bit */
  46. #if !defined(S_IFCHR)
  47. # define S_IFCHR _S_IFCHR
  48. #endif
  49. /* Pipe bit */
  50. #if !defined(S_IFFIFO)
  51. # define S_IFFIFO _S_IFFIFO
  52. #endif
  53. /* Regular file bit */
  54. #if !defined(S_IFREG)
  55. # define S_IFREG _S_IFREG
  56. #endif
  57. /* Read permission */
  58. #if !defined(S_IREAD)
  59. # define S_IREAD _S_IREAD
  60. #endif
  61. /* Write permission */
  62. #if !defined(S_IWRITE)
  63. # define S_IWRITE _S_IWRITE
  64. #endif
  65. /* Execute permission */
  66. #if !defined(S_IEXEC)
  67. # define S_IEXEC _S_IEXEC
  68. #endif
  69. /* Pipe */
  70. #if !defined(S_IFIFO)
  71. # define S_IFIFO _S_IFIFO
  72. #endif
  73. /* Block device */
  74. #if !defined(S_IFBLK)
  75. # define S_IFBLK 0
  76. #endif
  77. /* Link */
  78. #if !defined(S_IFLNK)
  79. # define S_IFLNK 0
  80. #endif
  81. /* Socket */
  82. #if !defined(S_IFSOCK)
  83. # define S_IFSOCK 0
  84. #endif
  85. /* Read user permission */
  86. #if !defined(S_IRUSR)
  87. # define S_IRUSR S_IREAD
  88. #endif
  89. /* Write user permission */
  90. #if !defined(S_IWUSR)
  91. # define S_IWUSR S_IWRITE
  92. #endif
  93. /* Execute user permission */
  94. #if !defined(S_IXUSR)
  95. # define S_IXUSR 0
  96. #endif
  97. /* Read group permission */
  98. #if !defined(S_IRGRP)
  99. # define S_IRGRP 0
  100. #endif
  101. /* Write group permission */
  102. #if !defined(S_IWGRP)
  103. # define S_IWGRP 0
  104. #endif
  105. /* Execute group permission */
  106. #if !defined(S_IXGRP)
  107. # define S_IXGRP 0
  108. #endif
  109. /* Read others permission */
  110. #if !defined(S_IROTH)
  111. # define S_IROTH 0
  112. #endif
  113. /* Write others permission */
  114. #if !defined(S_IWOTH)
  115. # define S_IWOTH 0
  116. #endif
  117. /* Execute others permission */
  118. #if !defined(S_IXOTH)
  119. # define S_IXOTH 0
  120. #endif
  121. /* Maximum length of file name */
  122. #if !defined(PATH_MAX)
  123. # define PATH_MAX MAX_PATH
  124. #endif
  125. #if !defined(FILENAME_MAX)
  126. # define FILENAME_MAX MAX_PATH
  127. #endif
  128. #if !defined(NAME_MAX)
  129. # define NAME_MAX FILENAME_MAX
  130. #endif
  131. /* File type flags for d_type */
  132. #define DT_UNKNOWN 0
  133. #define DT_REG S_IFREG
  134. #define DT_DIR S_IFDIR
  135. #define DT_FIFO S_IFIFO
  136. #define DT_SOCK S_IFSOCK
  137. #define DT_CHR S_IFCHR
  138. #define DT_BLK S_IFBLK
  139. #define DT_LNK S_IFLNK
  140. /* Macros for converting between st_mode and d_type */
  141. #define IFTODT(mode) ((mode) & S_IFMT)
  142. #define DTTOIF(type) (type)
  143. /*
  144. * File type macros. Note that block devices, sockets and links cannot be
  145. * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
  146. * only defined for compatibility. These macros should always return false
  147. * on Windows.
  148. */
  149. #if !defined(S_ISFIFO)
  150. # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
  151. #endif
  152. #if !defined(S_ISDIR)
  153. # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
  154. #endif
  155. #if !defined(S_ISREG)
  156. # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
  157. #endif
  158. #if !defined(S_ISLNK)
  159. # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
  160. #endif
  161. #if !defined(S_ISSOCK)
  162. # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
  163. #endif
  164. #if !defined(S_ISCHR)
  165. # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
  166. #endif
  167. #if !defined(S_ISBLK)
  168. # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
  169. #endif
  170. /* Return the exact length of d_namlen without zero terminator */
  171. #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
  172. /* Return number of bytes needed to store d_namlen */
  173. #define _D_ALLOC_NAMLEN(p) (PATH_MAX)
  174. #ifdef __cplusplus
  175. extern "C" {
  176. #endif
  177. /* Wide-character version */
  178. struct _wdirent {
  179. /* Always zero */
  180. long d_ino;
  181. /* Structure size */
  182. unsigned short d_reclen;
  183. /* Length of name without \0 */
  184. size_t d_namlen;
  185. /* File type */
  186. int d_type;
  187. /* File name */
  188. wchar_t d_name[PATH_MAX];
  189. };
  190. typedef struct _wdirent _wdirent;
  191. struct _WDIR {
  192. /* Current directory entry */
  193. struct _wdirent ent;
  194. /* Private file data */
  195. WIN32_FIND_DATAW data;
  196. /* True if data is valid */
  197. int cached;
  198. /* Win32 search handle */
  199. HANDLE handle;
  200. /* Initial directory name */
  201. wchar_t *patt;
  202. };
  203. typedef struct _WDIR _WDIR;
  204. static _WDIR *_wopendir (const wchar_t *dirname);
  205. static struct _wdirent *_wreaddir (_WDIR *dirp);
  206. static int _wclosedir (_WDIR *dirp);
  207. static void _wrewinddir (_WDIR* dirp);
  208. /* For compatibility with Symbian */
  209. #define wdirent _wdirent
  210. #define WDIR _WDIR
  211. #define wopendir _wopendir
  212. #define wreaddir _wreaddir
  213. #define wclosedir _wclosedir
  214. #define wrewinddir _wrewinddir
  215. /* Multi-byte character versions */
  216. struct dirent {
  217. /* Always zero */
  218. long d_ino;
  219. /* Structure size */
  220. unsigned short d_reclen;
  221. /* Length of name without \0 */
  222. size_t d_namlen;
  223. /* File type */
  224. int d_type;
  225. /* File name */
  226. char d_name[PATH_MAX];
  227. };
  228. typedef struct dirent dirent;
  229. struct DIR {
  230. struct dirent ent;
  231. struct _WDIR *wdirp;
  232. };
  233. typedef struct DIR DIR;
  234. static DIR *opendir (const char *dirname);
  235. static struct dirent *readdir (DIR *dirp);
  236. static int closedir (DIR *dirp);
  237. static void rewinddir (DIR* dirp);
  238. /* Internal utility functions */
  239. static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
  240. static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
  241. static int dirent_mbstowcs_s(
  242. size_t *pReturnValue,
  243. wchar_t *wcstr,
  244. size_t sizeInWords,
  245. const char *mbstr,
  246. size_t count);
  247. static int dirent_wcstombs_s(
  248. size_t *pReturnValue,
  249. char *mbstr,
  250. size_t sizeInBytes,
  251. const wchar_t *wcstr,
  252. size_t count);
  253. static void dirent_set_errno (int error);
  254. /*
  255. * Open directory stream DIRNAME for read and return a pointer to the
  256. * internal working area that is used to retrieve individual directory
  257. * entries.
  258. */
  259. static _WDIR*
  260. _wopendir(
  261. const wchar_t *dirname)
  262. {
  263. _WDIR *dirp = NULL;
  264. int error;
  265. /* Must have directory name */
  266. if (dirname == NULL || dirname[0] == '\0') {
  267. dirent_set_errno (ENOENT);
  268. return NULL;
  269. }
  270. /* Allocate new _WDIR structure */
  271. dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
  272. if (dirp != NULL) {
  273. DWORD n;
  274. /* Reset _WDIR structure */
  275. dirp->handle = INVALID_HANDLE_VALUE;
  276. dirp->patt = NULL;
  277. dirp->cached = 0;
  278. /* Compute the length of full path plus zero terminator
  279. *
  280. * Note that on WinRT there's no way to convert relative paths
  281. * into absolute paths, so just assume its an absolute path.
  282. */
  283. # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
  284. n = wcslen(dirname);
  285. # else
  286. n = GetFullPathNameW (dirname, 0, NULL, NULL);
  287. # endif
  288. /* Allocate room for absolute directory name and search pattern */
  289. dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
  290. if (dirp->patt) {
  291. /*
  292. * Convert relative directory name to an absolute one. This
  293. * allows rewinddir() to function correctly even when current
  294. * working directory is changed between opendir() and rewinddir().
  295. *
  296. * Note that on WinRT there's no way to convert relative paths
  297. * into absolute paths, so just assume its an absolute path.
  298. */
  299. # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
  300. wcsncpy_s(dirp->patt, n+1, dirname, n);
  301. # else
  302. n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
  303. # endif
  304. if (n > 0) {
  305. wchar_t *p;
  306. /* Append search pattern \* to the directory name */
  307. p = dirp->patt + n;
  308. if (dirp->patt < p) {
  309. switch (p[-1]) {
  310. case '\\':
  311. case '/':
  312. case ':':
  313. /* Directory ends in path separator, e.g. c:\temp\ */
  314. /*NOP*/;
  315. break;
  316. default:
  317. /* Directory name doesn't end in path separator */
  318. *p++ = '\\';
  319. }
  320. }
  321. *p++ = '*';
  322. *p = '\0';
  323. /* Open directory stream and retrieve the first entry */
  324. if (dirent_first (dirp)) {
  325. /* Directory stream opened successfully */
  326. error = 0;
  327. } else {
  328. /* Cannot retrieve first entry */
  329. error = 1;
  330. dirent_set_errno (ENOENT);
  331. }
  332. } else {
  333. /* Cannot retrieve full path name */
  334. dirent_set_errno (ENOENT);
  335. error = 1;
  336. }
  337. } else {
  338. /* Cannot allocate memory for search pattern */
  339. error = 1;
  340. }
  341. } else {
  342. /* Cannot allocate _WDIR structure */
  343. error = 1;
  344. }
  345. /* Clean up in case of error */
  346. if (error && dirp) {
  347. _wclosedir (dirp);
  348. dirp = NULL;
  349. }
  350. return dirp;
  351. }
  352. /*
  353. * Read next directory entry. The directory entry is returned in dirent
  354. * structure in the d_name field. Individual directory entries returned by
  355. * this function include regular files, sub-directories, pseudo-directories
  356. * "." and ".." as well as volume labels, hidden files and system files.
  357. */
  358. static struct _wdirent*
  359. _wreaddir(
  360. _WDIR *dirp)
  361. {
  362. WIN32_FIND_DATAW *datap;
  363. struct _wdirent *entp;
  364. /* Read next directory entry */
  365. datap = dirent_next (dirp);
  366. if (datap) {
  367. size_t n;
  368. DWORD attr;
  369. /* Pointer to directory entry to return */
  370. entp = &dirp->ent;
  371. /*
  372. * Copy file name as wide-character string. If the file name is too
  373. * long to fit in to the destination buffer, then truncate file name
  374. * to PATH_MAX characters and zero-terminate the buffer.
  375. */
  376. n = 0;
  377. while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
  378. entp->d_name[n] = datap->cFileName[n];
  379. n++;
  380. }
  381. dirp->ent.d_name[n] = 0;
  382. /* Length of file name excluding zero terminator */
  383. entp->d_namlen = n;
  384. /* File type */
  385. attr = datap->dwFileAttributes;
  386. if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
  387. entp->d_type = DT_CHR;
  388. } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  389. entp->d_type = DT_DIR;
  390. } else {
  391. entp->d_type = DT_REG;
  392. }
  393. /* Reset dummy fields */
  394. entp->d_ino = 0;
  395. entp->d_reclen = sizeof (struct _wdirent);
  396. } else {
  397. /* Last directory entry read */
  398. entp = NULL;
  399. }
  400. return entp;
  401. }
  402. /*
  403. * Close directory stream opened by opendir() function. This invalidates the
  404. * DIR structure as well as any directory entry read previously by
  405. * _wreaddir().
  406. */
  407. static int
  408. _wclosedir(
  409. _WDIR *dirp)
  410. {
  411. int ok;
  412. if (dirp) {
  413. /* Release search handle */
  414. if (dirp->handle != INVALID_HANDLE_VALUE) {
  415. FindClose (dirp->handle);
  416. dirp->handle = INVALID_HANDLE_VALUE;
  417. }
  418. /* Release search pattern */
  419. if (dirp->patt) {
  420. free (dirp->patt);
  421. dirp->patt = NULL;
  422. }
  423. /* Release directory structure */
  424. free (dirp);
  425. ok = /*success*/0;
  426. } else {
  427. /* Invalid directory stream */
  428. dirent_set_errno (EBADF);
  429. ok = /*failure*/-1;
  430. }
  431. return ok;
  432. }
  433. /*
  434. * Rewind directory stream such that _wreaddir() returns the very first
  435. * file name again.
  436. */
  437. static void
  438. _wrewinddir(
  439. _WDIR* dirp)
  440. {
  441. if (dirp) {
  442. /* Release existing search handle */
  443. if (dirp->handle != INVALID_HANDLE_VALUE) {
  444. FindClose (dirp->handle);
  445. }
  446. /* Open new search handle */
  447. dirent_first (dirp);
  448. }
  449. }
  450. /* Get first directory entry (internal) */
  451. static WIN32_FIND_DATAW*
  452. dirent_first(
  453. _WDIR *dirp)
  454. {
  455. WIN32_FIND_DATAW *datap;
  456. /* Open directory and retrieve the first entry */
  457. dirp->handle = FindFirstFileExW(
  458. dirp->patt, FindExInfoStandard, &dirp->data,
  459. FindExSearchNameMatch, NULL, 0);
  460. if (dirp->handle != INVALID_HANDLE_VALUE) {
  461. /* a directory entry is now waiting in memory */
  462. datap = &dirp->data;
  463. dirp->cached = 1;
  464. } else {
  465. /* Failed to re-open directory: no directory entry in memory */
  466. dirp->cached = 0;
  467. datap = NULL;
  468. }
  469. return datap;
  470. }
  471. /* Get next directory entry (internal) */
  472. static WIN32_FIND_DATAW*
  473. dirent_next(
  474. _WDIR *dirp)
  475. {
  476. WIN32_FIND_DATAW *p;
  477. /* Get next directory entry */
  478. if (dirp->cached != 0) {
  479. /* A valid directory entry already in memory */
  480. p = &dirp->data;
  481. dirp->cached = 0;
  482. } else if (dirp->handle != INVALID_HANDLE_VALUE) {
  483. /* Get the next directory entry from stream */
  484. if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
  485. /* Got a file */
  486. p = &dirp->data;
  487. } else {
  488. /* The very last entry has been processed or an error occured */
  489. FindClose (dirp->handle);
  490. dirp->handle = INVALID_HANDLE_VALUE;
  491. p = NULL;
  492. }
  493. } else {
  494. /* End of directory stream reached */
  495. p = NULL;
  496. }
  497. return p;
  498. }
  499. /*
  500. * Open directory stream using plain old C-string.
  501. */
  502. static DIR*
  503. opendir(
  504. const char *dirname)
  505. {
  506. struct DIR *dirp;
  507. int error;
  508. /* Must have directory name */
  509. if (dirname == NULL || dirname[0] == '\0') {
  510. dirent_set_errno (ENOENT);
  511. return NULL;
  512. }
  513. /* Allocate memory for DIR structure */
  514. dirp = (DIR*) malloc (sizeof (struct DIR));
  515. if (dirp) {
  516. wchar_t wname[PATH_MAX];
  517. size_t n;
  518. /* Convert directory name to wide-character string */
  519. error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX);
  520. if (!error) {
  521. /* Open directory stream using wide-character name */
  522. dirp->wdirp = _wopendir (wname);
  523. if (dirp->wdirp) {
  524. /* Directory stream opened */
  525. error = 0;
  526. } else {
  527. /* Failed to open directory stream */
  528. error = 1;
  529. }
  530. } else {
  531. /*
  532. * Cannot convert file name to wide-character string. This
  533. * occurs if the string contains invalid multi-byte sequences or
  534. * the output buffer is too small to contain the resulting
  535. * string.
  536. */
  537. error = 1;
  538. }
  539. } else {
  540. /* Cannot allocate DIR structure */
  541. error = 1;
  542. }
  543. /* Clean up in case of error */
  544. if (error && dirp) {
  545. free (dirp);
  546. dirp = NULL;
  547. }
  548. return dirp;
  549. }
  550. /*
  551. * Read next directory entry.
  552. *
  553. * When working with text consoles, please note that file names returned by
  554. * readdir() are represented in the default ANSI code page while any output to
  555. * console is typically formatted on another code page. Thus, non-ASCII
  556. * characters in file names will not usually display correctly on console. The
  557. * problem can be fixed in two ways: (1) change the character set of console
  558. * to 1252 using chcp utility and use Lucida Console font, or (2) use
  559. * _cprintf function when writing to console. The _cprinf() will re-encode
  560. * ANSI strings to the console code page so many non-ASCII characters will
  561. * display correcly.
  562. */
  563. static struct dirent*
  564. readdir(
  565. DIR *dirp)
  566. {
  567. WIN32_FIND_DATAW *datap;
  568. struct dirent *entp;
  569. /* Read next directory entry */
  570. datap = dirent_next (dirp->wdirp);
  571. if (datap) {
  572. size_t n;
  573. int error;
  574. /* Attempt to convert file name to multi-byte string */
  575. error = dirent_wcstombs_s(
  576. &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
  577. /*
  578. * If the file name cannot be represented by a multi-byte string,
  579. * then attempt to use old 8+3 file name. This allows traditional
  580. * Unix-code to access some file names despite of unicode
  581. * characters, although file names may seem unfamiliar to the user.
  582. *
  583. * Be ware that the code below cannot come up with a short file
  584. * name unless the file system provides one. At least
  585. * VirtualBox shared folders fail to do this.
  586. */
  587. if (error && datap->cAlternateFileName[0] != '\0') {
  588. error = dirent_wcstombs_s(
  589. &n, dirp->ent.d_name, PATH_MAX,
  590. datap->cAlternateFileName, PATH_MAX);
  591. }
  592. if (!error) {
  593. DWORD attr;
  594. /* Initialize directory entry for return */
  595. entp = &dirp->ent;
  596. /* Length of file name excluding zero terminator */
  597. entp->d_namlen = n - 1;
  598. /* File attributes */
  599. attr = datap->dwFileAttributes;
  600. if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
  601. entp->d_type = DT_CHR;
  602. } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  603. entp->d_type = DT_DIR;
  604. } else {
  605. entp->d_type = DT_REG;
  606. }
  607. /* Reset dummy fields */
  608. entp->d_ino = 0;
  609. entp->d_reclen = sizeof (struct dirent);
  610. } else {
  611. /*
  612. * Cannot convert file name to multi-byte string so construct
  613. * an errornous directory entry and return that. Note that
  614. * we cannot return NULL as that would stop the processing
  615. * of directory entries completely.
  616. */
  617. entp = &dirp->ent;
  618. entp->d_name[0] = '?';
  619. entp->d_name[1] = '\0';
  620. entp->d_namlen = 1;
  621. entp->d_type = DT_UNKNOWN;
  622. entp->d_ino = 0;
  623. entp->d_reclen = 0;
  624. }
  625. } else {
  626. /* No more directory entries */
  627. entp = NULL;
  628. }
  629. return entp;
  630. }
  631. /*
  632. * Close directory stream.
  633. */
  634. static int
  635. closedir(
  636. DIR *dirp)
  637. {
  638. int ok;
  639. if (dirp) {
  640. /* Close wide-character directory stream */
  641. ok = _wclosedir (dirp->wdirp);
  642. dirp->wdirp = NULL;
  643. /* Release multi-byte character version */
  644. free (dirp);
  645. } else {
  646. /* Invalid directory stream */
  647. dirent_set_errno (EBADF);
  648. ok = /*failure*/-1;
  649. }
  650. return ok;
  651. }
  652. /*
  653. * Rewind directory stream to beginning.
  654. */
  655. static void
  656. rewinddir(
  657. DIR* dirp)
  658. {
  659. /* Rewind wide-character string directory stream */
  660. _wrewinddir (dirp->wdirp);
  661. }
  662. /* Convert multi-byte string to wide character string */
  663. static int
  664. dirent_mbstowcs_s(
  665. size_t *pReturnValue,
  666. wchar_t *wcstr,
  667. size_t sizeInWords,
  668. const char *mbstr,
  669. size_t count)
  670. {
  671. int error;
  672. #if defined(_MSC_VER) && _MSC_VER >= 1400
  673. /* Microsoft Visual Studio 2005 or later */
  674. error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
  675. #else
  676. /* Older Visual Studio or non-Microsoft compiler */
  677. size_t n;
  678. /* Convert to wide-character string (or count characters) */
  679. n = mbstowcs (wcstr, mbstr, sizeInWords);
  680. if (!wcstr || n < count) {
  681. /* Zero-terminate output buffer */
  682. if (wcstr && sizeInWords) {
  683. if (n >= sizeInWords) {
  684. n = sizeInWords - 1;
  685. }
  686. wcstr[n] = 0;
  687. }
  688. /* Length of resuting multi-byte string WITH zero terminator */
  689. if (pReturnValue) {
  690. *pReturnValue = n + 1;
  691. }
  692. /* Success */
  693. error = 0;
  694. } else {
  695. /* Could not convert string */
  696. error = 1;
  697. }
  698. #endif
  699. return error;
  700. }
  701. /* Convert wide-character string to multi-byte string */
  702. static int
  703. dirent_wcstombs_s(
  704. size_t *pReturnValue,
  705. char *mbstr,
  706. size_t sizeInBytes, /* max size of mbstr */
  707. const wchar_t *wcstr,
  708. size_t count)
  709. {
  710. int error;
  711. #if defined(_MSC_VER) && _MSC_VER >= 1400
  712. /* Microsoft Visual Studio 2005 or later */
  713. error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
  714. #else
  715. /* Older Visual Studio or non-Microsoft compiler */
  716. size_t n;
  717. /* Convert to multi-byte string (or count the number of bytes needed) */
  718. n = wcstombs (mbstr, wcstr, sizeInBytes);
  719. if (!mbstr || n < count) {
  720. /* Zero-terminate output buffer */
  721. if (mbstr && sizeInBytes) {
  722. if (n >= sizeInBytes) {
  723. n = sizeInBytes - 1;
  724. }
  725. mbstr[n] = '\0';
  726. }
  727. /* Length of resulting multi-bytes string WITH zero-terminator */
  728. if (pReturnValue) {
  729. *pReturnValue = n + 1;
  730. }
  731. /* Success */
  732. error = 0;
  733. } else {
  734. /* Cannot convert string */
  735. error = 1;
  736. }
  737. #endif
  738. return error;
  739. }
  740. /* Set errno variable */
  741. static void
  742. dirent_set_errno(
  743. int error)
  744. {
  745. #if defined(_MSC_VER) && _MSC_VER >= 1400
  746. /* Microsoft Visual Studio 2005 and later */
  747. _set_errno (error);
  748. #else
  749. /* Non-Microsoft compiler or older Microsoft compiler */
  750. errno = error;
  751. #endif
  752. }
  753. #ifdef __cplusplus
  754. }
  755. #endif
  756. #endif /*DIRENT_H*/