Skip to content
Snippets Groups Projects
Commit 354829d8 authored by koenigl's avatar koenigl
Browse files

Needed functions for cat(1)

parent 2c613a9c
Branches
No related tags found
No related merge requests found
......@@ -7,3 +7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2"
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
use libc;
use libc::{__errno_location};
use libc::{c_char, c_int, c_void, size_t, ssize_t};
use std::str;
use std::ffi::CStr;
/// Get error message string
///
/// The `strerror` function returns a string describing the error specified by
/// the error number `errnum`.
///
/// Refer to [strerror(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html)
/// for details.
///
/// # Examples
///
/// Print error description of of [EACCES][EACCES]:
/// ```
/// use ti3_rust::strerror;
/// use libc::EACCES;
///
/// println!("EACCES means: {}", strerror(EACCES));
/// ```
///
/// [EACCES]: ../libc/constant.EACCES.html
///
/// # See also
///
/// [perror]
///
pub fn strerror(errnum: c_int) -> &'static str {
let cs = unsafe { CStr::from_ptr(libc::strerror(errnum)) };
match cs.to_str() {
Err(e) => panic!(e),
Ok(s) => s,
}
}
/// Write error messages to standard error
///
/// The `perror` function looks up the current global error number
/// [`errno`][get_errno] and maps it to a string description using
/// [`strerror][strerror], written to the standard error stream in the following
/// format:
///
/// ```test
/// str: Error description
/// ```
///
/// Refer to [perror(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/perror.html)
/// for details.
///
/// # Examples
///
/// Refer to [open].
///
/// # See also
///
/// [strerror]
///
pub fn perror(s: &str) {
let errnum = get_errno();
eprintln!("{}: {}", s, strerror(errnum));
}
/// Get error return value
///
/// The function `get_errno` gets the current global error number `errno`, used
/// by many functions to specify more detailed errors.
///
/// Refer to [errno(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html)
/// for details.
///
/// # Examples
///
/// Refer to [perror] and [strerror].
///
/// # See also
///
/// [perror], [strerror], [**Section 2.3, Error Numbers**](https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_03)
///
pub fn get_errno() -> c_int {
return unsafe { *__errno_location() };
}
/// Read from a file
///
/// The `read()` function tries to read the number of `nbyte` bytes from the
/// file specified by the open file descriptor `fildes`. It writes the result
/// into the buffer `buf` which must at least be of `nbyte` size. The number of
/// bytes actually read is returned.
///
/// Note that even if `nbyte` bytes are available, the function *may* read
/// less bytes if the operating system so chooses, thus checking the return
/// value is indespensible. It guarantees a read of 1 byte however (as long as
/// `nbyte` is greater 0 and there's data to read). If no bytes are available
/// it returns 0.
///
/// Refer to [read(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
/// for details.
///
/// # Examples
///
/// Read at most 1024 bytes from the standard input and end program if done.
/// ```
/// use libc::{ssize_t, size_t, c_int, c_char};
/// use ti3_rust::read;
///
/// const BUFSIZ: size_t = 1024;
/// const STDIN: c_int = 0; // file descriptor to stdin
///
/// let mut buffer: [c_char; BUFSIZ] = [0; BUFSIZ];
///
/// let read = match read(STDIN, &mut buffer, BUFSIZ) {
/// n if n < 0 => panic!("Error reading!"),
/// 0 => return, // End Of File reached
/// n => n as size_t, // cast ssize_t to size_t as we are definitely non-negative now
/// };
/// ```
///
/// Read 1024 bytes in a loop from standard input, writing them to standard
/// output again. Note that [write] doesn't guarantee it wrote all output either.
/// Additionally we use [strerror] and [get_errno] for error handling.
/// ```
/// use libc::{ssize_t, size_t, c_int, c_char};
/// use ti3_rust::{read,write,strerror,get_errno};
///
/// const BUFSIZ: size_t = 1024;
/// const STDIN: c_int = 0; // file descriptor to stdin
/// const STDOUT: c_int = 1; // file descriptor to stdout
///
/// loop {
/// let mut buffer: [c_char; BUFSIZ] = [0; BUFSIZ];
///
/// let read = match read(STDIN, &mut buffer, BUFSIZ) {
/// n if n < 0 => panic!("write: {}", strerror(get_errno())),
/// 0 => return, // End Of File reached
/// n => n as size_t, // cast ssize_t to size_t as we are definitely non-negative now
/// };
///
/// let mut remaining = read;
/// while remaining > 0 {
/// let written = match write(STDOUT, &buffer[BUFSIZ - remaining..], remaining) {
/// n if n < 0 => panic!("read: {}", strerror(get_errno())),
/// n => n as size_t,
/// };
/// remaining -= written;
/// }
/// }
/// ```
///
/// # Return Value
///
/// If reading the file was successful, the non-negative number of bytes read
/// shall be returned. This may be less than requested, either if the file
/// doesn't have enough bytes or the operating system chooses to do so.
///
/// Otherwise -1 is returned and [`errno`][get_errno] is set to an error value
/// describing the error.
///
/// # Errors
///
/// The function may *at least* fail with the following error(s):
///
/// * [EBADF][EBADF]: The `fildes` argument is not a valid file descriptor open
/// for reading.
///
/// [EBADF]: ../libc/constant.EBADF.html
///
/// # See also
///
/// [open], [write]
///
pub fn read(fildes: c_int, mut buf: &mut [c_char], nbyte: size_t) -> ssize_t {
let buf: *mut c_void = &mut buf as *mut _ as *mut c_void;
return unsafe { libc::read(fildes, buf, nbyte) };
}
/// Write to a file
///
/// The `write()` function tries to write the number of `nbyte` bytes to the
/// file specified by the open file descriptor `fildes`. The data is read from
/// the buffer `buf` which must at least be of `nbyte` size.
///
/// Note that even if space for `nbyte` bytes is available, the function *may* write
/// less bytes if the operating system so chooses, thus checking the return
/// value is indespensible. It guarantees a write of 1 byte however (as long as
/// `nbyte` is greater 0 and there's enough space). If all bytes are written
/// it returns `nbyte`.
///
/// Refer to [write(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
/// for details.
///
/// # Examples
///
/// Refer to [read]
///
/// # Return Value
///
/// If writing the file was successful, the non-negative number of bytes written
/// shall be returned. This may be less than requested, if the file
/// the operating system chooses to do so.
///
/// Otherwise -1 is returned and [`errno`][get_errno] is set to an error value
/// describing the error.
///
/// # Errors
///
/// The function may *at least* fail with the following error(s):
///
/// * [EBADF][EBADF]: The `fildes` argument is not a valid file descriptor open
/// for reading.
/// * [ENOSPC][ENOSPC]: There was no free space remaining on the device containing the file.
///
/// [EBADF]: ../libc/constant.EBADF.html
/// [ENOSPC]: ../libc/constant.ENOSPC.html
///
/// # See also
///
/// [open], [read]
///
pub fn write(fildes: c_int, mut buf: &[c_char], nbyte: size_t) -> ssize_t {
let buf: *mut c_void = &mut buf as *mut _ as *mut c_void;
return unsafe { libc::write(fildes, buf, nbyte) };
}
/// Open file
///
/// The `open()` function creates a connection between a file named by the
/// pathname `path` and a file descriptor which it creates and returns. The file
/// descriptor can then be used by other I/O functions to access that file.
///
/// Refer to [open(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html)
/// for details
///
/// # Examples
///
/// Open a file by reading and panic otherwise.
/// ```should_panic
/// use libc::O_RDONLY;
/// use ti3_rust::open;
///
/// let pathname = "/path/to/some/file";
/// let fd = match open(pathname, O_RDONLY) {
/// -1 => panic!("{}: Couldn't open", pathname),
/// n => n,
/// };
/// // ...
/// ```
///
/// Like above, but print more verbose error message using [perror] and Don't Panic!
/// Finally the file descriptor is deallocated using [close]
/// ```
/// use libc::O_RDONLY;
/// use ti3_rust::{open,perror,close};
///
/// let pathname = "/path/to/some/file";
/// let fd = open(pathname, O_RDONLY);
/// if fd == -1 {
/// perror(pathname);
/// return;
/// }
/// // ...
/// close(fd);
/// ```
///
/// # Return Value
///
/// If opening the file succeeded, a non-negative integer will be returned.
/// Otherwise -1 is returned and [`errno`][get_errno] set accordingly.
///
/// # Errors
///
/// The value [`errno`][get_errno] can assume *at least* the following values:
///
/// * [EACCES][EACCES]: Accessing either a component of the path prefix or the
/// file itself isn't allowed with the specified `oflags`.
///
/// * [ENOENT][ENOENT]: Either the path specified by `path` does not name
/// an existing file while O_CREAT is set, or O_CREAT is set but a component
/// of the path prefix does not name an existing directory, or `path` is an
/// empty string.
///
/// * [EINVAL][EINVAL]: The value of the `oflag` argument is not valid.
///
/// [EACCES]: ../libc/constant.EACCES.html
/// [ENOENT]: ../libc/constant.ENOENT.html
/// [EINVAL]: ../libc/constant.EINVAL.html
///
pub fn open(path: &str, oflag: c_int) -> c_int {
let path = path.as_bytes().as_ptr() as *const i8;
return unsafe { libc::open(path, oflag) };
}
//pub fn open_with_mode(path: &str, oflag: c_int, mode: mode_t) -> c_int {
// let path = path.as_bytes().as_ptr() as *const i8;
// return unsafe { libc::open(path, oflag, mode) };
//}
/// Close a file descriptor
///
/// The `close()` function shall deallocate the file descriptor `fildes`.
///
/// Refer to [close(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html)
/// for details.
///
/// # Examples
///
/// Refer to [open].
///
/// # Return Value
///
/// If the file descriptor could successfully be deallocated, 0 is returned.
/// Otherwise -1 is returned and [`errno`][get_errno] set accordingly.
///
/// # Errors
///
/// The value [`errno`][get_errno] can be set to *at least* the value(s):
///
/// * [EBADF][EBADF]: The value `fildes` does not refer to a valid open file
/// descriptor.
///
/// [EBADF]: ../libc/constant.EBADF.html
///
/// # See also
///
/// [open]
///
pub fn close(fildes: c_int) -> c_int {
return unsafe { libc::close(fildes) };
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment