Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/mimalloc/src/libc.c
6175 views
1
/* ----------------------------------------------------------------------------
2
Copyright (c) 2018-2023, Microsoft Research, Daan Leijen
3
This is free software; you can redistribute it and/or modify it under the
4
terms of the MIT license. A copy of the license can be found in the file
5
"LICENSE" at the root of this distribution.
6
-----------------------------------------------------------------------------*/
7
8
// --------------------------------------------------------
9
// This module defines various std libc functions to reduce
10
// the dependency on libc, and also prevent errors caused
11
// by some libc implementations when called before `main`
12
// executes (due to malloc redirection)
13
// --------------------------------------------------------
14
15
#include "mimalloc.h"
16
#include "mimalloc/internal.h"
17
#include "mimalloc/prim.h" // mi_prim_getenv
18
19
char _mi_toupper(char c) {
20
if (c >= 'a' && c <= 'z') return (c - 'a' + 'A');
21
else return c;
22
}
23
24
int _mi_strnicmp(const char* s, const char* t, size_t n) {
25
if (n == 0) return 0;
26
for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) {
27
if (_mi_toupper(*s) != _mi_toupper(*t)) break;
28
}
29
return (n == 0 ? 0 : *s - *t);
30
}
31
32
void _mi_strlcpy(char* dest, const char* src, size_t dest_size) {
33
if (dest==NULL || src==NULL || dest_size == 0) return;
34
// copy until end of src, or when dest is (almost) full
35
while (*src != 0 && dest_size > 1) {
36
*dest++ = *src++;
37
dest_size--;
38
}
39
// always zero terminate
40
*dest = 0;
41
}
42
43
void _mi_strlcat(char* dest, const char* src, size_t dest_size) {
44
if (dest==NULL || src==NULL || dest_size == 0) return;
45
// find end of string in the dest buffer
46
while (*dest != 0 && dest_size > 1) {
47
dest++;
48
dest_size--;
49
}
50
// and catenate
51
_mi_strlcpy(dest, src, dest_size);
52
}
53
54
size_t _mi_strlen(const char* s) {
55
if (s==NULL) return 0;
56
size_t len = 0;
57
while(s[len] != 0) { len++; }
58
return len;
59
}
60
61
size_t _mi_strnlen(const char* s, size_t max_len) {
62
if (s==NULL) return 0;
63
size_t len = 0;
64
while(s[len] != 0 && len < max_len) { len++; }
65
return len;
66
}
67
68
#ifdef MI_NO_GETENV
69
bool _mi_getenv(const char* name, char* result, size_t result_size) {
70
MI_UNUSED(name);
71
MI_UNUSED(result);
72
MI_UNUSED(result_size);
73
return false;
74
}
75
#else
76
bool _mi_getenv(const char* name, char* result, size_t result_size) {
77
if (name==NULL || result == NULL || result_size < 64) return false;
78
return _mi_prim_getenv(name,result,result_size);
79
}
80
#endif
81
82
// --------------------------------------------------------
83
// Define our own limited `_mi_vsnprintf` and `_mi_snprintf`
84
// This is mostly to avoid calling these when libc is not yet
85
// initialized (and to reduce dependencies)
86
//
87
// format: d i, p x u, s
88
// prec: z l ll L
89
// width: 10
90
// align-left: -
91
// fill: 0
92
// plus: +
93
// --------------------------------------------------------
94
95
static void mi_outc(char c, char** out, char* end) {
96
char* p = *out;
97
if (p >= end) return;
98
*p = c;
99
*out = p + 1;
100
}
101
102
static void mi_outs(const char* s, char** out, char* end) {
103
if (s == NULL) return;
104
char* p = *out;
105
while (*s != 0 && p < end) {
106
*p++ = *s++;
107
}
108
*out = p;
109
}
110
111
static void mi_out_fill(char fill, size_t len, char** out, char* end) {
112
char* p = *out;
113
for (size_t i = 0; i < len && p < end; i++) {
114
*p++ = fill;
115
}
116
*out = p;
117
}
118
119
static void mi_out_alignright(char fill, char* start, size_t len, size_t extra, char* end) {
120
if (len == 0 || extra == 0) return;
121
if (start + len + extra >= end) return;
122
// move `len` characters to the right (in reverse since it can overlap)
123
for (size_t i = 1; i <= len; i++) {
124
start[len + extra - i] = start[len - i];
125
}
126
// and fill the start
127
for (size_t i = 0; i < extra; i++) {
128
start[i] = fill;
129
}
130
}
131
132
133
static void mi_out_num(uintptr_t x, size_t base, char prefix, char** out, char* end)
134
{
135
if (x == 0 || base == 0 || base > 16) {
136
if (prefix != 0) { mi_outc(prefix, out, end); }
137
mi_outc('0',out,end);
138
}
139
else {
140
// output digits in reverse
141
char* start = *out;
142
while (x > 0) {
143
char digit = (char)(x % base);
144
mi_outc((digit <= 9 ? '0' + digit : 'A' + digit - 10),out,end);
145
x = x / base;
146
}
147
if (prefix != 0) {
148
mi_outc(prefix, out, end);
149
}
150
size_t len = *out - start;
151
// and reverse in-place
152
for (size_t i = 0; i < (len / 2); i++) {
153
char c = start[len - i - 1];
154
start[len - i - 1] = start[i];
155
start[i] = c;
156
}
157
}
158
}
159
160
161
#define MI_NEXTC() c = *in; if (c==0) break; in++;
162
163
void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) {
164
if (buf == NULL || bufsize == 0 || fmt == NULL) return;
165
buf[bufsize - 1] = 0;
166
char* const end = buf + (bufsize - 1);
167
const char* in = fmt;
168
char* out = buf;
169
while (true) {
170
if (out >= end) break;
171
char c;
172
MI_NEXTC();
173
if (c != '%') {
174
if ((c >= ' ' && c <= '~') || c=='\n' || c=='\r' || c=='\t') { // output visible ascii or standard control only
175
mi_outc(c, &out, end);
176
}
177
}
178
else {
179
MI_NEXTC();
180
char fill = ' ';
181
size_t width = 0;
182
char numtype = 'd';
183
char numplus = 0;
184
bool alignright = true;
185
if (c == '+' || c == ' ') { numplus = c; MI_NEXTC(); }
186
if (c == '-') { alignright = false; MI_NEXTC(); }
187
if (c == '0') { fill = '0'; MI_NEXTC(); }
188
if (c >= '1' && c <= '9') {
189
width = (c - '0'); MI_NEXTC();
190
while (c >= '0' && c <= '9') {
191
width = (10 * width) + (c - '0'); MI_NEXTC();
192
}
193
if (c == 0) break; // extra check due to while
194
}
195
if (c == 'z' || c == 't' || c == 'L') { numtype = c; MI_NEXTC(); }
196
else if (c == 'l') {
197
numtype = c; MI_NEXTC();
198
if (c == 'l') { numtype = 'L'; MI_NEXTC(); }
199
}
200
201
char* start = out;
202
if (c == 's') {
203
// string
204
const char* s = va_arg(args, const char*);
205
mi_outs(s, &out, end);
206
}
207
else if (c == 'p' || c == 'x' || c == 'u') {
208
// unsigned
209
uintptr_t x = 0;
210
if (c == 'x' || c == 'u') {
211
if (numtype == 'z') x = va_arg(args, size_t);
212
else if (numtype == 't') x = va_arg(args, uintptr_t); // unsigned ptrdiff_t
213
else if (numtype == 'L') x = (uintptr_t)va_arg(args, unsigned long long);
214
else x = va_arg(args, unsigned long);
215
}
216
else if (c == 'p') {
217
x = va_arg(args, uintptr_t);
218
mi_outs("0x", &out, end);
219
start = out;
220
width = (width >= 2 ? width - 2 : 0);
221
}
222
if (width == 0 && (c == 'x' || c == 'p')) {
223
if (c == 'p') { width = 2 * (x <= UINT32_MAX ? 4 : ((x >> 16) <= UINT32_MAX ? 6 : sizeof(void*))); }
224
if (width == 0) { width = 2; }
225
fill = '0';
226
}
227
mi_out_num(x, (c == 'x' || c == 'p' ? 16 : 10), numplus, &out, end);
228
}
229
else if (c == 'i' || c == 'd') {
230
// signed
231
intptr_t x = 0;
232
if (numtype == 'z') x = va_arg(args, intptr_t );
233
else if (numtype == 't') x = va_arg(args, ptrdiff_t);
234
else if (numtype == 'L') x = (intptr_t)va_arg(args, long long);
235
else x = va_arg(args, long);
236
char pre = 0;
237
if (x < 0) {
238
pre = '-';
239
if (x > INTPTR_MIN) { x = -x; }
240
}
241
else if (numplus != 0) {
242
pre = numplus;
243
}
244
mi_out_num((uintptr_t)x, 10, pre, &out, end);
245
}
246
else if (c >= ' ' && c <= '~') {
247
// unknown format
248
mi_outc('%', &out, end);
249
mi_outc(c, &out, end);
250
}
251
252
// fill & align
253
mi_assert_internal(out <= end);
254
mi_assert_internal(out >= start);
255
const size_t len = out - start;
256
if (len < width) {
257
mi_out_fill(fill, width - len, &out, end);
258
if (alignright && out <= end) {
259
mi_out_alignright(fill, start, len, width - len, end);
260
}
261
}
262
}
263
}
264
mi_assert_internal(out <= end);
265
*out = 0;
266
}
267
268
void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...) {
269
va_list args;
270
va_start(args, fmt);
271
_mi_vsnprintf(buf, buflen, fmt, args);
272
va_end(args);
273
}
274
275