mod.rs 11.4 KB
Newer Older
1
2
//! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html

Matija Skala's avatar
Matija Skala committed
3
use core::mem;
jD91mZM2's avatar
jD91mZM2 committed
4
5
use core::ptr;
use core::usize;
6

jD91mZM2's avatar
jD91mZM2 committed
7
8
use cbitset::BitSet256;

9
use header::errno::*;
Jeremy Soller's avatar
Format    
Jeremy Soller committed
10
use header::signal;
11
use platform;
jD91mZM2's avatar
jD91mZM2 committed
12
use platform::types::*;
13

Jeremy Soller's avatar
Jeremy Soller committed
14
#[no_mangle]
15
16
17
18
19
20
21
pub unsafe extern "C" fn memccpy(
    dest: *mut c_void,
    src: *const c_void,
    c: c_int,
    n: usize,
) -> *mut c_void {
    let to = memchr(src, c, n);
Tom Almeida's avatar
Tom Almeida committed
22
    if to.is_null() {
23
24
        return to;
    }
Tom Almeida's avatar
Tom Almeida committed
25
    let dist = (to as usize) - (src as usize);
Tom Almeida's avatar
Tom Almeida committed
26
27
    if memcpy(dest, src, dist).is_null() {
        return ptr::null_mut();
28
    }
29
    (dest as *mut u8).offset(dist as isize + 1) as *mut c_void
Jeremy Soller's avatar
Jeremy Soller committed
30
31
32
}

#[no_mangle]
33
pub unsafe extern "C" fn memchr(s: *const c_void, c: c_int, n: usize) -> *mut c_void {
Matija Skala's avatar
Matija Skala committed
34
    let mut s = s as *const u8;
35
    let c = c as u8;
Matija Skala's avatar
Matija Skala committed
36
37
38
39
40
    let mut n = n;
    // read one byte at a time until s is aligned
    while s as usize % mem::size_of::<usize>() != 0 {
        if n == 0 {
            return ptr::null_mut();
41
        }
Matija Skala's avatar
Matija Skala committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
        if *s == c {
            return s as *mut c_void;
        }
        n -= 1;
        s = s.offset(1);
    }
    let mut s = s as *const usize;
    let lowbits = !0 as usize / 255;
    let highbits = lowbits * 0x80;
    let repeated_c = lowbits * c as usize;
    while n >= mem::size_of::<usize>() {
        // read multiple bytes at a time
        // turn the requested byte into 8 zero bits
        let m = *s ^ repeated_c;
        // subtracting one from zero flips high bit from 0 to 1
        if (m.wrapping_sub(lowbits) & !m & highbits) != 0 {
            break;
        }
        n -= mem::size_of::<usize>();
        s = s.offset(1);
    }
    let mut s = s as *const u8;
    while n > 0 {
        if *s == c {
            return s as *mut c_void;
        }
        n -= 1;
        s = s.offset(1);
70
    }
Tom Almeida's avatar
Tom Almeida committed
71
    ptr::null_mut()
Jeremy Soller's avatar
Jeremy Soller committed
72
73
}

74
#[no_mangle]
Hermann Döppes's avatar
Hermann Döppes committed
75
pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    let (div, rem) = (n / mem::size_of::<usize>(), n % mem::size_of::<usize>());
    let mut a = s1 as *const usize;
    let mut b = s2 as *const usize;
    for _ in 0..div {
        if *a != *b {
            for i in 0..mem::size_of::<usize>() {
                let c = *(a as *const u8).offset(i as isize);
                let d = *(b as *const u8).offset(i as isize);
                if c != d {
                    return c as i32 - d as i32;
                }
            }
            unreachable!()
        }
        a = a.offset(1);
        b = b.offset(1);
    }

    let mut a = a as *const u8;
    let mut b = b as *const u8;
    for _ in 0..rem {
        if *a != *b {
98
99
            return a as i32 - b as i32;
        }
100
101
        a = a.offset(1);
        b = b.offset(1);
102
103
104
    }
    0
}
Jeremy Soller's avatar
Jeremy Soller committed
105

106
#[no_mangle]
Hermann Döppes's avatar
Hermann Döppes committed
107
pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: usize) -> *mut c_void {
108
109
110
111
112
113
114
115
116
117
    let mut i = 0;
    while i + 7 < n {
        *(s1.offset(i as isize) as *mut u64) = *(s2.offset(i as isize) as *const u64);
        i += 8;
    }
    while i < n {
        *(s1 as *mut u8).offset(i as isize) = *(s2 as *const u8).offset(i as isize);
        i += 1;
    }
    s1
118
}
Jeremy Soller's avatar
Jeremy Soller committed
119

120
#[no_mangle]
Hermann Döppes's avatar
Hermann Döppes committed
121
pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: usize) -> *mut c_void {
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
    if s2 < s1 as *const c_void {
        // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *(s1 as *mut u8).offset(i as isize) = *(s2 as *const u8).offset(i as isize);
        }
    } else {
        // copy from beginning
        let mut i = 0;
        while i < n {
            *(s1 as *mut u8).offset(i as isize) = *(s2 as *const u8).offset(i as isize);
            i += 1;
        }
    }
    s1
}
Jeremy Soller's avatar
Jeremy Soller committed
139

140
#[no_mangle]
Hermann Döppes's avatar
Hermann Döppes committed
141
pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void {
142
143
144
145
146
147
148
    let mut i = 0;
    while i < n {
        *(s as *mut u8).offset(i as isize) = c as u8;
        i += 1;
    }
    s
}
Jeremy Soller's avatar
Jeremy Soller committed
149
150

#[no_mangle]
151
152
pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
    strncat(s1, s2, usize::MAX)
Jeremy Soller's avatar
Jeremy Soller committed
153
154
155
}

#[no_mangle]
156
157
158
159
160
pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
    let c = c as c_char;
    while *s != 0 {
        if *s == c {
            return s as *mut c_char;
161
        }
162
        s = s.offset(1);
163
    }
Tom Almeida's avatar
Tom Almeida committed
164
    ptr::null_mut()
Jeremy Soller's avatar
Jeremy Soller committed
165
166
167
}

#[no_mangle]
168
169
pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
    strncmp(s1, s2, usize::MAX)
Jeremy Soller's avatar
Jeremy Soller committed
170
171
}

172
#[no_mangle]
jD91mZM2's avatar
jD91mZM2 committed
173
174
175
pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
    // relibc has no locale stuff (yet)
    strcmp(s1, s2)
Jeremy Soller's avatar
Jeremy Soller committed
176
177
178
}

#[no_mangle]
jD91mZM2's avatar
jD91mZM2 committed
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
    let mut i = 0;

    loop {
        let byte = *src.offset(i);
        *dst.offset(i) = byte;

        if byte == 0 {
            break;
        }

        i += 1;
    }

    dst
Jeremy Soller's avatar
Jeremy Soller committed
194
195
}

jD91mZM2's avatar
jD91mZM2 committed
196
pub unsafe fn inner_strspn(s1: *const c_char, s2: *const c_char, cmp: bool) -> size_t {
jD91mZM2's avatar
jD91mZM2 committed
197
198
    let mut s1 = s1 as *const u8;
    let mut s2 = s2 as *const u8;
Tom Almeida's avatar
Tom Almeida committed
199

jD91mZM2's avatar
jD91mZM2 committed
200
201
202
203
    // The below logic is effectively ripped from the musl implementation. It
    // works by placing each byte as it's own bit in an array of numbers. Each
    // number can hold up to 8 * mem::size_of::<usize>() bits. We need 256 bits
    // in total, to fit one byte.
204

jD91mZM2's avatar
jD91mZM2 committed
205
    let mut set = BitSet256::new();
206

jD91mZM2's avatar
jD91mZM2 committed
207
208
209
    while *s2 != 0 {
        set.insert(*s2 as usize);
        s2 = s2.offset(1);
210
211
    }

jD91mZM2's avatar
jD91mZM2 committed
212
213
214
215
216
    let mut i = 0;
    while *s1 != 0 {
        if set.contains(*s1 as usize) != cmp {
            break;
        }
217
        i += 1;
jD91mZM2's avatar
jD91mZM2 committed
218
        s1 = s1.offset(1);
219
    }
jD91mZM2's avatar
jD91mZM2 committed
220
    i
Jeremy Soller's avatar
Jeremy Soller committed
221
222
}

jD91mZM2's avatar
jD91mZM2 committed
223
224
225
226
227
#[no_mangle]
pub unsafe extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> size_t {
    inner_strspn(s1, s2, false)
}

Jeremy Soller's avatar
Jeremy Soller committed
228
#[no_mangle]
229
pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
230
231
232
233
234
    strndup(s1, usize::MAX)
}

#[no_mangle]
pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char {
235
    let len = strnlen(s1, size);
236

237
    // the "+ 1" is to account for the NUL byte
Jeremy Soller's avatar
Jeremy Soller committed
238
    let buffer = platform::alloc(len + 1) as *mut c_char;
239
    if buffer.is_null() {
Jeremy Soller's avatar
Jeremy Soller committed
240
        platform::errno = ENOMEM as c_int;
241
242
243
244
245
    } else {
        //memcpy(buffer, s1, len)
        for i in 0..len as isize {
            *buffer.offset(i) = *s1.offset(i);
        }
246
        *buffer.offset(len as isize) = 0;
247
248
249
    }

    buffer
Jeremy Soller's avatar
Jeremy Soller committed
250
251
252
}

#[no_mangle]
Jeremy Soller's avatar
Jeremy Soller committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
    use core::fmt::Write;

    static mut strerror_buf: [u8; 256] = [0; 256];

    let mut w = platform::StringWriter(strerror_buf.as_mut_ptr(), strerror_buf.len());

    if errnum >= 0 && errnum < STR_ERROR.len() as c_int {
        w.write_str(STR_ERROR[errnum as usize]);
    } else {
        w.write_fmt(format_args!("Unknown error {}", errnum));
    }

    strerror_buf.as_mut_ptr() as *mut c_char
Jeremy Soller's avatar
Jeremy Soller committed
267
268
}

269
270
#[no_mangle]
pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
271
272
273
274
275
    strnlen(s, usize::MAX)
}

#[no_mangle]
pub unsafe extern "C" fn strnlen(s: *const c_char, size: usize) -> size_t {
276
277
278
279
280
281
282
283
    let mut i = 0;
    while i < size {
        if *s.offset(i as isize) == 0 {
            break;
        }
        i += 1;
    }
    i as size_t
284
285
}

Jeremy Soller's avatar
Jeremy Soller committed
286
#[no_mangle]
287
288
289
290
291
292
293
294
295
296
297
298
299
pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: usize) -> *mut c_char {
    let mut idx = strlen(s1 as *const _) as isize;
    for i in 0..n as isize {
        if *s2.offset(i) == 0 {
            break;
        }

        *s1.offset(idx) = *s2.offset(i);
        idx += 1;
    }
    *s1.offset(idx) = 0;

    s1
Jeremy Soller's avatar
Jeremy Soller committed
300
301
302
}

#[no_mangle]
303
pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int {
304
305
306
307
308
    let s1 = core::slice::from_raw_parts(s1 as *const c_uchar, n);
    let s2 = core::slice::from_raw_parts(s2 as *const c_uchar, n);

    for (&a, &b) in s1.iter().zip(s2.iter()) {
        let val = (a as c_int) - (b as c_int);
309
        if a != b || a == 0 {
310
            return val;
311
312
313
        }
    }

314
    0
Jeremy Soller's avatar
Jeremy Soller committed
315
316
317
}

#[no_mangle]
jD91mZM2's avatar
jD91mZM2 committed
318
319
320
321
322
323
pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
    let mut i = 0;

    while *src.offset(i) != 0 && (i as usize) < n {
        *dst.offset(i) = *src.offset(i);
        i += 1;
324
325
    }

jD91mZM2's avatar
jD91mZM2 committed
326
327
    for i in i..n as isize {
        *dst.offset(i) = 0;
328
329
    }

jD91mZM2's avatar
jD91mZM2 committed
330
    dst
Jeremy Soller's avatar
Jeremy Soller committed
331
332
333
}

#[no_mangle]
334
pub unsafe extern "C" fn strpbrk(s1: *const c_char, s2: *const c_char) -> *mut c_char {
335
336
337
338
339
    let p = s1.offset(strcspn(s1, s2) as isize);
    if *p != 0 {
        p as *mut c_char
    } else {
        ptr::null_mut()
340
    }
Jeremy Soller's avatar
Jeremy Soller committed
341
342
343
}

#[no_mangle]
Justin Raymond's avatar
Justin Raymond committed
344
345
346
347
pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
    let len = strlen(s) as isize;
    let c = c as i8;
    let mut i = len - 1;
Justin Raymond's avatar
Justin Raymond committed
348
    while i >= 0 {
Justin Raymond's avatar
Justin Raymond committed
349
350
351
352
353
354
        if *s.offset(i) == c {
            return s.offset(i) as *mut c_char;
        }
        i -= 1;
    }
    ptr::null_mut()
Jeremy Soller's avatar
Jeremy Soller committed
355
356
}

357
358
359
360
361
362
363
#[no_mangle]
pub unsafe extern "C" fn strsignal(sig: c_int) -> *mut c_char {
    // Mutating this is undefined behavior I believe. But I just can't create a
    // &'static mut str. Alternative is allocating everything on the heap...
    signal::_signal_strings[sig as usize].as_ptr() as *const c_char as *mut c_char
}

Jeremy Soller's avatar
Jeremy Soller committed
364
#[no_mangle]
Timothy Bess's avatar
Timothy Bess committed
365
pub unsafe extern "C" fn strspn(s1: *const c_char, s2: *const c_char) -> size_t {
jD91mZM2's avatar
jD91mZM2 committed
366
    inner_strspn(s1, s2, true)
Jeremy Soller's avatar
Jeremy Soller committed
367
368
}

jD91mZM2's avatar
jD91mZM2 committed
369
370
371
372
373
374
375
unsafe fn inner_strstr(mut haystack: *const c_char, mut needle: *const c_char, mask: c_char) -> *mut c_char {
    while *haystack != 0 {
        let mut i = 0;
        loop {
            if *needle.offset(i) == 0 {
                // We reached the end of the needle, everything matches this far
                return haystack as *mut c_char;
376
            }
jD91mZM2's avatar
jD91mZM2 committed
377
378
            if *haystack.offset(i) & mask != *needle.offset(i) & mask {
                break;
379
            }
jD91mZM2's avatar
jD91mZM2 committed
380
381

            i += 1;
382
        }
jD91mZM2's avatar
jD91mZM2 committed
383
384

        haystack = haystack.offset(1);
385
386
    }
    ptr::null_mut()
Jeremy Soller's avatar
Jeremy Soller committed
387
388
}

jD91mZM2's avatar
jD91mZM2 committed
389
390
391
392
393
394
395
396
397
#[no_mangle]
pub unsafe extern "C" fn strstr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
    inner_strstr(haystack, needle, !0)
}
#[no_mangle]
pub unsafe extern "C" fn strcasestr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
    inner_strstr(haystack, needle, !32)
}

Jeremy Soller's avatar
Jeremy Soller committed
398
#[no_mangle]
Timothy Bess's avatar
Timothy Bess committed
399
pub extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char {
400
    static mut HAYSTACK: *mut c_char = ptr::null_mut();
Timothy Bess's avatar
Timothy Bess committed
401
    unsafe {
402
        return strtok_r(s1, delimiter, &mut HAYSTACK);
Timothy Bess's avatar
Timothy Bess committed
403
    }
Jeremy Soller's avatar
Jeremy Soller committed
404
405
406
407
408
}

#[no_mangle]
pub extern "C" fn strtok_r(
    s: *mut c_char,
Timothy Bess's avatar
Timothy Bess committed
409
    delimiter: *const c_char,
Jeremy Soller's avatar
Jeremy Soller committed
410
411
    lasts: *mut *mut c_char,
) -> *mut c_char {
Timothy Bess's avatar
Timothy Bess committed
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
    // Loosely based on GLIBC implementation
    unsafe {
        let mut haystack = s;
        if haystack.is_null() {
            if (*lasts).is_null() {
                return ptr::null_mut();
            }
            haystack = *lasts;
        }

        // Skip past any extra delimiter left over from previous call
        haystack = haystack.add(strspn(haystack, delimiter));
        if *haystack == 0 {
            *lasts = ptr::null_mut();
            return ptr::null_mut();
        }

        // Build token by injecting null byte into delimiter
        let token = haystack;
        haystack = strpbrk(token, delimiter);
        if !haystack.is_null() {
            haystack.write(0);
            haystack = haystack.add(1);
            *lasts = haystack;
        } else {
            *lasts = ptr::null_mut();
        }

        return token;
    }
Jeremy Soller's avatar
Jeremy Soller committed
442
443
}

jD91mZM2's avatar
jD91mZM2 committed
444
445
446
447
448
449
450
451
#[no_mangle]
pub unsafe extern "C" fn strxfrm(s1: *mut c_char, s2: *const c_char, n: usize) -> size_t {
    // relibc has no locale stuff (yet)
    let len = strlen(s2);
    if len < n {
        strcpy(s1, s2);
    }
    len
Jeremy Soller's avatar
Jeremy Soller committed
452
}