mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
240 lines
4.7 KiB
C
240 lines
4.7 KiB
C
// Copyright (c) 2021-2022 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by the MIT license
|
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
|
module std::io;
|
|
import libc;
|
|
|
|
struct File
|
|
{
|
|
CFile file;
|
|
}
|
|
|
|
|
|
fn int putchar(char c) @inline
|
|
{
|
|
return libc::putchar(c);
|
|
}
|
|
|
|
/**
|
|
* @param [&in] message
|
|
* @return `number of bytes printed.`
|
|
*/
|
|
fn int print(char* message)
|
|
{
|
|
char* pointer = message;
|
|
while (*pointer != '\0')
|
|
{
|
|
if (!putchar(*pointer)) return 0;
|
|
pointer++;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* @param [&in] message
|
|
* @return `number of bytes printed.`
|
|
*/
|
|
fn int println(char *message = "") @inline
|
|
{
|
|
return libc::puts(message);
|
|
}
|
|
|
|
fn void! File.open(File* file, char[] filename, char[] mode)
|
|
{
|
|
@pool()
|
|
{
|
|
char* filename_copy = tmalloc(filename.len + 1);
|
|
char* mode_copy = tmalloc(mode.len + 1);
|
|
|
|
mem::copy(filename_copy, (char*)(filename), filename.len);
|
|
mem::copy(mode_copy, (char*)(mode), mode.len);
|
|
filename_copy[filename.len] = 0;
|
|
mode_copy[filename.len] = 0;
|
|
file.file = libc::fopen(filename_copy, mode_copy);
|
|
if (!file.file) return IoError.FILE_NOT_FOUND!;
|
|
};
|
|
}
|
|
|
|
enum Seek
|
|
{
|
|
SET,
|
|
CURSOR,
|
|
END
|
|
}
|
|
|
|
fault IoError
|
|
{
|
|
FILE_NOT_FOUND,
|
|
FILE_NOT_SEEKABLE,
|
|
FILE_NOT_VALID,
|
|
FILE_INVALID_POSITION,
|
|
FILE_OVERFLOW,
|
|
FILE_IS_PIPE,
|
|
FILE_EOF,
|
|
FILE_INCOMPLETE_WRITE,
|
|
INTERRUPTED,
|
|
UNKNOWN_ERROR,
|
|
}
|
|
|
|
/**
|
|
* @require file.file != null
|
|
**/
|
|
fn void! File.seek(File *file, long offset, Seek seekMode = Seek.SET)
|
|
{
|
|
if (libc::fseek(file.file, (SeekIndex)(offset), (int)(seekMode)))
|
|
{
|
|
switch (libc::errno())
|
|
{
|
|
case errno::EBADF: return IoError.FILE_NOT_SEEKABLE!;
|
|
case errno::EINVAL: return IoError.FILE_INVALID_POSITION!;
|
|
case errno::EOVERFLOW: return IoError.FILE_OVERFLOW!;
|
|
case errno::ESPIPE: return IoError.FILE_IS_PIPE!;
|
|
default: return IoError.UNKNOWN_ERROR!;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @require file && file.file != null
|
|
*/
|
|
fn void! File.putc(File *file, char c)
|
|
{
|
|
if (!libc::fputc(c, file.file)) return IoError.FILE_EOF!;
|
|
}
|
|
|
|
/**
|
|
* @require file != null
|
|
*/
|
|
fn void! File.close(File *file) @inline
|
|
{
|
|
if (file.file && libc::fclose(file.file))
|
|
{
|
|
switch (libc::errno())
|
|
{
|
|
case errno::ECONNRESET:
|
|
case errno::EBADF: return IoError.FILE_NOT_VALID!;
|
|
case errno::EINTR: return IoError.INTERRUPTED!;
|
|
case errno::EDQUOT:
|
|
case errno::EFAULT:
|
|
case errno::EAGAIN:
|
|
case errno::EFBIG:
|
|
case errno::ENETDOWN:
|
|
case errno::ENETUNREACH:
|
|
case errno::ENOSPC:
|
|
case errno::EIO: return IoError.FILE_INCOMPLETE_WRITE!;
|
|
default: return IoError.UNKNOWN_ERROR!;
|
|
}
|
|
}
|
|
file.file = null;
|
|
}
|
|
|
|
/**
|
|
* @require file && file.file
|
|
*/
|
|
fn bool File.eof(File* file) @inline
|
|
{
|
|
return libc::feof(file.file) != 0;
|
|
}
|
|
|
|
/**
|
|
* @require file && file.file
|
|
*/
|
|
fn usize File.read(File* file, void* buffer, usize items, usize element_size = 1)
|
|
{
|
|
return libc::fread(buffer, element_size, items, file.file);
|
|
}
|
|
|
|
/**
|
|
* @param [&in] file
|
|
* @param [&out] buffer
|
|
* @param items
|
|
* @param element_size
|
|
* @require file.file `File must be initialized`
|
|
* @require element_size > 1
|
|
*/
|
|
fn usize File.write(File* file, void* buffer, usize items, usize element_size = 1)
|
|
{
|
|
return libc::fwrite(buffer, element_size, items, file.file);
|
|
}
|
|
|
|
/**
|
|
* @param [&in] file
|
|
* @require file.file `File must be initialized`
|
|
*/
|
|
fn usize! File.println(File* file, char[] string)
|
|
{
|
|
usize len = string.len;
|
|
if (len != libc::fwrite(string.ptr, 1, len, file.file)) return IoError.UNKNOWN_ERROR!;
|
|
if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR!;
|
|
return len + 1;
|
|
}
|
|
|
|
/**
|
|
* @param [&in] file
|
|
* @require file.file `File must be initialized`
|
|
*/
|
|
fn String File.getline(File* file, Allocator* allocator = mem::current_allocator())
|
|
{
|
|
String s = string::new_with_capacity(120, allocator);
|
|
while (!file.eof())
|
|
{
|
|
int c = libc::fgetc(file.file);
|
|
if (c == '\n') break;
|
|
s.append_char((char)c);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* @param [&in] file
|
|
* @require file.file `File must be initialized`
|
|
*/
|
|
fn void File.flush(File* file)
|
|
{
|
|
libc::fflush(file.file);
|
|
}
|
|
|
|
fn File stdout()
|
|
{
|
|
return { libc::stdout() };
|
|
}
|
|
|
|
fn File stderr()
|
|
{
|
|
return { libc::stderr() };
|
|
}
|
|
|
|
fn File stdin()
|
|
{
|
|
return { libc::stdin() };
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
error FileError
|
|
{
|
|
ulong errno;
|
|
}
|
|
|
|
fn FileError errorFromErrno()
|
|
{
|
|
return FileError { };
|
|
}
|
|
|
|
|
|
|
|
|
|
pubic fn void! File.clearerr(File *file) @inline
|
|
{
|
|
clearerr(file->file);
|
|
}
|
|
|
|
|
|
|
|
fn void File.error(File *file) @inline
|
|
{
|
|
int err = ferror
|
|
}
|
|
*/
|