~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to lib/misc/msgfmt.c

  • Committer: Package Import Robot
  • Author(s): Nate Muench
  • Date: 2012-01-23 16:09:45 UTC
  • mfrom: (1.4.6) (2.4.26 sid)
  • Revision ID: package-import@ubuntu.com-20120123160945-b6s0r1vkcovucpf3
Tags: 2011.12.20-562307-0ubuntu1
* Merge latest upstream git tag. Fixes building on Precise
  (LP: #898289, LP: #905612)

* Items merged from Debian unstable:
  - debian/control:
    + open-vm-tools recommends open-vm-dkms. (LP: #598933)
    + open-vm-tools now suggests open-vm-toolbox. (LP: #604998)
  (From 2011.08.21-471295-1 release)
  - Updating maintainer and uploaders fields.
  - Removing vcs fields.
  - Removing references to Daniel's old email address.
  - Updating years in copyright file.
  - Updating to standards version 3.9.2.
  - Updating to debhelper version 8.
  - Switching to source format 3.0 (quilt).
  - Removing manual chrpath setting.
  - Removing exclusion from plugins from debhelper shlibs.
  - Rediffing kvers.patch.
  (From 2011.09.23-491607-1 release)
  - Marking binary architecture-dependend packages as linux and kfreebsd
  only.
  - Removing liburiparser-dev from build-depends as upstream dropped
  unity support.
  - Building with libproc-dev on amd64 again.
  - Dropping disabling of dnet support.
  (From 2011.09.23-491607-2 release)
  - Adding doxygen to build-depends for api documentation.
  - Adding libcunit1-dev to build-depends for test suites.
  - Minimizing rules file.
  - Adding open-vm-tools-dev package, containing only the api
    documentation for now.
  (From 2011.09.23-491607-3 release)
  - Sorting overrides in rules alphabetically.
  - Compacting copyright file.
  - Adding udev rule to set timeout for vmware scsi devices
  (From 2011.12.20-562307-1 release)
  - Adding patch to correct typo in upstreams dkms configuration

* Remaining Changes:
  - Remove Stable part of version numbering.
  - debian folder:
    + Re-added open-vm-dkms.postinst & open-vm-dkms.prerm.
      * Allows dkms modules to compile upon installation.
  - debian/control:
    + Re-add open-vm-source and make into a transitional package
      for open-vm-toolbox.
    + Return dependancies that were moved to open-vm-tools back to
      open-vm-toolbox.
  - debian/rules and debian/open-vm-toolbox.lintian-overrides:
    + Make vmware-user-suid-wrapper suid-root
  - debian/rules:
    + Added CFLAGS field with -Wno-deprecated-declarations
      * Will suppress issues with glib 2.31 or later.
    + Add line to copy vmware-xdg-detect-de into place.
    + Install vmware-user.desktop through toolbox package.
  - debian/open-vm-tools.init:
    + Re-add 'modprobe [-r] vmblock'.
    + Add 'modprobe [-r] vmxnet'.
      * Incase it's not loaded during boot.
    + Remove and re-add pcnet32 module
      * Will be done before (remove) and after (readd) vmxnet module
        is added.
      * If vmxnet doesn't exist (aka modules fail to build), pcnet32 can be
        still used for network connectivity.
      * Workaround until a better fix can be done.
  - Re-add gnome-session to debian/local/xautostart.conf
  - Manpages removed (from debian/manpages):
    + vmmemctl.9
    + vmxnet3.9
    + Remove references to manpages that have been removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* **********************************************************
 
2
 * Copyright 2007 VMware, Inc.  All rights reserved.
 
3
 * **********************************************************/
 
4
 
 
5
/*
 
6
 * Copyright (c) 1990, 1993
 
7
 *   The Regents of the University of California.  All rights reserved.
 
8
 *
 
9
 * This code is derived from software contributed to Berkeley by
 
10
 * Chris Torek.
 
11
 *
 
12
 * Redistribution and use in source and binary forms, with or without
 
13
 * modification, are permitted provided that the following conditions
 
14
 * are met:
 
15
 * 1. Redistributions of source code must retain the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer.
 
17
 * 2. Redistributions in binary form must reproduce the above copyright
 
18
 *    notice, this list of conditions and the following disclaimer in the
 
19
 *    documentation and/or other materials provided with the distribution.
 
20
 * 4. Neither the name of the University nor the names of its contributors
 
21
 *    may be used to endorse or promote products derived from this software
 
22
 *    without specific prior written permission.
 
23
 *
 
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
34
 * SUCH DAMAGE.
 
35
 */
 
36
 
 
37
/*
 
38
 * msgfmt.c --
 
39
 *
 
40
 *      MsgFmt: format messages for the Msg module
 
41
 */
 
42
 
 
43
 
 
44
#ifdef VMKERNEL
 
45
   #include "vmkernel.h"
 
46
   #include "vm_types.h"
 
47
   #include "vm_libc.h"
 
48
#else
 
49
   #include <stdlib.h>
 
50
   #include <stdio.h>
 
51
   #include <stdarg.h>
 
52
   #include <stddef.h>
 
53
   #include <string.h>
 
54
   #if defined(__FreeBSD__)
 
55
      #include <sys/param.h>
 
56
   #endif
 
57
   #if !defined(_WIN32) && !defined(SOL9) && \
 
58
       (!defined(__FreeBSD__) || __FreeBSD_version >= 500029)
 
59
      #include <stdint.h>
 
60
   #endif
 
61
   #if !defined(__FreeBSD__) || __FreeBSD_version >= 400017
 
62
      #include <wchar.h>
 
63
   #endif
 
64
 
 
65
   #include "vmware.h"
 
66
   #include "bsdfmt.h"
 
67
   #include "err.h"
 
68
#endif
 
69
 
 
70
#include "msgfmt.h"
 
71
 
 
72
#ifdef HAS_BSD_PRINTF
 
73
   #include <limits.h>
 
74
   #include <locale.h>
 
75
   #include "msgid.h"
 
76
#endif
 
77
 
 
78
/*
 
79
 * Older versions of FreeBSD don't have C99 support (stdint), and also
 
80
 * do not have wide character support. Re-implement the stuff we need
 
81
 * in those cases.
 
82
 */
 
83
 
 
84
#if defined(__FreeBSD__) && __FreeBSD_version <= 320001
 
85
static INLINE const wchar_t *
 
86
wmemchr(const wchar_t *s, wchar_t c, size_t n)
 
87
{
 
88
   size_t i;
 
89
   for (i = 0; i < n; i++) {
 
90
      if (s[i] == c) {
 
91
         return &s[i];
 
92
      }
 
93
   }
 
94
 
 
95
   return NULL;
 
96
}
 
97
 
 
98
static INLINE size_t
 
99
wcslen(const wchar_t *s)
 
100
{
 
101
   size_t i;
 
102
 
 
103
   for (i = 0; s[i]; i++);
 
104
 
 
105
   return i;
 
106
}
 
107
#endif
 
108
 
 
109
/*
 
110
 * The vmkernel doesn't have the Str module, malloc(), or
 
111
 * some of the standard C string functions.
 
112
 * The only ones we really need are Str_Vsnprintf() and memchr().
 
113
 */
 
114
 
 
115
#ifdef VMKERNEL // {
 
116
 
 
117
typedef int32 wchar_t;
 
118
typedef int32 wint_t;
 
119
typedef int64 intmax_t;
 
120
typedef size_t ptrdiff_t;
 
121
 
 
122
#define STUB(t, f, a) \
 
123
        static INLINE t f a { NOT_IMPLEMENTED(); return (t) 0;}
 
124
#define VSTUB(f, a) \
 
125
        static INLINE void f a { NOT_IMPLEMENTED(); }
 
126
STUB(char *, Str_Vasprintf, (char **b, const char *f, va_list a))
 
127
STUB(void *, malloc, (size_t s))
 
128
STUB(void *, realloc, (void *p, size_t s))
 
129
STUB(wchar_t *, wmemchr, (const wchar_t *s, wchar_t c, size_t n))
 
130
STUB(size_t, wcslen, (const wchar_t *s))
 
131
STUB(char *, strdup, (const char *s))
 
132
VSTUB(free, (void *p))
 
133
#undef STUB
 
134
#undef VSTUB
 
135
 
 
136
typedef int Err_Number;
 
137
#define ERR_INVALID (-1)
 
138
static INLINE Err_Number
 
139
Err_String2Errno(const char *string)
 
140
{
 
141
   return ERR_INVALID;
 
142
}
 
143
 
 
144
#ifdef VMX86_DEBUG
 
145
static INLINE Err_Number
 
146
Err_String2ErrnoDebug(const char *string)
 
147
{
 
148
   return ERR_INVALID;
 
149
}
 
150
#endif
 
151
 
 
152
static INLINE int
 
153
Str_Vsnprintf(char *str, size_t size, const char *format, va_list ap) {
 
154
   int n = vsnprintf(str, size, format, ap);
 
155
   ASSERT(n >= 0);
 
156
   if (n >= size) {
 
157
      str[size - 1] = '\0';
 
158
      n = -1;
 
159
   }
 
160
   return n;
 
161
}
 
162
 
 
163
static INLINE const void *
 
164
memchr(const void *s, int c, size_t n)
 
165
{
 
166
   const uint8 *p = s;
 
167
   const uint8 *e = p + n;
 
168
   while (p < e) {
 
169
      if (*p++ == c) {
 
170
         return p;
 
171
      }
 
172
   }
 
173
   return NULL;
 
174
}
 
175
 
 
176
#endif // }
 
177
 
 
178
 
 
179
/*
 
180
 * Local data
 
181
 */
 
182
 
 
183
typedef struct MsgFmtParseState {
 
184
   MsgFmt_Arg *args;
 
185
   int numArgs;
 
186
   int maxArgs;
 
187
   char *error;
 
188
 
 
189
   /*
 
190
    * Allocator state for caller-supplied buffer.
 
191
    */
 
192
 
 
193
   void *buf;
 
194
   char *bufp;
 
195
   char *bufe;
 
196
} MsgFmtParseState;
 
197
 
 
198
/* d, i, o, u, x, X, e, E, f, F, g, G, a, A, c, s, C, S, p, and n --hpreg */
 
199
static int const isSpecifier[] = {
 
200
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
201
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
202
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
203
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
204
   0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 
205
   0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
 
206
   0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1,
 
207
   1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
 
208
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
209
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
210
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
211
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
212
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
213
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
214
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
215
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
216
};
 
217
 
 
218
 
 
219
/*
 
220
 * Local functions
 
221
 */
 
222
 
 
223
static MsgFmt_SpecFunc MsgFmtGetArg1;
 
224
static int MsgFmtAToI(char const **start, char const *end);
 
225
static void MsgFmtError(MsgFmtParseState *state, const char *fmt, ...);
 
226
 
 
227
static void MsgFmtAllocInit(MsgFmtParseState *state, void *buf, size_t size);
 
228
static void *MsgFmtAlloc(MsgFmtParseState *state, size_t size);
 
229
static Bool MsgFmtAllocArgs(MsgFmtParseState *state, int n);
 
230
static char *MsgFmtVasprintf(MsgFmtParseState *state,
 
231
                             const char *fmt, va_list args);
 
232
static void MsgFmtFreeAll(MsgFmtParseState *state);
 
233
static size_t MsgFmtBufUsed(MsgFmtParseState *state);
 
234
#ifdef HAS_BSD_PRINTF
 
235
static int MsgFmtSnprintfWork(char **outbuf, size_t bufSize, const char *fmt0,
 
236
                              const struct MsgFmt_Arg *args, int numArgs);
 
237
#endif
 
238
 
 
239
 
 
240
/*
 
241
 *-----------------------------------------------------------------------------
 
242
 *
 
243
 * MsgFmt_ParseWin32 --
 
244
 *
 
245
 *    Convert the Win32 representation of a format string into another
 
246
 *    representation --hpreg
 
247
 *
 
248
 *    XXX I haven't implemented %0 and %n, because they suck:
 
249
 *        . they mix content and presentation
 
250
 *        . they have nothing to do with parameters and hence have no
 
251
 *          equivalent in other systems
 
252
 *
 
253
 * Results:
 
254
 *     0 on success
 
255
 *    -1 on failure: out of memory
 
256
 *    -2 on failure: invalid 'in'
 
257
 *
 
258
 * Side effects:
 
259
 *    None
 
260
 *
 
261
 *-----------------------------------------------------------------------------
 
262
 */
 
263
 
 
264
int
 
265
MsgFmt_ParseWin32(MsgFmt_LitFunc *litFunc,    // IN
 
266
                  MsgFmt_SpecFunc *specFunc,  // IN
 
267
                  void *clientData,           // IN
 
268
                  char const *in)             // IN
 
269
{
 
270
   char const *startUnescaped;
 
271
   unsigned int sm;
 
272
   char const *pos = 0 /* Compiler warning --hpreg */;
 
273
   char const *type = 0 /* Compiler warning --hpreg */;
 
274
   int status;
 
275
 
 
276
   startUnescaped = in;
 
277
   sm = 0;
 
278
 
 
279
   for (; *in != '\0'; in++) {
 
280
      /* Unsigned does matter --hpreg */
 
281
      unsigned char ubyte;
 
282
 
 
283
      ubyte = *in;
 
284
      switch (sm) {
 
285
      case 2: /* Found %<1-9>...<byte> --hpreg */
 
286
         if (ubyte >= '0' && ubyte <= '9') {
 
287
            break;
 
288
         }
 
289
         if (ubyte == '!') {
 
290
            type = in + 1;
 
291
            sm = 3;
 
292
            break;
 
293
         }
 
294
         if ((status = (*litFunc)(clientData, startUnescaped,
 
295
                                  pos - 1 - startUnescaped)) < 0 ||
 
296
             (status = (*specFunc)(clientData, pos, in - pos, "s", 1)) < 0) {
 
297
            return status;
 
298
         }
 
299
         startUnescaped = in;
 
300
         sm = 0;
 
301
         /* Fall through --hpreg */
 
302
 
 
303
      case 0: /* Found <byte> --hpreg */
 
304
         if (ubyte == '%') {
 
305
            pos = in + 1;
 
306
            sm = 1;
 
307
         }
 
308
         break;
 
309
 
 
310
      case 1: /* Found %<byte> --hpreg */
 
311
         if (ubyte >= '1' && ubyte <= '9') {
 
312
            sm = 2;
 
313
         } else {
 
314
            ASSERT_NOT_IMPLEMENTED(ubyte != '0' && ubyte != 'n');
 
315
            status = (*litFunc)(clientData, startUnescaped,
 
316
                                in - 1 - startUnescaped);
 
317
            if (status < 0) {
 
318
               return status;
 
319
            }
 
320
            startUnescaped = in;
 
321
            sm = 0;
 
322
         }
 
323
         break;
 
324
 
 
325
      case 3: /* Found %<1-9>...!...<byte> --hpreg */
 
326
         if (ubyte == '!') {
 
327
            if (   (status = (*litFunc)(clientData, startUnescaped,
 
328
                                        pos - 1 - startUnescaped)) < 0
 
329
                || (status = (*specFunc)(clientData, pos, type - 1 - pos,
 
330
                                         type, in - type)) < 0) {
 
331
               return status;
 
332
            }
 
333
            startUnescaped = in + 1;
 
334
            sm = 0;
 
335
         }
 
336
         break;
 
337
 
 
338
      default:
 
339
         NOT_IMPLEMENTED();
 
340
         break;
 
341
      }
 
342
   }
 
343
 
 
344
   switch (sm) {
 
345
   case 0:
 
346
      status = (*litFunc)(clientData, startUnescaped, in - startUnescaped);
 
347
      if (status < 0) {
 
348
         return status;
 
349
      }
 
350
      break;
 
351
 
 
352
   case 2:
 
353
      if (   (status = (*litFunc)(clientData, startUnescaped,
 
354
                                  pos - 1 - startUnescaped)) < 0
 
355
          || (status = (*specFunc)(clientData, pos, in - pos, "s", 1)) < 0) {
 
356
         return status;
 
357
      }
 
358
      break;
 
359
 
 
360
   case 1:
 
361
   case 3:
 
362
      return -2;
 
363
      break;
 
364
 
 
365
   default:
 
366
      NOT_IMPLEMENTED();
 
367
      break;
 
368
   }
 
369
 
 
370
   return 0;
 
371
}
 
372
 
 
373
 
 
374
/*
 
375
 *-----------------------------------------------------------------------------
 
376
 *
 
377
 * MsgFmt_Parse --
 
378
 *
 
379
 *    Parse a message format.
 
380
 *
 
381
 * Results:
 
382
 *     0 on success
 
383
 *    -1 on failure: out of memory
 
384
 *    -2 on failure: invalid 'in'
 
385
 *
 
386
 * Side effects:
 
387
 *    None
 
388
 *
 
389
 *-----------------------------------------------------------------------------
 
390
 */
 
391
 
 
392
int
 
393
MsgFmt_Parse(MsgFmt_LitFunc *litFunc,    // IN
 
394
             MsgFmt_SpecFunc *specFunc,  // IN
 
395
             void *clientData,           // IN
 
396
             char const *in)             // IN
 
397
{
 
398
   char const *startUnescaped;
 
399
   unsigned int sm;
 
400
   unsigned int counter;
 
401
   int status;
 
402
   char const *startEscaped = 0 /* Compiler warning --hpreg */;
 
403
   char const *type = 0 /* Compiler warning --hpreg */;
 
404
   Bool usePos = FALSE /* Compiler warning --hpreg */;
 
405
 
 
406
   startUnescaped = in;
 
407
   sm = 0;
 
408
   counter = 0;
 
409
 
 
410
   for (; *in != '\0'; in++) {
 
411
      /* Unsigned does matter --hpreg */
 
412
      unsigned char ubyte;
 
413
 
 
414
      ubyte = *in;
 
415
      switch (sm) {
 
416
      case 0: /* Found <byte> --hpreg */
 
417
         if (ubyte == '%') {
 
418
            sm = 1;
 
419
         }
 
420
         break;
 
421
 
 
422
      case 1: /* Found %<byte> --hpreg */
 
423
         if (ubyte == '%') {
 
424
            if (litFunc != NULL &&
 
425
                (status = (*litFunc)(clientData, startUnescaped,
 
426
                                     in - 1 - startUnescaped)) < 0) {
 
427
               return status;
 
428
            }
 
429
            startUnescaped = in;
 
430
            sm = 0;
 
431
            break;
 
432
         }
 
433
         startEscaped = in;
 
434
         type = in;
 
435
         if (ubyte >= '1' && ubyte <= '9') {
 
436
            sm = 2;
 
437
            break;
 
438
         }
 
439
         sm = 3;
 
440
         /* Fall through --hpreg */
 
441
 
 
442
      case 3: /* Found %<1-9>...$...<byte> or %...<byte> --hpreg */
 
443
      variant3:
 
444
         if (isSpecifier[ubyte]) {
 
445
            char const *pos;
 
446
            char const *posEnd;
 
447
            char posBuf[10 /* 32 bits unsigned in decimal --hpreg */];
 
448
 
 
449
            if (counter) {
 
450
               if (usePos != (startEscaped != type)) {
 
451
                  return -2;
 
452
               }
 
453
            } else {
 
454
               usePos = (startEscaped != type);
 
455
            }
 
456
            counter++;
 
457
 
 
458
            if (usePos) {
 
459
               pos = startEscaped;
 
460
               posEnd = type - 1;
 
461
            } else {
 
462
               char *current;
 
463
               unsigned int value;
 
464
 
 
465
               current = posBuf + sizeof(posBuf);
 
466
               posEnd = current;
 
467
               value = counter;
 
468
               ASSERT(value);
 
469
               do {
 
470
                  current--;
 
471
                  ASSERT(current >= posBuf);
 
472
                  *current = '0' + value % 10;
 
473
                  value /= 10;
 
474
               } while (value);
 
475
               pos = current;
 
476
            }
 
477
 
 
478
            if (litFunc != NULL &&
 
479
                (status = (*litFunc)(clientData, startUnescaped,
 
480
                                     startEscaped - 1 - startUnescaped)) < 0) {
 
481
               return status;
 
482
            }
 
483
            if ((status = (*specFunc)(clientData, pos, posEnd - pos, type,
 
484
                                      in + 1 - type)) < 0) {
 
485
               return status;
 
486
            }
 
487
            startUnescaped = in + 1;
 
488
            sm = 0;
 
489
            break;
 
490
         }
 
491
         /* Digits for field width & precision, zero for leading zeroes,
 
492
            and dot for separator between width and precision. */
 
493
         if ((ubyte >= '0' && ubyte <= '9') || ubyte == '.') {
 
494
            break;
 
495
         }
 
496
         /* Flags */
 
497
         if (ubyte == '#' || ubyte == '-' || ubyte == ' ' || ubyte == '+' ||
 
498
             ubyte == '\'') {
 
499
            break;
 
500
         }
 
501
         /* Length modifiers */
 
502
         if (ubyte == 'L' || ubyte == 'l' || ubyte == 'h' || ubyte == 'z' ||
 
503
             ubyte == 'Z' || ubyte == 't' || ubyte == 'q' || ubyte == 'j' ||
 
504
             ubyte == 'I') {
 
505
            break;
 
506
         }
 
507
         return -2;
 
508
 
 
509
      case 2: /* Found %<1-9>...<byte> --hpreg */
 
510
         if (ubyte >= '0' && ubyte <= '9') {
 
511
            break;
 
512
         }
 
513
         if (ubyte == '$') {
 
514
            type = in + 1;
 
515
            sm = 3;
 
516
            break;
 
517
         }
 
518
         sm = 3;
 
519
         goto variant3;
 
520
 
 
521
      default:
 
522
         NOT_IMPLEMENTED();
 
523
         break;
 
524
      }
 
525
   }
 
526
 
 
527
   if (sm) {
 
528
      return -2;
 
529
   }
 
530
   if (litFunc != NULL &&
 
531
       (status = (*litFunc)(clientData, startUnescaped,
 
532
                            in - startUnescaped)) < 0) {
 
533
      return status;
 
534
   }
 
535
 
 
536
   return 0;
 
537
}
 
538
 
 
539
 
 
540
/*
 
541
 *-----------------------------------------------------------------------------
 
542
 *
 
543
 * MsgFmt_ParseSpec --
 
544
 *
 
545
 *      Given a format specifier (the % stuff), return its contituent parts.
 
546
 *
 
547
 * Results:
 
548
 *      0 on success, -2 (bad format) on failure.
 
549
 *      Out parameters:
 
550
 *         Width and precision are -1 if not specified.
 
551
 *         Length modifier is '\0' if not specified.
 
552
 *         Length modifier of "ll", "I64", or "q" is returned as 'L'.
 
553
 *         (This means we freely allow %llf and %qf, which is not strictly
 
554
 *         correct.  However, glibc printf allows them (as well as %Ld),
 
555
 *         and they mean the same thing.)
 
556
 *         Length modifier of "hh" is returned as 'H'.
 
557
 *         Length modifier of "Z" is returned as 'z', for compatibility
 
558
 *         with old glibc.
 
559
 *      On failure, some or all of the out parameters may be modified
 
560
 *      in an undefined manner.
 
561
 *
 
562
 * Side effects:
 
563
 *      None.
 
564
 *
 
565
 *-----------------------------------------------------------------------------
 
566
 */
 
567
 
 
568
int
 
569
MsgFmt_ParseSpec(char const *pos,       // IN: n$ location
 
570
                 unsigned int posSize,  // IN: n$ length
 
571
                 char const *type,      // IN: specifier after position
 
572
                 unsigned int typeSize, // IN: size of above
 
573
                 int *position,         // OUT: argument position
 
574
                 int *flags,            // OUT: flags
 
575
                 int *width,            // OUT: width
 
576
                 int *precision,        // OUT: precision
 
577
                 char *lengthMod,       // OUT: length modifier
 
578
                 char *conversion)      // OUT: conversion specifier
 
579
{
 
580
   char const *p = type;
 
581
   char const *end = type + typeSize;
 
582
 
 
583
   /*
 
584
    * Convert argument position to int.
 
585
    * Fail if not a good decimal number greater than 0.
 
586
    */
 
587
 
 
588
   {
 
589
      char const *posEnd = pos + posSize;
 
590
      *position = MsgFmtAToI(&pos, posEnd);
 
591
      if (*position <= 0 || pos != posEnd) {
 
592
         return -2;
 
593
      }
 
594
   }
 
595
 
 
596
   /*
 
597
    * The format specifier is, in this order,
 
598
    *    zero or more flags
 
599
    *    an optional width (a decimal number or *)
 
600
    *    an optional precision (. followed by optional decimal number or *)
 
601
    *    an optional length modifier (l, L, ll, z, etc.)
 
602
    *    conversion specifier (a character)
 
603
    *
 
604
    * The rest of this module does not recognize * as width or precision,
 
605
    * so we don't do it here either.
 
606
    *
 
607
    * glibc 2.2 supports the I flag, which we don't.  Instead, we
 
608
    * support the I, I32, and I64 length modifiers used by Microsoft.
 
609
    */
 
610
 
 
611
   /*
 
612
    * Flags
 
613
    */
 
614
 
 
615
   *flags = 0;
 
616
   for (; p < end; p++) {
 
617
      switch (*p) {
 
618
      case '#':
 
619
         *flags |= MSGFMT_FLAG_ALT;
 
620
         continue;
 
621
      case '0':
 
622
         *flags |= MSGFMT_FLAG_ZERO;
 
623
         continue;
 
624
      case '-':
 
625
         *flags |= MSGFMT_FLAG_MINUS;
 
626
         continue;
 
627
      case ' ':
 
628
         *flags |= MSGFMT_FLAG_SPACE;
 
629
         continue;
 
630
      case '+':
 
631
         *flags |= MSGFMT_FLAG_PLUS;
 
632
         continue;
 
633
      case '\'':
 
634
         *flags |= MSGFMT_FLAG_QUOTE;
 
635
         continue;
 
636
 
 
637
      default:
 
638
         break;
 
639
      }
 
640
      break;
 
641
   }
 
642
 
 
643
   /*
 
644
    * Width
 
645
    */
 
646
 
 
647
   if (p >= end || *p < '1' || *p > '9') {
 
648
      *width = -1;
 
649
   } else {
 
650
      *width = MsgFmtAToI(&p, end);
 
651
      if (*width < 0) {
 
652
         return -2;
 
653
      }
 
654
   }
 
655
 
 
656
   /*
 
657
    * Precision
 
658
    */
 
659
 
 
660
   if (p >= end || *p != '.') {
 
661
      *precision = -1;
 
662
   } else {
 
663
      p++;
 
664
      *precision = MsgFmtAToI(&p, end);
 
665
      if (*precision < 0) {
 
666
         return -2;
 
667
      }
 
668
   }
 
669
 
 
670
   /*
 
671
    * Length modifier
 
672
    */
 
673
 
 
674
   if (p >= end) {
 
675
      return -2;
 
676
   }
 
677
   *lengthMod = '\0';
 
678
   switch (*p) {
 
679
   case 'h':
 
680
      p++;
 
681
      if (p >= end || *p != 'h') {
 
682
         *lengthMod = 'h';
 
683
      } else {
 
684
         p++;
 
685
         *lengthMod = 'H';
 
686
      }
 
687
      break;
 
688
   case 'l':
 
689
      p++;
 
690
      if (p >= end || *p != 'l') {
 
691
         *lengthMod = 'l';
 
692
      } else {
 
693
         p++;
 
694
         *lengthMod = 'L';
 
695
      }
 
696
      break;
 
697
   case 'I':
 
698
      /*
 
699
       * Microsoft:
 
700
       *    I64 is 64-bit number.  For us, the same as L.
 
701
       *    I32 is 32-bit number.  For us, nothing.
 
702
       *    I is size_t.
 
703
       */
 
704
      if (p + 2 < end && p[1] == '6' && p[2] == '4') {
 
705
         p += 3;
 
706
         *lengthMod = 'L';
 
707
      } else if (p + 2 < end && p[1] == '3' && p[2] == '2') {
 
708
         p += 3;
 
709
      } else {
 
710
         p++;
 
711
         *lengthMod = 'z';
 
712
      }
 
713
      break;
 
714
   case 'q':
 
715
      p++;
 
716
      *lengthMod = 'L';
 
717
      break;
 
718
   case 'Z':
 
719
      p++;
 
720
      *lengthMod = 'z';
 
721
      break;
 
722
   case 'L':
 
723
   case 'j':
 
724
   case 'z':
 
725
   case 't':
 
726
      *lengthMod = *p++;
 
727
      break;
 
728
   }
 
729
 
 
730
   /*
 
731
    * Conversion specifier
 
732
    *
 
733
    * Return false if no conversion specifier or not the last character.
 
734
    */
 
735
 
 
736
   if (p + 1 == end && isSpecifier[(unsigned char) *p]) {
 
737
      *conversion = *p;
 
738
      return 0;
 
739
   }
 
740
   return -2;
 
741
}
 
742
 
 
743
 
 
744
/*
 
745
 *-----------------------------------------------------------------------------
 
746
 *
 
747
 * MsgFmtAToI --
 
748
 *
 
749
 *      Convert numeric string to integer.
 
750
 *      The range is 0 to MAX_INT32 (nonnegative 32-bit signed int).
 
751
 *      Empty string or a string that does not begin with
 
752
 *      a digit is treated as 0.
 
753
 *
 
754
 * Results:
 
755
 *      The number or -1 on overflow.
 
756
 *      Start pointer updated to point to first nonnumeric character.
 
757
 *      or first character before overflow.
 
758
 *
 
759
 * Side effects:
 
760
 *      None.
 
761
 *
 
762
 *-----------------------------------------------------------------------------
 
763
 */
 
764
 
 
765
static int
 
766
MsgFmtAToI(char const **start,  // IN/OUT: string pointer
 
767
           char const *end)     // IN: end of string
 
768
{
 
769
   char const *p;
 
770
   int n = 0;
 
771
 
 
772
   ASSERT_ON_COMPILE(sizeof (int) >= 4);
 
773
   for (p = *start; p < end && *p >= '0' && *p <= '9'; p++) {
 
774
      if (n > MAX_INT32 / 10) {
 
775
         n = -1;
 
776
         break;
 
777
      }
 
778
      n *= 10;
 
779
      n += *p - '0';
 
780
      if (n < 0) {
 
781
         n = -1;
 
782
         break;
 
783
      }
 
784
   }
 
785
   *start = p;
 
786
   return n;
 
787
}
 
788
 
 
789
 
 
790
/*
 
791
 *-----------------------------------------------------------------------------
 
792
 *
 
793
 * MsgFmt_GetArgs --
 
794
 *
 
795
 *      Parse a format string and return the arguments implied by it.
 
796
 *
 
797
 * Results:
 
798
 *      TRUE on sucess.
 
799
 *      Out parameters:
 
800
 *        The array of MsgFmt_Arg structures.
 
801
 *        The number of arguments.
 
802
 *        An error string on failure.
 
803
 *
 
804
 * Side effects:
 
805
 *      Memory is allocated.
 
806
 *
 
807
 *-----------------------------------------------------------------------------
 
808
 */
 
809
 
 
810
Bool
 
811
MsgFmt_GetArgs(const char *fmt,         // IN: format string
 
812
               va_list va,              // IN: the argument list
 
813
               MsgFmt_Arg **args,       // OUT: the returned arguments
 
814
               int *numArgs,            // OUT: number of returned arguments
 
815
               char **error)            // OUT: error string
 
816
{
 
817
   return MsgFmt_GetArgsWithBuf(fmt, va, args, numArgs, error, NULL, NULL);
 
818
}
 
819
 
 
820
 
 
821
/*
 
822
 *-----------------------------------------------------------------------------
 
823
 *
 
824
 * MsgFmt_GetArgsWithBuf --
 
825
 *
 
826
 *      Parse a format string and return the arguments implied by it.
 
827
 *
 
828
 *      If buf is supplied, allocate memory there instead of with malloc().
 
829
 *
 
830
 * Results:
 
831
 *      TRUE on sucess.
 
832
 *      Out parameters:
 
833
 *        The array of MsgFmt_Arg structures.
 
834
 *        The number of arguments.
 
835
 *        An error string on failure.
 
836
 *        The amount of buf used (if caller supplied buf)
 
837
 *
 
838
 * Side effects:
 
839
 *      Memory may be allocated.
 
840
 *
 
841
 *-----------------------------------------------------------------------------
 
842
 */
 
843
 
 
844
Bool
 
845
MsgFmt_GetArgsWithBuf(const char *fmt,    // IN: format string
 
846
                      va_list va,         // IN: the argument list
 
847
                      MsgFmt_Arg **args,  // OUT: the returned arguments
 
848
                      int *numArgs,       // OUT: number of returned arguments
 
849
                      char **error,       // OUT: error string
 
850
                      void *buf,          // OUT: memory to store output
 
851
                      size_t *bufSize)    // IN/OUT: size of buf /
 
852
                                          //         amount of buf used
 
853
{
 
854
   MsgFmtParseState state;
 
855
   int status;
 
856
   int i;
 
857
 
 
858
   memset(&state, 0, sizeof state);
 
859
   if (buf != NULL) {
 
860
      ASSERT(bufSize != NULL);
 
861
      MsgFmtAllocInit(&state, buf, *bufSize);
 
862
   }
 
863
 
 
864
   /*
 
865
    * First pass: parse format to get argument information
 
866
    */
 
867
 
 
868
   status = MsgFmt_Parse(NULL, MsgFmtGetArg1, &state, fmt);
 
869
   if (status < 0) {
 
870
      goto bad;
 
871
   }
 
872
 
 
873
   /*
 
874
    * Second pass: get argument values
 
875
    *
 
876
    * While we can store most values directly in the MsgFmt_Arg
 
877
    * structure, strings have to be copied into allocated space.
 
878
    * When precision is specified (see comment about it in
 
879
    * MsgFmtGetArg1()), we copy at most that many bytes because
 
880
    * that's how many printf() looks at, and we must not touch
 
881
    * memory beyond what printf() would.
 
882
    */
 
883
 
 
884
   for (i = 0; i < state.numArgs; i++) {
 
885
      MsgFmt_Arg *a = state.args + i;
 
886
      switch (a->type) {
 
887
      case MSGFMT_ARG_INVALID:
 
888
         MsgFmtError(&state, "MsgFmt_GetArgs: gap in arguments at position %d",
 
889
                     i + 1);
 
890
         goto bad;
 
891
         break;
 
892
 
 
893
      case MSGFMT_ARG_INT32:
 
894
         ASSERT_ON_COMPILE(sizeof (int) == sizeof (int32));
 
895
         a->v.signed32 = va_arg(va, int);
 
896
         break;
 
897
      case MSGFMT_ARG_INT64:
 
898
         ASSERT_ON_COMPILE(sizeof (long long) == sizeof (int64));
 
899
         a->v.signed64 = va_arg(va, long long);
 
900
         break;
 
901
 
 
902
      case MSGFMT_ARG_PTR32:
 
903
         // we can only handle this case if native pointer is 4 bytes
 
904
         ASSERT(sizeof (void *) == sizeof (uint32));
 
905
         a->v.unsigned32 = (uint32) (uintptr_t) va_arg(va, void *);
 
906
         break;
 
907
      case MSGFMT_ARG_PTR64:
 
908
         // we can only handle this case if native pointer is 8 bytes
 
909
         ASSERT(sizeof (void *) == sizeof (uint64));
 
910
         a->v.unsigned64 = (uint64) (uintptr_t) va_arg(va, void *);
 
911
         break;
 
912
 
 
913
      case MSGFMT_ARG_FLOAT64:
 
914
         ASSERT_ON_COMPILE(sizeof (double) == 8);
 
915
         a->v.float64 = va_arg(va, double);
 
916
         break;
 
917
 
 
918
      case MSGFMT_ARG_STRING8: {
 
919
         const char *p = va_arg(va, char *);
 
920
         size_t n;
 
921
         Err_Number errorNumber;
 
922
         ASSERT_ON_COMPILE(sizeof (char) == sizeof (int8));
 
923
         ASSERT_ON_COMPILE(offsetof(MsgFmt_Arg, v.string8) ==
 
924
                           offsetof(MsgFmt_Arg, v.ptr));
 
925
         if (p == NULL) {
 
926
            a->v.string8 = NULL;
 
927
         } else {
 
928
            if (a->p.precision < 0) {
 
929
               n = strlen(p);
 
930
            } else {
 
931
               const char *q;
 
932
               n = a->p.precision;
 
933
               q = memchr(p, '\0', n);
 
934
               if (q != NULL) {
 
935
                  n = q - p;
 
936
               }
 
937
            }
 
938
            // yes, sizeof (int8) is 1.
 
939
            a->v.string8 = MsgFmtAlloc(&state, n + 1);
 
940
            if (a->v.string8 == NULL) {
 
941
               status = -1;
 
942
               goto bad;
 
943
            }
 
944
            memcpy(a->v.string8, p, n);
 
945
            a->v.string8[n] = '\0';
 
946
         }
 
947
         errorNumber = Err_String2Errno(p);
 
948
#ifdef VMX86_DEBUG
 
949
         if (errorNumber == ERR_INVALID && p != NULL) {
 
950
            // p may not be null terminated, so use string8
 
951
            errorNumber = Err_String2ErrnoDebug(a->v.string8char);
 
952
            if (errorNumber != ERR_INVALID) {
 
953
               // Err_String2ErrnoDebug already logged its info
 
954
               Log("%s: failed to look up copied error string at %p.\n",
 
955
                   __FUNCTION__, p);
 
956
            }
 
957
         }
 
958
#endif
 
959
         if (errorNumber != ERR_INVALID) {
 
960
            ASSERT_NOT_IMPLEMENTED(MSGFMT_CURRENT_PLATFORM !=
 
961
                                   MSGFMT_PLATFORM_UNKNOWN);
 
962
            ASSERT_ON_COMPILE(sizeof errorNumber == sizeof a->e.number);
 
963
            a->type = MSGFMT_ARG_ERRNO;
 
964
            a->e.platform = MSGFMT_CURRENT_PLATFORM;
 
965
            a->e.number = errorNumber;
 
966
            break;
 
967
         }
 
968
         break;
 
969
         }
 
970
      case MSGFMT_ARG_STRING16:
 
971
      case MSGFMT_ARG_STRING32: {
 
972
         // we can only handle the case when native wchar_t matches
 
973
         // the string char size
 
974
         const wchar_t *p = va_arg(va, wchar_t *);
 
975
         size_t n;
 
976
         ASSERT(a->type == MSGFMT_ARG_STRING16 ?
 
977
                sizeof (wchar_t) == sizeof (int16) :
 
978
                sizeof (wchar_t) == sizeof (int32));
 
979
         ASSERT_ON_COMPILE(offsetof(MsgFmt_Arg, v.string16) ==
 
980
                           offsetof(MsgFmt_Arg, v.ptr));
 
981
         ASSERT_ON_COMPILE(offsetof(MsgFmt_Arg, v.string32) ==
 
982
                           offsetof(MsgFmt_Arg, v.ptr));
 
983
         if (p == NULL) {
 
984
            a->v.ptr = NULL;
 
985
         } else {
 
986
            if ((n = a->p.precision) < 0) {
 
987
               n = wcslen(p);
 
988
            } else {
 
989
#ifndef _WIN32
 
990
               const wchar_t *q = wmemchr(p, 0, n);
 
991
               if (q != NULL) {
 
992
                  n = q - p;
 
993
               }
 
994
#else
 
995
               // XXX no wmemchar()
 
996
               // fix this when we get new compiler -- edward
 
997
               const wchar_t *e = p + n;
 
998
               const wchar_t *q;
 
999
               for (q = p; q < e && *q != 0; q++) {
 
1000
               }
 
1001
               n = q - p;
 
1002
#endif
 
1003
            }
 
1004
            a->v.ptr = MsgFmtAlloc(&state, sizeof (wchar_t) * (n + 1));
 
1005
            if (a->v.ptr == NULL) {
 
1006
               status = -1;
 
1007
               goto bad;
 
1008
            }
 
1009
            memcpy(a->v.ptr, p, sizeof (wchar_t) * n);
 
1010
            ((wchar_t *) a->v.ptr)[n] = 0;
 
1011
         }
 
1012
         break;
 
1013
         }
 
1014
 
 
1015
      case MSGFMT_ARG_ERRNO:    // there shouldn't be this case here
 
1016
      default:
 
1017
         NOT_REACHED();
 
1018
      }
 
1019
 
 
1020
      // clear private data
 
1021
      memset(&a->p, 0, sizeof a->p);
 
1022
   }
 
1023
 
 
1024
   /*
 
1025
    * Pass results back
 
1026
    */
 
1027
 
 
1028
   if (args == NULL) {
 
1029
      MsgFmtFreeAll(&state);
 
1030
   } else {
 
1031
      *args = state.args;
 
1032
   }
 
1033
   if (numArgs != NULL) {
 
1034
      *numArgs = state.numArgs;
 
1035
   }
 
1036
   if (bufSize != NULL) {
 
1037
      *bufSize = MsgFmtBufUsed(&state);
 
1038
   }
 
1039
   ASSERT(state.error == NULL);
 
1040
   *error = NULL;
 
1041
   return TRUE;
 
1042
 
 
1043
bad:
 
1044
   if (state.error == NULL) {
 
1045
      switch (status) {
 
1046
      case -1:
 
1047
         MsgFmtError(&state, "MsgFmt_GetArgs: out of memory");
 
1048
         break;
 
1049
      case -2:
 
1050
         MsgFmtError(&state, "MsgFmt_GetArgs: error in format string");
 
1051
         break;
 
1052
      default:
 
1053
         MsgFmtError(&state, "MsgFmt_GetArgs: error %d", status);
 
1054
      }
 
1055
   }
 
1056
   ASSERT(state.args == NULL);  // MsgFmtError() frees args
 
1057
   *error = state.error;
 
1058
   return FALSE;
 
1059
}
 
1060
 
 
1061
 
 
1062
/*
 
1063
 *-----------------------------------------------------------------------------
 
1064
 *
 
1065
 * MsgFmtGetArg1 --
 
1066
 *
 
1067
 *      Process one format specifier for MsgFmt_GetArgs().
 
1068
 *      Called by MsgFmt_Parse().
 
1069
 *
 
1070
 * Results:
 
1071
 *      0 on success,
 
1072
 *      negative status on failure (see MsgFmt_Parse()).
 
1073
 *      error string in state.error on failure.
 
1074
 *
 
1075
 * Side effects:
 
1076
 *      Memory is allocated.
 
1077
 *
 
1078
 *-----------------------------------------------------------------------------
 
1079
 */
 
1080
 
 
1081
static int
 
1082
MsgFmtGetArg1(void *clientData,      // IN: state
 
1083
              const char *pos,       // IN: n$ location
 
1084
              unsigned int posSize,  // IN: n$ length
 
1085
              char const *type,      // IN: specifier after position
 
1086
              unsigned int typeSize) // IN: size of above
 
1087
{
 
1088
   MsgFmtParseState *state = clientData;
 
1089
   MsgFmt_Arg *a;
 
1090
   int position;
 
1091
   int flags;
 
1092
   int width;
 
1093
   int precision;
 
1094
   char lengthMod;
 
1095
   char conversion;
 
1096
   MsgFmt_ArgType argType = MSGFMT_ARG_INVALID;
 
1097
   int status;
 
1098
 
 
1099
   /*
 
1100
    * Parse format specifier
 
1101
    */
 
1102
 
 
1103
   status = MsgFmt_ParseSpec(pos, posSize, type, typeSize,
 
1104
                             &position, &flags, &width, &precision,
 
1105
                             &lengthMod, &conversion);
 
1106
   if (status < 0) {
 
1107
      MsgFmtError(state,
 
1108
                  "MsgFmtGetArg1: bad specifier, "
 
1109
                  "status %d, pos \"%.*s\", type \"%.*s\"",
 
1110
                  status, posSize, pos, typeSize, type);
 
1111
      return status;
 
1112
   }
 
1113
 
 
1114
   /*
 
1115
    * Make room in argument array if necessary.
 
1116
    */
 
1117
 
 
1118
   if (position > state->numArgs) {
 
1119
      if (!MsgFmtAllocArgs(state, position)) {
 
1120
         MsgFmtError(state, "MsgFmtGetArg1: out of memory at arg %d",
 
1121
                     position);
 
1122
         return -1;
 
1123
      }
 
1124
      state->numArgs = position;
 
1125
   }
 
1126
 
 
1127
   /*
 
1128
    * Fill in argument structure based on the format specifier.
 
1129
    *
 
1130
    * For strings, the precision argument is the maximum length
 
1131
    * to print.  We need to keep track of it so MsgFmt_GetArgs()
 
1132
    * can know how many characters to squirrel away, in case
 
1133
    * the string isn't null terminated, is very long, or falls off
 
1134
    * the end of the world.
 
1135
    *
 
1136
    * In all other cases, the precision is unimportant to us
 
1137
    * and we don't keep it around.
 
1138
    */
 
1139
 
 
1140
   a = state->args + position - 1;
 
1141
 
 
1142
   switch (conversion) {
 
1143
   case 'd':
 
1144
   case 'i':
 
1145
   case 'o':
 
1146
   case 'u':
 
1147
   case 'x':
 
1148
   case 'X':
 
1149
      switch (lengthMod) {
 
1150
      // all of these take an int argument, they just print differently
 
1151
      case '\0':
 
1152
      case 'h':
 
1153
      case 'H':
 
1154
         ASSERT_ON_COMPILE(sizeof (int) == sizeof (int32));
 
1155
         argType = MSGFMT_ARG_INT32;
 
1156
         break;
 
1157
 
 
1158
      case 'l':
 
1159
         ASSERT_ON_COMPILE(sizeof (long) == sizeof (int32) ||
 
1160
                           sizeof (long) == sizeof (int64));
 
1161
         if (sizeof (long) == sizeof (int32)) {
 
1162
            argType = MSGFMT_ARG_INT32;
 
1163
         } else {
 
1164
            argType = MSGFMT_ARG_INT64;
 
1165
         }
 
1166
         break;
 
1167
 
 
1168
      case 'j':
 
1169
#ifndef _WIN32 // no intmax_t, bsd_vsnprintf() uses 64 bits
 
1170
         ASSERT_ON_COMPILE(sizeof (intmax_t) == sizeof (int64));
 
1171
#endif
 
1172
      case 'L':
 
1173
         ASSERT_ON_COMPILE(sizeof (long long) == sizeof (int64));
 
1174
         argType = MSGFMT_ARG_INT64;
 
1175
         break;
 
1176
 
 
1177
      case 't':
 
1178
         ASSERT_ON_COMPILE(sizeof (ptrdiff_t) == sizeof (size_t));
 
1179
      case 'z':
 
1180
         ASSERT_ON_COMPILE(sizeof (size_t) == sizeof (int32) ||
 
1181
                           sizeof (size_t) == sizeof (int64));
 
1182
         if (sizeof (size_t) == sizeof (int32)) {
 
1183
            argType = MSGFMT_ARG_INT32;
 
1184
         } else {
 
1185
            argType = MSGFMT_ARG_INT64;
 
1186
         }
 
1187
         break;
 
1188
      default:
 
1189
         NOT_REACHED();
 
1190
      }
 
1191
      break;
 
1192
 
 
1193
   case 'e':
 
1194
   case 'E':
 
1195
   case 'f':
 
1196
   case 'F':
 
1197
   case 'g':
 
1198
   case 'G':
 
1199
   case 'a':
 
1200
   case 'A':
 
1201
      switch (lengthMod) {
 
1202
      // l h hh t z are not defined by man page, but allowed by glibc
 
1203
      case '\0':
 
1204
      case 'l':
 
1205
      case 'h':
 
1206
      case 'H':
 
1207
      case 't':
 
1208
      case 'z':
 
1209
         ASSERT_ON_COMPILE(sizeof (double) == 8);
 
1210
         argType = MSGFMT_ARG_FLOAT64;
 
1211
         break;
 
1212
      // j is not defined by man page, but allowed by glibc
 
1213
      case 'L':
 
1214
      case 'j':
 
1215
         /*
 
1216
          * We don't do %Lf because it's not that useful to us, and
 
1217
          * long double has a number of implementations.  For example,
 
1218
          * on Win32 it's the same as double, and it would have a hard
 
1219
          * time dealing with a bigger one passed to it.
 
1220
          * We can just coerce it down to a double at the source,
 
1221
          * but then why bother?
 
1222
          */
 
1223
         MsgFmtError(state,
 
1224
                     "MsgFmtGetArg1: %%%c%c not supported, "
 
1225
                     "pos \"%.*s\", type \"%.*s\"",
 
1226
                     lengthMod, conversion, posSize, pos, typeSize, type);
 
1227
         return -2;
 
1228
      default:
 
1229
         NOT_REACHED();
 
1230
      }
 
1231
      break;
 
1232
 
 
1233
   case 'c':
 
1234
      switch (lengthMod) {
 
1235
      // h hh t z not defined by man page, but allowed by glibc
 
1236
      case '\0':
 
1237
      case 'h':
 
1238
      case 'H':
 
1239
      case 't':
 
1240
      case 'z':
 
1241
         ASSERT_ON_COMPILE(sizeof (int) == sizeof (int32));
 
1242
         argType = MSGFMT_ARG_INT32;
 
1243
         break;
 
1244
      // j ll L not defined by man page nor actually supported
 
1245
      case 'l':
 
1246
      case 'j':
 
1247
      case 'L':
 
1248
         goto caseC;
 
1249
      default:
 
1250
         NOT_REACHED();
 
1251
      }
 
1252
      break;
 
1253
 
 
1254
   case 'C':
 
1255
   caseC:
 
1256
      // man page says it's a wint_t argument, but we assume promotion to int
 
1257
      ASSERT_ON_COMPILE(sizeof (wint_t) <= sizeof (int) &&
 
1258
                        sizeof (int) == sizeof (int32));
 
1259
      argType = MSGFMT_ARG_INT32;
 
1260
      break;
 
1261
 
 
1262
   case 's':
 
1263
      // we interpret the length modifier like we do for %c
 
1264
      switch (lengthMod) {
 
1265
      case '\0':
 
1266
      case 'h':
 
1267
      case 'H':
 
1268
      case 't':
 
1269
      case 'z':
 
1270
         ASSERT_ON_COMPILE(sizeof (char) == sizeof (int8));
 
1271
         argType = MSGFMT_ARG_STRING8;
 
1272
         break;
 
1273
      case 'l':
 
1274
      case 'j':
 
1275
      case 'L':
 
1276
         goto caseS;
 
1277
      default:
 
1278
         NOT_REACHED();
 
1279
      }
 
1280
      // keep track of maximum string length, see block comment above
 
1281
      a->p.precision = precision;
 
1282
      ASSERT(a->v.ptr == NULL);
 
1283
      break;
 
1284
 
 
1285
   case 'S':
 
1286
   caseS:
 
1287
 
 
1288
#if defined __ANDROID__
 
1289
      ASSERT_ON_COMPILE(sizeof (wchar_t) == sizeof (int16) ||
 
1290
                        sizeof (wchar_t) == sizeof (int32) ||
 
1291
                        sizeof (wchar_t) == sizeof (int8));
 
1292
#else
 
1293
      ASSERT_ON_COMPILE(sizeof (wchar_t) == sizeof (int16) ||
 
1294
                        sizeof (wchar_t) == sizeof (int32));
 
1295
#endif
 
1296
 
 
1297
      if (sizeof (wchar_t) == sizeof (int16)) {
 
1298
         argType = MSGFMT_ARG_STRING16;
 
1299
#if defined __ANDROID__
 
1300
      } else if (sizeof (wchar_t) == sizeof (int8)) {
 
1301
         argType = MSGFMT_ARG_STRING8;
 
1302
#endif
 
1303
      } else {
 
1304
         argType = MSGFMT_ARG_STRING32;
 
1305
      }
 
1306
      // keep track of maximum string length, see block comment above
 
1307
      a->p.precision = precision;
 
1308
      ASSERT(a->v.ptr == NULL);
 
1309
      break;
 
1310
 
 
1311
   case 'p':
 
1312
      ASSERT_ON_COMPILE(sizeof (void *) == sizeof (int32) ||
 
1313
                        sizeof (void *) == sizeof (int64));
 
1314
      if (sizeof (void *) == sizeof (int32)) {
 
1315
         argType = MSGFMT_ARG_PTR32;
 
1316
      } else {
 
1317
         argType = MSGFMT_ARG_PTR64;
 
1318
      }
 
1319
      break;
 
1320
 
 
1321
   case 'n':
 
1322
      MsgFmtError(state,
 
1323
                  "MsgFmtGetArg1: %%n not supported, "
 
1324
                  "pos \"%.*s\", type \"%.*s\"",
 
1325
                  posSize, pos, typeSize, type);
 
1326
      return -2;
 
1327
 
 
1328
   // MsgFmt_ParseSpec() doesn't do %m, and we don't see %%
 
1329
   default:
 
1330
      MsgFmtError(state,
 
1331
                  "MsgFmtGetArg1: %%%c not understood, "
 
1332
                  "pos \"%.*s\", type \"%.*s\"",
 
1333
                  conversion, posSize, pos, typeSize, type);
 
1334
      NOT_REACHED();
 
1335
   }
 
1336
 
 
1337
   ASSERT(argType != MSGFMT_ARG_INVALID);
 
1338
   if (a->type != MSGFMT_ARG_INVALID && a->type != argType) {
 
1339
      MsgFmtError(state,
 
1340
                  "MsgFmtGetArg1: incompatible specifiers for argument %d, "
 
1341
                  "old type %d, new type %d, pos \"%.*s\", type \"%.*s\"",
 
1342
                  position, a->type, argType, posSize, pos, typeSize, type);
 
1343
      return -2;
 
1344
   }
 
1345
   a->type = argType;
 
1346
 
 
1347
   return 0;
 
1348
}
 
1349
 
 
1350
 
 
1351
/*
 
1352
 *-----------------------------------------------------------------------------
 
1353
 *
 
1354
 * MsgFmtError --
 
1355
 *
 
1356
 *      Format an error string and squirrel it away.
 
1357
 *
 
1358
 * Results:
 
1359
 *      Error string returned in state variable.
 
1360
 *
 
1361
 * Side effects:
 
1362
 *      Memory may be allocated.
 
1363
 *
 
1364
 *-----------------------------------------------------------------------------
 
1365
 */
 
1366
 
 
1367
static void
 
1368
MsgFmtError(MsgFmtParseState *state,    // IN/OUT: state structure
 
1369
            const char *fmt,            // IN: error format
 
1370
            ...)                        // IN: error args
 
1371
{
 
1372
   va_list args;
 
1373
 
 
1374
   ASSERT(state->error == NULL);
 
1375
   // free up space (in call-supplied buffer) for error string
 
1376
   MsgFmtFreeAll(state);
 
1377
   va_start(args, fmt);
 
1378
   state->error = MsgFmtVasprintf(state, fmt, args);
 
1379
   va_end(args);
 
1380
}
 
1381
 
 
1382
 
 
1383
/*
 
1384
 *-----------------------------------------------------------------------------
 
1385
 *
 
1386
 * MsgFmt_FreeArgs --
 
1387
 *
 
1388
 *      Free an array of MsgFmt_Arg structures.
 
1389
 *      Do not call this on an array in a caller-supplied
 
1390
 *      buffer from MsgFmt_GetArgsWithBuf().
 
1391
 *
 
1392
 * Results:
 
1393
 *      None.
 
1394
 *
 
1395
 * Side effects:
 
1396
 *      Memory is freed.
 
1397
 *
 
1398
 *-----------------------------------------------------------------------------
 
1399
 */
 
1400
 
 
1401
void
 
1402
MsgFmt_FreeArgs(MsgFmt_Arg *args,       // IN/OUT: arguments to free
 
1403
                int numArgs)            // IN: number of arguments
 
1404
{
 
1405
   int i;
 
1406
 
 
1407
   for (i = 0; i < numArgs; i++) {
 
1408
      switch (args[i].type) {
 
1409
      case MSGFMT_ARG_STRING8:
 
1410
      case MSGFMT_ARG_STRING16:
 
1411
      case MSGFMT_ARG_STRING32:
 
1412
      case MSGFMT_ARG_ERRNO:
 
1413
         free(args[i].v.ptr);
 
1414
         break;
 
1415
      default:
 
1416
         ;
 
1417
      }
 
1418
   }
 
1419
   free(args);
 
1420
}
 
1421
 
 
1422
 
 
1423
/*
 
1424
 *-----------------------------------------------------------------------------
 
1425
 *
 
1426
 * MsgFmtAllocInit --
 
1427
 *
 
1428
 *      Initialize allocator for caller-supplied buffer.
 
1429
 *
 
1430
 * Results:
 
1431
 *      None.
 
1432
 *
 
1433
 * Side effects:
 
1434
 *      As described.
 
1435
 *
 
1436
 *-----------------------------------------------------------------------------
 
1437
 */
 
1438
 
 
1439
static void
 
1440
MsgFmtAllocInit(MsgFmtParseState *state, // IN/OUT: state structure
 
1441
                void *buf,               // IN: buffer
 
1442
                size_t size)             // IN: size to allocate
 
1443
{
 
1444
   state->bufp = state->buf = buf;
 
1445
   state->bufe = state->bufp + size;
 
1446
}
 
1447
 
 
1448
 
 
1449
/*
 
1450
 *-----------------------------------------------------------------------------
 
1451
 *
 
1452
 * MsgFmtAlloc --
 
1453
 *
 
1454
 *      Allocate memory from malloc() or from supplied buffer.
 
1455
 *
 
1456
 * Results:
 
1457
 *      Pointer or NULL on failure.
 
1458
 *
 
1459
 * Side effects:
 
1460
 *      Memory allocated or state updated.
 
1461
 *
 
1462
 *-----------------------------------------------------------------------------
 
1463
 */
 
1464
 
 
1465
static void *
 
1466
MsgFmtAlloc(MsgFmtParseState *state,    // IN/OUT: state structure
 
1467
            size_t size)                // IN: size to allocate
 
1468
{
 
1469
   void *p;
 
1470
 
 
1471
   if (state->buf == NULL) {
 
1472
      p = malloc(size);
 
1473
   } else {
 
1474
      if (state->bufe - state->bufp < size) {
 
1475
         return NULL;
 
1476
      }
 
1477
      p = state->bufp;
 
1478
      state->bufp += size;
 
1479
   }
 
1480
   return p;
 
1481
}
 
1482
 
 
1483
 
 
1484
/*
 
1485
 *-----------------------------------------------------------------------------
 
1486
 *
 
1487
 * MsgFmtAllocArgs --
 
1488
 *
 
1489
 *      Grow MsgFmt_Arg array to accomodate new entry.
 
1490
 *
 
1491
 * Results:
 
1492
 *      TRUE on success.
 
1493
 *      State updated.
 
1494
 *
 
1495
 * Side effects:
 
1496
 *      Memory may be allocated.
 
1497
 *
 
1498
 *-----------------------------------------------------------------------------
 
1499
 */
 
1500
 
 
1501
static Bool
 
1502
MsgFmtAllocArgs(MsgFmtParseState *state, // IN/OUT: state structure
 
1503
                int n)                   // IN: 1-based argument number
 
1504
{
 
1505
   if (n <= state->maxArgs) {
 
1506
      return TRUE;
 
1507
   }
 
1508
 
 
1509
   /*
 
1510
    * If using malloc, then reallocate() the array with some slack.
 
1511
    * If using our own buffer, just grow it exactly.
 
1512
    */
 
1513
 
 
1514
   if (state->buf == NULL) {
 
1515
      void *p;
 
1516
      n = MAX(4, n + state->maxArgs);
 
1517
      p = realloc(state->args, n * sizeof *state->args);
 
1518
      if (p == NULL) {
 
1519
         return FALSE;
 
1520
      }
 
1521
      state->args = p;
 
1522
   } else {
 
1523
      if (state->args == NULL) {
 
1524
         // first time
 
1525
         state->args = (void *) state->bufp;
 
1526
      } else {
 
1527
         // growing: there must be nothing after the args array
 
1528
         ASSERT((void *) state->bufp == state->args + state->maxArgs);
 
1529
      }
 
1530
      if ((char *) (state->args + n) > state->bufe) {
 
1531
         return FALSE;
 
1532
      }
 
1533
      state->bufp = (char *) (state->args + n);
 
1534
   }
 
1535
   memset(state->args + state->maxArgs, 0,
 
1536
          sizeof *state->args * (n - state->maxArgs));
 
1537
   state->maxArgs = n;
 
1538
   return TRUE;
 
1539
}
 
1540
 
 
1541
 
 
1542
/*
 
1543
 *-----------------------------------------------------------------------------
 
1544
 *
 
1545
 * MsgFmtVasprintf --
 
1546
 *
 
1547
 *      Format a string in allocated space.
 
1548
 *
 
1549
 * Results:
 
1550
 *      String.
 
1551
 *
 
1552
 * Side effects:
 
1553
 *      Memory allocated or state updated.
 
1554
 *      Panic if can't allocate.
 
1555
 *
 
1556
 *-----------------------------------------------------------------------------
 
1557
 */
 
1558
 
 
1559
static char *
 
1560
MsgFmtVasprintf(MsgFmtParseState *state,        // IN/OUT: state structure
 
1561
                const char *fmt,                // IN: error format
 
1562
                va_list args)           // IN: error args
 
1563
{
 
1564
   char *p;
 
1565
 
 
1566
   ASSERT(state->error == NULL);
 
1567
   if (state->buf == NULL) {
 
1568
      p = Str_Vasprintf(NULL, fmt, args);
 
1569
      ASSERT_MEM_ALLOC(p != NULL);
 
1570
   } else {
 
1571
      int n;
 
1572
      p = state->bufp;
 
1573
      // Str_Vsnprintf() may truncate
 
1574
      n = Str_Vsnprintf(p, (char *)state->bufe - p, fmt, args);
 
1575
      state->bufp = (n < 0) ? state->bufe : state->bufp + n + 1;
 
1576
   }
 
1577
   return p;
 
1578
}
 
1579
 
 
1580
 
 
1581
/*
 
1582
 *-----------------------------------------------------------------------------
 
1583
 *
 
1584
 * MsgFmtFreeAll --
 
1585
 *
 
1586
 *      Free all memory associated with current MsgFmt_Arg array.
 
1587
 *
 
1588
 * Results:
 
1589
 *      State updated.
 
1590
 *
 
1591
 * Side effects:
 
1592
 *      Memory may be freed.
 
1593
 *
 
1594
 *-----------------------------------------------------------------------------
 
1595
 */
 
1596
 
 
1597
static void
 
1598
MsgFmtFreeAll(MsgFmtParseState *state) // IN/OUT: state structure
 
1599
{
 
1600
   if (state->args == NULL)
 
1601
      return;
 
1602
 
 
1603
   if (state->buf == NULL) {
 
1604
      MsgFmt_FreeArgs(state->args, state->numArgs);
 
1605
   } else {
 
1606
      state->bufp = state->buf;
 
1607
   }
 
1608
   state->numArgs = state->maxArgs = 0;
 
1609
   state->args = NULL;
 
1610
}
 
1611
 
 
1612
 
 
1613
/*
 
1614
 *-----------------------------------------------------------------------------
 
1615
 *
 
1616
 * MsgFmtBufUsed --
 
1617
 *
 
1618
 *      Return the amount of space used in the caller supplied buffer.
 
1619
 *
 
1620
 * Results:
 
1621
 *      size_t  
 
1622
 *
 
1623
 * Side effects:
 
1624
 *      None.
 
1625
 *
 
1626
 *-----------------------------------------------------------------------------
 
1627
 */
 
1628
 
 
1629
static size_t
 
1630
MsgFmtBufUsed(MsgFmtParseState *state) // IN: state structure
 
1631
{
 
1632
   if (state->buf == NULL) {
 
1633
      return 0;
 
1634
   } else {
 
1635
      return state->bufp - (char *)state->buf;
 
1636
   }
 
1637
}
 
1638
 
 
1639
 
 
1640
/*
 
1641
 *-----------------------------------------------------------------------------
 
1642
 *
 
1643
 * MsgFmt_SwizzleArgs --
 
1644
 *
 
1645
 *      Pointer swizzling. Flattens pointers in the MsgFmt_Arg array by
 
1646
 *      converting them to offsets relative to the start of the args array.
 
1647
 *      This should only be invoked if the MsgFmt_Arg array was allocated 
 
1648
 *      from a caller-supplied buffer from MsgFmt_GetArgsWithBuf.
 
1649
 *
 
1650
 * Results:
 
1651
 *      None.
 
1652
 *
 
1653
 * Side effects:
 
1654
 *      For all i such that args[i] is a string parameter,
 
1655
 *      args[i].v.offset is set to the offset from args to the start
 
1656
 *      of the string, or to 0 if the string was NULL.
 
1657
 *
 
1658
 *-----------------------------------------------------------------------------
 
1659
 */
 
1660
 
 
1661
void
 
1662
MsgFmt_SwizzleArgs(MsgFmt_Arg *args,
 
1663
                   int numArgs)
 
1664
{
 
1665
   int i;
 
1666
   int8* bufStart = (int8*)args;
 
1667
 
 
1668
   for (i = 0; i < numArgs; i++) {
 
1669
      
 
1670
      switch (args[i].type) {
 
1671
         case MSGFMT_ARG_STRING8:
 
1672
         case MSGFMT_ARG_STRING16:
 
1673
         case MSGFMT_ARG_STRING32:
 
1674
            if (args[i].v.ptr == NULL) {
 
1675
               // offset is never 0 otherwise
 
1676
               args[i].v.offset = 0;
 
1677
            } else {
 
1678
               args[i].v.offset = (int8*)args[i].v.ptr - bufStart;
 
1679
            }
 
1680
            break;
 
1681
         default:
 
1682
            break;
 
1683
      }
 
1684
   }
 
1685
}
 
1686
 
 
1687
 
 
1688
/*
 
1689
 *-----------------------------------------------------------------------------
 
1690
 *
 
1691
 * MsgFmt_GetSwizzledString --
 
1692
 *
 
1693
 *      Helper for pointer un-swizzling.  Obtains the pointer encoded
 
1694
 *      by a swizzled argument, if it is a string and the pointer is
 
1695
 *      within the proper bounds.
 
1696
 *
 
1697
 * Results:
 
1698
 *      NULL and a non-zero return value if the given argument is not
 
1699
 *      a string, or the pointer is out of bounds (below the end of
 
1700
 *      the args array or above the end of the buffer), or the string
 
1701
 *      is not null-terminated within the buffer.
 
1702
 *
 
1703
 *      Exception to the above: an offset of 0 is used to encode the
 
1704
 *      NULL pointer.  In this case, yields NULL and returns zero.
 
1705
 *
 
1706
 *      Otherwise, yields a pointer to the string and returns zero.
 
1707
 *
 
1708
 * Side effects:
 
1709
 *      None.
 
1710
 *
 
1711
 *-----------------------------------------------------------------------------
 
1712
 */
 
1713
 
 
1714
int
 
1715
MsgFmt_GetSwizzledString(const MsgFmt_Arg *args,    // IN: argument array
 
1716
                         int               numArgs, // IN: size of the array
 
1717
                         int               i,       // IN: index into the array
 
1718
                         const void       *bufEnd,  // IN: string space bound
 
1719
                         const int8      **str)     // OUT: the string
 
1720
{
 
1721
   const int8 *bufStart = (const int8*)args;
 
1722
   const int8 *strStart = (const int8*)(args + numArgs);
 
1723
   const int8 *strEnd = bufEnd;
 
1724
   
 
1725
   switch(args[i].type) {
 
1726
      case MSGFMT_ARG_STRING8:
 
1727
      case MSGFMT_ARG_STRING16:
 
1728
      case MSGFMT_ARG_STRING32:
 
1729
         if (args[i].v.offset == 0) {
 
1730
            // offset is never 0 otherwise
 
1731
            *str = NULL;
 
1732
            return 0;
 
1733
         } else {
 
1734
            const int8 *ptr = args[i].v.offset + bufStart;
 
1735
            
 
1736
            if (ptr < strStart || ptr >= strEnd
 
1737
                || memchr(ptr, '\0', strEnd - ptr) == NULL) {
 
1738
               *str = NULL;
 
1739
               return -1;
 
1740
            } else {
 
1741
               *str = ptr;
 
1742
               return 0;
 
1743
            }
 
1744
         }
 
1745
         break;
 
1746
      default:
 
1747
         *str = NULL;
 
1748
         return -1;
 
1749
   }
 
1750
   NOT_REACHED();
 
1751
}
 
1752
 
 
1753
 
 
1754
/*
 
1755
 *-----------------------------------------------------------------------------
 
1756
 *
 
1757
 * MsgFmt_UnswizzleArgs --
 
1758
 *
 
1759
 *      Pointer un-swizzling. Re-instates the pointers in the arg array.
 
1760
 *      This should only be invoked if the MsgFmt_Arg array was previously
 
1761
 *      swizzled using MsgFmt_SwizzleArgs.
 
1762
 *
 
1763
 *      If a reconstituted pointer would be out of range -- i.e.,
 
1764
 *      before the end of the args array or after the provided
 
1765
 *      end-of-buffer pointer -- it is replaced with NULL and an error
 
1766
 *      is returned.  This is also done if the resulting string is not
 
1767
 *      null-terminated within the provided bound.
 
1768
 *
 
1769
 * Results:
 
1770
 *      0 on success; -1 in case of bad pointer.
 
1771
 *
 
1772
 * Side effects:
 
1773
 *      For all i such that args[i] is a string parameter, sets
 
1774
 *      args[i].v.ptr to the string previously encoded as an offset,
 
1775
 *      or to NULL if the offset was 0, or to NULL in case of error.
 
1776
 *
 
1777
 *-----------------------------------------------------------------------------
 
1778
 */
 
1779
 
 
1780
int
 
1781
MsgFmt_UnswizzleArgs(MsgFmt_Arg *args,    // IN/OUT: the arguments (+ strings)
 
1782
                     int         numArgs, // IN: number of arguments
 
1783
                     void       *bufEnd)  // IN: string space bound
 
1784
{
 
1785
   int i;
 
1786
   int failures = 0;
 
1787
 
 
1788
   for (i = 0; i < numArgs; i++) {
 
1789
      switch (args[i].type) {
 
1790
         case MSGFMT_ARG_STRING8:
 
1791
         case MSGFMT_ARG_STRING16:
 
1792
         case MSGFMT_ARG_STRING32:
 
1793
            if (MsgFmt_GetSwizzledString(args, numArgs, i, bufEnd,
 
1794
                                         (const int8**)&args[i].v.ptr) != 0) {
 
1795
               ++failures;
 
1796
            }
 
1797
            break;
 
1798
         default:
 
1799
            break;
 
1800
      }
 
1801
   }
 
1802
   return failures > 0 ? -1 : 0;
 
1803
}
 
1804
 
 
1805
 
 
1806
/*
 
1807
 *-----------------------------------------------------------------------------
 
1808
 *
 
1809
 * MsgFmt_CopyArgs --
 
1810
 *      
 
1811
 *      Copy all args from the given 'copyArgs' array. 
 
1812
 *
 
1813
 * Results:
 
1814
 *      Pointer to copied args array.
 
1815
 *
 
1816
 * Side effects:
 
1817
 *      Allocates memory for new args array.
 
1818
 *
 
1819
 *-----------------------------------------------------------------------------
 
1820
 */
 
1821
 
 
1822
MsgFmt_Arg*
 
1823
MsgFmt_CopyArgs(MsgFmt_Arg* copyArgs,      // IN: Args to be copied
 
1824
                int numArgs)               // IN: number of args
 
1825
{
 
1826
   MsgFmt_Arg *args;
 
1827
   int i;
 
1828
 
 
1829
   args = malloc(numArgs * sizeof(MsgFmt_Arg));
 
1830
   if (args == NULL) {
 
1831
      return NULL;
 
1832
   }
 
1833
 
 
1834
   memcpy(args, copyArgs, numArgs * sizeof(MsgFmt_Arg));
 
1835
   
 
1836
   for (i = 0; i < numArgs; i++) {
 
1837
      switch (args[i].type) {
 
1838
         case MSGFMT_ARG_STRING8:
 
1839
         case MSGFMT_ARG_ERRNO:
 
1840
            if (args[i].v.string8 != NULL) {
 
1841
               args[i].v.string8char = strdup(copyArgs[i].v.string8char);
 
1842
               if (args[i].v.string8 == NULL) {
 
1843
                  MsgFmt_FreeArgs(args, i);
 
1844
                  return NULL;
 
1845
               }
 
1846
            }
 
1847
            break;
 
1848
         case MSGFMT_ARG_STRING16:
 
1849
         case MSGFMT_ARG_STRING32:
 
1850
            /*
 
1851
             * We don't care about these types.
 
1852
             */
 
1853
            NOT_IMPLEMENTED();
 
1854
            break;
 
1855
         default:
 
1856
            break;
 
1857
      }
 
1858
   }
 
1859
 
 
1860
   return args;
 
1861
}
 
1862
 
 
1863
 
 
1864
#ifdef HAS_BSD_PRINTF // {
 
1865
 
 
1866
/*
 
1867
 *-----------------------------------------------------------------------------
 
1868
 *
 
1869
 * MsgFmt_Snprintf --
 
1870
 *
 
1871
 *      MsgFmt_Arg version of Str_Vsnprintf().
 
1872
 *
 
1873
 * Results:
 
1874
 *      Number of character written, not including null termination,
 
1875
 *      or number of characters would have been written on overflow.
 
1876
 *      (This is exactly the same as vsnprintf(), but different
 
1877
 *      from Str_Vsnprintf().)
 
1878
 *      String is always null terminated, even on overflow.
 
1879
 *
 
1880
 * Side effects:
 
1881
 *      None.
 
1882
 *
 
1883
 *-----------------------------------------------------------------------------
 
1884
 */
 
1885
 
 
1886
int
 
1887
MsgFmt_Snprintf(char *buf,               // OUT: formatted string
 
1888
                size_t size,             // IN: size of buffer
 
1889
                const char *format,      // IN: format
 
1890
                const MsgFmt_Arg *args,  // IN: message arguments
 
1891
                int numArgs)             // IN: number of arguments
 
1892
{
 
1893
   return MsgFmtSnprintfWork(&buf, size, format, args, numArgs);
 
1894
}
 
1895
 
 
1896
 
 
1897
/*
 
1898
 *-----------------------------------------------------------------------------
 
1899
 *
 
1900
 * MsgFmt_Asprintf --
 
1901
 *
 
1902
 *      MsgFmt_Arg version of Str_Vasprintf().
 
1903
 *
 
1904
 * Results:
 
1905
 *      Allocated string on success.
 
1906
 *      NULL on failure.
 
1907
 *      Length of returned string (not including null termination)
 
1908
 *      in *length (if length != NULL).
 
1909
 *
 
1910
 * Side effects:
 
1911
 *      None.
 
1912
 *
 
1913
 *-----------------------------------------------------------------------------
 
1914
 */
 
1915
 
 
1916
char *
 
1917
MsgFmt_Asprintf(size_t *length,          // OUT: length of returned string
 
1918
                const char *format,      // IN: format
 
1919
                const MsgFmt_Arg *args,  // IN: message arguments
 
1920
                int numArgs)             // IN: number of arguments
 
1921
{
 
1922
   char *p = NULL;
 
1923
   int n = MsgFmtSnprintfWork(&p, 0, format, args, numArgs);
 
1924
 
 
1925
   if (n < 0) {
 
1926
      return NULL;
 
1927
   }
 
1928
   if (length != NULL) {
 
1929
      *length = n;
 
1930
   }
 
1931
   return p;
 
1932
}
 
1933
 
 
1934
static int
 
1935
MsgFmtSnprintfWork(char **outbuf, size_t bufSize, const char *fmt0,
 
1936
                   const MsgFmt_Arg *args, int numArgs)
 
1937
{
 
1938
   char *fmt;      /* format string */
 
1939
   int ch;         /* character from fmt */
 
1940
   int n;          /* handy integer (short term usage) */
 
1941
   char *cp;      /* handy char pointer (short term usage) */
 
1942
   BSDFmt_IOV *iovp;   /* for PRINT macro */
 
1943
   int flags;      /* flags as above */
 
1944
   int ret;      /* return value accumulator */
 
1945
   int width;      /* width from format (%8d), or 0 */
 
1946
   int prec;      /* precision from format; <0 for N/A */
 
1947
   char sign;      /* sign prefix (' ', '+', '-', or \0) */
 
1948
   char thousands_sep;   /* locale specific thousands separator */
 
1949
   const char *grouping;   /* locale specific numeric grouping rules */
 
1950
 
 
1951
#ifndef NO_FLOATING_POINT
 
1952
   /*
 
1953
    * We can decompose the printed representation of floating
 
1954
    * point numbers into several parts, some of which may be empty:
 
1955
    *
 
1956
    * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
 
1957
    *    A       B     ---C---      D       E   F
 
1958
    *
 
1959
    * A:   'sign' holds this value if present; '\0' otherwise
 
1960
    * B:   ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
 
1961
    * C:   cp points to the string MMMNNN.  Leading and trailing
 
1962
    *   zeros are not in the string and must be added.
 
1963
    * D:   expchar holds this character; '\0' if no exponent, e.g. %f
 
1964
    * F:   at least two digits for decimal, at least one digit for hex
 
1965
    */
 
1966
   char *decimal_point;   /* locale specific decimal point */
 
1967
#if defined __ANDROID__
 
1968
   static const char dp = '.';
 
1969
#endif
 
1970
   int signflag;      /* true if float is negative */
 
1971
   union {         /* floating point arguments %[aAeEfFgG] */
 
1972
      double dbl;
 
1973
      long double ldbl;
 
1974
   } fparg;
 
1975
   int expt;      /* integer value of exponent */
 
1976
   char expchar;      /* exponent character: [eEpP\0] */
 
1977
   char *dtoaend;      /* pointer to end of converted digits */
 
1978
   int expsize;      /* character count for expstr */
 
1979
   int lead;      /* sig figs before decimal or group sep */
 
1980
   int ndig;      /* actual number of digits returned by dtoa */
 
1981
   char expstr[MAXEXPDIG+2];   /* buffer for exponent string: e+ZZZ */
 
1982
   char *dtoaresult;   /* buffer allocated by dtoa */
 
1983
   int nseps;      /* number of group separators with ' */
 
1984
   int nrepeats;      /* number of repeats of the last group */
 
1985
#endif
 
1986
   uintmax_t ujval;   /* %j, %ll, %q, %t, %z integers */
 
1987
   int base;      /* base for [diouxX] conversion */
 
1988
   int dprec;      /* a copy of prec if [diouxX], 0 otherwise */
 
1989
   int realsz;      /* field size expanded by dprec, sign, etc */
 
1990
   int size;      /* size of converted field or string */
 
1991
   int prsize;             /* max size of printed field */
 
1992
   const char *xdigs;        /* digits for %[xX] conversion */
 
1993
   BSDFmt_UIO uio;   /* output information: summary */
 
1994
   BSDFmt_IOV iov[BSDFMT_NIOV]; /* ... and individual io vectors */
 
1995
   char buf[INT_CONV_BUF];/* buffer with space for digits of uintmax_t */
 
1996
   char ox[2];      /* space for 0x; ox[1] is either x, X, or \0 */
 
1997
   int nextarg;            /* 1-based argument index */
 
1998
   const MsgFmt_Arg *a;
 
1999
   char *convbuf;      /* wide to multibyte conversion result */
 
2000
   BSDFmt_StrBuf sbuf;
 
2001
 
 
2002
   /*
 
2003
    * BEWARE, these `goto error' on error, and PAD uses `n'.
 
2004
    */
 
2005
#define   PRINT(ptr, len) {                             \
 
2006
      iovp->iov_base = (ptr);                           \
 
2007
      iovp->iov_len = (len);                            \
 
2008
      uio.uio_resid += (len);                           \
 
2009
      iovp++;                                           \
 
2010
      if (++uio.uio_iovcnt >= BSDFMT_NIOV) {            \
 
2011
         if (BSDFmt_SPrint(&sbuf, &uio))                \
 
2012
            goto error;                                 \
 
2013
         iovp = iov;                                    \
 
2014
      }                                                 \
 
2015
   }
 
2016
#define   PAD(howmany, with) {                  \
 
2017
      if ((n = (howmany)) > 0) {                \
 
2018
         while (n > PADSIZE) {                  \
 
2019
            PRINT(with, PADSIZE);               \
 
2020
            n -= PADSIZE;                       \
 
2021
         }                                      \
 
2022
         PRINT(with, n);                        \
 
2023
      }                                         \
 
2024
   }
 
2025
#define   PRINTANDPAD(p, ep, len, with) do {    \
 
2026
      int n2 = (ep) - (p);                      \
 
2027
      if (n2 > (len))                           \
 
2028
         n2 = (len);                            \
 
2029
      if (n2 > 0)                               \
 
2030
         PRINT((p), n2);                        \
 
2031
      PAD((len) - (n2 > 0 ? n2 : 0), (with));   \
 
2032
   } while(0)
 
2033
#define   FLUSH() {                                                     \
 
2034
      if (uio.uio_resid && BSDFmt_SPrint(&sbuf, &uio))                  \
 
2035
         goto error;                                                    \
 
2036
      uio.uio_iovcnt = 0;                                               \
 
2037
      iovp = iov;                                                       \
 
2038
   }
 
2039
 
 
2040
#define FETCHARG(a, i) do { \
 
2041
   int ii = (i) - 1; \
 
2042
   if (ii >= numArgs) { \
 
2043
      sbuf.error = TRUE; \
 
2044
      goto error; \
 
2045
   } \
 
2046
   (a) = args + ii; \
 
2047
} while (FALSE)
 
2048
 
 
2049
   /*
 
2050
    * Get * arguments, including the form *nn$.
 
2051
    */
 
2052
#define GETASTER(val) do { \
 
2053
   int n2 = 0; \
 
2054
   char *cp = fmt; \
 
2055
   const MsgFmt_Arg *a; \
 
2056
   while (is_digit(*cp)) { \
 
2057
      n2 = 10 * n2 + to_digit(*cp); \
 
2058
      cp++; \
 
2059
   } \
 
2060
   if (*cp == '$') { \
 
2061
      FETCHARG(a, n2); \
 
2062
      fmt = cp + 1; \
 
2063
   } else { \
 
2064
      FETCHARG(a, nextarg++); \
 
2065
   } \
 
2066
   if (a->type != MSGFMT_ARG_INT32) { \
 
2067
      sbuf.error = TRUE; \
 
2068
      goto error; \
 
2069
   } \
 
2070
   val = a->v.signed32; \
 
2071
} while (FALSE)
 
2072
 
 
2073
   xdigs = xdigs_lower;
 
2074
   thousands_sep = '\0';
 
2075
   grouping = NULL;
 
2076
   convbuf = NULL;
 
2077
#ifndef NO_FLOATING_POINT
 
2078
   dtoaresult = NULL;
 
2079
#if defined __ANDROID__
 
2080
   /*
 
2081
    * Struct lconv is not working! For decimal_point,
 
2082
    * using '.' instead is a workaround.
 
2083
    */
 
2084
   NOT_TESTED();
 
2085
   decimal_point = &dp;
 
2086
#else
 
2087
   decimal_point = localeconv()->decimal_point;
 
2088
#endif
 
2089
#endif
 
2090
 
 
2091
   fmt = (char *)fmt0;
 
2092
   nextarg = 1;
 
2093
   uio.uio_iov = iovp = iov;
 
2094
   uio.uio_resid = 0;
 
2095
   uio.uio_iovcnt = 0;
 
2096
   ret = 0;
 
2097
 
 
2098
   /*
 
2099
    * Set up output string buffer structure.
 
2100
    */
 
2101
 
 
2102
   sbuf.alloc = *outbuf == NULL;
 
2103
   sbuf.error = FALSE;
 
2104
   sbuf.buf = *outbuf;
 
2105
   sbuf.size = bufSize;
 
2106
   sbuf.index = 0;
 
2107
 
 
2108
   /*
 
2109
    * If asprintf(), allocate initial buffer based on format length.
 
2110
    * Empty format only needs one byte.
 
2111
    * Otherwise, round up to multiple of 64.
 
2112
    */
 
2113
 
 
2114
   if (sbuf.alloc) {
 
2115
      size_t n = strlen(fmt0) + 1;      // +1 for \0
 
2116
      if (n > 1) {
 
2117
         n = ROUNDUP(n, 64);
 
2118
      }
 
2119
      if ((sbuf.buf = malloc(n * sizeof (char))) == NULL) {
 
2120
         sbuf.error = TRUE;
 
2121
         goto error;
 
2122
      }
 
2123
      sbuf.size = n;
 
2124
   }
 
2125
 
 
2126
   // shut compile up
 
2127
#ifndef NO_FLOATING_POINT
 
2128
   expt = 0;
 
2129
   expchar = 0;
 
2130
   dtoaend = NULL;
 
2131
   expsize = 0;
 
2132
   lead = 0;
 
2133
   ndig = 0;
 
2134
   nseps = 0;
 
2135
   nrepeats = 0;
 
2136
#endif
 
2137
   ujval = 0;
 
2138
 
 
2139
   /*
 
2140
    * Scan the format for conversions (`%' character).
 
2141
    */
 
2142
   for (;;) {
 
2143
      for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
 
2144
         /* void */;
 
2145
      if ((n = fmt - cp) != 0) {
 
2146
         if ((unsigned)ret + n > INT_MAX) {
 
2147
            ret = EOF;
 
2148
            goto error;
 
2149
         }
 
2150
         PRINT(cp, n);
 
2151
         ret += n;
 
2152
      }
 
2153
      if (ch == '\0')
 
2154
         goto done;
 
2155
      fmt++;      /* skip over '%' */
 
2156
 
 
2157
      flags = 0;
 
2158
      dprec = 0;
 
2159
      width = 0;
 
2160
      prec = -1;
 
2161
      sign = '\0';
 
2162
      ox[1] = '\0';
 
2163
 
 
2164
     rflag:      ch = *fmt++;
 
2165
     reswitch:   switch (ch) {
 
2166
      case ' ':
 
2167
         /*-
 
2168
          * ``If the space and + flags both appear, the space
 
2169
          * flag will be ignored.''
 
2170
          *   -- ANSI X3J11
 
2171
          */
 
2172
         if (!sign)
 
2173
            sign = ' ';
 
2174
         goto rflag;
 
2175
      case '#':
 
2176
         flags |= ALT;
 
2177
         goto rflag;
 
2178
      case '*':
 
2179
         /*-
 
2180
          * ``A negative field width argument is taken as a
 
2181
          * - flag followed by a positive field width.''
 
2182
          *   -- ANSI X3J11
 
2183
          * They don't exclude field widths read from args.
 
2184
          */
 
2185
         GETASTER (width);
 
2186
         if (width >= 0)
 
2187
            goto rflag;
 
2188
         width = -width;
 
2189
         /* FALLTHROUGH */
 
2190
      case '-':
 
2191
         flags |= LADJUST;
 
2192
         goto rflag;
 
2193
      case '+':
 
2194
         sign = '+';
 
2195
         goto rflag;
 
2196
      case '\'':
 
2197
         flags |= GROUPING;
 
2198
#if defined __ANDROID__
 
2199
         /*
 
2200
          * Struct lconv is not working! The code below is a workaround.
 
2201
          */
 
2202
         NOT_TESTED();
 
2203
         thousands_sep = ',';
 
2204
#else
 
2205
         thousands_sep = *(localeconv()->thousands_sep);
 
2206
         grouping = localeconv()->grouping;
 
2207
#endif
 
2208
         goto rflag;
 
2209
      case '.':
 
2210
         if ((ch = *fmt++) == '*') {
 
2211
            GETASTER (prec);
 
2212
            goto rflag;
 
2213
         }
 
2214
         prec = 0;
 
2215
         while (is_digit(ch)) {
 
2216
            prec = 10 * prec + to_digit(ch);
 
2217
            ch = *fmt++;
 
2218
         }
 
2219
         goto reswitch;
 
2220
      case '0':
 
2221
         /*-
 
2222
          * ``Note that 0 is taken as a flag, not as the
 
2223
          * beginning of a field width.''
 
2224
          *   -- ANSI X3J11
 
2225
          */
 
2226
         flags |= ZEROPAD;
 
2227
         goto rflag;
 
2228
      case '1': case '2': case '3': case '4':
 
2229
      case '5': case '6': case '7': case '8': case '9':
 
2230
         n = 0;
 
2231
         do {
 
2232
            n = 10 * n + to_digit(ch);
 
2233
            ch = *fmt++;
 
2234
         } while (is_digit(ch));
 
2235
         if (ch == '$') {
 
2236
            nextarg = n;
 
2237
            goto rflag;
 
2238
         }
 
2239
         width = n;
 
2240
         goto reswitch;
 
2241
      case 'h':
 
2242
         if (flags & SHORTINT) {
 
2243
            flags &= ~SHORTINT;
 
2244
            flags |= CHARINT;
 
2245
         } else
 
2246
            flags |= SHORTINT;
 
2247
         goto rflag;
 
2248
      case 'j':
 
2249
         flags |= INTMAXT;
 
2250
         goto rflag;
 
2251
      case 'I':
 
2252
         /* could be I64 - long long int is 64bit */
 
2253
         if (fmt[0] == '6' && fmt[1] == '4') {
 
2254
            fmt += 2;
 
2255
            flags |= LLONGINT;
 
2256
            goto rflag;
 
2257
         }
 
2258
         /* could be I32 - normal int is 32bit */
 
2259
         if (fmt[0] == '3' && fmt[1] == '2') {
 
2260
            fmt += 2;
 
2261
            /* flags |= normal integer - it is 32bit for all our targets */
 
2262
            goto rflag;
 
2263
         }
 
2264
         /*
 
2265
          * I alone - use Microsoft's semantic as size_t modifier.  We do
 
2266
          * not support glibc's semantic to use alternative digits.
 
2267
          */
 
2268
         flags |= SIZET;
 
2269
         goto rflag;
 
2270
      case 'l':
 
2271
         if (flags & LONGINT) {
 
2272
            flags &= ~LONGINT;
 
2273
            flags |= LLONGINT;
 
2274
         } else
 
2275
            flags |= LONGINT;
 
2276
         goto rflag;
 
2277
      case 'L':
 
2278
      case 'q':
 
2279
         flags |= LLONGINT;   /* not necessarily */
 
2280
         goto rflag;
 
2281
      case 't':
 
2282
         flags |= PTRDIFFT;
 
2283
         goto rflag;
 
2284
      case 'Z':
 
2285
      case 'z':
 
2286
         flags |= SIZET;
 
2287
         goto rflag;
 
2288
      case 'C':
 
2289
         flags |= LONGINT;
 
2290
         /*FALLTHROUGH*/
 
2291
      case 'c':
 
2292
         FETCHARG(a, nextarg++);
 
2293
         if (a->type != MSGFMT_ARG_INT32) {
 
2294
            sbuf.error = TRUE;
 
2295
            goto error;
 
2296
         }
 
2297
         if (flags & LONGINT) {
 
2298
            static const mbstate_t initial;
 
2299
            mbstate_t mbs;
 
2300
            size_t mbseqlen;
 
2301
 
 
2302
            mbs = initial;
 
2303
            // XXX must deal with mismatch between wchar_t size
 
2304
            mbseqlen = wcrtomb(cp = buf, (wchar_t)a->v.signed32, &mbs);
 
2305
            if (mbseqlen == (size_t)-1) {
 
2306
               sbuf.error = TRUE;
 
2307
               goto error;
 
2308
            }
 
2309
            size = (int)mbseqlen;
 
2310
         } else {
 
2311
            *(cp = buf) = a->v.signed32;
 
2312
            size = 1;
 
2313
         }
 
2314
         sign = '\0';
 
2315
         break;
 
2316
      case 'D':
 
2317
         flags |= LONGINT;
 
2318
         /*FALLTHROUGH*/
 
2319
      case 'd':
 
2320
      case 'i':
 
2321
         FETCHARG(a, nextarg++);
 
2322
         if ((flags & (INTMAXT|LLONGINT)) != 0) {
 
2323
            if (a->type == MSGFMT_ARG_INT64) {
 
2324
               ujval = a->v.signed64;
 
2325
            } else {
 
2326
               sbuf.error = TRUE;
 
2327
               goto error;
 
2328
            }
 
2329
         } else if ((flags & (SIZET|PTRDIFFT|LONGINT)) != 0) {
 
2330
            if (a->type == MSGFMT_ARG_INT64) {
 
2331
               ujval = a->v.signed64;
 
2332
            } else if (a->type == MSGFMT_ARG_INT32) {
 
2333
               ujval = (intmax_t) a->v.signed32;
 
2334
            } else {
 
2335
               sbuf.error = TRUE;
 
2336
               goto error;
 
2337
            }
 
2338
         } else if ((flags & SHORTINT) != 0) {
 
2339
            if (a->type == MSGFMT_ARG_INT32) {
 
2340
               ujval = (intmax_t) (short) a->v.signed32;
 
2341
            } else {
 
2342
               sbuf.error = TRUE;
 
2343
               goto error;
 
2344
            }
 
2345
         } else if ((flags & CHARINT) != 0) {
 
2346
            if (a->type == MSGFMT_ARG_INT32) {
 
2347
               ujval = (intmax_t) (signed char) a->v.signed32;
 
2348
            } else {
 
2349
               sbuf.error = TRUE;
 
2350
               goto error;
 
2351
            }
 
2352
         } else {
 
2353
            if (a->type == MSGFMT_ARG_INT32) {
 
2354
               ujval = (intmax_t) a->v.signed32;
 
2355
            } else {
 
2356
               sbuf.error = TRUE;
 
2357
               goto error;
 
2358
            }
 
2359
         }
 
2360
         if ((intmax_t)ujval < 0) {
 
2361
            ujval = -ujval;
 
2362
            sign = '-';
 
2363
         }
 
2364
         base = 10;
 
2365
         goto number;
 
2366
#ifndef NO_FLOATING_POINT
 
2367
      case 'e':
 
2368
      case 'E':
 
2369
         expchar = ch;
 
2370
         if (prec < 0)   /* account for digit before decpt */
 
2371
            prec = DEFPREC + 1;
 
2372
         else
 
2373
            prec++;
 
2374
         goto fp_begin;
 
2375
      case 'f':
 
2376
      case 'F':
 
2377
         expchar = '\0';
 
2378
         goto fp_begin;
 
2379
      case 'g':
 
2380
      case 'G':
 
2381
         expchar = ch - ('g' - 'e');
 
2382
         if (prec == 0)
 
2383
            prec = 1;
 
2384
      fp_begin:
 
2385
         if (flags & LLONGINT) {
 
2386
            sbuf.error = TRUE;
 
2387
            goto error;
 
2388
         }
 
2389
         if (prec < 0)
 
2390
            prec = DEFPREC;
 
2391
         if (dtoaresult != NULL)
 
2392
            freedtoa(dtoaresult);
 
2393
         FETCHARG(a, nextarg++);
 
2394
         if (a->type != MSGFMT_ARG_FLOAT64) {
 
2395
            sbuf.error = TRUE;
 
2396
            goto error;
 
2397
         }
 
2398
         fparg.dbl = a->v.float64;
 
2399
         dtoaresult = cp =
 
2400
            dtoa(fparg.dbl, expchar ? 2 : 3, prec,
 
2401
                 &expt, &signflag, &dtoaend);
 
2402
         if (expt == 9999)
 
2403
            expt = INT_MAX;
 
2404
         if (signflag)
 
2405
            sign = '-';
 
2406
         if (expt == INT_MAX) {   /* inf or nan */
 
2407
            if (*cp == 'N') {
 
2408
               cp = (ch >= 'a') ? "nan" : "NAN";
 
2409
               sign = '\0';
 
2410
            } else
 
2411
               cp = (ch >= 'a') ? "inf" : "INF";
 
2412
            size = 3;
 
2413
            break;
 
2414
         }
 
2415
         flags |= FPT;
 
2416
         ndig = dtoaend - cp;
 
2417
         if (ch == 'g' || ch == 'G') {
 
2418
            if (expt > -4 && expt <= prec) {
 
2419
               /* Make %[gG] smell like %[fF] */
 
2420
               expchar = '\0';
 
2421
               if (flags & ALT)
 
2422
                  prec -= expt;
 
2423
               else
 
2424
                  prec = ndig - expt;
 
2425
               if (prec < 0)
 
2426
                  prec = 0;
 
2427
            } else {
 
2428
               /*
 
2429
                * Make %[gG] smell like %[eE], but
 
2430
                * trim trailing zeroes if no # flag.
 
2431
                */
 
2432
               if (!(flags & ALT))
 
2433
                  prec = ndig;
 
2434
            }
 
2435
         }
 
2436
         if (expchar) {
 
2437
            expsize = BSDFmt_Exponent(expstr, expt - 1, expchar);
 
2438
            size = expsize + prec;
 
2439
            if (prec > 1 || flags & ALT)
 
2440
               ++size;
 
2441
         } else {
 
2442
            /* space for digits before decimal point */
 
2443
            if (expt > 0)
 
2444
               size = expt;
 
2445
            else   /* "0" */
 
2446
               size = 1;
 
2447
            /* space for decimal pt and following digits */
 
2448
            if (prec || flags & ALT)
 
2449
               size += prec + 1;
 
2450
            if (grouping && expt > 0) {
 
2451
               /* space for thousands' grouping */
 
2452
               nseps = nrepeats = 0;
 
2453
               lead = expt;
 
2454
               while (*grouping != CHAR_MAX) {
 
2455
                  if (lead <= *grouping)
 
2456
                     break;
 
2457
                  lead -= *grouping;
 
2458
                  if (*(grouping+1)) {
 
2459
                     nseps++;
 
2460
                     grouping++;
 
2461
                  } else
 
2462
                     nrepeats++;
 
2463
               }
 
2464
               size += nseps + nrepeats;
 
2465
            } else
 
2466
               lead = expt;
 
2467
         }
 
2468
         break;
 
2469
#endif /* !NO_FLOATING_POINT */
 
2470
      case 'n':
 
2471
         sbuf.error = TRUE;
 
2472
         goto error;
 
2473
      case 'O':
 
2474
         flags |= LONGINT;
 
2475
         /*FALLTHROUGH*/
 
2476
      case 'o':
 
2477
         base = 8;
 
2478
         goto get_unsigned;
 
2479
      case 'p':
 
2480
         /*-
 
2481
          * ``The argument shall be a pointer to void.  The
 
2482
          * value of the pointer is converted to a sequence
 
2483
          * of printable characters, in an implementation-
 
2484
          * defined manner.''
 
2485
          *   -- ANSI X3J11
 
2486
          */
 
2487
         FETCHARG(a, nextarg++);
 
2488
         if (a->type == MSGFMT_ARG_PTR32) {
 
2489
            ujval = a->v.unsigned32;
 
2490
         } else if (a->type == MSGFMT_ARG_PTR64) {
 
2491
            ujval = a->v.unsigned64;
 
2492
         } else {
 
2493
            sbuf.error = TRUE;
 
2494
            goto error;
 
2495
         }
 
2496
         base = 16;
 
2497
         xdigs = xdigs_upper;
 
2498
         flags = flags | INTMAXT;
 
2499
         /*
 
2500
          * PR 103201
 
2501
          * VisualC sscanf doesn't grok '0x', so prefix zeroes.
 
2502
          */
 
2503
//         ox[1] = 'x';
 
2504
         goto nosign;
 
2505
      case 'S':
 
2506
         flags |= LONGINT;
 
2507
         /*FALLTHROUGH*/
 
2508
      case 's':
 
2509
         FETCHARG(a, nextarg++);
 
2510
         if (flags & LONGINT) {
 
2511
            wchar_t *wcp;
 
2512
#if defined __ANDROID__
 
2513
            ASSERT_ON_COMPILE(sizeof (wchar_t) == sizeof (int16) ||
 
2514
                              sizeof (wchar_t) == sizeof (int32) ||
 
2515
                              sizeof (wchar_t) == sizeof (int8));
 
2516
            if ((sizeof (wchar_t) == sizeof (int16) &&
 
2517
                 a->type != MSGFMT_ARG_STRING16) ||
 
2518
                (sizeof (wchar_t) == sizeof (int32) &&
 
2519
                 a->type != MSGFMT_ARG_STRING32) ||
 
2520
                (sizeof (wchar_t) == sizeof (int8) &&
 
2521
                 a->type != MSGFMT_ARG_STRING8)) {
 
2522
#else
 
2523
            ASSERT_ON_COMPILE(sizeof (wchar_t) == 2 || sizeof (wchar_t) == 4);
 
2524
            if (sizeof (wchar_t) == 2 ?
 
2525
                a->type != MSGFMT_ARG_STRING16 :
 
2526
                a->type != MSGFMT_ARG_STRING32) {
 
2527
#endif
 
2528
               sbuf.error = TRUE;
 
2529
               goto error;
 
2530
            }
 
2531
            if ((wcp = (wchar_t *) a->v.ptr) == NULL)
 
2532
               cp = "(null)";
 
2533
            else {
 
2534
               if (convbuf != NULL)
 
2535
                  free(convbuf);
 
2536
               convbuf = BSDFmt_WCharToUTF8(wcp, prec);
 
2537
               if (convbuf == NULL) {
 
2538
                  sbuf.error = TRUE;
 
2539
                  goto error;
 
2540
               }
 
2541
               cp = convbuf;
 
2542
            }
 
2543
         } else {
 
2544
            if (a->type != MSGFMT_ARG_STRING8 &&
 
2545
                a->type != MSGFMT_ARG_ERRNO) {
 
2546
               sbuf.error = TRUE;
 
2547
               goto error;
 
2548
            }
 
2549
 
 
2550
            /*
 
2551
             * Use localized string (in localString) if available.
 
2552
             * Strip off Msg ID if unlocalized string has one.
 
2553
             * Use (null) for null pointer.
 
2554
             */
 
2555
 
 
2556
            if (a->p.localString != NULL) {
 
2557
               cp = a->p.localString;
 
2558
            } else if (a->v.string8 != NULL) {
 
2559
               cp = (char *) Msg_StripMSGID(a->v.string8char);
 
2560
            } else {
 
2561
               cp = "(null)";
 
2562
            }
 
2563
         }
 
2564
         if (prec >= 0) {
 
2565
            /*
 
2566
             * We can use strlen here because the string is always
 
2567
             * terminated, unlike the string passed to MsgFmt_GetArgs.
 
2568
             * However, it's somewhat faster to use memchr.
 
2569
             */
 
2570
            char *p = memchr(cp, 0, prec);
 
2571
 
 
2572
            if (p != NULL) {
 
2573
               size = p - cp;
 
2574
               if (size > prec)
 
2575
                  size = prec;
 
2576
            } else
 
2577
               size = prec;
 
2578
         } else
 
2579
            size = strlen(cp);
 
2580
         sign = '\0';
 
2581
         break;
 
2582
      case 'U':
 
2583
         flags |= LONGINT;
 
2584
         /*FALLTHROUGH*/
 
2585
      case 'u':
 
2586
         base = 10;
 
2587
         goto get_unsigned;
 
2588
      case 'X':
 
2589
         xdigs = xdigs_upper;
 
2590
         goto hex;
 
2591
      case 'x':
 
2592
         xdigs = xdigs_lower;
 
2593
      hex:
 
2594
         base = 16;
 
2595
         if (flags & ALT)
 
2596
            ox[1] = ch;
 
2597
         flags &= ~GROUPING;
 
2598
 
 
2599
      get_unsigned:
 
2600
         FETCHARG(a, nextarg++);
 
2601
         if ((flags & (INTMAXT|LLONGINT)) != 0) {
 
2602
            if (a->type == MSGFMT_ARG_INT64) {
 
2603
               ujval = a->v.unsigned64;
 
2604
            } else {
 
2605
               sbuf.error = TRUE;
 
2606
               goto error;
 
2607
            }
 
2608
         } else if ((flags & (SIZET|PTRDIFFT|LONGINT)) != 0) {
 
2609
            if (a->type == MSGFMT_ARG_INT64) {
 
2610
               ujval = a->v.unsigned64;
 
2611
            } else if (a->type == MSGFMT_ARG_INT32) {
 
2612
               ujval = (uintmax_t) a->v.unsigned32;
 
2613
            } else {
 
2614
               sbuf.error = TRUE;
 
2615
               goto error;
 
2616
            }
 
2617
         } else if ((flags & SHORTINT) != 0) {
 
2618
            if (a->type == MSGFMT_ARG_INT32) {
 
2619
               ujval = (intmax_t) (unsigned short) a->v.unsigned32;
 
2620
            } else {
 
2621
               sbuf.error = TRUE;
 
2622
               goto error;
 
2623
            }
 
2624
         } else if ((flags & CHARINT) != 0) {
 
2625
            if (a->type == MSGFMT_ARG_INT32) {
 
2626
               ujval = (intmax_t) (unsigned char) a->v.unsigned32;
 
2627
            } else {
 
2628
               sbuf.error = TRUE;
 
2629
               goto error;
 
2630
            }
 
2631
         } else {
 
2632
            if (a->type == MSGFMT_ARG_INT32) {
 
2633
               ujval = (intmax_t) a->v.unsigned32;
 
2634
            } else {
 
2635
               sbuf.error = TRUE;
 
2636
               goto error;
 
2637
            }
 
2638
         }
 
2639
         if (ujval == 0) /* squash 0x/X if zero */
 
2640
            ox[1] = '\0';
 
2641
 
 
2642
         /* unsigned conversions */
 
2643
      nosign:
 
2644
         sign = '\0';
 
2645
         /*-
 
2646
          * ``... diouXx conversions ... if a precision is
 
2647
          * specified, the 0 flag will be ignored.''
 
2648
          *   -- ANSI X3J11
 
2649
          */
 
2650
      number:
 
2651
         if ((dprec = prec) >= 0)
 
2652
            flags &= ~ZEROPAD;
 
2653
 
 
2654
         /*-
 
2655
          * ``The result of converting a zero value with an
 
2656
          * explicit precision of zero is no characters.''
 
2657
          *   -- ANSI X3J11
 
2658
          *
 
2659
          * ``The C Standard is clear enough as is.  The call
 
2660
          * printf("%#.0o", 0) should print 0.''
 
2661
          *   -- Defect Report #151
 
2662
          */
 
2663
         cp = buf + INT_CONV_BUF;
 
2664
         if (ujval != 0 || prec != 0 ||
 
2665
             (flags & ALT && base == 8))
 
2666
            cp = BSDFmt_UJToA(ujval, cp, base,
 
2667
                              flags & ALT, xdigs,
 
2668
                              flags & GROUPING, thousands_sep,
 
2669
                              grouping);
 
2670
         size = buf + INT_CONV_BUF - cp;
 
2671
         if (size > INT_CONV_BUF)   /* should never happen */
 
2672
            abort();
 
2673
         break;
 
2674
      default:   /* "%?" prints ?, unless ? is NUL */
 
2675
         if (ch == '\0')
 
2676
            goto done;
 
2677
         /* pretend it was %c with argument ch */
 
2678
         cp = buf;
 
2679
         *cp = ch;
 
2680
         size = 1;
 
2681
         sign = '\0';
 
2682
         break;
 
2683
      }
 
2684
 
 
2685
      /*
 
2686
       * All reasonable formats wind up here.  At this point, `cp'
 
2687
       * points to a string which (if not flags&LADJUST) should be
 
2688
       * padded out to `width' places.  If flags&ZEROPAD, it should
 
2689
       * first be prefixed by any sign or other prefix; otherwise,
 
2690
       * it should be blank padded before the prefix is emitted.
 
2691
       * After any left-hand padding and prefixing, emit zeroes
 
2692
       * required by a decimal [diouxX] precision, then print the
 
2693
       * string proper, then emit zeroes required by any leftover
 
2694
       * floating precision; finally, if LADJUST, pad with blanks.
 
2695
       *
 
2696
       * Compute actual size, so we know how much to pad.
 
2697
       * size excludes decimal prec; realsz includes it.
 
2698
       */
 
2699
      realsz = dprec > size ? dprec : size;
 
2700
      if (sign)
 
2701
         realsz++;
 
2702
      if (ox[1])
 
2703
         realsz += 2;
 
2704
 
 
2705
      prsize = width > realsz ? width : realsz;
 
2706
      if ((unsigned)ret + prsize > INT_MAX) {
 
2707
         ret = EOF;
 
2708
         goto error;
 
2709
      }
 
2710
 
 
2711
      /* right-adjusting blank padding */
 
2712
      if ((flags & (LADJUST|ZEROPAD)) == 0)
 
2713
         PAD(width - realsz, blanks);
 
2714
 
 
2715
      /* prefix */
 
2716
      if (sign)
 
2717
         PRINT(&sign, 1);
 
2718
 
 
2719
      if (ox[1]) {   /* ox[1] is either x, X, or \0 */
 
2720
         ox[0] = '0';
 
2721
         PRINT(ox, 2);
 
2722
      }
 
2723
 
 
2724
      /* right-adjusting zero padding */
 
2725
      if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
 
2726
         PAD(width - realsz, zeroes);
 
2727
 
 
2728
      /* leading zeroes from decimal precision */
 
2729
      PAD(dprec - size, zeroes);
 
2730
 
 
2731
      /* the string or number proper */
 
2732
#ifndef NO_FLOATING_POINT
 
2733
      if ((flags & FPT) == 0) {
 
2734
         PRINT(cp, size);
 
2735
      } else {   /* glue together f_p fragments */
 
2736
         if (!expchar) {   /* %[fF] or sufficiently short %[gG] */
 
2737
            if (expt <= 0) {
 
2738
               PRINT(zeroes, 1);
 
2739
               if (prec || flags & ALT)
 
2740
                  PRINT(decimal_point, 1);
 
2741
               PAD(-expt, zeroes);
 
2742
               /* already handled initial 0's */
 
2743
               prec += expt;
 
2744
            } else {
 
2745
               PRINTANDPAD(cp, dtoaend, lead, zeroes);
 
2746
               cp += lead;
 
2747
               if (grouping) {
 
2748
                  while (nseps>0 || nrepeats>0) {
 
2749
                     if (nrepeats > 0)
 
2750
                        nrepeats--;
 
2751
                     else {
 
2752
                        grouping--;
 
2753
                        nseps--;
 
2754
                     }
 
2755
                     PRINT(&thousands_sep,
 
2756
                           1);
 
2757
                     PRINTANDPAD(cp,dtoaend,
 
2758
                                 *grouping, zeroes);
 
2759
                     cp += *grouping;
 
2760
                  }
 
2761
                  if (cp > dtoaend)
 
2762
                     cp = dtoaend;
 
2763
               }
 
2764
               if (prec || flags & ALT)
 
2765
                  PRINT(decimal_point,1);
 
2766
            }
 
2767
            PRINTANDPAD(cp, dtoaend, prec, zeroes);
 
2768
         } else {   /* %[eE] or sufficiently long %[gG] */
 
2769
            if (prec > 1 || flags & ALT) {
 
2770
               buf[0] = *cp++;
 
2771
               buf[1] = *decimal_point;
 
2772
               PRINT(buf, 2);
 
2773
               PRINT(cp, ndig-1);
 
2774
               PAD(prec - ndig, zeroes);
 
2775
            } else   /* XeYYY */
 
2776
               PRINT(cp, 1);
 
2777
            PRINT(expstr, expsize);
 
2778
         }
 
2779
      }
 
2780
#else
 
2781
      PRINT(cp, size);
 
2782
#endif
 
2783
      /* left-adjusting padding (always blank) */
 
2784
      if (flags & LADJUST)
 
2785
         PAD(width - realsz, blanks);
 
2786
 
 
2787
      /* finally, adjust ret */
 
2788
      ret += prsize;
 
2789
 
 
2790
      FLUSH();   /* copy out the I/O vectors */
 
2791
   }
 
2792
done:
 
2793
   FLUSH();
 
2794
 
 
2795
   /*
 
2796
    * Always null terminate, unless buffer is size 0.
 
2797
    */
 
2798
 
 
2799
   ASSERT(!sbuf.error && ret >= 0);
 
2800
   if (sbuf.size <= 0) {
 
2801
      ASSERT(!sbuf.alloc);
 
2802
   } else {
 
2803
      ASSERT(sbuf.index < sbuf.size);
 
2804
      sbuf.buf[sbuf.index] = '\0';
 
2805
   }
 
2806
 
 
2807
error:
 
2808
#ifndef NO_FLOATING_POINT
 
2809
   if (dtoaresult != NULL)
 
2810
      freedtoa(dtoaresult);
 
2811
#endif
 
2812
   if (convbuf != NULL)
 
2813
      free(convbuf);
 
2814
   if (sbuf.error) {
 
2815
      ret = EOF;
 
2816
   }
 
2817
 
 
2818
   // return allocated buffer on success, free it on failure
 
2819
   if (sbuf.alloc) {
 
2820
      if (ret < 0) {
 
2821
         free(sbuf.buf);
 
2822
      } else {
 
2823
         *outbuf = sbuf.buf;
 
2824
      }
 
2825
   }
 
2826
 
 
2827
   return (ret);
 
2828
   /* NOTREACHED */
 
2829
 
 
2830
#undef PRINT
 
2831
#undef PAD
 
2832
#undef PRINTANDPAD
 
2833
#undef FLUSH
 
2834
#undef FETCHARG
 
2835
#undef GETASTER
 
2836
}
 
2837
 
 
2838
#endif // }