Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/utils/sprintf.c
1476 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2019-2024 CTCaer
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms and conditions of the GNU General Public License,
7
* version 2, as published by the Free Software Foundation.
8
*
9
* This program is distributed in the hope it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
#include <stdarg.h>
19
#include <string.h>
20
21
#include <utils/types.h>
22
23
char **sout_buf;
24
25
static void _s_putc(char c)
26
{
27
**sout_buf = c;
28
*sout_buf += 1;
29
}
30
31
static void _s_putspace(int fcnt)
32
{
33
if (fcnt <= 0)
34
return;
35
36
for (int i = 0; i < fcnt; i++)
37
_s_putc(' ');
38
}
39
40
static void _s_puts(char *s, char fill, int fcnt)
41
{
42
if (fcnt)
43
{
44
fcnt = fcnt - strlen(s);
45
46
// Left padding. Check if padding is not space based (dot counts as such).
47
if (fill != '.')
48
_s_putspace(fcnt);
49
}
50
51
for (; *s; s++)
52
_s_putc(*s);
53
54
// Right padding. Check if padding is space based (dot counts as such).
55
if (fill == '.')
56
_s_putspace(fcnt);
57
}
58
59
static void _s_putn(u32 v, int base, char fill, int fcnt)
60
{
61
static const char digits[] = "0123456789ABCDEF";
62
63
char *p;
64
char buf[65]; // Number char size + leftover for padding.
65
int c = fcnt;
66
bool negative = false;
67
68
if (base != 10 && base != 16)
69
return;
70
71
// Account for negative numbers.
72
if (base == 10 && v & 0x80000000)
73
{
74
negative = true;
75
v = (int)v * -1;
76
c--;
77
}
78
79
p = buf + 64;
80
*p = 0;
81
do
82
{
83
c--;
84
*--p = digits[v % base];
85
v /= base;
86
} while (v);
87
88
if (negative)
89
*--p = '-';
90
91
if (fill != 0)
92
{
93
while (c > 0 && p > buf)
94
{
95
*--p = fill;
96
c--;
97
}
98
}
99
100
_s_puts(p, 0, 0);
101
}
102
103
/*
104
* Padding:
105
* Numbers:
106
* %3d: Fill: ' ', Count: 3.
107
* % 3d: Fill: ' ', Count: 3.
108
* %.3d: Fill: '.', Count: 3.
109
* %23d: Fill: '2', Count: 3.
110
* % 23d: Fill: ' ', Count: 23.
111
* %223d: Fill: '2', Count: 23.
112
*
113
* Strings, Fill: ' ':
114
* %3s: Count: 5, Left.
115
* %23s: Count: 5, Left.
116
* %223s: Count: 25, Left.
117
* %.3s: Count: 5, Right.
118
* %.23s: Count: 25, Right.
119
* %.223s: Count: 225, Right.
120
*/
121
122
void s_printf(char *out_buf, const char *fmt, ...)
123
{
124
va_list ap;
125
int fill, fcnt;
126
127
sout_buf = &out_buf;
128
129
va_start(ap, fmt);
130
while (*fmt)
131
{
132
if (*fmt == '%')
133
{
134
fmt++;
135
fill = 0;
136
fcnt = 0;
137
138
// Check for padding. Number or space based (dot count as space for string).
139
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ' || *fmt == '.')
140
{
141
fcnt = *fmt; // Padding size or padding type.
142
fmt++;
143
144
if (*fmt >= '0' && *fmt <= '9')
145
{
146
// Padding size exists. Previous char was type.
147
fill = fcnt;
148
fcnt = *fmt - '0';
149
fmt++;
150
parse_padding_dec:
151
// Parse padding size extra digits.
152
if (*fmt >= '0' && *fmt <= '9')
153
{
154
fcnt = fcnt * 10 + *fmt - '0';
155
fmt++;
156
goto parse_padding_dec;
157
}
158
}
159
else
160
{
161
// No padding type, use space. (Max padding size is 9).
162
fill = ' ';
163
fcnt -= '0';
164
}
165
}
166
167
switch (*fmt)
168
{
169
case 'c':
170
char c = va_arg(ap, u32);
171
if (c != '\0')
172
_s_putc(c);
173
break;
174
175
case 'd':
176
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
177
break;
178
179
case 's':
180
_s_puts(va_arg(ap, char *), fill, fcnt);
181
break;
182
183
case 'p':
184
case 'P':
185
case 'x':
186
case 'X':
187
_s_putn(va_arg(ap, u32), 16, fill, fcnt);
188
break;
189
190
case '%':
191
_s_putc('%');
192
break;
193
194
case '\0':
195
goto out;
196
197
default:
198
_s_putc('%');
199
_s_putc(*fmt);
200
break;
201
}
202
}
203
else
204
_s_putc(*fmt);
205
fmt++;
206
}
207
208
out:
209
**sout_buf = '\0';
210
va_end(ap);
211
}
212
213
void s_vprintf(char *out_buf, const char *fmt, va_list ap)
214
{
215
int fill, fcnt;
216
217
sout_buf = &out_buf;
218
219
while (*fmt)
220
{
221
if (*fmt == '%')
222
{
223
fmt++;
224
fill = 0;
225
fcnt = 0;
226
227
// Check for padding. Number or space based.
228
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
229
{
230
fcnt = *fmt; // Padding size or padding type.
231
fmt++;
232
233
if (*fmt >= '0' && *fmt <= '9')
234
{
235
// Padding size exists. Previous char was type.
236
fill = fcnt;
237
fcnt = *fmt - '0';
238
fmt++;
239
parse_padding_dec:
240
// Parse padding size extra digits.
241
if (*fmt >= '0' && *fmt <= '9')
242
{
243
fcnt = fcnt * 10 + *fmt - '0';
244
fmt++;
245
goto parse_padding_dec;
246
}
247
}
248
else
249
{
250
// No padding type, use space. (Max padding size is 9).
251
fill = ' ';
252
fcnt -= '0';
253
}
254
}
255
256
switch (*fmt)
257
{
258
case 'c':
259
char c = va_arg(ap, u32);
260
if (c != '\0')
261
_s_putc(c);
262
break;
263
264
case 'd':
265
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
266
break;
267
268
case 's':
269
_s_puts(va_arg(ap, char *), fill, fcnt);
270
break;
271
272
case 'p':
273
case 'P':
274
case 'x':
275
case 'X':
276
_s_putn(va_arg(ap, u32), 16, fill, fcnt);
277
break;
278
279
case '%':
280
_s_putc('%');
281
break;
282
283
case '\0':
284
goto out;
285
286
default:
287
_s_putc('%');
288
_s_putc(*fmt);
289
break;
290
}
291
}
292
else
293
_s_putc(*fmt);
294
fmt++;
295
}
296
297
out:
298
**sout_buf = '\0';
299
}
300
301