192a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant// -*- C++ -*-
2efbe4067f225856814465913bf51e87ec8f17bdbHoward Hinnant//===----------------------- support/win32/support.h ----------------------===//
392a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant//
492a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant//                     The LLVM Compiler Infrastructure
592a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant//
692a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant// This file is dual licensed under the MIT and the University of Illinois Open
792a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant// Source Licenses. See LICENSE.TXT for details.
892a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant//
992a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant//===----------------------------------------------------------------------===//
1092a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant
119e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant#include <cstdarg> // va_start, va_end
129e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant#include <cstddef> // size_t
139e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant#include <cstdlib> // malloc
149e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant#include <cstdio>  // vsprintf, vsnprintf
159e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant#include <cstring> // strcpy, wcsncpy
169e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant#include <cwchar>  // mbstate_t
176cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant
189e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant// Some of these functions aren't standard or if they conform, the name does not.
199e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant
209e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnantint asprintf(char **sptr, const char *__restrict format, ...)
21efbe4067f225856814465913bf51e87ec8f17bdbHoward Hinnant{
22efbe4067f225856814465913bf51e87ec8f17bdbHoward Hinnant    va_list ap;
239e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant    va_start(ap, format);
249e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant    int result;
255ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    result = vasprintf(sptr, format, ap);
26efbe4067f225856814465913bf51e87ec8f17bdbHoward Hinnant    va_end(ap);
278db4acad3b67808114c495fc21d4db6e7e277087Howard Hinnant    return result;
28efbe4067f225856814465913bf51e87ec8f17bdbHoward Hinnant}
29a1985ebbc84c8f8536ce9e2003d43c4aa2603a56Howard Hinnant
305ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// Like sprintf, but when return value >= 0 it returns
315ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// a pointer to a malloc'd string in *sptr.
32a1985ebbc84c8f8536ce9e2003d43c4aa2603a56Howard Hinnant// If return >= 0, use free to delete *sptr.
339e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnantint vasprintf( char **sptr, const char *__restrict format, va_list ap )
3492a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant{
356cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant    *sptr = NULL;
365ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    // Query the count required.
375ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    int count = _vsnprintf( NULL, 0, format, ap );
385ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    if (count < 0)
395ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant        return count;
405ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    size_t buffer_size = static_cast<size_t>(count) + 1;
415ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    char* p = static_cast<char*>(malloc(buffer_size));
425ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    if ( ! p )
435ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant        return -1;
445ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    // If we haven't used exactly what was required, something is wrong.
455ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    // Maybe bug in vsnprintf. Report the error and return.
465ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    if (_vsnprintf(p, buffer_size, format, ap) != count) {
475ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant        free(p);
485ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant        return -1;
4992a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant    }
505ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    // All good. This is returning memory to the caller not freeing it.
515ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant    *sptr = p;
5292a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant    return count;
5392a07003b2ce449b22709fbd9b4f1e49b3a2fd3eHoward Hinnant}
546cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant
555ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// Returns >= 0: the number of wide characters found in the
565ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// multi byte sequence src (of src_size_bytes), that fit in the buffer dst
575ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// (of max_dest_chars elements size). The count returned excludes the
585ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// null terminator. When dst is NULL, no characters are copied
595ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// and no "out" parameters are updated.
60cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant// Returns (size_t) -1: an incomplete sequence encountered.
615ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// Leaves *src pointing the next character to convert or NULL
625ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// if a null character was converted from *src.
6378b6828f1420a266e02687685bc2ab993a54eaddHoward Hinnantsize_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
64cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant                   size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps )
656cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant{
66cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    const size_t terminated_sequence = static_cast<size_t>(0);
67cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    //const size_t invalid_sequence = static_cast<size_t>(-1);
68cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    const size_t incomplete_sequence = static_cast< size_t>(-2);
69cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
70cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t dest_converted = 0;
71cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t source_converted = 0;
72cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t source_remaining = src_size_bytes;
73cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t result = 0;
74cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    bool have_result = false;
75cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
76cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    while ( source_remaining ) {
77cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( dst && dest_converted >= max_dest_chars )
78cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            break;
79cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        // Converts one multi byte character.
80cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        // if result > 0, it's the size in bytes of that character.
81cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        // othewise if result is zero it indicates the null character has been found.
82cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        // otherwise it's an error and errno may be set.
83cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps );
84cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        // Don't do anything to change errno from here on.
85cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( char_size > 0 ) {
86cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            source_remaining -= char_size;
87cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            source_converted += char_size;
88cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            ++dest_converted;
89cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            continue;
90cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        }
91cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        result = char_size;
92cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        have_result = true;
93cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        break;
94cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    }
95cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    if ( dst ) {
96cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( have_result && result == terminated_sequence )
97cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            *src = NULL;
98cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        else
99cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            *src += source_converted;
100cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    }
101cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    if ( have_result && result != terminated_sequence && result != incomplete_sequence )
102cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        return static_cast<size_t>(-1);
103cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
104cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    return dest_converted;
1056cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant}
106cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
107cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant// Converts max_source_chars from the wide character buffer pointer to by *src,
1085ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// into the multi byte character sequence buffer stored at dst which must be
1095ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// dst_size_bytes bytes in size.
1105ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// Returns >= 0: the number of bytes in the sequence sequence
1115ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// converted frome *src, excluding the null terminator.
112cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant// Returns size_t(-1) if an error occurs, also sets errno.
1135ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
1145ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant// and no "out" parameters are updated.
11578b6828f1420a266e02687685bc2ab993a54eaddHoward Hinnantsize_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
116cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant                   size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps )
1176cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant{
118cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    //const size_t invalid_sequence = static_cast<size_t>(-1);
119cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
120cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t source_converted = 0;
121cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t dest_converted = 0;
122cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t dest_remaining = dst_size_bytes;
123cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    size_t char_size = 0;
124cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    const errno_t no_error = ( errno_t) 0;
125cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    errno_t result = ( errno_t ) 0;
126cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    bool have_result = false;
127cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    bool terminator_found = false;
128cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
129cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    while ( source_converted != max_source_chars ) {
130cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( ! dest_remaining )
131cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            break;
132cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        wchar_t c = (*src)[source_converted];
133cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( dst )
134cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps);
135cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        else
1369e98b34a8c03460dacab05068d900dd424e45e53Howard Hinnant            result = wcrtomb_s( &char_size, NULL, 0, c, ps);
1375ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant        // If result is zero there is no error and char_size contains the
1385ec0ff81cecfbc317b2a53894f8bf2da6eb0e8c7Howard Hinnant        // size of the multi-byte-sequence converted.
139cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        // Otherwise result indicates an errno type error.
140cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( result == no_error ) {
141cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            if ( c == L'\0' ) {
142cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant                terminator_found = true;
143cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant                break;
144cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            }
145cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            ++source_converted;
146cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            if ( dst )
147cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant                dest_remaining -= char_size;
148cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            dest_converted += char_size;
149cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            continue;
150cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        }
151cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        have_result = true;
152cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        break;
153cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    }
154cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    if ( dst ) {
155cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        if ( terminator_found )
156cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            *src = NULL;
157cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        else
158cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant            *src = *src + source_converted;
159cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    }
160cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    if ( have_result && result != no_error ) {
161cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        errno = result;
162cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant        return static_cast<size_t>(-1);
163cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    }
164cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant
165cf31d3864e94e52790c7d2db1c85a015de4da8feHoward Hinnant    return dest_converted;
1666cd05eeb35636c33a5cd951a7b5501f51611b469Howard Hinnant}
167