~sergiusens/libhybris/autotests

« back to all changes in this revision

Viewing changes to hybris/common/jb/linker_format.c

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo
  • Date: 2013-06-04 07:33:11 UTC
  • Revision ID: package-import@ubuntu.com-20130604073311-20ldi2hm1axkvjl1
Tags: upstream-0.1.0+git20130601+dfb2e26
ImportĀ upstreamĀ versionĀ 0.1.0+git20130601+dfb2e26

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 The Android Open Source Project
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *  * Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 *  * Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in
 
12
 *    the documentation and/or other materials provided with the
 
13
 *    distribution.
 
14
 *
 
15
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
16
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
17
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 
18
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 
19
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 
20
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 
21
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 
22
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 
23
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
24
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 
25
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
26
 * SUCH DAMAGE.
 
27
 */
 
28
 
 
29
#include <stdarg.h>
 
30
#include <string.h>
 
31
#include <errno.h>
 
32
#include <unistd.h>
 
33
#include <stdint.h>
 
34
#include <stddef.h>
 
35
#include "linker_format.h"
 
36
#include "linker_debug.h"
 
37
 
 
38
/* define UNIT_TESTS to build this file as a single executable that runs
 
39
 * the formatter's unit tests
 
40
 */
 
41
#define xxUNIT_TESTS
 
42
 
 
43
/*** Generic output sink
 
44
 ***/
 
45
 
 
46
typedef struct {
 
47
    void *opaque;
 
48
    void (*send)(void *opaque, const char *data, int len);
 
49
} Out;
 
50
 
 
51
static void
 
52
out_send(Out *o, const void *data, size_t len)
 
53
{
 
54
    o->send(o->opaque, data, (int)len);
 
55
}
 
56
 
 
57
static void
 
58
out_send_repeat(Out *o, char ch, int count)
 
59
{
 
60
    char pad[8];
 
61
    const int padSize = (int)sizeof(pad);
 
62
 
 
63
    memset(pad, ch, sizeof(pad));
 
64
    while (count > 0) {
 
65
        int avail = count;
 
66
        if (avail > padSize) {
 
67
            avail = padSize;
 
68
        }
 
69
        o->send(o->opaque, pad, avail);
 
70
        count -= avail;
 
71
    }
 
72
}
 
73
 
 
74
/* forward declaration */
 
75
static void
 
76
out_vformat(Out *o, const char *format, va_list args);
 
77
 
 
78
/*** Bounded buffer output
 
79
 ***/
 
80
 
 
81
typedef struct {
 
82
    Out out[1];
 
83
    char *buffer;
 
84
    char *pos;
 
85
    char *end;
 
86
    int total;
 
87
} BufOut;
 
88
 
 
89
static void
 
90
buf_out_send(void *opaque, const char *data, int len)
 
91
{
 
92
    BufOut *bo = opaque;
 
93
 
 
94
    if (len < 0)
 
95
        len = strlen(data);
 
96
 
 
97
    bo->total += len;
 
98
 
 
99
    while (len > 0) {
 
100
        int avail = bo->end - bo->pos;
 
101
        if (avail == 0)
 
102
            break;
 
103
        if (avail > len)
 
104
            avail = len;
 
105
        memcpy(bo->pos, data, avail);
 
106
        bo->pos += avail;
 
107
        bo->pos[0] = '\0';
 
108
        len -= avail;
 
109
    }
 
110
}
 
111
 
 
112
static Out*
 
113
buf_out_init(BufOut *bo, char *buffer, size_t size)
 
114
{
 
115
    if (size == 0)
 
116
        return NULL;
 
117
 
 
118
    bo->out->opaque = bo;
 
119
    bo->out->send   = buf_out_send;
 
120
    bo->buffer      = buffer;
 
121
    bo->end         = buffer + size - 1;
 
122
    bo->pos         = bo->buffer;
 
123
    bo->pos[0]      = '\0';
 
124
    bo->total       = 0;
 
125
 
 
126
    return bo->out;
 
127
}
 
128
 
 
129
static int
 
130
buf_out_length(BufOut *bo)
 
131
{
 
132
    return bo->total;
 
133
}
 
134
 
 
135
static int
 
136
vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
 
137
{
 
138
    BufOut bo;
 
139
    Out *out;
 
140
 
 
141
    out = buf_out_init(&bo, buff, buffsize);
 
142
    if (out == NULL)
 
143
        return 0;
 
144
 
 
145
    out_vformat(out, format, args);
 
146
 
 
147
    return buf_out_length(&bo);
 
148
}
 
149
 
 
150
int
 
151
format_buffer(char *buff, size_t buffsize, const char *format, ...)
 
152
{
 
153
    va_list args;
 
154
    int ret;
 
155
 
 
156
    va_start(args, format);
 
157
    ret = vformat_buffer(buff, buffsize, format, args);
 
158
    va_end(args);
 
159
 
 
160
    return ret;
 
161
}
 
162
 
 
163
/* The __stack_chk_fail() function calls __libc_android_log_print()
 
164
 * which calls vsnprintf().
 
165
 *
 
166
 * We define our version of the function here to avoid dragging
 
167
 * about 25 KB of C library routines related to formatting.
 
168
 */
 
169
#if 0
 
170
int
 
171
vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
 
172
{
 
173
    return format_buffer(buff, bufsize, format, args);
 
174
}
 
175
#endif
 
176
 
 
177
#if LINKER_DEBUG
 
178
 
 
179
#if !LINKER_DEBUG_TO_LOG
 
180
 
 
181
/*** File descriptor output
 
182
 ***/
 
183
 
 
184
typedef struct {
 
185
    Out out[1];
 
186
    int fd;
 
187
    int total;
 
188
} FdOut;
 
189
 
 
190
static void
 
191
fd_out_send(void *opaque, const char *data, int len)
 
192
{
 
193
    FdOut *fdo = opaque;
 
194
 
 
195
    if (len < 0)
 
196
        len = strlen(data);
 
197
 
 
198
    while (len > 0) {
 
199
        int ret = write(fdo->fd, data, len);
 
200
        if (ret < 0) {
 
201
            if (errno == EINTR)
 
202
                continue;
 
203
            break;
 
204
        }
 
205
        data += ret;
 
206
        len -= ret;
 
207
        fdo->total += ret;
 
208
    }
 
209
}
 
210
 
 
211
static Out*
 
212
fd_out_init(FdOut *fdo, int  fd)
 
213
{
 
214
    fdo->out->opaque = fdo;
 
215
    fdo->out->send = fd_out_send;
 
216
    fdo->fd = fd;
 
217
    fdo->total = 0;
 
218
 
 
219
    return fdo->out;
 
220
}
 
221
 
 
222
static int
 
223
fd_out_length(FdOut *fdo)
 
224
{
 
225
    return fdo->total;
 
226
}
 
227
 
 
228
 
 
229
int
 
230
format_fd(int fd, const char *format, ...)
 
231
{
 
232
    FdOut fdo;
 
233
    Out* out;
 
234
    va_list args;
 
235
 
 
236
    out = fd_out_init(&fdo, fd);
 
237
    if (out == NULL)
 
238
        return 0;
 
239
 
 
240
    va_start(args, format);
 
241
    out_vformat(out, format, args);
 
242
    va_end(args);
 
243
 
 
244
    return fd_out_length(&fdo);
 
245
}
 
246
 
 
247
#else /* LINKER_DEBUG_TO_LOG */
 
248
 
 
249
/*** Log output
 
250
 ***/
 
251
 
 
252
/* We need our own version of __libc_android_log_vprint, otherwise
 
253
 * the log output is completely broken. Probably due to the fact
 
254
 * that the C library is not initialized yet.
 
255
 *
 
256
 * You can test that by setting CUSTOM_LOG_VPRINT to 0
 
257
 */
 
258
#define  CUSTOM_LOG_VPRINT  1
 
259
 
 
260
#if CUSTOM_LOG_VPRINT
 
261
 
 
262
#include <unistd.h>
 
263
#include <fcntl.h>
 
264
#include <sys/uio.h>
 
265
 
 
266
static int log_vprint(int prio, const char *tag, const char *fmt, va_list  args)
 
267
{
 
268
    char buf[1024];
 
269
    int result;
 
270
    static int log_fd = -1;
 
271
 
 
272
    result = vformat_buffer(buf, sizeof buf, fmt, args);
 
273
 
 
274
    if (log_fd < 0) {
 
275
        log_fd = open("/dev/log/main", O_WRONLY);
 
276
        if (log_fd < 0) {
 
277
            log_fd = fileno(stdout); // kernel doesn't have android log
 
278
            return result;
 
279
        }
 
280
    }
 
281
 
 
282
    {
 
283
        ssize_t ret;
 
284
        struct iovec vec[3];
 
285
 
 
286
        vec[0].iov_base = (unsigned char *) &prio;
 
287
        vec[0].iov_len = 1;
 
288
        vec[1].iov_base = (void *) tag;
 
289
        vec[1].iov_len = strlen(tag) + 1;
 
290
        vec[2].iov_base = (void *) buf;
 
291
        vec[2].iov_len = strlen(buf) + 1;
 
292
 
 
293
        do {
 
294
            ret = writev(log_fd, vec, 3);
 
295
        } while ((ret < 0) && (errno == EINTR));
 
296
    }
 
297
    return result;
 
298
}
 
299
 
 
300
#define  __libc_android_log_vprint  log_vprint
 
301
 
 
302
#else /* !CUSTOM_LOG_VPRINT */
 
303
 
 
304
extern int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
 
305
 
 
306
#endif /* !CUSTOM_LOG_VPRINT */
 
307
 
 
308
int
 
309
format_log(int prio, const char *tag, const char *format, ...)
 
310
{
 
311
    int ret;
 
312
    va_list  args;
 
313
    va_start(args, format);
 
314
    ret = __libc_android_log_vprint(prio, tag, format, args);
 
315
    va_end(args);
 
316
    return ret;
 
317
}
 
318
 
 
319
#endif /* LINKER_DEBUG_TO_LOG */
 
320
 
 
321
#endif /* LINKER_DEBUG */
 
322
 
 
323
/*** formatted output implementation
 
324
 ***/
 
325
 
 
326
/* Parse a decimal string from 'format + *ppos',
 
327
 * return the value, and writes the new position past
 
328
 * the decimal string in '*ppos' on exit.
 
329
 *
 
330
 * NOTE: Does *not* handle a sign prefix.
 
331
 */
 
332
static unsigned
 
333
parse_decimal(const char *format, int *ppos)
 
334
{
 
335
    const char* p = format + *ppos;
 
336
    unsigned result = 0;
 
337
 
 
338
    for (;;) {
 
339
        int ch = *p;
 
340
        unsigned d = (unsigned)(ch - '0');
 
341
 
 
342
        if (d >= 10U)
 
343
            break;
 
344
 
 
345
        result = result*10 + d;
 
346
        p++;
 
347
    }
 
348
    *ppos = p - format;
 
349
    return result;
 
350
}
 
351
 
 
352
/* write an octal/decimal/number into a bounded buffer.
 
353
 * assumes that bufsize > 0, and 'digits' is a string of
 
354
 * digits of at least 'base' values.
 
355
 */
 
356
static void
 
357
format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
 
358
{
 
359
    char *pos = buffer;
 
360
    char *end = buffer + bufsize - 1;
 
361
 
 
362
    /* generate digit string in reverse order */
 
363
    while (value) {
 
364
        unsigned d = value % base;
 
365
        value /= base;
 
366
        if (pos < end) {
 
367
            *pos++ = digits[d];
 
368
        }
 
369
    }
 
370
 
 
371
    /* special case for 0 */
 
372
    if (pos == buffer) {
 
373
        if (pos < end) {
 
374
            *pos++ = '0';
 
375
        }
 
376
    }
 
377
    pos[0] = '\0';
 
378
 
 
379
    /* now reverse digit string in-place */
 
380
    end = pos - 1;
 
381
    pos = buffer;
 
382
    while (pos < end) {
 
383
        int ch = pos[0];
 
384
        pos[0] = end[0];
 
385
        end[0] = (char) ch;
 
386
        pos++;
 
387
        end--;
 
388
    }
 
389
}
 
390
 
 
391
/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
 
392
static void
 
393
format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
 
394
{
 
395
    if (isSigned && (int64_t)value < 0) {
 
396
        buffer[0] = '-';
 
397
        buffer += 1;
 
398
        buffsize -= 1;
 
399
        value = (uint64_t)(-(int64_t)value);
 
400
    }
 
401
 
 
402
    format_number(buffer, buffsize, value, base, "0123456789");
 
403
}
 
404
 
 
405
/* Write an octal into a buffer, assumes buffsize > 2 */
 
406
static void
 
407
format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
 
408
{
 
409
    format_integer(buffer, buffsize, value, 8, isSigned);
 
410
}
 
411
 
 
412
/* Write a decimal into a buffer, assumes buffsize > 2 */
 
413
static void
 
414
format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
 
415
{
 
416
    format_integer(buffer, buffsize, value, 10, isSigned);
 
417
}
 
418
 
 
419
/* Write an hexadecimal into a buffer, isCap is true for capital alphas.
 
420
 * Assumes bufsize > 2 */
 
421
static void
 
422
format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
 
423
{
 
424
    const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
 
425
 
 
426
    format_number(buffer, buffsize, value, 16, digits);
 
427
}
 
428
 
 
429
 
 
430
/* Perform formatted output to an output target 'o' */
 
431
static void
 
432
out_vformat(Out *o, const char *format, va_list args)
 
433
{
 
434
    int nn = 0;
 
435
 
 
436
    for (;;) {
 
437
        int mm;
 
438
        int padZero = 0;
 
439
        int padLeft = 0;
 
440
        char sign = '\0';
 
441
        int width = -1;
 
442
        int prec  = -1;
 
443
        size_t bytelen = sizeof(int);
 
444
        const char*  str;
 
445
        int slen;
 
446
        char buffer[32];  /* temporary buffer used to format numbers */
 
447
 
 
448
        char  c;
 
449
 
 
450
        /* first, find all characters that are not 0 or '%' */
 
451
        /* then send them to the output directly */
 
452
        mm = nn;
 
453
        do {
 
454
            c = format[mm];
 
455
            if (c == '\0' || c == '%')
 
456
                break;
 
457
            mm++;
 
458
        } while (1);
 
459
 
 
460
        if (mm > nn) {
 
461
            out_send(o, format+nn, mm-nn);
 
462
            nn = mm;
 
463
        }
 
464
 
 
465
        /* is this it ? then exit */
 
466
        if (c == '\0')
 
467
            break;
 
468
 
 
469
        /* nope, we are at a '%' modifier */
 
470
        nn++;  // skip it
 
471
 
 
472
        /* parse flags */
 
473
        for (;;) {
 
474
            c = format[nn++];
 
475
            if (c == '\0') {  /* single trailing '%' ? */
 
476
                c = '%';
 
477
                out_send(o, &c, 1);
 
478
                return;
 
479
            }
 
480
            else if (c == '0') {
 
481
                padZero = 1;
 
482
                continue;
 
483
            }
 
484
            else if (c == '-') {
 
485
                padLeft = 1;
 
486
                continue;
 
487
            }
 
488
            else if (c == ' ' || c == '+') {
 
489
                sign = c;
 
490
                continue;
 
491
            }
 
492
            break;
 
493
        }
 
494
 
 
495
        /* parse field width */
 
496
        if ((c >= '0' && c <= '9')) {
 
497
            nn --;
 
498
            width = (int)parse_decimal(format, &nn);
 
499
            c = format[nn++];
 
500
        }
 
501
 
 
502
        /* parse precision */
 
503
        if (c == '.') {
 
504
            prec = (int)parse_decimal(format, &nn);
 
505
            c = format[nn++];
 
506
        }
 
507
 
 
508
        /* length modifier */
 
509
        switch (c) {
 
510
        case 'h':
 
511
            bytelen = sizeof(short);
 
512
            if (format[nn] == 'h') {
 
513
                bytelen = sizeof(char);
 
514
                nn += 1;
 
515
            }
 
516
            c = format[nn++];
 
517
            break;
 
518
        case 'l':
 
519
            bytelen = sizeof(long);
 
520
            if (format[nn] == 'l') {
 
521
                bytelen = sizeof(long long);
 
522
                nn += 1;
 
523
            }
 
524
            c = format[nn++];
 
525
            break;
 
526
        case 'z':
 
527
            bytelen = sizeof(size_t);
 
528
            c = format[nn++];
 
529
            break;
 
530
        case 't':
 
531
            bytelen = sizeof(ptrdiff_t);
 
532
            c = format[nn++];
 
533
            break;
 
534
        default:
 
535
            ;
 
536
        }
 
537
 
 
538
        /* conversion specifier */
 
539
        if (c == 's') {
 
540
            /* string */
 
541
            str = va_arg(args, const char*);
 
542
        } else if (c == 'c') {
 
543
            /* character */
 
544
            /* NOTE: char is promoted to int when passed through the stack */
 
545
            buffer[0] = (char) va_arg(args, int);
 
546
            buffer[1] = '\0';
 
547
            str = buffer;
 
548
        } else if (c == 'p') {
 
549
            uint64_t  value = (uintptr_t) va_arg(args, void*);
 
550
            buffer[0] = '0';
 
551
            buffer[1] = 'x';
 
552
            format_hex(buffer + 2, sizeof buffer-2, value, 0);
 
553
            str = buffer;
 
554
        } else {
 
555
            /* integers - first read value from stack */
 
556
            uint64_t value;
 
557
            int isSigned = (c == 'd' || c == 'i' || c == 'o');
 
558
 
 
559
            /* NOTE: int8_t and int16_t are promoted to int when passed
 
560
             *       through the stack
 
561
             */
 
562
            switch (bytelen) {
 
563
            case 1: value = (uint8_t)  va_arg(args, int); break;
 
564
            case 2: value = (uint16_t) va_arg(args, int); break;
 
565
            case 4: value = va_arg(args, uint32_t); break;
 
566
            case 8: value = va_arg(args, uint64_t); break;
 
567
            default: return;  /* should not happen */
 
568
            }
 
569
 
 
570
            /* sign extension, if needed */
 
571
            if (isSigned) {
 
572
                int shift = 64 - 8*bytelen;
 
573
                value = (uint64_t)(((int64_t)(value << shift)) >> shift);
 
574
            }
 
575
 
 
576
            /* format the number properly into our buffer */
 
577
            switch (c) {
 
578
            case 'i': case 'd':
 
579
                format_integer(buffer, sizeof buffer, value, 10, isSigned);
 
580
                break;
 
581
            case 'o':
 
582
                format_integer(buffer, sizeof buffer, value, 8, isSigned);
 
583
                break;
 
584
            case 'x': case 'X':
 
585
                format_hex(buffer, sizeof buffer, value, (c == 'X'));
 
586
                break;
 
587
            default:
 
588
                buffer[0] = '\0';
 
589
            }
 
590
            /* then point to it */
 
591
            str = buffer;
 
592
        }
 
593
 
 
594
        /* if we are here, 'str' points to the content that must be
 
595
         * outputted. handle padding and alignment now */
 
596
 
 
597
        slen = strlen(str);
 
598
 
 
599
        if (slen < width && !padLeft) {
 
600
            char padChar = padZero ? '0' : ' ';
 
601
            out_send_repeat(o, padChar, width - slen);
 
602
        }
 
603
 
 
604
        out_send(o, str, slen);
 
605
 
 
606
        if (slen < width && padLeft) {
 
607
            char padChar = padZero ? '0' : ' ';
 
608
            out_send_repeat(o, padChar, width - slen);
 
609
        }
 
610
    }
 
611
}
 
612
 
 
613
 
 
614
#ifdef UNIT_TESTS
 
615
 
 
616
#include <stdio.h>
 
617
 
 
618
static int   gFails = 0;
 
619
 
 
620
#define  MARGIN  40
 
621
 
 
622
#define  UTEST_CHECK(condition,message) \
 
623
    printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
 
624
    if (!(condition)) { \
 
625
        printf("KO\n"); \
 
626
        gFails += 1; \
 
627
    } else { \
 
628
        printf("ok\n"); \
 
629
    }
 
630
 
 
631
static void
 
632
utest_BufOut(void)
 
633
{
 
634
    char buffer[16];
 
635
    BufOut bo[1];
 
636
    Out* out;
 
637
    int ret;
 
638
 
 
639
    buffer[0] = '1';
 
640
    out = buf_out_init(bo, buffer, sizeof buffer);
 
641
    UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
 
642
    out_send(out, "abc", 3);
 
643
    UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
 
644
    out_send_repeat(out, 'X', 4);
 
645
    UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
 
646
    buffer[sizeof buffer-1] = 'x';
 
647
    out_send_repeat(out, 'Y', 2*sizeof(buffer));
 
648
    UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
 
649
 
 
650
    out = buf_out_init(bo, buffer, sizeof buffer);
 
651
    out_send_repeat(out, 'X', 2*sizeof(buffer));
 
652
    ret = buf_out_length(bo);
 
653
    UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
 
654
}
 
655
 
 
656
static void
 
657
utest_expect(const char*  result, const char*  format, ...)
 
658
{
 
659
    va_list args;
 
660
    BufOut bo[1];
 
661
    char buffer[256];
 
662
    Out* out = buf_out_init(bo, buffer, sizeof buffer);
 
663
 
 
664
    printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
 
665
    va_start(args, format);
 
666
    out_vformat(out, format, args);
 
667
    va_end(args);
 
668
 
 
669
    if (strcmp(result, buffer)) {
 
670
        printf("KO. got '%s' expecting '%s'\n", buffer, result);
 
671
        gFails += 1;
 
672
    } else {
 
673
        printf("ok. got '%s'\n", result);
 
674
    }
 
675
}
 
676
 
 
677
int  main(void)
 
678
{
 
679
    utest_BufOut();
 
680
    utest_expect("", "");
 
681
    utest_expect("a", "a");
 
682
    utest_expect("01234", "01234", "");
 
683
    utest_expect("01234", "%s", "01234");
 
684
    utest_expect("aabbcc", "aa%scc", "bb");
 
685
    utest_expect("a", "%c", 'a');
 
686
    utest_expect("1234", "%d", 1234);
 
687
    utest_expect("-8123", "%d", -8123);
 
688
    utest_expect("16", "%hd", 0x7fff0010);
 
689
    utest_expect("16", "%hhd", 0x7fffff10);
 
690
    utest_expect("68719476736", "%lld", 0x1000000000LL);
 
691
    utest_expect("70000", "%ld", 70000);
 
692
    utest_expect("0xb0001234", "%p", (void*)0xb0001234);
 
693
    utest_expect("12ab", "%x", 0x12ab);
 
694
    utest_expect("12AB", "%X", 0x12ab);
 
695
    utest_expect("00123456", "%08x", 0x123456);
 
696
    utest_expect("01234", "0%d", 1234);
 
697
    utest_expect(" 1234", "%5d", 1234);
 
698
    utest_expect("01234", "%05d", 1234);
 
699
    utest_expect("    1234", "%8d", 1234);
 
700
    utest_expect("1234    ", "%-8d", 1234);
 
701
    utest_expect("abcdef     ", "%-11s", "abcdef");
 
702
    utest_expect("something:1234", "%s:%d", "something", 1234);
 
703
    utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
 
704
    utest_expect("5,0x0", "%d,%p", 5, NULL);
 
705
    utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
 
706
    return gFails != 0;
 
707
}
 
708
 
 
709
#endif /* UNIT_TESTS */