WIP: add an initial skeleton for a real scsi.device based upon the ata device impleme...
[AROS.git] / compiler / fmtprintf / fmtprintf_pre.c
blobd0a5f42e15a82aa5ed07908fd48c31d0c90ed247
1 /*
2 Copyright © 2018, The AROS Development Team. All rights reserved.
3 $Id$
5 Prelude for common code block to format a string like printf().
6 */
8 #include <dos/bptr.h>
10 #ifndef BITSPERBYTE
11 # define BITSPERBYTE 8
12 #endif
14 #if (__WORDSIZE == 64)
15 /* On 64-bit machines long and long long are the same, so we don't need separate processing for long long */
16 #undef AROS_HAVE_LONG_LONG
17 #endif
19 #define MININTSIZE (sizeof(unsigned long)*BITSPERBYTE/3+1)
20 #define MINPOINTSIZE (sizeof(void *)*BITSPERBYTE/4+1)
21 #if defined(FULL_SPECIFIERS)
22 #define MINFLOATSIZE (DBL_DIG+1) /* Why not 1 more - it's 97% reliable */
23 #define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE? \
24 (MININTSIZE>MINFLOATSIZE?MININTSIZE:MINFLOATSIZE): \
25 (MINPOINTSIZE>MINFLOATSIZE?MINPOINTSIZE:MINFLOATSIZE))
26 #else
27 #define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE ? (MININTSIZE) : (MINPOINTSIZE))
28 #endif
29 #define ALTERNATEFLAG 1 /* '#' is set */
30 #define ZEROPADFLAG 2 /* '0' is set */
31 #define LALIGNFLAG 4 /* '-' is set */
32 #define BLANKFLAG 8 /* ' ' is set */
33 #define SIGNFLAG 16 /* '+' is set */
34 #define LDBLFLAG 64 /* Processing a long double */
36 static size_t format_long(char *buffer, char type, int base, unsigned long v)
38 size_t size = 0;
39 char hex = 'a' - 10;
40 unsigned char mask = 0;
41 unsigned char shift = 0;
43 switch (type)
45 case 'X':
46 hex = 'A' - 10;
47 case 'x':
48 shift = 4;
49 mask = 0x0F;
50 if (base == 10)
51 base = 16;
52 break;
54 case 'o':
55 shift = 3;
56 mask = 0x07;
57 if (base == 10)
58 base = 8;
59 break;
61 default: /* 'd' and 'u' */
62 /* Use slow divide operations for decimal numbers */
65 char c = v % base;
67 *--buffer = c + '0';
68 v /= base;
69 size++;
70 } while (v);
72 return size;
75 /* Divisor is a power of 2, so use fast shifts for division */
78 char c = v & mask;
80 *--buffer = (c < 10) ? c + '0' : c + hex;
81 v >>= shift;
82 size++;
83 } while (v);
85 return size;
88 #ifdef AROS_HAVE_LONG_LONG
91 * This is the same as format_long(), but takes long long argument.
92 * This is used to process long long values on 32-bit machines. 64-bit
93 * operations are performed slower there, and may need to call libgcc routines.
95 static size_t format_longlong(char *buffer, char type, int base, unsigned long long v)
97 size_t size = 0;
98 char hex = 'a' - 10;
99 unsigned char mask = 0;
100 unsigned char shift = 0;
102 switch (type)
104 case 'X':
105 hex = 'A' - 10;
107 case 'x':
108 shift = 4;
109 mask = 0x0F;
110 if (base == 10)
111 base = 16;
112 break;
114 case 'o':
115 shift = 3;
116 mask = 0x07;
117 if (base == 10)
118 base = 8;
119 break;
121 default:
123 * FIXME: this is not compiled for $(GENDIR)/lib32/librom.a because this requires
124 * __umoddi3() and __udivdi3() from 32-bit version of libgcc which is not supplied
125 * with 64-bit AROS gcc.
126 * Perhaps these routines needs to be implemented explicitly for the bootstrap. Or
127 * this code needs to be rewritten without these division operations, implementing
128 * decimal division explicitly.
129 * As a consequence, %llu and %lld do not work in x86-64 bootstrap. Use hexadecimal
130 * output or fix this.
132 #ifndef STDC_LIB32
135 char c = v % base;
137 *--buffer = c + '0';
138 v /= base;
139 size++;
140 } while (v);
141 #endif
143 return size;
148 char c = v & mask;
150 *--buffer = (c < 10) ? c + '0' : c + hex;
151 v >>= shift;
152 size++;
153 } while (v);
155 return size;
158 #endif