1 : /*
2 : * Copyright (c) 2008 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Generic I/O interface.
9 : */
10 : #include "native_client/src/include/portability.h"
11 :
12 : #include <stdlib.h>
13 :
14 : #include "native_client/src/shared/gio/gio.h"
15 :
16 : /*
17 : * Windows Visual Studio pre-2013 does not provide va_copy. When
18 : * compiled with a pre-2013 Visual Studio, we use knowledge of MSVS's
19 : * implementation to poly-fill. This is ugly, but the API for earlier
20 : * versions is extremely unlikely to change, since it would break
21 : * other existing code that depends on it.
22 : */
23 : #if NACL_WINDOWS
24 : /* check definition of _MSC_VER first, in case we switch to clang */
25 : # if defined(_MSC_VER) && _MSC_VER < 1800
26 : # define va_copy(dst, src) do { (dst) = (src); } while (0)
27 : # endif
28 : #endif
29 :
30 : size_t gvprintf(struct Gio *gp,
31 : char const *fmt,
32 11 : va_list ap) {
33 11 : size_t bufsz = 1024;
34 11 : char *buf = malloc(bufsz);
35 : int rv;
36 : va_list ap_copy;
37 :
38 11 : if (!buf) return -1;
39 :
40 11 : va_copy(ap_copy, ap);
41 :
42 : while ((rv = vsnprintf(buf, bufsz, fmt, ap_copy)) < 0 ||
43 11 : (unsigned) rv >= bufsz) {
44 1 : va_end(ap_copy);
45 1 : free(buf);
46 1 : buf = 0;
47 :
48 : /**
49 : * Since the buffer size wasn't big enough, we want to double it.
50 : * Stop doubling when we reach SIZE_MAX / 2, though, otherwise we
51 : * risk wraparound.
52 : *
53 : * On Windows, vsnprintf returns -1 if the supplied buffer is not
54 : * large enough; on Linux and OSX, it returns the number of actual
55 : * characters that would have been output (excluding the NUL
56 : * byte), which means a single resize would have been sufficient.
57 : * Since buffer size increase should be infrequent, we do doubly
58 : * on Linux and OSX as well.
59 : */
60 1 : if (bufsz < SIZE_MAX / 2) {
61 1 : bufsz *= 2;
62 1 : buf = malloc(bufsz);
63 : }
64 :
65 1 : if (!buf) {
66 0 : return (size_t) -1;
67 : }
68 1 : va_copy(ap_copy, ap);
69 1 : }
70 11 : va_end(ap_copy);
71 11 : if (rv >= 0) {
72 11 : rv = (int) (*gp->vtbl->Write)(gp, buf, rv);
73 : }
74 11 : free(buf);
75 :
76 11 : return rv;
77 11 : }
78 :
79 : size_t gprintf(struct Gio *gp,
80 11 : char const *fmt, ...) {
81 : va_list ap;
82 : size_t rv;
83 :
84 11 : va_start(ap, fmt);
85 11 : rv = gvprintf(gp, fmt, ap);
86 11 : va_end(ap);
87 :
88 11 : return rv;
89 11 : }
|