Start implementing CRT I/O
authorcoderain <coderain@sdf.org>
Mon, 23 Oct 2017 04:30:31 +0000 (06:30 +0200)
committercoderain <coderain@sdf.org>
Mon, 23 Oct 2017 04:30:31 +0000 (06:30 +0200)
crt/include/stdio.h [new file with mode: 0644]
crt/src/io.c [new file with mode: 0644]
kernel/include/common.h
sdk/defs.h

diff --git a/crt/include/stdio.h b/crt/include/stdio.h
new file mode 100644 (file)
index 0000000..53d31a0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * stdio.h
+ *
+ * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _STDIO_H_
+#define _STDIO_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define EOF -1
+
+#define getc(s) fgetc(s)
+#define getchar() fgetc(stdin)
+#define putc(c, s) fputc(c, s)
+#define putchar(c) fputc(c, stdout)
+
+#define getc_unlocked(s) fgetc_unlocked(s)
+#define getchar_unlocked() fgetc_unlocked(stdin)
+#define putc_unlocked(c, s) fputc_unlocked(c, s)
+#define putchar_unlocked(c) fputc(c, stdout)
+
+struct __crt_file;
+typedef struct __crt_file FILE;
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+int fgetc(FILE *stream);
+int fputc(int c, FILE *stream);
+char *fgets(char *s, int size, FILE *stream);
+int fputs(const char *s, FILE *stream);
+int ungetc(int c, FILE *stream);
+char *gets(char *s);
+int puts(const char *s);
+
+int fgetc_unlocked(FILE *stream);
+int fputc_unlocked(int c, FILE *stream);
+char *fgets_unlocked(char *s, int size, FILE *stream);
+int fputs_unlocked(const char *s, FILE *stream);
+
+FILE *fmemopen(void *buf, size_t size, const char *mode);
+int fclose(FILE *stream);
+
+#endif
diff --git a/crt/src/io.c b/crt/src/io.c
new file mode 100644 (file)
index 0000000..0c64c6b
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * io.c
+ *
+ * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <monolithium.h>
+
+#define FILE_READ        (1 << 0)
+#define FILE_WRITE       (1 << 1)
+#define FILE_APPEND      (1 << 2)
+#define FILE_BUFFER_DIR  (1 << 3)
+#define FILE_BUFFER_FULL (1 << 31)
+
+struct __crt_file
+{
+    list_entry_t link;
+    handle_t mutex;
+    uint32_t flags;
+
+    int fd;
+    long position;
+    size_t size;
+
+    uint8_t *buffer;
+    size_t buffer_size;
+    size_t buffer_start, buffer_end;
+};
+
+static list_entry_t open_files;
+
+FILE *stdin  = NULL;
+FILE *stdout = NULL;
+FILE *stderr = NULL;
+
+int fileno_unlocked(FILE *stream)
+{
+    if (stream->fd == -1) errno = EBADF;
+    return stream->fd;
+}
+
+int fileno(FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+    int ret = fileno_unlocked(stream);
+    syscall_release_mutex(stream->mutex);
+    return ret;
+}
+
+static int __crt_fflush_stream(FILE *stream)
+{
+    if (!(stream->flags & FILE_BUFFER_DIR))
+    {
+        stream->buffer_start = stream->buffer_end = 0;
+        stream->flags &= ~FILE_BUFFER_FULL;
+        return 0;
+    }
+
+    if (stream->fd != -1)
+    {
+        // TODO: Not implemented
+        errno = ENOSYS;
+        return EOF;
+    }
+
+    return 0;
+}
+
+int fflush_unlocked(FILE *stream)
+{
+    if (stream) return __crt_fflush_stream(stream);
+
+    list_entry_t *entry;
+    int result = 0;
+
+    for (entry = open_files.next; entry != &open_files; entry = entry->next)
+    {
+        if (__crt_fflush_stream(CONTAINER_OF(entry, struct __crt_file, link)) == EOF)
+        {
+            result = EOF;
+        }
+    }
+
+    return result;
+}
+
+int fflush(FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+    int ret = fflush_unlocked(stream);
+    syscall_release_mutex(stream->mutex);
+    return ret;
+}
+
+inline int fgetc_unlocked(FILE *stream)
+{
+    if (!(stream->flags & FILE_READ))
+    {
+        errno = EPERM;
+        return EOF;
+    }
+
+    if (stream->position == stream->size) return EOF;
+
+    if (stream->flags & FILE_BUFFER_DIR)
+    {
+        fflush_unlocked(stream);
+        stream->flags &= ~FILE_BUFFER_DIR;
+    }
+
+    if (stream->fd != -1
+        && stream->buffer_start == stream->buffer_end
+        && !(stream->flags & FILE_BUFFER_FULL))
+    {
+        // TODO: Not implemented
+        errno = ENOSYS;
+        return EOF;
+    }
+
+    uint8_t c = stream->buffer[stream->buffer_start];
+    stream->buffer_start++;
+    stream->buffer_end %= stream->buffer_size;
+    stream->position++;
+
+    stream->flags &= ~FILE_BUFFER_FULL;
+    return (int)((unsigned int)c);
+}
+
+int fgetc(FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+    int ret = fgetc_unlocked(stream);
+    syscall_release_mutex(stream->mutex);
+    return ret;
+}
+
+inline int fputc_unlocked(int c, FILE *stream)
+{
+    if (!(stream->flags & FILE_WRITE))
+    {
+        errno = EPERM;
+        return EOF;
+    }
+
+    if (!(stream->flags & FILE_BUFFER_DIR))
+    {
+        fflush_unlocked(stream);
+        stream->flags |= FILE_BUFFER_DIR;
+    }
+
+    if ((stream->flags & FILE_APPEND) && (stream->position < stream->size))
+    {
+        fflush_unlocked(stream);
+        stream->position = stream->size;
+    }
+
+    if (stream->flags & FILE_BUFFER_FULL)
+    {
+        errno = ENOSPC;
+        return EOF;
+    }
+
+    stream->buffer[stream->buffer_end] = (uint8_t)c;
+    stream->buffer_end++;
+    stream->buffer_end %= stream->buffer_size;
+
+    stream->position++;
+    if (stream->position > stream->size) stream->size = stream->position;
+
+    if (stream->fd != -1 && ((char)c == '\n' || (stream->buffer_start == stream->buffer_end)))
+    {
+        stream->flags |= FILE_BUFFER_FULL;
+        fflush_unlocked(stream);
+    }
+
+    return 0;
+}
+
+int fputc(int c, FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+    int ret = fputc_unlocked(c, stream);
+    syscall_release_mutex(stream->mutex);
+    return ret;
+}
+
+char *fgets_unlocked(char *s, int size, FILE *stream)
+{
+    int c;
+    char *ptr = s;
+
+    while (size-- > 0 && (c = fgetc_unlocked(stream)) != EOF)
+    {
+        *ptr++ = (char)c;
+        if (c == '\n') break;
+    }
+
+    return (s != ptr) ? s : NULL;
+}
+
+char *fgets(char *s, int size, FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+    char *ret = fgets_unlocked(s, size, stream);
+    syscall_release_mutex(stream->mutex);
+    return ret;
+}
+
+int fputs_unlocked(const char *s, FILE *stream)
+{
+    const char *ptr = s;
+    while (*ptr) if (fputc_unlocked(*ptr++, stream) == EOF) return EOF;
+    return 0;
+}
+
+int fputs(const char *s, FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+    int ret = fputs_unlocked(s, stream);
+    syscall_release_mutex(stream->mutex);
+    return ret;
+}
+
+int ungetc(int c, FILE *stream)
+{
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+
+    if (stream->flags & FILE_BUFFER_DIR)
+    {
+        fflush_unlocked(stream);
+        stream->flags &= ~FILE_BUFFER_DIR;
+    }
+
+    if (stream->buffer_start == 0) stream->buffer_start = stream->buffer_size;
+    stream->buffer_start--;
+
+    stream->buffer[stream->buffer_start] = (uint8_t)c;
+    stream->position--;
+
+    syscall_release_mutex(stream->mutex);
+    return c;
+}
+
+char *gets(char *s)
+{
+    char *ptr = s;
+    int c;
+    while ((c = getchar()) != EOF) *ptr++ = (char)c;
+    return ptr != s ? s : NULL;
+}
+
+int puts(const char *s)
+{
+    if (fputs(s, stdout) == EOF) return EOF;
+    if (fputc('\n', stdout) == EOF) return EOF;
+    return 0;
+}
+
+FILE *fmemopen(void *buf, size_t size, const char *mode)
+{
+    FILE *stream = (FILE*)malloc(sizeof(FILE));
+
+    sysret_t status = syscall_create_mutex(NULL, TRUE, &stream->mutex);
+    if (status != ERR_SUCCESS)
+    {
+        free(stream);
+        errno = __crt_translate_error(status);
+        return NULL;
+    }
+
+    stream->flags = 0;
+    stream->fd = -1;
+    stream->position = 0;
+    stream->size = size;
+    stream->buffer = buf;
+    stream->buffer_size = size;
+    stream->buffer_start = stream->buffer_end = 0;
+
+    list_append(&open_files, &stream->link);
+    return stream;
+}
+
+int fclose(FILE *stream)
+{
+    list_remove(&stream->link);
+    free(stream);
+    return 0;
+}
index 6cf9f1b2e045a98bd14c83b09fce4886ac636240..7932ab121f6f0a0bd24a26a44bb48f55b873f02f 100644 (file)
 #include <sdk/defs.h>
 
 /* Monolithium-specific Helper Macros */
-#define UNUSED_PARAMETER(x) (x)=(x)
 #define SEGMENT_RPL(x) ((x) & 0x03)
-#define OFFSET_OF(type, field) ((uintptr_t)(&((type*)NULL)->field))
-#define CONTAINER_OF(ptr, type, field) ((type*)((uintptr_t)(ptr) - OFFSET_OF(type, field)))
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
index 7c3088f21553354844d3055e1136d557aa400ee2..9851be64505c74d461f803c7890ccdbe5d37d8eb 100644 (file)
 
 #define MAX_PATH 16384
 
+#define UNUSED_PARAMETER(x) (x)=(x)
+#define OFFSET_OF(type, field) ((uintptr_t)(&((type*)NULL)->field))
+#define CONTAINER_OF(ptr, type, field) ((type*)((uintptr_t)(ptr) - OFFSET_OF(type, field)))
+
 /* Monolithium-specific Types */
 typedef uint8_t bool_t;
 typedef uint8_t byte_t;