OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [libc/] [src/] [format.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Australian Public Licence B (OZPLB)
3
 *
4
 * Version 1-0
5
 *
6
 * Copyright (c) 2004 University of New South Wales
7
 *
8
 * All rights reserved.
9
 *
10
 * Developed by: Operating Systems and Distributed Systems Group (DiSy)
11
 *               University of New South Wales
12
 *               http://www.disy.cse.unsw.edu.au
13
 *
14
 * Permission is granted by University of New South Wales, free of charge, to
15
 * any person obtaining a copy of this software and any associated
16
 * documentation files (the "Software") to deal with the Software without
17
 * restriction, including (without limitation) the rights to use, copy,
18
 * modify, adapt, merge, publish, distribute, communicate to the public,
19
 * sublicense, and/or sell, lend or rent out copies of the Software, and
20
 * to permit persons to whom the Software is furnished to do so, subject
21
 * to the following conditions:
22
 *
23
 *     * Redistributions of source code must retain the above copyright
24
 *       notice, this list of conditions and the following disclaimers.
25
 *
26
 *     * Redistributions in binary form must reproduce the above
27
 *       copyright notice, this list of conditions and the following
28
 *       disclaimers in the documentation and/or other materials provided
29
 *       with the distribution.
30
 *
31
 *     * Neither the name of University of New South Wales, nor the names of its
32
 *       contributors, may be used to endorse or promote products derived
33
 *       from this Software without specific prior written permission.
34
 *
35
 * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
36
 * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
37
 * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
38
 * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
39
 * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
40
 * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
41
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
42
 * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
43
 * ERRORS, WHETHER OR NOT DISCOVERABLE.
44
 *
45
 * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
46
 * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
47
 * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
48
 * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
49
 * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
50
 * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
51
 * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
52
 * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
53
 * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
54
 * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
55
 * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
56
 * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
57
 * DAMAGES OR OTHER LIABILITY.
58
 *
59
 * If applicable legislation implies representations, warranties, or
60
 * conditions, or imposes obligations or liability on University of New South
61
 * Wales or one of its contributors in respect of the Software that
62
 * cannot be wholly or partly excluded, restricted or modified, the
63
 * liability of University of New South Wales or the contributor is limited, to
64
 * the full extent permitted by the applicable legislation, at its
65
 * option, to:
66
 * a.  in the case of goods, any one or more of the following:
67
 * i.  the replacement of the goods or the supply of equivalent goods;
68
 * ii.  the repair of the goods;
69
 * iii. the payment of the cost of replacing the goods or of acquiring
70
 *  equivalent goods;
71
 * iv.  the payment of the cost of having the goods repaired; or
72
 * b.  in the case of services:
73
 * i.  the supplying of the services again; or
74
 * ii.  the payment of the cost of having the services supplied again.
75
 *
76
 * The construction, validity and performance of this licence is governed
77
 * by the laws in force in New South Wales, Australia.
78
 */
79
/*
80
  Authors: Cristan Szmadja, Ben Leslie
81
*/
82
#include <stdint.h>
83
#include <stdio.h>
84
#include <stdbool.h>
85
#include <string.h>
86
#include "format.h"
87
/*
88
 * lookup tables for umaxtostr
89
 */
90
static const char xdigits[16] = "0123456789abcdef";
91
static const char Xdigits[16] = "0123456789ABCDEF";
92
 
93
/*
94
 * Convert an unsigned integer to a string of digits in the specified base.
95
 * Buf should point to the END of the buffer: 22 characters is probably big
96
 * enough.  NO '\0' is appended to buf.
97
 *
98
 * If u == 0, NO digits are generated.  The '0' is supplied by vfprintf using
99
 * its default zero padding, except in certain rare situations (e.g., "%.0d").
100
 */
101
static inline char *
102
umaxtostr(char *buf, uintmax_t u, int base, const char *digits)
103
{
104
        unsigned long u2;
105
 
106
        /*
107
         * generate the digits in reverse order
108
         */
109
#if UINTMAX_MAX > ULONG_MAX
110
        /*
111
         * Uintmax_t arithmetic may be very slow.  Use it only until the
112
         * residual fits in an unsigned long.
113
         */
114
        while (u > ULONG_MAX) {
115
                *--buf = digits[u % base];
116
                u /= base;
117
        }
118
#endif
119
        for (u2 = u; u2 != 0UL;) {
120
                *--buf = digits[u2 % base];
121
                u2 /= base;
122
        }
123
        return buf;
124
}
125
 
126
 
127
/*
128
This macro is *really* nasty.
129
 
130
It isn't an inline function because it relies on variables declared in the
131
surrounding scope. Specifically:
132
  stream_or_memory   -> Indicates if we are going to a file, or memory
133
  r                  -> The output counter
134
  n                  -> max size
135
  output             -> output buffer (if going to memory)
136
  stream             -> output stream (if going to file)
137
*/
138
 
139
#define WRITE_CHAR(x) {           \
140
 if (n != -1 && r == n) {         \
141
        *output++ = '\0';         \
142
        overflowed = 1;           \
143
 }                                \
144
 if (stream_or_memory) {          \
145
        fputc(x, stream);         \
146
 } else if (! overflowed) {       \
147
        *output++ = x;            \
148
 }                                \
149
 r++;                             \
150
}                                 \
151
 
152
 
153
 
154
 
155
/*
156
 * Print one formatted field.  The length of s is len; any '\0's in s are
157
 * IGNORED.  The field may have an optional prefix ('+', ' ', '-', '0x', or
158
 * '0X', packed into an unsigned int), and is padded appropriately to the
159
 * specified width.  If width < 0, the field is left-justified.
160
 */
161
static inline int
162
fprintf1(char *output, FILE *stream, bool stream_or_memory, size_t r, size_t n,
163
         const char *s, int len, unsigned int prefix,
164
         int prefixlen, int width, int prec, bool *over)
165
{
166
        size_t i;
167
        size_t y = r;            /* Keep a copy the starting value */
168
        bool overflowed = *over; /* Current start of overflow flag */
169
 
170
        if (stream != NULL)
171
                lock_stream(stream);
172
        if (width - prec - prefixlen > 0) {
173
                for (i = 0; i < width - prec - prefixlen; i++) {
174
                        WRITE_CHAR(' ');  /* left-padding (if any) */
175
                }
176
        }
177
 
178
        for (; prefix != 0; prefix >>= 8) {
179
                WRITE_CHAR(prefix & 0377); /* prefix string */
180
        }
181
 
182
        for (i = 0; i < prec - len; i++) {
183
                WRITE_CHAR('0');  /* zero-padding (if any) */
184
        }
185
 
186
        for (i = 0; i < len; i++) {
187
                WRITE_CHAR(s[i]); /* actual string */
188
        }
189
 
190
        if (width < 0) {
191
                while(y < -width) {
192
                        WRITE_CHAR(' '); /* right-padding (if any) */
193
                }
194
        }
195
 
196
        *over = overflowed; /* Set overflow flag in the caller */
197
 
198
        if (stream != NULL)
199
                unlock_stream(stream);
200
        return r - y;      /* We return the number of chars added */
201
}
202
 
203
#include <assert.h>
204
/*
205
 * parse printf format string
206
 * if stream_or_memory == 1 -> use fputc, otherwise write to memory
207
 * if n == -1, then don't check overflow
208
 */
209
int
210
format_string(char *output, FILE *stream, bool stream_or_memory, size_t n,
211
              const char *fmt, va_list ap)
212
{
213
        bool alt, ljust, point, zeropad, overflowed = 0;
214
        int  lflags;    /* 'h', 'j', 'l', 't', 'z' */
215
        unsigned int prefix;    /* a very small string */
216
        int width, prec, base = 0, prefixlen;
217
        size_t r, len;
218
        const char *p, *s, *digits;
219
        char buf[24], *const buf_end = buf + sizeof buf;
220
        intmax_t d;
221
        uintmax_t u = 0;
222
 
223
        r = 0;
224
        if (stream != NULL)
225
                lock_stream(stream);
226
        for (p = fmt; *p != '\0'; p++) {
227
                if (*p != '%') {
228
                putc:
229
                        WRITE_CHAR(*p);
230
                        continue;
231
                }
232
                alt = false;
233
                ljust = false;
234
                point = false;
235
                zeropad = false;
236
                lflags = 0;
237
                prefix = '\0';
238
                prefixlen = 0;
239
                width = 0;
240
                prec = 1;       /* make sure 0 prints as "0" */
241
                digits = xdigits;
242
                for (p++;; p++) {
243
                      again:
244
                        switch (*p) {
245
                        case '%':
246
                                goto putc;
247
                        case '#':
248
                                alt = true;
249
                                continue;
250
                        case '-':       /* takes precedence over '0' */
251
                                ljust = true;
252
                                continue;
253
                        case '0':
254
                                zeropad = true;
255
                                continue;
256
                        case '+':       /* XXX should take precedence over
257
                                         * ' ' */
258
                        case ' ':
259
                                prefix = *p;
260
                                prefixlen = 1;
261
                                continue;
262
                        case '*':
263
                                width = va_arg(ap, int);
264
                                if (ljust)
265
                                        width = -width;
266
                                continue;
267
                        case '1':
268
                        case '2':
269
                        case '3':
270
                        case '4':
271
                        case '5':
272
                        case '6':
273
                        case '7':
274
                        case '8':
275
                        case '9':
276
                                /*
277
                                 * width = strtol(p, &p, 10), sort of
278
                                 */
279
                                width = *p - '0';
280
                                for (p++; (unsigned int) (*p - '0') < 10;
281
                                     p++)
282
                                        width = width * 10 + (*p - '0');
283
                                if (ljust)
284
                                        width = -width;
285
                                goto again;     /* don't increment p */
286
                        case '.':
287
                                point = true;
288
                                if (*++p == '*') {
289
                                        prec = va_arg(ap, int);
290
                                        continue;
291
                                } else {
292
                                        /*
293
                                         * prec = strtol(p, &p, 10), sort
294
                                         * of
295
                                         */
296
                                        for (prec = 0;
297
                                             (unsigned int) (*p - '0') <
298
                                             10; p++)
299
                                                prec =
300
                                                    prec * 10 + (*p - '0');
301
                                        goto again;     /* don't increment
302
                                                         * p */
303
                                }
304
                        case 'h':
305
                                lflags--;
306
                                continue;
307
                        case 'L':
308
                        case 'l':
309
                                lflags++;
310
                                continue;
311
                        case 't':
312
                        case 'z':
313
                                lflags = 1;     /* assume ptrdiff_t and
314
                                                 * size_t are long */
315
                                continue;
316
                        case 'j':
317
                                lflags = 2;     /* assume intmax_t is long
318
                                                 * long */
319
                                continue;
320
#ifndef NO_FLOAT
321
                        case 'a':
322
                        case 'A':
323
                        case 'e':
324
                        case 'E':
325
                        case 'f':
326
                        case 'g':
327
                        case 'G':
328
                                /*
329
                                 * NOT IMPLEMENTED
330
                                 */
331
                                switch (lflags) {
332
                                case 0:
333
                                        va_arg(ap, double);
334
                                        break;
335
                                case 1:
336
                                        va_arg(ap, long double);
337
                                        break;
338
                                default:
339
                                        goto default_case;
340
                                }
341
                                break;
342
#endif                          /* !NO_FLOAT */
343
                        case 'c':
344
#ifndef NO_WCHAR
345
                                /*
346
                                 * NOT IMPLEMENTED
347
                                 */
348
                                if (lflags > 0)
349
                                        va_arg(ap, wchar_t);
350
                                else
351
#endif
352
                                        *(buf_end - 1) = va_arg(ap, int);
353
                                s = buf_end - 1;
354
                                len = 1;
355
                                goto common3;
356
                        case 'd':
357
                        case 'i':
358
                                switch (lflags) {
359
                                case -2:
360
                                        // d = va_arg(ap, signed char);
361
                                        d = va_arg(ap, int);
362
                                        break;
363
                                case -1:
364
                                        // d = va_arg(ap, short);
365
                                        d = va_arg(ap, int);
366
                                        break;
367
                                case 0:
368
                                        d = va_arg(ap, int);
369
                                        break;
370
                                case 1:
371
                                        d = va_arg(ap, long);
372
                                        break;
373
#ifndef NO_LONG_LONG
374
                                case 2:
375
                                        d = va_arg(ap, long long);
376
                                        break;
377
#endif
378
                                default:
379
                                        goto default_case;
380
                                }
381
                                if (d < 0LL) {
382
                                        /*
383
                                         * safely negate d, even
384
                                         * INTMAX_MIN
385
                                         */
386
                                        u = -(uintmax_t) d;
387
                                        prefix = '-';   /* override ' ' or
388
                                                         * '+' */
389
                                        prefixlen = 1;
390
                                } else {
391
                                        u = d;
392
                                }
393
                                base = 10;
394
                                goto common2;
395
                        case 'n':
396
                                switch (lflags) {
397
                                case -2:
398
                                        *va_arg(ap, signed char *) = r;
399
                                        break;
400
                                case -1:
401
                                        *va_arg(ap, short *) = r;
402
                                        break;
403
                                case 0:
404
                                        *va_arg(ap, int *) = r;
405
                                        break;
406
                                case 1:
407
                                        *va_arg(ap, long *) = r;
408
                                        break;
409
                                case 2:
410
                                        *va_arg(ap, long long *) = r;
411
                                        break;
412
                                default:
413
                                        goto default_case;
414
                                }
415
                                break;
416
                        case 'o':
417
                                base = 8;
418
                                goto common1;
419
                        case 'p':
420
                                u = (uintptr_t) va_arg(ap, const void *);
421
                                if (u != (uintptr_t) NULL) {
422
                                        base = 16;
423
                                        prec = 2 * sizeof(const void *);
424
                                        prefix = '0' | 'x' << 8;
425
                                        prefixlen = 2;
426
                                        goto common2;
427
                                } else {
428
                                        s = "(nil)";
429
                                        len = 5;
430
                                        goto common3;
431
                                }
432
                        case 's':
433
                                s = va_arg(ap, const char *);
434
                                /*
435
                                 * XXX left-justified strings are scanned
436
                                 * twice
437
                                 */
438
                                if (point) {
439
                                        /*
440
                                         * len = min(prec, strlen(s))
441
                                         */
442
                                        for (len = 0; len < prec; len++)
443
                                                if (s[len] == '\0')
444
                                                        break;
445
                                } else {
446
                                        len = strlen(s);
447
                                }
448
                                goto common3;
449
                        case 'u':
450
                                base = 10;
451
                                goto common1;
452
                        case 'X':
453
                                digits = Xdigits;
454
                                /*
455
                                 * FALLTHROUGH
456
                                 */
457
                        case 'x':
458
                                base = 16;
459
                                if (alt) {
460
                                        prefix = '0' | *p << 8;
461
                                        prefixlen = 2;
462
                                }
463
                                /*
464
                                 * FALLTHROUGH
465
                                 */
466
                              common1:
467
                                /*
468
                                 * common code for %o, %u, %X, and %x
469
                                 */
470
                                switch (lflags) {
471
                                case -2:
472
                                        // u = va_arg(ap, unsigned char);
473
                                        u = va_arg(ap, int);
474
                                        break;
475
                                case -1:
476
                                        // u = va_arg(ap, unsigned short);
477
                                        u = va_arg(ap, int);
478
                                        break;
479
                                case 0:
480
                                        u = va_arg(ap, unsigned int);
481
                                        break;
482
                                case 1:
483
                                        u = va_arg(ap, unsigned long);
484
                                        break;
485
#ifndef NO_LONG_LONG
486
                                case 2:
487
                                        u = va_arg(ap, unsigned long long);
488
                                        break;
489
#endif
490
                                default:
491
                                        goto default_case;
492
                                }
493
                                /*
494
                                 * FALLTHROUGH
495
                                 */
496
                              common2:
497
                                s = umaxtostr(buf_end, u, base, digits);
498
                                len = buf_end - s;
499
                                /*
500
                                 * the field may overflow prec
501
                                 */
502
                                if (prec < len)
503
                                        /*
504
                                         * FALLTHOUGH
505
                                         */
506
                                      common3:
507
                                        prec = len;
508
                                if (zeropad && prec < width - prefixlen)
509
                                        prec = width - prefixlen;
510
                                else if (alt && base == 8 && u != 0LL)
511
                                        prec++;
512
 
513
                                {
514
                                        int tmp = fprintf1(output, stream, stream_or_memory, r, n,
515
                                                           s, len, prefix,
516
                                                           prefixlen, width, prec, &overflowed);
517
                                        r += tmp;
518
                                        output += tmp;
519
                                }
520
 
521
                                break;
522
                        default:        /* unrecognized conversion
523
                                         * specifier */
524
                              default_case:
525
                                /*
526
                                 * print uninterpreted
527
                                 */
528
                                for (s = p - 1; *s != '%'; s--);
529
                                for (; s <= p; s++) {
530
                                        WRITE_CHAR(*p);
531
                                }
532
                                break;
533
                        }
534
                        break;  /* finished the conversion specifier */
535
                }
536
        }
537
        if (! stream_or_memory && ! overflowed)
538
                *output++ = '\0';
539
        if (stream != NULL)
540
                unlock_stream(stream);
541
        return r;
542
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.