1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 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
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Subset of C standard library.
//!
//! This module implements some functions from libc. Thus it eases linking Drone
//! applications with C libraries.
//!
//! Dynamic memory functions (e.g. `malloc`, `free`) are implemented in terms of
//! [Drone Heap](crate::heap).

use crate::ffi::{c_char, c_int};
use ::alloc::alloc;
use core::{alloc::Layout, ffi::c_void, ptr};

/// A type able to represent the size of any object in bytes.
#[allow(non_camel_case_types)]
pub type size_t = usize;

/// Calculates the length of the string `s`, excluding the terminating null byte
/// (`'\0'`).
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
    let mut cursor = s;
    while *cursor != 0 {
        cursor = cursor.add(1);
    }
    (cursor as size_t) - (s as size_t)
}

/// Returns a pointer to the first occurrence of the character `c` in the string
/// `s`.
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
    loop {
        match *s {
            x if x == c as c_char => return s as *mut _,
            0 => return ptr::null_mut(),
            _ => s = s.add(1),
        }
    }
}

/// Compares the two strings `s1` and `s2`. It returns an integer less than,
/// equal to, or greater than zero if `s1` is found, respectively, to be less
/// than, to match, or be greater than `s2`.
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn strcmp(mut s1: *const c_char, mut s2: *const c_char) -> c_int {
    while *s1 != 0 && *s1 == *s2 {
        s1 = s1.add(1);
        s2 = s2.add(1);
    }
    c_int::from(*s1) - c_int::from(*s2)
}

/// Allocates size bytes and returns a pointer to the allocated memory. *The
/// memory is not initialized*. If `size` is `0`, then it returns either `NULL`,
/// or a unique pointer value that can later be successfully passed to
/// [`free`](free).
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
    alloc::alloc(Layout::from_size_align_unchecked(size, 1)) as *mut c_void
}

/// Allocates memory for an array of `nmemb` elements of `size` bytes each and
/// returns a pointer to the allocated memory. The memory is set to zero. If
/// `nmemb` or `size` is 0, then it returns either `NULL`, or a unique pointer
/// value that can later be successfully passed to [`free`](free).
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn calloc(nmemb: size_t, size: size_t) -> *mut c_void {
    alloc::alloc_zeroed(Layout::from_size_align_unchecked(nmemb * size, 1)) as *mut c_void
}

/// Changes the size of the memory block pointed to by `ptr` to `size` bytes.
/// The contents will be unchanged in the range from the start of the region up
/// to the minimum of the old and new sizes. If the new size is larger than the
/// old size, the added memory will not be initialized. If `ptr` is `NULL`, then
/// the call is equivalent to `malloc(size)`, for all values of `size`; if
/// `size` is equal to zero, and `ptr` is not `NULL`, then the call is
/// equivalent to `free(ptr)`. Unless `ptr` is `NULL`, it must have been
/// returned by an earlier call to [`malloc`](malloc), [`calloc`](calloc), or
/// [`realloc`](realloc). If the area pointed to was moved, a `free(ptr)` is
/// done.
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
    alloc::realloc(
        ptr as *mut u8,
        Layout::from_size_align_unchecked(1, 1),
        size,
    ) as *mut c_void
}

/// Frees the memory space pointed to by `ptr`, which must have been returned by
/// a previous call to [`malloc`](malloc), [`calloc`](calloc), or
/// [`realloc`](realloc). Otherwise, or if `free(ptr)` has already been called
/// before, undefined behavior occurs. If `ptr` is `NULL`, no operation is
/// performed.
///
/// # Safety
///
/// This function works with raw pointers.
#[cfg_attr(not(feature = "std"), no_mangle)]
pub unsafe extern "C" fn free(ptr: *mut c_void) {
    alloc::dealloc(ptr as *mut u8, Layout::from_size_align_unchecked(1, 1))
}