hello world from initrd

master
Clyne Sullivan 6 years ago
parent 22615096de
commit 563c92e6d0

@ -18,17 +18,16 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
CROSS = arm-none-eabi- CROSS = arm-stmos-
CC = gcc CC = gcc
AS = as AS = as
OBJCOPY = objcopy OBJCOPY = objcopy
MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16 MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16
AFLAGS = $(MCUFLAGS) AFLAGS = $(MCUFLAGS) -meabi=5
CFLAGS = $(MCUFLAGS) -ggdb -ffreestanding -nostdlib -fsigned-char -I.. \ CFLAGS = $(MCUFLAGS) -ggdb -fsigned-char -I.. \
-Wall -Werror -Wextra -pedantic -Wall -Werror -Wextra -pedantic
#-Wno-overlength-strings -Wno-discarded-qualifiers LFLAGS = -T link.ld
LFLAGS = -T link.ld
OUT = main.elf OUT = main.elf
@ -46,6 +45,9 @@ all:
@$(CROSS)$(CC) $(CFLAGS) $(LFLAGS) -o $(OUT) \ @$(CROSS)$(CC) $(CFLAGS) $(LFLAGS) -o $(OUT) \
$$(find src/fs src/kernel src/user -name "*.o") initrd.img.o $$(find src/fs src/kernel src/user -name "*.o") initrd.img.o
crt:
@arm-stmos-$(CC) $(MCUFLAGS) -fsigned-char -Os -fPIE -c src/crt/crt0.c \
-o src/crt/crt0.o
clean: clean:
@echo " CLEAN" @echo " CLEAN"
@ -53,4 +55,5 @@ clean:
@$(MAKE) -C src/fs clean @$(MAKE) -C src/fs clean
@$(MAKE) -C src/user clean @$(MAKE) -C src/user clean
@rm -f $(OUT) @rm -f $(OUT)
@rm -f initrd.img initrd.img.o

@ -1,6 +1,12 @@
##
# A simple Makefile for building executables loadable by stmos.
#
ARCH = arm-stmos-
CC = gcc -mcpu=cortex-m4 -mthumb -fsigned-char
CFLAGS = -Os -fPIE
all: all:
@arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -fsigned-char -Os \ @$(ARCH)$(CC) $(CFLAGS) init.c -o init
-nostdinc -nostdlib \ @arm-stmos-strip init
-fdata-sections -ffunction-sections -Wl,--gc-sections \
-I../src/pdclib/include -I../src/pdclib/platform/stmos/include \
test.c ../src/pdclib/pdclib.a -s -o test

@ -1 +0,0 @@
Hello, world!!

Binary file not shown.

@ -0,0 +1,14 @@
/**
* @file test.c
* Basic userland code to be loaded by stmos for program load testing.
*/
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
while (1);
return 0;
}

Binary file not shown.

@ -1,16 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
int main(void);
void _start(void)
{
exit(main());
}
int main(void)
{
printf("Hello, world!\n");
return 0;
}

@ -1,5 +1,6 @@
/** /**
* @file linker.ld * @file linker.ld
* Linker script for the kernel/os
* *
* Copyright (C) 2018 Clyne Sullivan * Copyright (C) 2018 Clyne Sullivan
* *

@ -1,5 +1,4 @@
#!/bin/bash #!/bin/bash
#
# @file run.sh # @file run.sh
# Starts openocd and connects gdb to the target, for programming/debugging # Starts openocd and connects gdb to the target, for programming/debugging
# #

@ -0,0 +1,42 @@
##
# @file Makefile
# Script to build folder of source files
#
# Copyright (C) 2018 Clyne Sullivan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
CFILES = $(wildcard *.c)
AFILES = $(wildcard *.s)
OFILES = $(patsubst %.c, %.o, $(CFILES)) \
$(patsubst %.s, %.asm.o, $(AFILES))
CFLAGS += -ffreestanding -nostdlib -I.. -I../arch/cmsis
all: $(OFILES)
%.o: %.c
@echo " CC " $<
@$(CROSS)$(CC) $(CFLAGS) -c $< -o $@
%.asm.o: %.s
@echo " AS " $<
@$(CROSS)$(AS) $(AFLAGS) -c $< -o $@
clean:
@echo " CLEAN"
@rm -f $(OFILES)

@ -0,0 +1,60 @@
/**
* @file crt0.c
* Userland executable startup code
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
extern int main(int, char **);
static void stdio_init(void);
void _start(void)
{
stdio_init();
exit(main(0, 0));
}
void stdio_init(void)
{
stderr = calloc(1, sizeof(FILE));
stderr->handle = 2;
stderr->buffer = malloc(BUFSIZ);
stderr->bufsize = BUFSIZ;
stderr->ungetbuf = malloc(_PDCLIB_UNGETCBUFSIZE);
stderr->status = _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC;
stderr->next = NULL;
stdout = calloc(1, sizeof(FILE));
stdout->handle = 1;
stdout->buffer = malloc(BUFSIZ);
stdout->bufsize = BUFSIZ;
stdout->ungetbuf = malloc(_PDCLIB_UNGETCBUFSIZE);
stdout->status = _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC;
stdout->next = stderr;
stdin = calloc(1, sizeof(FILE));
stdin->handle = 0;
stdin->buffer = malloc(BUFSIZ);
stdin->bufsize = BUFSIZ;
stdin->ungetbuf = malloc(_PDCLIB_UNGETCBUFSIZE);
stdin->status = _IOLBF | _PDCLIB_FREAD | _PDCLIB_STATIC;
stdin->next = stdout;
}

@ -1,9 +1,29 @@
##
# @file Makefile
# Script to build folder of source files
#
# Copyright (C) 2018 Clyne Sullivan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
CFILES = $(wildcard *.c) CFILES = $(wildcard *.c)
AFILES = $(wildcard *.s) AFILES = $(wildcard *.s)
OFILES = $(patsubst %.c, %.o, $(CFILES)) \ OFILES = $(patsubst %.c, %.o, $(CFILES)) \
$(patsubst %.s, %.asm.o, $(AFILES)) $(patsubst %.s, %.asm.o, $(AFILES))
CFLAGS += -I.. -I../arch/cmsis CFLAGS += -ffreestanding -nostdlib -I.. -I../arch/cmsis
all: $(OFILES) all: $(OFILES)

@ -1,3 +1,23 @@
/**
* @file initrd.c
* Filesystem module for handling the initrd
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdint.h> #include <stdint.h>
#include <kernel/heap.h> #include <kernel/heap.h>
@ -5,7 +25,6 @@
typedef struct { typedef struct {
char *address; char *address;
uint32_t pos;
uint32_t size; uint32_t size;
} initrd_info; } initrd_info;
@ -16,8 +35,9 @@ static const uint8_t *initrd_start = (uint8_t *)_binary_initrd_img_start;
static const uint32_t initrd_size = (uint32_t)_binary_initrd_img_size; static const uint32_t initrd_size = (uint32_t)_binary_initrd_img_size;
void *initrd_open(const char *file); void *initrd_open(const char *file);
uint32_t initrd_read(void *info, uint32_t count, uint8_t *buffer); uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer);
int initrd_close(void *info); int initrd_close(vfs_file_info *info);
int initrd_seek(vfs_file_info *info, uint32_t offset, int whence);
char *initrd_getfile(uint32_t offset); char *initrd_getfile(uint32_t offset);
@ -26,7 +46,8 @@ static const vfs_volume_funcs initrd_funcs = {
initrd_close, initrd_close,
initrd_read, initrd_read,
0, // write 0, // write
0 // readdir 0, // readdir
initrd_seek
}; };
int initrd_strncmp(const char *a, const char *b, unsigned int n) int initrd_strncmp(const char *a, const char *b, unsigned int n)
@ -53,7 +74,6 @@ void *initrd_open(const char *file)
initrd_info *file = (initrd_info *)malloc( initrd_info *file = (initrd_info *)malloc(
sizeof(initrd_info)); sizeof(initrd_info));
file->address = ptr + len + 8; file->address = ptr + len + 8;
file->pos = 0;
file->size = *(uint32_t *)(ptr + len + 4); file->size = *(uint32_t *)(ptr + len + 4);
return file; return file;
} }
@ -62,41 +82,48 @@ void *initrd_open(const char *file)
return 0; return 0;
} }
int initrd_close(void *info) int initrd_close(vfs_file_info *info)
{ {
// Nothing to do // Nothing to do
free(info); free(info->fsinfo);
return 0; return 0;
} }
uint32_t initrd_read(void *info, uint32_t count, uint8_t *buffer) uint32_t initrd_read(vfs_file_info *info, uint32_t count, uint8_t *buffer)
{ {
initrd_info *iinfo = (initrd_info *)info; initrd_info *iinfo = (initrd_info *)info->fsinfo;
if (iinfo == 0 || iinfo->address == 0) if (iinfo == 0 || iinfo->address == 0)
return 0; return 0;
uint32_t i; uint32_t i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (iinfo->pos >= iinfo->size) if (info->pos >= iinfo->size)
break; break;
buffer[iinfo->pos] = iinfo->address[iinfo->pos]; buffer[info->pos] = iinfo->address[info->pos];
iinfo->pos++; info->pos++;
} }
return i; return i;
} }
/*char *readfile(const char *name) int initrd_seek(vfs_file_info *info, uint32_t offset, int whence)
{ {
char *ptr; initrd_info *iinfo = (initrd_info *)info->fsinfo;
for (uint32_t i = 0; ptr = getfile(i), ptr != 0; i++) { if (iinfo == 0 || iinfo->address == 0)
uint32_t len = *((uint32_t *)ptr); return 0;
if (!strncmp(name, ptr + 4, len))
return ptr + len + 8; if (whence == SEEK_SET)
} info->pos = offset;
else if (whence == SEEK_CUR)
info->pos += offset;
else if (whence == SEEK_END)
info->pos = iinfo->size + offset;
else
return -1;
return 0; return 0;
}*/ }
char *initrd_getfile(uint32_t offset) char *initrd_getfile(uint32_t offset)
{ {

@ -1,6 +1,29 @@
/**
* @file initrd.h
* Filesystem module for handling the initrd
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef INTIRD_H_ #ifndef INTIRD_H_
#define INITRD_H_ #define INITRD_H_
/**
* Mounts the initrd (initrd is built into kernel).
*/
void initrd_init(void); void initrd_init(void);
#endif // INITRD_H_ #endif // INITRD_H_

@ -1,12 +1,32 @@
/**
* @file stdio.c
* Filesystem module for handling stdio (stdout, stdin, stderr)
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "stdio.h" #include "stdio.h"
#include <kernel/heap.h> #include <kernel/heap.h>
#include <kernel/serial.h> #include <kernel/serial.h>
void *stdio_open(const char *path); void *stdio_open(const char *path);
int stdio_close(void *info); int stdio_close(vfs_file_info *info);
uint32_t stdio_read(void *info, uint32_t count, uint8_t *buffer); uint32_t stdio_read(vfs_file_info *info, uint32_t count, uint8_t *buffer);
uint32_t stdio_write(void *info, uint32_t count, const uint8_t *buffer); uint32_t stdio_write(vfs_file_info *info, uint32_t count, const uint8_t *buffer);
const vfs_volume_funcs stdio_funcs = { const vfs_volume_funcs stdio_funcs = {
stdio_open, stdio_open,
@ -14,6 +34,7 @@ const vfs_volume_funcs stdio_funcs = {
stdio_read, stdio_read,
stdio_write, stdio_write,
0, // readdir 0, // readdir
0 // seek
}; };
void *stdio_open(const char *path) void *stdio_open(const char *path)
@ -30,14 +51,14 @@ void *stdio_open(const char *path)
return id; return id;
} }
int stdio_close(void *info) int stdio_close(vfs_file_info *info)
{ {
// Nothing to do // Nothing to do
free(info); free(info->fsinfo);
return 0; return 0;
} }
uint32_t stdio_read(void *info, uint32_t count, uint8_t *buffer) uint32_t stdio_read(vfs_file_info *info, uint32_t count, uint8_t *buffer)
{ {
(void)info; (void)info;
(void)count; (void)count;
@ -45,11 +66,11 @@ uint32_t stdio_read(void *info, uint32_t count, uint8_t *buffer)
return 0; return 0;
} }
uint32_t stdio_write(void *info, uint32_t count, const uint8_t *buffer) uint32_t stdio_write(vfs_file_info *info, uint32_t count, const uint8_t *buffer)
{ {
(void)info; (void)info;
for (uint32_t i = 0; i < count; i++) for (uint32_t i = 0; i < count; i++)
serial_put(buffer[count]); serial_put(buffer[i]);
return count; return count;
} }

@ -1,8 +1,31 @@
/**
* @file stdio.h
* Filesystem module for handling stdio (stdout, stdin, stderr)
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef INTIRD_H_ #ifndef INTIRD_H_
#define INITRD_H_ #define INITRD_H_
#include <kernel/vfs.h> #include <kernel/vfs.h>
/**
* Structure of function calls for stdio filesystem operations.
*/
extern const vfs_volume_funcs stdio_funcs; extern const vfs_volume_funcs stdio_funcs;
#endif // INITRD_H_ #endif // INITRD_H_

@ -1,9 +1,29 @@
##
# @file Makefile
# Script to build folder of source files
#
# Copyright (C) 2018 Clyne Sullivan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
CFILES = $(wildcard *.c) CFILES = $(wildcard *.c)
AFILES = $(wildcard *.s) AFILES = $(wildcard *.s)
OFILES = $(patsubst %.c, %.o, $(CFILES)) \ OFILES = $(patsubst %.c, %.o, $(CFILES)) \
$(patsubst %.s, %.asm.o, $(AFILES)) $(patsubst %.s, %.asm.o, $(AFILES))
CFLAGS += -I.. -I../arch/cmsis CFLAGS += -ffreestanding -nostdlib -I.. -I../arch/cmsis
all: $(OFILES) all: $(OFILES)

@ -23,20 +23,18 @@
#include <arch/stm/stm32l476xx.h> #include <arch/stm/stm32l476xx.h>
// ticks since init // ticks since init
volatile uint32_t ticks = 0; volatile uint32_t clock_ticks = 0;
volatile uint8_t tim2_finished = 1; volatile uint8_t tim2_finished = 1;
extern task_t *current;
void clock_svc(uint32_t *args) void clock_svc(uint32_t *args)
{ {
if (args[0] == 0) if (args[0] == 0)
task_sleep(args[1]); task_sleep(args[1]);
else if (args[0] == 1) else if (args[0] == 1)
udelay(args[1]); clock_udelay(args[1]);
else if (args[0] == 2) else if (args[0] == 2)
*((unsigned int *)args[1]) = ticks; *((unsigned int *)args[1]) = clock_millis();
} }
void clock_init(void) void clock_init(void)
@ -79,18 +77,13 @@ void clock_init(void)
TIM2->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN; TIM2->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
} }
uint32_t millis(void) void clock_delay(uint32_t count)
{
return ticks;
}
void delay(uint32_t count)
{ {
uint32_t target = ticks + count; uint32_t target = clock_ticks + count;
while (ticks < target); while (clock_ticks < target);
} }
void udelay(uint32_t count) void clock_udelay(uint32_t count)
{ {
tim2_finished = 0; tim2_finished = 0;
TIM2->ARR = count; TIM2->ARR = count;
@ -98,13 +91,18 @@ void udelay(uint32_t count)
while (tim2_finished == 0); while (tim2_finished == 0);
} }
uint32_t clock_millis(void)
{
return clock_ticks;
}
void SysTick_Handler(void) void SysTick_Handler(void)
{ {
// just keep counting // just keep counting
ticks++; clock_ticks++;
// task switch every four ticks (4ms) // task switch every four ticks (4ms)
if (!(ticks & 3)) if (!(clock_ticks & 3))
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
} }

@ -28,18 +28,22 @@
*/ */
extern void clock_init(void); extern void clock_init(void);
uint32_t millis(void);
/** /**
* Sleeps for given amount of milliseconds. * Sleeps for given amount of milliseconds.
* @param ms Number of milliseconds to sleep for * @param ms Number of milliseconds to sleep for
*/ */
void delay(uint32_t ms); void clock_delay(uint32_t ms);
/** /**
* Sleeps for the given amount of microseconds. * Sleeps for the given amount of microseconds.
* @param count Number of microseconds to sleep for * @param count Number of microseconds to sleep for
*/ */
void udelay(uint32_t count); void clock_udelay(uint32_t count);
/**
* Returns the number of milliseconds since clock initialization.
* @return milliseconds since init
*/
uint32_t clock_millis(void);
#endif // CLOCK_H_ #endif // CLOCK_H_

@ -0,0 +1,136 @@
/**
* @file elf.c
* Functionality to execute ELF files
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "elf.h"
#include "vfs.h"
#include "heap.h"
#include <string.h>
Elf32_Shdr *elf_find_section(Elf32_Ehdr *ehdr, const char *name)
{
Elf32_Shdr *shdr = (Elf32_Shdr *)((char *)ehdr + ehdr->e_shoff);
Elf32_Shdr *shdr_str = (Elf32_Shdr *)((char *)ehdr + ehdr->e_shoff +
ehdr->e_shstrndx * ehdr->e_shentsize);
for (Elf32_Half i = 0; i < ehdr->e_shnum; i++) {
char *section = ((char *)ehdr + shdr_str->sh_offset) +
shdr->sh_name;
if (!strcmp(section, name))
return shdr;
shdr = (Elf32_Shdr *)((char *)shdr + ehdr->e_shentsize);
}
return 0;
}
uint32_t elf_execve(const char *file, char * const argv[], char * const envp[])
{
(void)argv;
(void)envp;
// Open the given file
int fd = vfs_open(file, VFS_FILE_READ);
if (fd == -1)
return -1;
// Get file size
vfs_seek(fd, 0, SEEK_END);
unsigned int fileLength = vfs_tell(fd);
vfs_seek(fd, 0, SEEK_SET);
// Read entire file
char *elfData = malloc(fileLength);
if (vfs_read(fd, fileLength, (uint8_t *)elfData) != fileLength) {
vfs_close(fd);
free(elfData);
return -1;
}
// ELF signature check
if (elfData[0] != '\177' || elfData[1] != 'E' || elfData[2] != 'L' ||
elfData[3] != 'F') {
vfs_close(fd);
free(elfData);
return -1;
}
uint32_t ELF_OFFSET = 0;
// Load program headers
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfData;
Elf32_Phdr *phdr = (Elf32_Phdr *)(elfData + ehdr->e_phoff);
for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) {
if (phdr->p_type == PT_LOAD) {
// There should only be one PT_LOAD section...
if (ELF_OFFSET != 0)
while (1);
ELF_OFFSET = (uint32_t)malloc(phdr->p_memsz + 8) & ~7;
uint8_t *src = (uint8_t *)elfData + phdr->p_offset;
uint8_t *dst = (uint8_t *)(ELF_OFFSET + phdr->p_vaddr);
for (uint32_t j = 0; j < phdr->p_filesz; j++)
dst[j] = src[j];
}
phdr = (Elf32_Phdr *)((char *)phdr + ehdr->e_phentsize);
}
// Zero the .bss section
Elf32_Shdr *bssSection = elf_find_section(ehdr, ".bss");
if (bssSection != 0) {
uint32_t *bssArray = (Elf32_Addr *)(ELF_OFFSET + bssSection->sh_addr);
Elf32_Word bssSize = bssSection->sh_size / sizeof(void *);
for (Elf32_Word i = 0; i < bssSize; i++)
bssArray[i] = 0;
}
// Fix GOT entries if they exist
Elf32_Shdr *gotSection = elf_find_section(ehdr, ".got");
if (gotSection != 0) {
Elf32_Addr *gotArray = (Elf32_Addr *)(ELF_OFFSET + gotSection->sh_addr);
Elf32_Word gotSize = gotSection->sh_size / sizeof(void *);
for (Elf32_Word i = 0; i < gotSize; i++)
gotArray[i] += ELF_OFFSET;
}
// Run any constructors
Elf32_Shdr *initArraySection = elf_find_section(ehdr, ".init_array");
if (initArraySection != 0) {
Elf32_Addr *initArray = (Elf32_Addr *)(ELF_OFFSET +
initArraySection->sh_addr);
Elf32_Word initArraySize = initArraySection->sh_size / sizeof(void *);
for (Elf32_Word i = 0; i < initArraySize; i++) {
initArray[i] += ELF_OFFSET;
((void (*)(void))(initArray[i]))();
}
}
vfs_close(fd);
free(elfData);
// Return entry point
return (ELF_OFFSET + ehdr->e_entry);
}

@ -0,0 +1,124 @@
/**
* @file elf.h
* Functionality to execute ELF files
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ELF_H_
#define ELF_H_
#include <stdint.h>
/**
* Attempts to open the given ELF file.
* @param file Path of the ELF file
* @param argv argv to be passed to the program
* @param envp envp to be passed to the program
* @return -1 on fail, otherwise returns address of ELF entry
*/
uint32_t elf_execve(const char *file, char * const argv[], char * const envp[]);
//
// ELF Standard macros and structures below
#define EI_NIDENT 16
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_RESERVED 0x70000000
#define ELF32_ST_BIND(i) ((i) >> 4)
#define ELF32_ST_TYPE(i) ((i) & 0xF)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xF))
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((i) & 0xFF)
#define ELF32_R_INFO(s, t) (((s) << 8) + ((t) & 0xFF))
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef uint32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} __attribute__((packed)) Elf32_Ehdr;
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} __attribute__((packed)) Elf32_Shdr;
typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} __attribute__((packed)) Elf32_Sym;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} __attribute__((packed)) Elf32_Rel;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} __attribute__((packed)) Elf32_Rela;
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} __attribute__((packed)) Elf32_Phdr;
#endif // ELF_H_

@ -1,5 +1,26 @@
/**
* @file fault.c
* Fault managing functions
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
__attribute__ ((naked)) __attribute__ ((naked))
void HardFault_Handler(void) void HardFault_Handler(void)
{ {
// TODO have a real fault handler...
while (1); while (1);
} }

@ -63,5 +63,5 @@ void init_idle(void)
task_start(user_main, 4096); task_start(user_main, 4096);
while (1) while (1)
delay(10); clock_delay(10);
} }

@ -44,7 +44,7 @@ void serial_put(int c)
char serial_get(void) char serial_get(void)
{ {
while (!(USART2->ISR & USART_ISR_RXNE)) while (!(USART2->ISR & USART_ISR_RXNE))
delay(10); clock_delay(10);
return USART2->RDR & 0xFF; return USART2->RDR & 0xFF;
} }

@ -1,6 +1,6 @@
/** /**
* @file svc.c * @file svc.c
* An unused handler for SVC calls * Handler code for SVC calls
* *
* Copyright (C) 2018 Clyne Sullivan * Copyright (C) 2018 Clyne Sullivan
* *
@ -48,6 +48,7 @@ void SVC_Handler(void) {
* 2 - getpid * 2 - getpid
* 3 - waitpid * 3 - waitpid
* 4 - sbrk (TODO bad) * 4 - sbrk (TODO bad)
* 5 - execve
*/ */
task_svc(args); task_svc(args);
break; break;

@ -19,6 +19,7 @@
*/ */
#include "clock.h" #include "clock.h"
#include "elf.h"
#include "heap.h" #include "heap.h"
#include "task.h" #include "task.h"
#include <arch/stm/stm32l476xx.h> #include <arch/stm/stm32l476xx.h>
@ -49,6 +50,10 @@ void task_svc(uint32_t *args)
case 4: case 4:
*((void **)args[2]) = task_sbrk(args[1]); *((void **)args[2]) = task_sbrk(args[1]);
break; break;
case 5:
*((uint32_t *)args[4]) = elf_execve((const char *)args[1],
(char * const *)args[2], (char * const *)args[3]);
break;
default: default:
break; break;
} }
@ -56,18 +61,19 @@ void task_svc(uint32_t *args)
void *task_sbrk(uint32_t bytes) void *task_sbrk(uint32_t bytes)
{ {
if (task_current->heap == 0) { return malloc(bytes);
/*if (task_current->heap == 0)
task_current->heap = malloc(1024 * 16); task_current->heap = malloc(1024 * 16);
return (uint8_t *)task_current->heap + (1024 * 16);
}
if (bytes == 0) { if (bytes == 0) {
alloc_t *alloc = (alloc_t *)((uint8_t *)task_current->heap - alloc_t *alloc = (alloc_t *)((uint8_t *)task_current->heap -
sizeof(alloc_t)); sizeof(alloc_t));
return (uint8_t *)task_current->heap + alloc->size; return (uint8_t *)(((uint32_t)task_current->heap + alloc->size)
& ~0xFFF);
} }
return (void *)-1; return (void *)-1;*/
} }
void task_hold(uint8_t hold) void task_hold(uint8_t hold)
@ -81,7 +87,7 @@ void task_hold(uint8_t hold)
void task_sleep(uint32_t ms) void task_sleep(uint32_t ms)
{ {
task_current->status.state = TASK_SLEEPING; task_current->status.state = TASK_SLEEPING;
task_current->status.value = millis() + ms; task_current->status.value = clock_millis() + ms;
YIELD; YIELD;
} }
@ -312,7 +318,7 @@ void PendSV_Handler(void)
" : "=r" (task_current->sp)); " : "=r" (task_current->sp));
// Load next task // Load next task
uint32_t ticks = millis(); uint32_t ticks = clock_millis();
do { do {
task_current = task_current->next; task_current = task_current->next;
if (task_current == 0) if (task_current == 0)

@ -1,3 +1,23 @@
/**
* @file vfs.c
* An implementation of filesystem abstraction
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "vfs.h" #include "vfs.h"
#include <kernel/task.h> #include <kernel/task.h>
@ -10,6 +30,11 @@
static vfs_volume vfs_volumes[VFS_MAX_VOLS]; static vfs_volume vfs_volumes[VFS_MAX_VOLS];
static vfs_file vfs_files[VFS_MAX_FILES]; static vfs_file vfs_files[VFS_MAX_FILES];
#define VFS_PID_CHECK(fpid) { \
uint32_t pid = task_getpid(); \
if (pid != fpid && fpid != 0) \
return 0; }
void vfs_svc(uint32_t *args) void vfs_svc(uint32_t *args)
{ {
switch (args[0]) { switch (args[0]) {
@ -114,7 +139,8 @@ int vfs_open(const char *path, uint32_t flags)
vfs_files[file].flags = VFS_FILE_OPEN | flags; vfs_files[file].flags = VFS_FILE_OPEN | flags;
vfs_files[file].vol = drive; vfs_files[file].vol = drive;
vfs_files[file].pid = task_getpid(); vfs_files[file].pid = task_getpid();
vfs_files[file].fsinfo = fsinfo; vfs_files[file].info.pos = 0;
vfs_files[file].info.fsinfo = fsinfo;
return file; return file;
} }
@ -125,14 +151,13 @@ int vfs_close(int fd)
return -1; return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->close == 0) if (vfs_volumes[vfs_files[fd].vol].funcs->close == 0)
return -1; return -1;
if (vfs_files[fd].pid != task_getpid()) VFS_PID_CHECK(vfs_files[fd].pid);
return -1;
if (!(vfs_files[fd].flags & VFS_FILE_OPEN)) if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
return 0; return 0;
// TODO care // TODO care
/*int ret =*/ vfs_volumes[vfs_files[fd].vol].funcs->close( /*int ret =*/ vfs_volumes[vfs_files[fd].vol].funcs->close(
vfs_files[fd].fsinfo); &vfs_files[fd].info);
vfs_files[fd].flags = 0; vfs_files[fd].flags = 0;
vfs_files[fd].pid = 0; vfs_files[fd].pid = 0;
@ -143,16 +168,17 @@ uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer)
{ {
if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0) if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0)
return 0; return 0;
if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->read == 0) if (vfs_volumes[vfs_files[fd].vol].funcs->read == 0)
return -1; return -1;
if (vfs_files[fd].pid != task_getpid()) VFS_PID_CHECK(vfs_files[fd].pid);
return 0;
if ((!(vfs_files[fd].flags & VFS_FILE_READ)) || (vfs_files[fd].flags & if ((!(vfs_files[fd].flags & VFS_FILE_READ)) || (vfs_files[fd].flags &
VFS_EOF)) VFS_EOF))
return 0; return 0;
uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->read( uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->read(
vfs_files[fd].fsinfo, count, buffer); &vfs_files[fd].info, count, buffer);
if (ret < count) if (ret < count)
vfs_files[fd].flags |= VFS_EOF; vfs_files[fd].flags |= VFS_EOF;
@ -164,17 +190,18 @@ uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer)
{ {
if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0) if (fd < 0 || fd > VFS_MAX_FILES || count == 0 || buffer == 0)
return 0; return 0;
if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->write == 0) if (vfs_volumes[vfs_files[fd].vol].funcs->write == 0)
return -1; return -1;
if (vfs_files[fd].pid != task_getpid()) VFS_PID_CHECK(vfs_files[fd].pid);
return 0;
// TODO append? // TODO append?
if ((!(vfs_files[fd].flags & VFS_FILE_WRITE)) || (vfs_files[fd].flags & if ((!(vfs_files[fd].flags & VFS_FILE_WRITE)) || (vfs_files[fd].flags &
VFS_EOF)) VFS_EOF))
return 0; return 0;
uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->write( uint32_t ret = vfs_volumes[vfs_files[fd].vol].funcs->write(
vfs_files[fd].fsinfo, count, buffer); &vfs_files[fd].info, count, buffer);
if (ret < count) if (ret < count)
vfs_files[fd].flags |= VFS_EOF; vfs_files[fd].flags |= VFS_EOF;
@ -182,3 +209,28 @@ uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer)
return ret; return ret;
} }
int vfs_seek(int fd, int32_t offset, int whence)
{
if (fd < 0 || fd > VFS_MAX_FILES)
return -1;
if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
return -1;
if (vfs_volumes[vfs_files[fd].vol].funcs->seek == 0)
return -1;
VFS_PID_CHECK(vfs_files[fd].pid);
return vfs_volumes[vfs_files[fd].vol].funcs->seek(&vfs_files[fd].info,
offset, whence);
}
int32_t vfs_tell(int fd)
{
if (fd < 0 || fd > VFS_MAX_FILES)
return -1;
if (!(vfs_files[fd].flags & VFS_FILE_OPEN))
return -1;
VFS_PID_CHECK(vfs_files[fd].pid);
return (int32_t)vfs_files[fd].info.pos;
}

@ -1,18 +1,95 @@
/**
* @file vfs.h
* An implementation of filesystem abstraction
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef VFS_H_ #ifndef VFS_H_
#define VFS_H_ #define VFS_H_
#include <stdint.h> #include <stdint.h>
/**
* Holds file info that can be used by filesystem drivers/modules.
*/
typedef struct {
uint32_t pos; /**< Position within the file */
void *fsinfo; /**< Filesystem-specific data, handled by fs driver */
} vfs_file_info;
/**
* Directory entry data, used by readdir.
*/
typedef struct { typedef struct {
char name[32]; char name[32];
} vfs_dirent; } vfs_dirent;
/**
* Functions that a filesystem driver/module should implement.
*/
typedef struct vfs_volume_funcs_t { typedef struct vfs_volume_funcs_t {
/**
* Opens the given file.
* @param file Path to the file
* @return 0 on fail, otherwise pointer to be stored in
* vfs_file_info.fsinfo
*/
void *(*open)(const char *file); void *(*open)(const char *file);
int (*close)(void *info);
uint32_t (*read)(void *info, uint32_t count, uint8_t *buffer); /**
uint32_t (*write)(void *info, uint32_t count, const uint8_t *buffer); * Closes the file, releasing given info however necessary.
* @param info File info
* @return 0 on success, non-zero on failure
*/
int (*close)(vfs_file_info *info);
/**
* Reads bytes from the given file.
* @param info Info on the file
* @param count Number of bytes to read
* @param buffer Pre-allocated buffer to store data to
* @return Number of bytes read
*/
uint32_t (*read)(vfs_file_info *info, uint32_t count, uint8_t *buffer);
/**
* Writes bytes from the given file.
* @param info Info on the file
* @param count Number of bytes to write
* @param buffer Data to write to file
* @return Number of bytes written
*/
uint32_t (*write)(vfs_file_info *info, uint32_t count, const uint8_t *buffer);
/**
* Creates an array of vfs_dirent for the given directory.
* @param path Directory to read
* @return 0 on fail, an array of vfs_dirent otherwise
*/
vfs_dirent *(*readdir)(const char *path); vfs_dirent *(*readdir)(const char *path);
/**
* Seeks file to the given position.
* @param info The file's info
* @param offset Offset to seek to
* @param whence Where to seek from (beginning, end, or current pos.)
* @return 0 on succes, non-zero otherwise
*/
int (*seek)(vfs_file_info *info, uint32_t offset, int whence);
} vfs_volume_funcs; } vfs_volume_funcs;
// Indicates mounted volume // Indicates mounted volume
@ -20,9 +97,12 @@ typedef struct vfs_volume_funcs_t {
// Set if filesystem is read-only // Set if filesystem is read-only
#define VFS_READONLY (1 << 1) #define VFS_READONLY (1 << 1)
/**
* Data defining a VFS volume.
*/
typedef struct { typedef struct {
uint32_t flags; uint32_t flags; /**< Flags regarding volume state */
const vfs_volume_funcs *funcs; const vfs_volume_funcs *funcs; /**< Volume-managing functions */
} vfs_volume; } vfs_volume;
// Indicates an opened file // Indicates an opened file
@ -34,13 +114,19 @@ typedef struct {
// Set if EOF has been reached // Set if EOF has been reached
#define VFS_EOF (1 << 3) #define VFS_EOF (1 << 3)
/**
* Contains data to manage open files.
*/
typedef struct { typedef struct {
uint32_t flags; /**< File attribute flags */ uint32_t flags; /**< File attribute flags */
uint32_t vol; /**< Index of volume file is stored on */ uint32_t vol; /**< Index of volume file is stored on */
uint32_t pid; /**< PID of process handling this file */ uint32_t pid; /**< PID of process handling this file */
void *fsinfo; /**< Filesystem-specific data, handled by fs driver */ vfs_file_info info; /**< File info used by file IO functions */
} vfs_file; } vfs_file;
/**
* Initializes the filesystem abstraction layer.
*/
void vfs_init(void); void vfs_init(void);
int vfs_mount(const vfs_volume_funcs *funcs, uint32_t flags); int vfs_mount(const vfs_volume_funcs *funcs, uint32_t flags);
@ -49,4 +135,11 @@ int vfs_close(int fd);
uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer); uint32_t vfs_read(int fd, uint32_t count, uint8_t *buffer);
uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer); uint32_t vfs_write(int fd, uint32_t count, const uint8_t *buffer);
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
int vfs_seek(int fd, int32_t offset, int whence);
int32_t vfs_tell(int fd);
#endif // VFS_H_ #endif // VFS_H_

@ -24,10 +24,10 @@ REGDEPFILES := $(patsubst %,$(BUILDDIR)/%.d,$(REGFILES))
# All files belonging to the source distribution # All files belonging to the source distribution
ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES) ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES)
CC = arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -fsigned-char --specs=nosys.specs CC = arm-stmos-gcc -mcpu=cortex-m4 -mthumb -fsigned-char
WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wuninitialized -Wstrict-prototypes -Wdeclaration-after-statement WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wuninitialized -Wstrict-prototypes -Wdeclaration-after-statement
CFLAGS := -fno-builtin -g -std=c99 -I./testing -I./platform/stmos/include $(WARNINGS) $(USERFLAGS) CFLAGS := -fPIC -Os -ffreestanding -std=c99 -I./testing -I./platform/stmos/include $(WARNINGS) $(USERFLAGS)
.PHONY: all clean srcdist tests testdrivers regtests regtestdrivers todos fixmes help .PHONY: all clean srcdist tests testdrivers regtests regtestdrivers todos fixmes help

@ -1,21 +0,0 @@
"Example" Platform Overlay
==========================
This is an example platform overlay, as described in the main Readme.txt of
this archive. For ease of development, it applies (and tests) correctly on the
machine of the author; no other guarantees can be given.
It should give you a good idea of what is REQUIRED to make a copy of PDCLib
work. There is a lot more you could do, and even some things you SHOULD do, in
order to experience anything but abysmal performance:
- Read / write operations on binary streams, and even on text streams for
machines that do not do any text conversion, can be made much more efficient
by using some sort of page buffer instead of the linear buffer implemented
here. It requires some special and platform-dependent manipulations, though,
which is why it is not done by default.
- Anything relating to floating point logic is written in generic C. While
this is (hopefully) highly portable and should get you started on your
platform of choice, it is also highly inefficient and should be replaced by
inline assembly. Just make sure that your assembly keeps all the promises
the C library makes.

@ -1,40 +0,0 @@
/* _PDCLIB_exit( int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_exit() fit for use with POSIX
kernels.
*/
#include <stdlib.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
extern void _exit( int status ) _PDCLIB_NORETURN;
void _PDCLIB_Exit( int status )
{
_exit( status );
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
#ifndef REGTEST
int UNEXPECTED_RETURN = 0;
_PDCLIB_Exit( 0 );
TESTCASE( UNEXPECTED_RETURN );
#endif
return TEST_RESULTS;
}
#endif

@ -1,40 +0,0 @@
/* _PDCLIB_exit( int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_exit() fit for use with POSIX
kernels.
*/
#include <stdlib.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
extern void _exit( int status ) _PDCLIB_NORETURN;
void _PDCLIB_Exit( int status )
{
_exit( status );
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
#ifndef REGTEST
int UNEXPECTED_RETURN = 0;
_PDCLIB_Exit( 0 );
TESTCASE( UNEXPECTED_RETURN );
#endif
return TEST_RESULTS;
}
#endif

@ -1,86 +0,0 @@
/* _PDCLIB_allocpages( int const )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_allocpages() fit for use with
POSIX kernels.
*/
#include <stdint.h>
#include <stddef.h>
#ifndef REGTEST
int brk( void * );
void * sbrk( intptr_t );
#include "pdclib/_PDCLIB_glue.h"
static void * membreak = NULL;
void * _PDCLIB_allocpages( int const n )
{
void * oldbreak;
if ( membreak == NULL )
{
/* first call, make sure end-of-heap is page-aligned */
intptr_t unaligned = 0;
membreak = sbrk( 0 );
unaligned = _PDCLIB_PAGESIZE - (intptr_t)membreak % _PDCLIB_PAGESIZE;
if ( unaligned < _PDCLIB_PAGESIZE )
{
/* end-of-heap not page-aligned - adjust */
if ( sbrk( unaligned ) != membreak )
{
/* error */
return NULL;
}
membreak = (char *)membreak + unaligned;
}
}
/* increasing or decreasing heap - standard operation */
oldbreak = membreak;
membreak = (void *)( (char *)membreak + ( n * _PDCLIB_PAGESIZE ) );
#ifdef __CYGWIN__
if ( sbrk( (char*)membreak - (char*)oldbreak ) == membreak )
#else
if ( brk( membreak ) == 0 )
#endif
{
/* successful */
return oldbreak;
}
else
{
/* out of memory */
membreak = oldbreak;
return NULL;
}
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
#ifndef REGTEST
char * startbreak = sbrk( 0 );
TESTCASE( _PDCLIB_allocpages( 0 ) );
TESTCASE( ( (char *)sbrk( 0 ) - startbreak ) <= _PDCLIB_PAGESIZE );
startbreak = sbrk( 0 );
TESTCASE( _PDCLIB_allocpages( 1 ) );
TESTCASE( sbrk( 0 ) == startbreak + ( 1 * _PDCLIB_PAGESIZE ) );
TESTCASE( _PDCLIB_allocpages( 5 ) );
TESTCASE( sbrk( 0 ) == startbreak + ( 6 * _PDCLIB_PAGESIZE ) );
TESTCASE( _PDCLIB_allocpages( -3 ) );
TESTCASE( sbrk( 0 ) == startbreak + ( 3 * _PDCLIB_PAGESIZE ) );
#endif
return TEST_RESULTS;
}
#endif

@ -1,36 +0,0 @@
/* _PDCLIB_close( _PDCLIB_fd_t )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_close() fit for use with POSIX
kernels.
*/
#include <stdio.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
extern int close( int fd );
int _PDCLIB_close( int fd )
{
return close( fd );
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* No testdriver; tested in driver for _PDCLIB_open(). */
return TEST_RESULTS;
}
#endif

@ -1,78 +0,0 @@
/* _PDCLIB_fillbuffer( struct _PDCLIB_file_t * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_fillbuffer() fit for
use with POSIX kernels.
*/
#include <stdio.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
#include </usr/include/errno.h>
typedef long ssize_t;
extern ssize_t read( int fd, void * buf, size_t count );
int _PDCLIB_fillbuffer( struct _PDCLIB_file_t * stream )
{
/* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */
ssize_t rc = read( stream->handle, stream->buffer, stream->bufsize );
if ( rc > 0 )
{
/* Reading successful. */
if ( ! ( stream->status & _PDCLIB_FBIN ) )
{
/* TODO: Text stream conversion here */
}
stream->pos.offset += rc;
stream->bufend = rc;
stream->bufidx = 0;
return 0;
}
if ( rc < 0 )
{
/* Reading error */
switch ( errno )
{
/* See comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
case EBADF:
case EFAULT:
case EINTR:
case EINVAL:
case EIO:
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
stream->status |= _PDCLIB_ERRORFLAG;
return EOF;
}
/* End-of-File */
stream->status |= _PDCLIB_EOFFLAG;
return EOF;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* Testing covered by ftell.c */
return TEST_RESULTS;
}
#endif

@ -1,110 +0,0 @@
/* _PDCLIB_flushbuffer( struct _PDCLIB_file_t * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_flushbuffer() fit for
use with POSIX kernels.
*/
#include <stdio.h>
#include <string.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
#include </usr/include/errno.h>
typedef long ssize_t;
extern ssize_t write( int fd, const void * buf, size_t count );
/* The number of attempts to complete an output buffer flushing before giving
* up.
* */
#define _PDCLIB_IO_RETRIES 1
/* What the system should do after an I/O operation did not succeed, before */
/* trying again. (Empty by default.) */
#define _PDCLIB_IO_RETRY_OP( stream )
int _PDCLIB_flushbuffer( struct _PDCLIB_file_t * stream )
{
/* No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */
_PDCLIB_size_t written = 0;
int rc;
unsigned int retries;
if ( ! ( stream->status & _PDCLIB_FBIN ) )
{
/* TODO: Text stream conversion here */
}
/* Keep trying to write data until everything is written, an error
occurs, or the configured number of retries is exceeded.
*/
for ( retries = _PDCLIB_IO_RETRIES; retries > 0; --retries )
{
rc = (int)write( stream->handle, stream->buffer + written, stream->bufidx - written );
if ( rc < 0 )
{
/* Write error */
switch ( errno )
{
/* See <_PDCLIB_config.h>. There should be differenciated errno
handling here, possibly even a 1:1 mapping; but that is up
to the individual platform.
*/
case EBADF:
case EFAULT:
case EFBIG:
case EINTR:
case EINVAL:
case EIO:
case ENOSPC:
case EPIPE:
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
stream->status |= _PDCLIB_ERRORFLAG;
/* Move unwritten remains to begin of buffer. */
stream->bufidx -= written;
memmove( stream->buffer, stream->buffer + written, stream->bufidx );
return EOF;
}
written += (_PDCLIB_size_t)rc;
stream->pos.offset += rc;
if ( written == stream->bufidx )
{
/* Buffer written completely. */
stream->bufidx = 0;
return 0;
}
}
/* Number of retries exceeded. You probably want a different errno value
here.
*/
_PDCLIB_errno = _PDCLIB_ERROR;
stream->status |= _PDCLIB_ERRORFLAG;
/* Move unwritten remains to begin of buffer. */
stream->bufidx -= written;
memmove( stream->buffer, stream->buffer + written, stream->bufidx );
return EOF;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* Testing covered by ftell.c */
return TEST_RESULTS;
}
#endif

@ -1,167 +0,0 @@
/* _PDCLIB_open( const char * const, int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_open() fit for use with POSIX
kernels.
*/
#include <stdio.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "/usr/include/errno.h"
int _PDCLIB_open( const char * const filename, unsigned int mode )
{
/* This is an example implementation of _PDCLIB_open() fit for use with
POSIX kernels.
*/
int osmode;
int rc;
switch ( mode & ( _PDCLIB_FREAD | _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_FRW ) )
{
case _PDCLIB_FREAD: /* "r" */
osmode = O_RDONLY;
break;
case _PDCLIB_FWRITE: /* "w" */
osmode = O_WRONLY | O_CREAT | O_TRUNC;
break;
case _PDCLIB_FAPPEND: /* "a" */
osmode = O_WRONLY | O_APPEND | O_CREAT;
break;
case _PDCLIB_FREAD | _PDCLIB_FRW: /* "r+" */
osmode = O_RDWR;
break;
case _PDCLIB_FWRITE | _PDCLIB_FRW: /* "w+" */
osmode = O_RDWR | O_CREAT | O_TRUNC;
break;
case _PDCLIB_FAPPEND | _PDCLIB_FRW: /* "a+" */
osmode = O_RDWR | O_APPEND | O_CREAT;
break;
default: /* Invalid mode */
return -1;
}
if ( osmode & O_CREAT )
{
rc = open( filename, osmode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
}
else
{
rc = open( filename, osmode );
}
if ( rc == -1 )
{
switch ( errno )
{
/* See the comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
case EACCES:
case EFAULT:
case EINTR:
case EISDIR:
case ELOOP:
case EMFILE:
case ENAMETOOLONG:
case ENFILE:
case ENODEV:
case ENOENT:
case ENOMEM:
case ENOSPC:
case ENOTDIR:
case EOVERFLOW:
case EROFS:
case ETXTBSY:
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
}
return rc;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
#include <stdlib.h>
#include <string.h>
int main( void )
{
#ifndef REGTEST
/* This testdriver assumes POSIX, i.e. _PDCLIB_fd_t being int and being
incremented by one on each successful open.
*/
int fh;
char buffer[ 10 ];
remove( testfile );
/* Trying to read non-existent file. */
TESTCASE( _PDCLIB_open( testfile, _PDCLIB_FREAD ) == _PDCLIB_NOHANDLE );
/* Writing to file, trying to read from it. */
TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FWRITE ) ) != _PDCLIB_NOHANDLE );
TESTCASE( write( fh, "test", 4 ) == 4 );
TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 );
TESTCASE( read( fh, buffer, 4 ) == -1 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Reading from file, trying to write to it. */
TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FREAD ) ) != _PDCLIB_NOHANDLE );
TESTCASE( write( fh, "test", 4 ) == -1 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Appending to file, trying to read from it. */
TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FAPPEND ) ) != _PDCLIB_NOHANDLE );
TESTCASE( write( fh, "app", 3 ) == 3 );
TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 );
TESTCASE( read( fh, buffer, 10 ) == -1 );
TESTCASE( write( fh, "end", 3 ) == 3 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Reading and writing from file ("r+"). */
TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FREAD | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE );
TESTCASE( read( fh, buffer, 10 ) == 10 );
TESTCASE( memcmp( buffer, "testappend", 10 ) == 0 );
TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 );
TESTCASE( write( fh, "wedo", 4 ) == 4 );
TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 );
TESTCASE( read( fh, buffer, 10 ) == 10 );
TESTCASE( memcmp( buffer, "wedoappend", 10 ) == 0 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Writing and reading from file ("w+"). */
TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FWRITE | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE );
TESTCASE( write( fh, "test", 4 ) == 4 );
TESTCASE( lseek( fh, 1, SEEK_SET ) == 1 );
TESTCASE( read( fh, buffer, 2 ) == 2 );
TESTCASE( memcmp( buffer, "es", 2 ) == 0 );
TESTCASE( write( fh, "sie", 3 ) == 3 );
TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 );
TESTCASE( read( fh, buffer, 6 ) == 6 );
TESTCASE( memcmp( buffer, "tessie", 6 ) == 0 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Appending and reading from file ("a+"). */
TESTCASE( ( fh = _PDCLIB_open( testfile, _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) != _PDCLIB_NOHANDLE );
TESTCASE( write( fh, "baby", 4 ) == 4 );
TESTCASE( lseek( fh, 0, SEEK_SET ) == 0 );
TESTCASE( read( fh, buffer, 10 ) == 10 );
TESTCASE( memcmp( buffer, "tessiebaby", 10 ) == 0 );
TESTCASE( _PDCLIB_close( fh ) == 0 );
/* Cleaning up. */
TESTCASE( remove( testfile ) == 0 );
#endif
return TEST_RESULTS;
}
#endif

@ -1,144 +0,0 @@
/* _PDCLIB_rename( const char *, const char * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_rename() fit for use with
POSIX kernels.
*/
#include <stdio.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
#include </usr/include/errno.h>
extern int unlink( const char * pathname );
extern int link( const char * old, const char * new );
int _PDCLIB_rename( const char * old, const char * new )
{
/* Note that the behaviour if new file exists is implementation-defined.
There is nothing wrong with either overwriting it or failing the
operation, but you might want to document whichever you chose.
This example fails if new file exists.
*/
if ( link( old, new ) == 0 )
{
if ( unlink( old ) == EOF )
{
switch ( errno )
{
/* See the comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
case EACCES:
case EFAULT:
case EIO:
case EISDIR:
case ELOOP:
case ENAMETOOLONG:
case ENOENT:
case ENOMEM:
case ENOTDIR:
case EPERM:
case EROFS:
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
return -1;
}
else
{
return 0;
}
}
else
{
switch ( errno )
{
/* See the comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
case EACCES:
case EEXIST:
case EFAULT:
case EIO:
case ELOOP:
case EMLINK:
case ENAMETOOLONG:
case ENOENT:
case ENOMEM:
case ENOSPC:
case ENOTDIR:
case EPERM:
case EROFS:
case EXDEV:
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
return EOF;
}
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
#include <stdlib.h>
int main( void )
{
#ifndef REGTEST
FILE * file;
remove( testfile1 );
remove( testfile2 );
/* check that neither file exists */
TESTCASE( fopen( testfile1, "r" ) == NULL );
TESTCASE( fopen( testfile2, "r" ) == NULL );
/* rename file 1 to file 2 - expected to fail */
TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == -1 );
/* create file 1 */
TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL );
TESTCASE( fputc( 'x', file ) == 'x' );
TESTCASE( fclose( file ) == 0 );
/* check that file 1 exists */
TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL );
TESTCASE( fclose( file ) == 0 );
/* rename file 1 to file 2 */
TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == 0 );
/* check that file 2 exists, file 1 does not */
TESTCASE( fopen( testfile1, "r" ) == NULL );
TESTCASE( ( file = fopen( testfile2, "r" ) ) != NULL );
TESTCASE( fclose( file ) == 0 );
/* create another file 1 */
TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL );
TESTCASE( fputc( 'x', file ) == 'x' );
TESTCASE( fclose( file ) == 0 );
/* check that file 1 exists */
TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL );
TESTCASE( fclose( file ) == 0 );
/* rename file 1 to file 2 - expected to fail, see comment in
_PDCLIB_rename() itself.
*/
TESTCASE( _PDCLIB_rename( testfile1, testfile2 ) == -1 );
/* remove both files */
remove( testfile1 );
remove( testfile2 );
#endif
return TEST_RESULTS;
}
#endif

@ -1,82 +0,0 @@
/* int64_t _PDCLIB_seek( FILE *, int64_t, int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of _PDCLIB_seek() fit for use with POSIX
kernels.
*/
#include <stdio.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
#include "/usr/include/errno.h"
extern _PDCLIB_int64_t lseek64( int fd, _PDCLIB_int64_t offset, int whence );
extern long lseek( int fd, long offset, int whence );
_PDCLIB_int64_t _PDCLIB_seek( struct _PDCLIB_file_t * stream, _PDCLIB_int64_t offset, int whence )
{
_PDCLIB_int64_t rc;
switch ( whence )
{
case SEEK_SET:
case SEEK_CUR:
case SEEK_END:
/* EMPTY - OK */
break;
default:
/* See comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
_PDCLIB_errno = _PDCLIB_ERROR;
return EOF;
break;
}
#ifdef __CYGWIN__
rc = lseek( stream->handle, offset, whence );
#else
rc = lseek64( stream->handle, offset, whence );
#endif
if ( rc != EOF )
{
stream->ungetidx = 0;
stream->bufidx = 0;
stream->bufend = 0;
stream->pos.offset = rc;
return rc;
}
switch ( errno )
{
case EBADF:
case EFAULT:
/* See comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
return EOF;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* Testing covered by ftell.c */
return TEST_RESULTS;
}
#endif

@ -1,430 +0,0 @@
/* _PDCLIB_stdinit
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example initialization of stdin, stdout and stderr to the integer
file descriptors 0, 1, and 2, respectively. This applies for a great variety
of operating systems, including POSIX compliant ones.
*/
#include <stdio.h>
#include <locale.h>
#include <limits.h>
#ifndef REGTEST
/* In a POSIX system, stdin / stdout / stderr are equivalent to the (int) file
descriptors 0, 1, and 2 respectively.
*/
/* TODO: This is proof-of-concept, requires finetuning. */
static char _PDCLIB_sin_buffer[BUFSIZ];
static char _PDCLIB_sout_buffer[BUFSIZ];
static char _PDCLIB_serr_buffer[BUFSIZ];
static unsigned char _PDCLIB_sin_ungetbuf[_PDCLIB_UNGETCBUFSIZE];
static unsigned char _PDCLIB_sout_ungetbuf[_PDCLIB_UNGETCBUFSIZE];
static unsigned char _PDCLIB_serr_ungetbuf[_PDCLIB_UNGETCBUFSIZE];
static struct _PDCLIB_file_t _PDCLIB_serr = { 2, _PDCLIB_serr_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_serr_ungetbuf, _IONBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, NULL };
static struct _PDCLIB_file_t _PDCLIB_sout = { 1, _PDCLIB_sout_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sout_ungetbuf, _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, &_PDCLIB_serr };
static struct _PDCLIB_file_t _PDCLIB_sin = { 0, _PDCLIB_sin_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sin_ungetbuf, _IOLBF | _PDCLIB_FREAD | _PDCLIB_STATIC, NULL, &_PDCLIB_sout };
struct _PDCLIB_file_t * stdin = &_PDCLIB_sin;
struct _PDCLIB_file_t * stdout = &_PDCLIB_sout;
struct _PDCLIB_file_t * stderr = &_PDCLIB_serr;
/* FIXME: This approach is a possible attack vector. */
struct _PDCLIB_file_t * _PDCLIB_filelist = &_PDCLIB_sin;
/* "C" locale - defaulting to ASCII-7.
1 kByte (+ 4 byte) of <ctype.h> data.
Each line: flags, lowercase, uppercase, collation.
*/
static struct _PDCLIB_lc_ctype_entry_t _ctype_entries[ _PDCLIB_CHARSET_SIZE + 1 ] = {
{ /* EOF */ 0, 0, 0 },
{ /* NUL */ _PDCLIB_CTYPE_CNTRL, 0x00, 0x00 },
{ /* SOH */ _PDCLIB_CTYPE_CNTRL, 0x01, 0x01 },
{ /* STX */ _PDCLIB_CTYPE_CNTRL, 0x02, 0x02 },
{ /* ETX */ _PDCLIB_CTYPE_CNTRL, 0x03, 0x03 },
{ /* EOT */ _PDCLIB_CTYPE_CNTRL, 0x04, 0x04 },
{ /* ENQ */ _PDCLIB_CTYPE_CNTRL, 0x05, 0x05 },
{ /* ACK */ _PDCLIB_CTYPE_CNTRL, 0x06, 0x06 },
{ /* BEL */ _PDCLIB_CTYPE_CNTRL, 0x07, 0x07 },
{ /* BS */ _PDCLIB_CTYPE_CNTRL, 0x08, 0x08 },
{ /* HT */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_BLANK | _PDCLIB_CTYPE_SPACE, 0x09, 0x09 },
{ /* LF */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0A, 0x0A },
{ /* VT */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0B, 0x0B },
{ /* FF */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0C, 0x0C },
{ /* CR */ _PDCLIB_CTYPE_CNTRL | _PDCLIB_CTYPE_SPACE, 0x0D, 0x0D },
{ /* SO */ _PDCLIB_CTYPE_CNTRL, 0x0E, 0x0E },
{ /* SI */ _PDCLIB_CTYPE_CNTRL, 0x0F, 0x0F },
{ /* DLE */ _PDCLIB_CTYPE_CNTRL, 0x10, 0x10 },
{ /* DC1 */ _PDCLIB_CTYPE_CNTRL, 0x11, 0x11 },
{ /* DC2 */ _PDCLIB_CTYPE_CNTRL, 0x12, 0x12 },
{ /* DC3 */ _PDCLIB_CTYPE_CNTRL, 0x13, 0x13 },
{ /* DC4 */ _PDCLIB_CTYPE_CNTRL, 0x14, 0x14 },
{ /* NAK */ _PDCLIB_CTYPE_CNTRL, 0x15, 0x15 },
{ /* SYN */ _PDCLIB_CTYPE_CNTRL, 0x16, 0x16 },
{ /* ETB */ _PDCLIB_CTYPE_CNTRL, 0x17, 0x17 },
{ /* CAN */ _PDCLIB_CTYPE_CNTRL, 0x18, 0x18 },
{ /* EM */ _PDCLIB_CTYPE_CNTRL, 0x19, 0x19 },
{ /* SUB */ _PDCLIB_CTYPE_CNTRL, 0x1A, 0x1A },
{ /* ESC */ _PDCLIB_CTYPE_CNTRL, 0x1B, 0x1B },
{ /* FS */ _PDCLIB_CTYPE_CNTRL, 0x1C, 0x1C },
{ /* GS */ _PDCLIB_CTYPE_CNTRL, 0x1D, 0x1D },
{ /* RS */ _PDCLIB_CTYPE_CNTRL, 0x1E, 0x1E },
{ /* US */ _PDCLIB_CTYPE_CNTRL, 0x1F, 0x1F },
{ /* SP */ _PDCLIB_CTYPE_BLANK | _PDCLIB_CTYPE_SPACE, 0x20, 0x20 },
{ /* '!' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x21, 0x21 },
{ /* '"' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x22, 0x22 },
{ /* '#' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x23, 0x23 },
{ /* '$' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x24, 0x24 },
{ /* '%' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x25, 0x25 },
{ /* '&' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x26, 0x26 },
{ /* ''' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x27, 0x27 },
{ /* '(' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x28, 0x28 },
{ /* ')' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x29, 0x29 },
{ /* '*' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2A, 0x2A },
{ /* '+' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2B, 0x2B },
{ /* ',' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2C, 0x2C },
{ /* '-' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2D, 0x2D },
{ /* '.' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2E, 0x2E },
{ /* '/' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x2F, 0x2F },
{ /* '0' */ _PDCLIB_CTYPE_GRAPH, 0x30, 0x30 },
{ /* '1' */ _PDCLIB_CTYPE_GRAPH, 0x31, 0x31 },
{ /* '2' */ _PDCLIB_CTYPE_GRAPH, 0x32, 0x32 },
{ /* '3' */ _PDCLIB_CTYPE_GRAPH, 0x33, 0x33 },
{ /* '4' */ _PDCLIB_CTYPE_GRAPH, 0x34, 0x34 },
{ /* '5' */ _PDCLIB_CTYPE_GRAPH, 0x35, 0x35 },
{ /* '6' */ _PDCLIB_CTYPE_GRAPH, 0x36, 0x36 },
{ /* '7' */ _PDCLIB_CTYPE_GRAPH, 0x37, 0x37 },
{ /* '8' */ _PDCLIB_CTYPE_GRAPH, 0x38, 0x38 },
{ /* '9' */ _PDCLIB_CTYPE_GRAPH, 0x39, 0x39 },
{ /* ':' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3A, 0x3A },
{ /* ';' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3B, 0x3B },
{ /* '<' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3C, 0x3C },
{ /* '=' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3D, 0x3D },
{ /* '>' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3E, 0x3E },
{ /* '?' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x3F, 0x3F },
{ /* '@' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x40, 0x40 },
{ /* 'A' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x41, 0x61 },
{ /* 'B' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x42, 0x62 },
{ /* 'C' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x43, 0x63 },
{ /* 'D' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x44, 0x64 },
{ /* 'E' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x45, 0x65 },
{ /* 'F' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x46, 0x66 },
{ /* 'G' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x47, 0x67 },
{ /* 'H' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x48, 0x68 },
{ /* 'I' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x49, 0x69 },
{ /* 'J' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4A, 0x6A },
{ /* 'K' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4B, 0x6B },
{ /* 'L' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4C, 0x6C },
{ /* 'M' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4D, 0x6D },
{ /* 'N' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4E, 0x6E },
{ /* 'O' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x4F, 0x6F },
{ /* 'P' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x50, 0x70 },
{ /* 'Q' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x51, 0x71 },
{ /* 'R' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x52, 0x72 },
{ /* 'S' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x53, 0x73 },
{ /* 'T' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x54, 0x74 },
{ /* 'U' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x55, 0x75 },
{ /* 'V' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x56, 0x76 },
{ /* 'W' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x57, 0x77 },
{ /* 'X' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x58, 0x78 },
{ /* 'Y' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x59, 0x79 },
{ /* 'Z' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x5A, 0x7A },
{ /* '[' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5B, 0x5B },
{ /* '\' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5C, 0x5C },
{ /* ']' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5D, 0x5D },
{ /* '^' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5E, 0x5E },
{ /* '_' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x5F, 0x5F },
{ /* '`' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x60, 0x60 },
{ /* 'a' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x41, 0x61 },
{ /* 'b' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x42, 0x62 },
{ /* 'c' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x43, 0x63 },
{ /* 'd' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x44, 0x64 },
{ /* 'e' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x45, 0x65 },
{ /* 'f' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x46, 0x66 },
{ /* 'g' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x47, 0x67 },
{ /* 'h' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x48, 0x68 },
{ /* 'i' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x49, 0x69 },
{ /* 'j' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4A, 0x6A },
{ /* 'k' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4B, 0x6B },
{ /* 'l' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4C, 0x6C },
{ /* 'm' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4D, 0x6D },
{ /* 'n' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4E, 0x6E },
{ /* 'o' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x4F, 0x6F },
{ /* 'p' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x50, 0x70 },
{ /* 'q' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x51, 0x71 },
{ /* 'r' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x52, 0x72 },
{ /* 's' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x53, 0x73 },
{ /* 't' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x54, 0x74 },
{ /* 'u' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x55, 0x75 },
{ /* 'v' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x56, 0x76 },
{ /* 'w' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x57, 0x77 },
{ /* 'x' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x58, 0x78 },
{ /* 'y' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x59, 0x79 },
{ /* 'z' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x5A, 0x7A },
{ /* '{' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7B, 0x7B },
{ /* '|' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7C, 0x7C },
{ /* '}' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7D, 0x7D },
{ /* '~' */ _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_PUNCT, 0x7E, 0x7E },
{ /* DEL */ _PDCLIB_CTYPE_CNTRL, 0x7F, 0x7F },
{ 0x00, 0x80, 0x80 },
{ 0x00, 0x81, 0x81 },
{ 0x00, 0x82, 0x82 },
{ 0x00, 0x83, 0x83 },
{ 0x00, 0x84, 0x84 },
{ 0x00, 0x85, 0x85 },
{ 0x00, 0x86, 0x86 },
{ 0x00, 0x87, 0x87 },
{ 0x00, 0x88, 0x88 },
{ 0x00, 0x89, 0x89 },
{ 0x00, 0x8A, 0x8A },
{ 0x00, 0x8B, 0x8B },
{ 0x00, 0x8C, 0x8C },
{ 0x00, 0x8D, 0x8D },
{ 0x00, 0x8E, 0x8E },
{ 0x00, 0x8F, 0x8F },
{ 0x00, 0x90, 0x90 },
{ 0x00, 0x91, 0x91 },
{ 0x00, 0x92, 0x92 },
{ 0x00, 0x93, 0x93 },
{ 0x00, 0x94, 0x94 },
{ 0x00, 0x95, 0x95 },
{ 0x00, 0x96, 0x96 },
{ 0x00, 0x97, 0x97 },
{ 0x00, 0x98, 0x98 },
{ 0x00, 0x99, 0x99 },
{ 0x00, 0x9A, 0x9A },
{ 0x00, 0x9B, 0x9B },
{ 0x00, 0x9C, 0x9C },
{ 0x00, 0x9D, 0x9D },
{ 0x00, 0x9E, 0x9E },
{ 0x00, 0x9F, 0x9F },
{ 0x00, 0xA0, 0xA0 },
{ 0x00, 0xA1, 0xA1 },
{ 0x00, 0xA2, 0xA2 },
{ 0x00, 0xA3, 0xA3 },
{ 0x00, 0xA4, 0xA4 },
{ 0x00, 0xA5, 0xA5 },
{ 0x00, 0xA6, 0xA6 },
{ 0x00, 0xA7, 0xA7 },
{ 0x00, 0xA8, 0xA8 },
{ 0x00, 0xA9, 0xA9 },
{ 0x00, 0xAA, 0xAA },
{ 0x00, 0xAB, 0xAB },
{ 0x00, 0xAC, 0xAC },
{ 0x00, 0xAD, 0xAD },
{ 0x00, 0xAE, 0xAE },
{ 0x00, 0xAF, 0xAF },
{ 0x00, 0xB0, 0xB0 },
{ 0x00, 0xB1, 0xB1 },
{ 0x00, 0xB2, 0xB2 },
{ 0x00, 0xB3, 0xB3 },
{ 0x00, 0xB4, 0xB4 },
{ 0x00, 0xB5, 0xB5 },
{ 0x00, 0xB6, 0xB6 },
{ 0x00, 0xB7, 0xB7 },
{ 0x00, 0xB8, 0xB8 },
{ 0x00, 0xB9, 0xB9 },
{ 0x00, 0xBA, 0xBA },
{ 0x00, 0xBB, 0xBB },
{ 0x00, 0xBC, 0xBC },
{ 0x00, 0xBD, 0xBD },
{ 0x00, 0xBE, 0xBE },
{ 0x00, 0xBF, 0xBF },
{ 0x00, 0xC0, 0xC0 },
{ 0x00, 0xC1, 0xC1 },
{ 0x00, 0xC2, 0xC2 },
{ 0x00, 0xC3, 0xC3 },
{ 0x00, 0xC4, 0xC4 },
{ 0x00, 0xC5, 0xC5 },
{ 0x00, 0xC6, 0xC6 },
{ 0x00, 0xC7, 0xC7 },
{ 0x00, 0xC8, 0xC8 },
{ 0x00, 0xC9, 0xC9 },
{ 0x00, 0xCA, 0xCA },
{ 0x00, 0xCB, 0xCB },
{ 0x00, 0xCC, 0xCC },
{ 0x00, 0xCD, 0xCD },
{ 0x00, 0xCE, 0xCE },
{ 0x00, 0xCF, 0xCF },
{ 0x00, 0xD0, 0xD0 },
{ 0x00, 0xD1, 0xD1 },
{ 0x00, 0xD2, 0xD2 },
{ 0x00, 0xD3, 0xD3 },
{ 0x00, 0xD4, 0xD4 },
{ 0x00, 0xD5, 0xD5 },
{ 0x00, 0xD6, 0xD6 },
{ 0x00, 0xD7, 0xD7 },
{ 0x00, 0xD8, 0xD8 },
{ 0x00, 0xD9, 0xD9 },
{ 0x00, 0xDA, 0xDA },
{ 0x00, 0xDB, 0xDB },
{ 0x00, 0xDC, 0xDC },
{ 0x00, 0xDD, 0xDD },
{ 0x00, 0xDE, 0xDE },
{ 0x00, 0xDF, 0xDF },
{ 0x00, 0xE0, 0xE0 },
{ 0x00, 0xE1, 0xE1 },
{ 0x00, 0xE2, 0xE2 },
{ 0x00, 0xE3, 0xE3 },
{ 0x00, 0xE4, 0xE4 },
{ 0x00, 0xE5, 0xE5 },
{ 0x00, 0xE6, 0xE6 },
{ 0x00, 0xE7, 0xE7 },
{ 0x00, 0xE8, 0xE8 },
{ 0x00, 0xE9, 0xE9 },
{ 0x00, 0xEA, 0xEA },
{ 0x00, 0xEB, 0xEB },
{ 0x00, 0xEC, 0xEC },
{ 0x00, 0xED, 0xED },
{ 0x00, 0xEE, 0xEE },
{ 0x00, 0xEF, 0xEF },
{ 0x00, 0xF0, 0xF0 },
{ 0x00, 0xF1, 0xF1 },
{ 0x00, 0xF2, 0xF2 },
{ 0x00, 0xF3, 0xF3 },
{ 0x00, 0xF4, 0xF4 },
{ 0x00, 0xF5, 0xF5 },
{ 0x00, 0xF6, 0xF6 },
{ 0x00, 0xF7, 0xF7 },
{ 0x00, 0xF8, 0xF8 },
{ 0x00, 0xF9, 0xF9 },
{ 0x00, 0xFA, 0xFA },
{ 0x00, 0xFB, 0xFB },
{ 0x00, 0xFC, 0xFC },
{ 0x00, 0xFD, 0xFD },
{ 0x00, 0xFE, 0xFE },
{ 0x00, 0xFF, 0xFF }
};
struct _PDCLIB_lc_ctype_t _PDCLIB_lc_ctype = { 0, 0x30, 0x39, 0x41, 0x46, 0x61, 0x66, &_ctype_entries[1] };
struct _PDCLIB_lc_collate_t _PDCLIB_lc_collate = { 0 };
struct lconv _PDCLIB_lconv = {
/* decimal_point */ (char *)".",
/* thousands_sep */ (char *)"",
/* grouping */ (char *)"",
/* mon_decimal_point */ (char *)"",
/* mon_thousands_sep */ (char *)"",
/* mon_grouping */ (char *)"",
/* positive_sign */ (char *)"",
/* negative_sign */ (char *)"",
/* currency_symbol */ (char *)"",
/* int_curr_symbol */ (char *)"",
/* frac_digits */ CHAR_MAX,
/* p_cs_precedes */ CHAR_MAX,
/* n_cs_precedes */ CHAR_MAX,
/* p_sep_by_space */ CHAR_MAX,
/* n_sep_by_space */ CHAR_MAX,
/* p_sign_posn */ CHAR_MAX,
/* n_sign_posn */ CHAR_MAX,
/* int_frac_digits */ CHAR_MAX,
/* int_p_cs_precedes */ CHAR_MAX,
/* int_n_cs_precedes */ CHAR_MAX,
/* int_p_sep_by_space */ CHAR_MAX,
/* int_n_sep_by_space */ CHAR_MAX,
/* int_p_sign_posn */ CHAR_MAX,
/* int_n_sign_posn */ CHAR_MAX
};
struct _PDCLIB_lc_numeric_monetary_t _PDCLIB_lc_numeric_monetary = {
&_PDCLIB_lconv,
0, /* numeric_allocated */
0 /* monetary_allocated */
};
struct _PDCLIB_lc_messages_t _PDCLIB_lc_messages = {
0,
/* _PDCLIB_errno_texts */
{
/* no error */ (char *)"",
/* ERANGE */ (char *)"ERANGE (Range error)",
/* EDOM */ (char *)"EDOM (Domain error)",
/* EILSEQ */ (char *)"EILSEQ (Illegal sequence)"
}
};
struct _PDCLIB_lc_time_t _PDCLIB_lc_time = {
0,
/* _PDCLIB_month_name_abbr */
{
(char *)"Jan",
(char *)"Feb",
(char *)"Mar",
(char *)"Apr",
(char *)"May",
(char *)"Jun",
(char *)"Jul",
(char *)"Aug",
(char *)"Sep",
(char *)"Oct",
(char *)"Now",
(char *)"Dec"
},
/* _PDCLIB_month_name_full */
{
(char *)"January",
(char *)"February",
(char *)"March",
(char *)"April",
(char *)"May",
(char *)"June",
(char *)"July",
(char *)"August",
(char *)"September",
(char *)"October",
(char *)"November",
(char *)"December"
},
/* _PDCLIB_day_name_abbr */
{
(char *)"Sun",
(char *)"Mon",
(char *)"Tue",
(char *)"Wed",
(char *)"Thu",
(char *)"Fri",
(char *)"Sat"
},
/* _PDCLIB_day_name_full */
{
(char *)"Sunday",
(char *)"Monday",
(char *)"Tuesday",
(char *)"Wednesday",
(char *)"Thursday",
(char *)"Friday",
(char *)"Saturday"
},
/* date / time format */ (char *)"%a %b %e %T %Y",
/* 12h time format */ (char *)"%I:%M:%S %p",
/* date format */ (char *)"%m/%d/%y",
/* time format */ (char *)"%T",
/* AM / PM designation */
{
(char *)"AM",
(char *)"PM"
}
};
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* Testing covered by several other testdrivers using stdin / stdout /
stderr.
*/
return TEST_RESULTS;
}
#endif

@ -1,114 +0,0 @@
/* raise( int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <signal.h>
#ifndef REGTEST
#include <stdio.h>
#include <stdlib.h>
extern void (*_PDCLIB_sigabrt)( int );
extern void (*_PDCLIB_sigfpe)( int );
extern void (*_PDCLIB_sigill)( int );
extern void (*_PDCLIB_sigint)( int );
extern void (*_PDCLIB_sigsegv)( int );
extern void (*_PDCLIB_sigterm)( int );
int raise( int sig )
{
void (*sighandler)( int );
const char * message;
switch ( sig )
{
case SIGABRT:
sighandler = _PDCLIB_sigabrt;
message = "Abnormal termination (SIGABRT)";
break;
case SIGFPE:
sighandler = _PDCLIB_sigfpe;
message = "Arithmetic exception (SIGFPE)";
break;
case SIGILL:
sighandler = _PDCLIB_sigill;
message = "Illegal instruction (SIGILL)";
break;
case SIGINT:
sighandler = _PDCLIB_sigint;
message = "Interactive attention signal (SIGINT)";
break;
case SIGSEGV:
sighandler = _PDCLIB_sigsegv;
message = "Invalid memory access (SIGSEGV)";
break;
case SIGTERM:
sighandler = _PDCLIB_sigterm;
message = "Termination request (SIGTERM)";
break;
default:
fprintf( stderr, "Unknown signal #%d\n", sig );
_Exit( EXIT_FAILURE );
}
if ( sighandler == SIG_DFL )
{
fputs( message, stderr );
_Exit( EXIT_FAILURE );
}
else if ( sighandler != SIG_IGN )
{
sighandler = signal( sig, SIG_DFL );
sighandler( sig );
}
return 0;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
#include <stdlib.h>
static volatile sig_atomic_t flag = 0;
static int expected_signal = 0;
static void test_handler( int sig )
{
TESTCASE( sig == expected_signal );
flag = 1;
}
int main( void )
{
/* Could be other than SIG_DFL if you changed the implementation. */
TESTCASE( signal( SIGABRT, SIG_IGN ) == SIG_DFL );
/* Should be ignored. */
TESTCASE( raise( SIGABRT ) == 0 );
/* Installing test handler, old handler should be returned */
TESTCASE( signal( SIGABRT, test_handler ) == SIG_IGN );
/* Raising and checking SIGABRT */
expected_signal = SIGABRT;
TESTCASE( raise( SIGABRT ) == 0 );
TESTCASE( flag == 1 );
/* Re-installing test handler, should have been reset to default */
/* Could be other than SIG_DFL if you changed the implementation. */
TESTCASE( signal( SIGABRT, test_handler ) == SIG_DFL );
/* Raising and checking SIGABRT */
flag = 0;
TESTCASE( raise( SIGABRT ) == 0 );
TESTCASE( flag == 1 );
/* Installing test handler for different signal... */
TESTCASE( signal( SIGTERM, test_handler ) == SIG_DFL );
/* Raising and checking SIGTERM */
expected_signal = SIGTERM;
TESTCASE( raise( SIGTERM ) == 0 );
TESTCASE( flag == 1 );
return TEST_RESULTS;
}
#endif

@ -1,75 +0,0 @@
/* signal( int, void (*)( int ) )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <signal.h>
#ifndef REGTEST
#include <stdlib.h>
void (*_PDCLIB_sigabrt)( int ) = SIG_DFL;
void (*_PDCLIB_sigfpe)( int ) = SIG_DFL;
void (*_PDCLIB_sigill)( int ) = SIG_DFL;
void (*_PDCLIB_sigint)( int ) = SIG_DFL;
void (*_PDCLIB_sigsegv)( int ) = SIG_DFL;
void (*_PDCLIB_sigterm)( int ) = SIG_DFL;
void (*signal( int sig, void (*func)( int ) ) )( int )
{
void (*oldhandler)( int );
if ( sig <= 0 || func == SIG_ERR )
{
return SIG_ERR;
}
switch ( sig )
{
case SIGABRT:
oldhandler = _PDCLIB_sigabrt;
_PDCLIB_sigabrt = func;
break;
case SIGFPE:
oldhandler = _PDCLIB_sigfpe;
_PDCLIB_sigfpe = func;
break;
case SIGILL:
oldhandler = _PDCLIB_sigill;
_PDCLIB_sigill = func;
break;
case SIGINT:
oldhandler = _PDCLIB_sigint;
_PDCLIB_sigint = func;
break;
case SIGSEGV:
oldhandler = _PDCLIB_sigsegv;
_PDCLIB_sigsegv = func;
break;
case SIGTERM:
oldhandler = _PDCLIB_sigterm;
_PDCLIB_sigterm = func;
break;
default:
/* The standard calls for an unspecified "positive value". You
will probably want to define a specific value for this.
*/
_PDCLIB_errno = 1;
return SIG_ERR;
}
return oldhandler;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* Testing covered by raise.c */
return TEST_RESULTS;
}
#endif

@ -1,75 +0,0 @@
/* remove( const char * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of remove() fit for use with POSIX kernels.
*/
#include <stdio.h>
#ifndef REGTEST
#include <string.h>
#include "/usr/include/errno.h"
extern struct _PDCLIB_file_t * _PDCLIB_filelist;
extern int unlink( const char * pathname );
int remove( const char * pathname )
{
int rc;
struct _PDCLIB_file_t * current = _PDCLIB_filelist;
while ( current != NULL )
{
if ( ( current->filename != NULL ) && ( strcmp( current->filename, pathname ) == 0 ) )
{
return EOF;
}
current = current->next;
}
if ( ( rc = unlink( pathname ) ) == -1 )
{
switch ( errno )
{
/* See the comments on implementation-defined errno values in
<_PDCLIB_config.h>.
*/
case EACCES:
case EFAULT:
case EIO:
case EISDIR:
case ELOOP:
case ENAMETOOLONG:
case ENOENT:
case ENOMEM:
case ENOTDIR:
case EPERM:
case EROFS:
_PDCLIB_errno = _PDCLIB_ERROR;
break;
default:
/* This should be something like EUNKNOWN. */
_PDCLIB_errno = _PDCLIB_ERROR;
break;
}
}
return rc;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
/* Testing covered by ftell.c (and several others) */
return TEST_RESULTS;
}
#endif

@ -1,114 +0,0 @@
/* tmpfile( void )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <stdio.h>
#ifndef REGTEST
#include "pdclib/_PDCLIB_glue.h"
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
extern struct _PDCLIB_file_t * _PDCLIB_filelist;
/* This is an example implementation of tmpfile() fit for use with POSIX
kernels.
*/
struct _PDCLIB_file_t * tmpfile( void )
{
FILE * rc;
/* This is the chosen way to get high-quality randomness. Replace as
appropriate.
*/
FILE * randomsource = fopen( "/proc/sys/kernel/random/uuid", "rb" );
char filename[ L_tmpnam ];
_PDCLIB_fd_t fd;
if ( randomsource == NULL )
{
return NULL;
}
for ( ;; )
{
/* Get a filename candidate. What constitutes a valid filename and
where temporary files are usually located is platform-dependent,
which is one reason why this function is located in the platform
overlay. The other reason is that a *good* implementation should
use high-quality randomness instead of a pseudo-random sequence to
generate the filename candidate, which is *also* platform-dependent.
*/
unsigned int random;
fscanf( randomsource, "%u", &random );
sprintf( filename, "/tmp/%u.tmp", random );
/* Check if file of this name exists. Note that fopen() is a very weak
check, which does not take e.g. access permissions into account
(file might exist but not readable). Replace with something more
appropriate.
*/
fd = open( filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR );
if ( fd != -1 )
{
break;
}
close( fd );
}
fclose( randomsource );
/* See fopen(). */
if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + L_tmpnam + BUFSIZ ) ) == NULL )
{
/* No memory to set up FILE structure */
close( fd );
return NULL;
}
rc->status = _PDCLIB_filemode( "wb+" ) | _IOLBF | _PDCLIB_DELONCLOSE;
rc->handle = fd;
rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t );
rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE;
rc->buffer = rc->filename + L_tmpnam;
strcpy( rc->filename, filename );
rc->bufsize = BUFSIZ;
rc->bufidx = 0;
rc->ungetidx = 0;
rc->next = _PDCLIB_filelist;
_PDCLIB_filelist = rc;
return rc;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
#include <string.h>
int main( void )
{
FILE * fh;
#ifndef REGTEST
char filename[ L_tmpnam ];
FILE * fhtest;
#endif
TESTCASE( ( fh = tmpfile() ) != NULL );
TESTCASE( fputc( 'x', fh ) == 'x' );
/* Checking that file is actually there */
TESTCASE_NOREG( strcpy( filename, fh->filename ) == filename );
TESTCASE_NOREG( ( fhtest = fopen( filename, "r" ) ) != NULL );
TESTCASE_NOREG( fclose( fhtest ) == 0 );
/* Closing tmpfile */
TESTCASE( fclose( fh ) == 0 );
/* Checking that file was deleted */
TESTCASE_NOREG( fopen( filename, "r" ) == NULL );
return TEST_RESULTS;
}
#endif

@ -1,45 +0,0 @@
/* getenv( const char * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
/* This is an example implementation of getenv() fit for use with POSIX kernels.
*/
#include <string.h>
#include <stdlib.h>
#ifndef REGTEST
extern char * * environ;
char * getenv( const char * name )
{
size_t len = strlen( name );
size_t index = 0;
while ( environ[ index ] != NULL )
{
if ( strncmp( environ[ index ], name, len ) == 0 )
{
return environ[ index ] + len + 1;
}
index++;
}
return NULL;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
TESTCASE( strcmp( getenv( "SHELL" ), "/bin/bash" ) == 0 );
/* TESTCASE( strcmp( getenv( "SHELL" ), "/bin/sh" ) == 0 ); */
return TEST_RESULTS;
}
#endif

@ -1,57 +0,0 @@
/* system( const char * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <stdlib.h>
/* This is an example implementation of system() fit for use with POSIX kernels.
*/
extern int fork( void );
extern int execve( const char * filename, char * const argv[], char * const envp[] );
extern int wait( int * status );
int system( const char * string )
{
const char * argv[] = { "sh", "-c", NULL, NULL };
argv[2] = string;
if ( string != NULL )
{
int pid = fork();
if ( pid == 0 )
{
execve( "/bin/sh", (char * * const)argv, NULL );
}
else if ( pid > 0 )
{
while( wait( NULL ) != pid );
}
}
return -1;
}
#ifdef TEST
#include "_PDCLIB_test.h"
#define SHELLCOMMAND "echo 'SUCCESS testing system()'"
int main( void )
{
FILE * fh;
char buffer[25];
buffer[24] = 'x';
TESTCASE( ( fh = freopen( testfile, "wb+", stdout ) ) != NULL );
TESTCASE( system( SHELLCOMMAND ) );
rewind( fh );
TESTCASE( fread( buffer, 1, 24, fh ) == 24 );
TESTCASE( memcmp( buffer, "SUCCESS testing system()", 24 ) == 0 );
TESTCASE( buffer[24] == 'x' );
TESTCASE( fclose( fh ) == 0 );
TESTCASE( remove( testfile ) == 0 );
return TEST_RESULTS;
}
#endif

@ -1,35 +0,0 @@
/* clock( void )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <time.h>
#ifndef REGTEST
#include <sys/times.h>
clock_t clock( void )
{
struct tms buf;
if ( times( &buf ) != (clock_t)-1 )
{
return buf.tms_utime + buf.tms_stime;
}
return -1;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
TESTCASE( NO_TESTDRIVER );
return TEST_RESULTS;
}
#endif

@ -1,41 +0,0 @@
/* time( time_t * )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <time.h>
#ifndef REGTEST
#include <sys/time.h>
/* See comments in time.h on the semantics of time_t. */
time_t time( time_t * timer )
{
struct timeval tv;
if ( gettimeofday( &tv, NULL ) == 0 )
{
if ( timer != NULL )
{
*timer = tv.tv_sec;
}
return tv.tv_sec;
}
return -1;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
TESTCASE( NO_TESTDRIVER );
return TEST_RESULTS;
}
#endif

@ -1,42 +0,0 @@
/* timespec_get( struct timespec *, int )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#include <time.h>
#ifndef REGTEST
#include <sys/time.h>
int timespec_get( struct timespec * ts, int base )
{
if ( base == TIME_UTC )
{
/* We can make do with a really thin wrapper here. */
struct timeval tv;
if ( gettimeofday( &tv, NULL ) == 0 )
{
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec * 1000;
return base;
}
}
/* Not supporting any other time base than TIME_UTC for now. */
return 0;
}
#endif
#ifdef TEST
#include "_PDCLIB_test.h"
int main( void )
{
TESTCASE( NO_TESTDRIVER );
return TEST_RESULTS;
}
#endif

@ -1,75 +0,0 @@
/* Characteristics of floating types <float.h>
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#ifndef _PDCLIB_FLOAT_H
#define _PDCLIB_FLOAT_H _PDCLIB_FLOAT_H
#include "pdclib/_PDCLIB_config.h"
#define FLT_ROUNDS _PDCLIB_FLT_ROUNDS
#define FLT_EVAL_METHOD _PDCLIB_FLT_EVAL_METHOD
#define DECIMAL_DIG _PDCLIB_DECIMAL_DIG
/* Radix of exponent representation */
#define FLT_RADIX __FLT_RADIX__
/* Number of base-FLT_RADIX digits in the significand of a float */
#define FLT_MANT_DIG __FLT_MANT_DIG__
/* Number of decimal digits of precision in a float */
#define FLT_DIG __FLT_DIG__
/* Difference between 1.0 and the minimum float greater than 1.0 */
#define FLT_EPSILON __FLT_EPSILON__
/* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
#define FLT_MIN_EXP __FLT_MIN_EXP__
/* Minimum normalised float */
#define FLT_MIN __FLT_MIN__
/* Minimum int x such that 10**x is a normalised float */
#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__
/* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
#define FLT_MAX_EXP __FLT_MAX_EXP__
/* Maximum float */
#define FLT_MAX __FLT_MAX__
/* Maximum int x such that 10**x is a representable float */
#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__
/* Number of base-FLT_RADIX digits in the significand of a double */
#define DBL_MANT_DIG __DBL_MANT_DIG__
/* Number of decimal digits of precision in a double */
#define DBL_DIG __DBL_DIG__
/* Difference between 1.0 and the minimum double greater than 1.0 */
#define DBL_EPSILON __DBL_EPSILON__
/* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
#define DBL_MIN_EXP __DBL_MIN_EXP__
/* Minimum normalised double */
#define DBL_MIN __DBL_MIN__
/* Minimum int x such that 10**x is a normalised double */
#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__
/* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
#define DBL_MAX_EXP __DBL_MAX_EXP__
/* Maximum double */
#define DBL_MAX __DBL_MAX__
/* Maximum int x such that 10**x is a representable double */
#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__
/* Number of base-FLT_RADIX digits in the significand of a long double */
#define LDBL_MANT_DIG __LDBL_MANT_DIG__
/* Number of decimal digits of precision in a long double */
#define LDBL_DIG __LDBL_DIG__
/* Difference between 1.0 and the minimum long double greater than 1.0 */
#define LDBL_EPSILON __LDBL_EPSILON__
/* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
#define LDBL_MIN_EXP __LDBL_MIN_EXP__
/* Minimum normalised long double */
#define LDBL_MIN __LDBL_MIN__
/* Minimum int x such that 10**x is a normalised long double */
#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
/* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
#define LDBL_MAX_EXP __LDBL_MAX_EXP__
/* Maximum long double */
#define LDBL_MAX __LDBL_MAX__
/* Maximum int x such that 10**x is a representable long double */
#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
#endif

@ -1,426 +0,0 @@
/* Internal PDCLib configuration <_PDCLIB_config.h>
(Generic Template)
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#ifndef _PDCLIB_CONFIG_H
#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H
/* -------------------------------------------------------------------------- */
/* Misc */
/* -------------------------------------------------------------------------- */
/* The character (sequence) your platform uses as newline. */
#define _PDCLIB_endl "\n"
/* exit() can signal success to the host environment by the value of zero or */
/* the constant EXIT_SUCCESS. Failure is signaled by EXIT_FAILURE. Note that */
/* any other return value is "implementation-defined", i.e. your environment */
/* is not required to handle it gracefully. Set your definitions here. */
#define _PDCLIB_SUCCESS 0
#define _PDCLIB_FAILURE -1
/* qsort() in <stdlib.h> requires a function that swaps two memory areas. */
/* Below is a naive implementation that can be improved significantly for */
/* specific platforms, e.g. by swapping int instead of char. */
#define _PDCLIB_memswp( i, j, size ) char tmp; do { tmp = *i; *i++ = *j; *j++ = tmp; } while ( --size );
/* Define this to some compiler directive that can be written after the */
/* parameter list of a function declaration to indicate the function does */
/* never return. If your compiler does not support such a directive, define */
/* to nothing. (This is to avoid warnings with the exit functions under GCC.) */
#define _PDCLIB_NORETURN __attribute__(( noreturn ))
/* -------------------------------------------------------------------------- */
/* Integers */
/* -------------------------------------------------------------------------- */
/* Assuming 8-bit char, two's-complement architecture here. 'short' being */
/* 16 bit, 'int' being either 16, 32 or 64 bit, 'long' being either 32 or 64 */
/* bit (but 64 bit only if 'int' is 32 bit), and 'long long' being 64 bit if */
/* 'long' is not, 64 or 128 bit otherwise. */
/* Author is quite willing to support other systems but would like to hear of */
/* interest in such support and details on the to-be-supported architecture */
/* first, before going to lengths about it. */
/* -------------------------------------------------------------------------- */
/* Set to 0 if your 'char' type is unsigned. */
#ifdef __CHAR_UNSIGNED__
#define _PDCLIB_CHAR_SIGNED 0
#else
#define _PDCLIB_CHAR_SIGNED 1
#endif
/* Width of the integer types short, int, long, and long long, in bytes. */
/* SHRT == 2, INT >= SHRT, LONG >= INT >= 4, LLONG >= LONG - check your */
/* compiler manuals. */
#define _PDCLIB_SHRT_BYTES 2
#define _PDCLIB_INT_BYTES 4
#ifdef __LP64__
#define _PDCLIB_LONG_BYTES 8
#else
#define _PDCLIB_LONG_BYTES 4
#endif
#define _PDCLIB_LLONG_BYTES 8
/* <stdlib.h> defines the div() function family that allows taking quotient */
/* and remainder of an integer division in one operation. Many platforms */
/* support this in hardware / opcode, and the standard permits ordering of */
/* the return structure in any way to fit the hardware. That is why those */
/* structs can be configured here. */
struct _PDCLIB_div_t
{
int quot;
int rem;
};
struct _PDCLIB_ldiv_t
{
long int quot;
long int rem;
};
struct _PDCLIB_lldiv_t
{
long long int quot;
long long int rem;
};
/* -------------------------------------------------------------------------- */
/* <stdint.h> defines a set of integer types that are of a minimum width, and */
/* "usually fastest" on the system. (If, for example, accessing a single char */
/* requires the CPU to access a complete int and then mask out the char, the */
/* "usually fastest" type of at least 8 bits would be int, not char.) */
/* If you do not have information on the relative performance of the types, */
/* the standard allows you to define any type that meets minimum width and */
/* signedness requirements. */
/* The defines below are just configuration for the real typedefs and limit */
/* definitions done in <_PDCLIB_int.h>. The uppercase define shall be either */
/* SHRT, INT, LONG, or LLONG (telling which values to use for the *_MIN and */
/* *_MAX limits); the lowercase define either short, int, long, or long long */
/* (telling the actual type to use). */
/* The third define is the length modifier used for the type in printf() and */
/* scanf() functions (used in <inttypes.h>). */
/* If you require a non-standard datatype to define the "usually fastest" */
/* types, PDCLib as-is doesn't support that. Please contact the author with */
/* details on your platform in that case, so support can be added. */
/* -------------------------------------------------------------------------- */
#define _PDCLIB_FAST8 INT
#define _PDCLIB_fast8 int
#define _PDCLIB_FAST8_CONV
#define _PDCLIB_FAST16 INT
#define _PDCLIB_fast16 int
#define _PDCLIB_FAST16_CONV
#define _PDCLIB_FAST32 INT
#define _PDCLIB_fast32 int
#define _PDCLIB_FAST32_CONV
#define _PDCLIB_FAST64 LONG
#define _PDCLIB_fast64 long
#define _PDCLIB_FAST64_CONV l
/* -------------------------------------------------------------------------- */
/* What follows are a couple of "special" typedefs and their limits. Again, */
/* the actual definition of the limits is done in <_PDCLIB_int.h>, and the */
/* defines here are merely "configuration". See above for details. */
/* -------------------------------------------------------------------------- */
/* The result type of substracting two pointers */
#define _PDCLIB_ptrdiff long
#define _PDCLIB_PTRDIFF LONG
#define _PDCLIB_PTR_CONV l
/* An integer type that can be accessed as atomic entity (think asynchronous
interrupts). The type itself is not defined in a freestanding environment,
but its limits are. (Don't ask.)
*/
#define _PDCLIB_sig_atomic int
#define _PDCLIB_SIG_ATOMIC INT
/* Result type of the 'sizeof' operator (must be unsigned) */
#define _PDCLIB_size unsigned long
#define _PDCLIB_SIZE ULONG
/* Large enough an integer to hold all character codes of the largest supported
locale.
*/
#define _PDCLIB_wchar unsigned int
#define _PDCLIB_WCHAR UINT
/* Large enough an integer to hold all character codes of the largest supported
locale plus WEOF (which needs not to be equal to EOF, nor needs to be of
negative value).
*/
#define _PDCLIB_wint unsigned int
#define _PDCLIB_WINT UINT
/* (Signed) integer type capable of taking the (cast) value of a void *, and
having the value cast back to void *, comparing equal to the original.
*/
#define _PDCLIB_intptr long
#define _PDCLIB_INTPTR LONG
/* Largest supported integer type. Implementation note: see _PDCLIB_atomax(). */
#define _PDCLIB_intmax long long int
#define _PDCLIB_INTMAX LLONG
#define _PDCLIB_MAX_CONV ll
/* You are also required to state the literal suffix for the intmax type */
#define _PDCLIB_INTMAX_LITERAL ll
/* <inttypes.h> defines imaxdiv(), which is equivalent to the div() function */
/* family (see further above) with intmax_t as basis. */
struct _PDCLIB_imaxdiv_t
{
_PDCLIB_intmax quot;
_PDCLIB_intmax rem;
};
/* -------------------------------------------------------------------------- */
/* Time types */
/* -------------------------------------------------------------------------- */
/* See <time.h> for a couple of comments on these types and their semantics. */
#define _PDCLIB_time long
#define _PDCLIB_clock long
#define _PDCLIB_CLOCKS_PER_SEC 1000000
#define _PDCLIB_TIME_UTC 1
/* -------------------------------------------------------------------------- */
/* Floating Point */
/* -------------------------------------------------------------------------- */
/* Whether the implementation rounds toward zero (0), to nearest (1), toward
positive infinity (2), or toward negative infinity (3). (-1) signifies
indeterminable rounding, any other value implementation-specific rounding.
*/
#define _PDCLIB_FLT_ROUNDS -1
/* Whether the implementation uses exact-width precision (0), promotes float
to double (1), or promotes float and double to long double (2). (-1)
signifies indeterminable behaviour, any other value implementation-specific
behaviour.
*/
#define _PDCLIB_FLT_EVAL_METHOD -1
/* "Number of the decimal digits (n), such that any floating-point number in the
widest supported floating type with p(max) radix (b) digits can be rounded to
a floating-point number with (n) decimal digits and back again without change
to the value p(max) log(10)b if (b) is a power of 10, [1 + p(max) log(10)b]
otherwise."
64bit IEC 60559 double format (53bit mantissa) is DECIMAL_DIG 17.
80bit IEC 60559 double-extended format (64bit mantissa) is DECIMAL_DIG 21.
*/
#define _PDCLIB_DECIMAL_DIG 17
/* -------------------------------------------------------------------------- */
/* Platform-dependent macros defined by the standard headers. */
/* -------------------------------------------------------------------------- */
/* The offsetof macro
Contract: Expand to an integer constant expression of type size_t, which
represents the offset in bytes to the structure member from the beginning
of the structure. If the specified member is a bitfield, behaviour is
undefined.
There is no standard-compliant way to do this.
This implementation casts an integer zero to 'pointer to type', and then
takes the address of member. This is undefined behaviour but should work on
most compilers.
*/
#define _PDCLIB_offsetof( type, member ) ( (size_t) &( ( (type *) 0 )->member ) )
/* Variable Length Parameter List Handling (<stdarg.h>)
The macros defined by <stdarg.h> are highly dependent on the calling
conventions used, and you probably have to replace them with builtins of
your compiler.
*/
#if defined( __i386 )
/* The following generic implementation works only for pure
stack-based architectures, and only if arguments are aligned to pointer
type. Credits to Michael Moody, who contributed this to the Public Domain.
*/
/* Internal helper macro. va_round is not part of <stdarg.h>. */
#define _PDCLIB_va_round( type ) ( (sizeof(type) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) )
typedef char * _PDCLIB_va_list;
#define _PDCLIB_va_arg( ap, type ) ( (ap) += (_PDCLIB_va_round(type)), ( *(type*) ( (ap) - (_PDCLIB_va_round(type)) ) ) )
#define _PDCLIB_va_copy( dest, src ) ( (dest) = (src), (void)0 )
#define _PDCLIB_va_end( ap ) ( (ap) = (void *)0, (void)0 )
#define _PDCLIB_va_start( ap, parmN ) ( (ap) = (char *) &parmN + ( _PDCLIB_va_round(parmN) ), (void)0 )
#elif defined( __x86_64 ) || defined( __arm__ )
/* No way to cover x86_64 or arm with a generic implementation, as it uses
register-based parameter passing. Using compiler builtins here.
*/
typedef __builtin_va_list _PDCLIB_va_list;
#define _PDCLIB_va_arg( ap, type ) ( __builtin_va_arg( ap, type ) )
#define _PDCLIB_va_copy( dest, src ) ( __builtin_va_copy( dest, src ) )
#define _PDCLIB_va_end( ap ) ( __builtin_va_end( ap ) )
#define _PDCLIB_va_start( ap, parmN ) ( __builtin_va_start( ap, parmN ) )
#else
#error Please create your own _PDCLIB_config.h. Using the existing one as-is will not work.
#endif
/* -------------------------------------------------------------------------- */
/* OS "glue", part 1 */
/* These are values and data type definitions that you would have to adapt to */
/* the capabilities and requirements of your OS. */
/* The actual *functions* of the OS interface are declared in _PDCLIB_glue.h. */
/* -------------------------------------------------------------------------- */
/* Memory management -------------------------------------------------------- */
/* Set this to the page size of your OS. If your OS does not support paging, set
to an appropriate value. (Too small, and malloc() will call the kernel too
often. Too large, and you will waste memory.)
*/
#define _PDCLIB_PAGESIZE 4096
/* Set this to the minimum memory node size. Any malloc() for a smaller size
will be satisfied by a malloc() of this size instead (to avoid excessive
fragmentation).
*/
#define _PDCLIB_MINALLOC 8
/* I/O ---------------------------------------------------------------------- */
/* The type of the file descriptor returned by _PDCLIB_open(). */
typedef int _PDCLIB_fd_t;
/* The value (of type _PDCLIB_fd_t) returned by _PDCLIB_open() if the operation
failed.
*/
#define _PDCLIB_NOHANDLE ( (_PDCLIB_fd_t) -1 )
/* The default size for file buffers. Must be at least 256. */
#define _PDCLIB_BUFSIZ 1024
/* The minimum number of files the implementation can open simultaneously. Must
be at least 8. Depends largely on how the bookkeeping is done by fopen() /
freopen() / fclose(). The example implementation limits the number of open
files only by available memory.
*/
#define _PDCLIB_FOPEN_MAX 8
/* Length of the longest filename the implementation guarantees to support. */
#define _PDCLIB_FILENAME_MAX 128
/* Maximum length of filenames generated by tmpnam(). (See tmpfile.c.) */
#define _PDCLIB_L_tmpnam 46
/* Number of distinct file names that can be generated by tmpnam(). */
#define _PDCLIB_TMP_MAX 50
/* The values of SEEK_SET, SEEK_CUR and SEEK_END, used by fseek().
Since at least one platform (POSIX) uses the same symbols for its own "seek"
function, we use whatever the host defines (if it does define them).
*/
#define _PDCLIB_SEEK_SET 0
#define _PDCLIB_SEEK_CUR 1
#define _PDCLIB_SEEK_END 2
/* The number of characters that can be buffered with ungetc(). The standard
guarantees only one (1); anything larger would make applications relying on
this capability dependent on implementation-defined behaviour (not good).
*/
#define _PDCLIB_UNGETCBUFSIZE 1
/* errno -------------------------------------------------------------------- */
/* These are the values that _PDCLIB_errno can be set to by the library.
By keeping PDCLib's errno in the _PDCLIB_* namespace, the library is capable
to "translate" between errno values used by the hosting operating system and
those used and passed out by the library.
Example: In the example platform, the remove() function uses the unlink()
system call as backend. Linux sets its errno to EISDIR if you try to unlink()
a directory, but POSIX demands EPERM. Within the remove() function, you can
catch the 'errno == EISDIR', and set '_PDCLIB_errno = _PDCLIB_EPERM'. Anyone
using PDCLib's <errno.h> will "see" EPERM instead of EISDIR (the _PDCLIB_*
prefix removed by <errno.h> mechanics).
If you do not want that kind of translation, you might want to "match" the
values used by PDCLib with those used by the host OS, as to avoid confusion.
The standard only defines three distinct errno values: ERANGE, EDOM, and
EILSEQ. The standard leaves it up to "the implementation" whether there are
any more beyond those three. There is some controversy as to whether errno is
such a good idea at all, so you might want to come up with a different error
reporting facility for your platform. Since errno values beyond the three
defined by the standard are not portable anyway (unless you look at POSIX),
having your own error reporting facility would not hurt anybody either.
*/
#define _PDCLIB_ERANGE 1
#define _PDCLIB_EDOM 2
#define _PDCLIB_EILSEQ 3
/* The following is not strictly "configuration", but there is no better place
to explain it than here.
PDCLib strives to be as generic as possible, so by default it does NOT define
any values beyond the three standard ones above, even where it would have
been prudent and convenient to do so. Any errno "caught" from the host OS,
and some internal error conditions as well, are all lumped together into the
value of '_PDCLIB_ERROR'.
'_PDCLIB_ERROR' is STRICLY meant as a PLACEHOLDER only.
You should NEVER ship an adaption of PDCLib still using that particular
value. You should NEVER write code that *tests* for that value. Indeed it is
not even conforming, since errno values should be defined as beginning with
an uppercase 'E', and there is no mechanics in <errno.h> to unmask that
particular value (for exactly that reason).
There also is no error message available for this value through either the
strerror() or perror() functions. It is being reported as "unknown" error.
The idea is that you scan the source of PDCLib for occurrences of this macro
and replace _PDCLIB_ERROR with whatever additional errno value you came up
with for your platform.
If you cannot find it within you to do that, tell your clients to check for
an errno value larger than zero. That, at least, would be standard compliant
(and fully portable).
*/
#define _PDCLIB_ERROR 4
/* The maximum value that errno can be set to. This is used to set the size */
/* of the array in struct _PDCLIB_lc_text_t holding error messages for the */
/* strerror() and perror() functions. (If you change this value because you */
/* are using additional errno values, you *HAVE* to provide appropriate error */
/* messages for *ALL* locales.) */
/* Default is 4 (0, ERANGE, EDOM, EILSEQ). */
#define _PDCLIB_ERRNO_MAX 4
/* locale data -------------------------------------------------------------- */
/* The default path where PDCLib should look for its locale data. */
/* Must end with the appropriate separator character. */
#define _PDCLIB_LOCALE_PATH "/usr/share/pdclib/i18n"
/* The name of the environment variable that can be used to override that */
/* path setting. */
#define _PDCLIB_LOCALE_PATH_ENV PDCLIB_I18N
#ifdef __CYGWIN__
typedef unsigned int wint_t;
#endif
#endif

@ -1,84 +0,0 @@
/* Signal handling <string.h>
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
#ifndef _PDCLIB_SIGNAL_H
#define _PDCLIB_SIGNAL_H _PDCLIB_SIGNAL_H
#include "pdclib/_PDCLIB_config.h"
/* Signals ------------------------------------------------------------------ */
/* A word on signals, to the people using PDCLib in their OS projects.
The definitions of the C standard leave about everything that *could* be
useful to be "implementation defined". Without additional, non-standard
arrangements, it is not possible to turn them into a useful tool.
This example implementation chose to "not generate any of these signals,
except as a result of explicit calls to the raise function", which is
allowed by the standard but of course does nothing for the usefulness of
<signal.h>.
A useful signal handling would:
1) make signal() a system call that registers the signal handler with the OS
2) make raise() a system call triggering an OS signal to the running process
3) make provisions that further signals of the same type are blocked until
the signal handler returns (optional for SIGILL)
*/
/* These are the values used by Linux. */
/* Abnormal termination / abort() */
#define SIGABRT 6
/* Arithmetic exception / division by zero / overflow */
#define SIGFPE 8
/* Illegal instruction */
#define SIGILL 4
/* Interactive attention signal */
#define SIGINT 2
/* Invalid memory access */
#define SIGSEGV 11
/* Termination request */
#define SIGTERM 15
/* The following should be defined to pointer values that could NEVER point to
a valid signal handler function. (They are used as special arguments to
signal().) Again, these are the values used by Linux.
*/
#define SIG_DFL (void (*)( int ))0
#define SIG_ERR (void (*)( int ))-1
#define SIG_IGN (void (*)( int ))1
typedef _PDCLIB_sig_atomic sig_atomic_t;
/* Installs a signal handler "func" for the given signal.
A signal handler is a function that takes an integer as argument (the signal
number) and returns void.
Note that a signal handler can do very little else than:
1) assign a value to a static object of type "volatile sig_atomic_t",
2) call signal() with the value of sig equal to the signal received,
3) call _Exit(),
4) call abort().
Virtually everything else is undefind.
The signal() function returns the previous installed signal handler, which
at program start may be SIG_DFL or SIG_ILL. (This implementation uses
SIG_DFL for all handlers.) If the request cannot be honored, SIG_ERR is
returned and errno is set to an unspecified positive value.
*/
void (*signal( int sig, void (*func)( int ) ) )( int );
/* Raises the given signal (executing the registered signal handler with the
given signal number as parameter).
This implementation does not prevent further signals of the same time from
occuring, but executes signal( sig, SIG_DFL ) before entering the signal
handler (i.e., a second signal before the signal handler re-registers itself
or SIG_IGN will end the program).
Returns zero if successful, nonzero otherwise. */
int raise( int sig );
#endif

@ -17,43 +17,47 @@
#include "pdclib/_PDCLIB_glue.h" #include "pdclib/_PDCLIB_glue.h"
static void * membreak = NULL; //static void * membreak = NULL;
void * _PDCLIB_allocpages( int const n ) void * _PDCLIB_allocpages( int const n )
{ {
void * oldbreak; // TODO eek
if ( membreak == NULL ) // sbrk actually mallocs (kernel side)
{ return sbrk(n * _PDCLIB_PAGESIZE);
/* first call, make sure end-of-heap is page-aligned */
intptr_t unaligned = 0;
membreak = sbrk( 0 );
unaligned = _PDCLIB_PAGESIZE - (intptr_t)membreak % _PDCLIB_PAGESIZE;
if ( unaligned < _PDCLIB_PAGESIZE )
{
/* end-of-heap not page-aligned - adjust */
if ( sbrk( unaligned ) != membreak )
{
/* error */
return NULL;
}
membreak = (char *)membreak + unaligned;
}
}
/* increasing or decreasing heap - standard operation */
oldbreak = membreak;
membreak = (void *)( (char *)membreak + ( n * _PDCLIB_PAGESIZE ) );
if ( sbrk( (char*)membreak - (char*)oldbreak ) == membreak ) // void * oldbreak;
{ // if ( membreak == NULL )
/* successful */ // {
return oldbreak; // /* first call, make sure end-of-heap is page-aligned */
} // intptr_t unaligned = 0;
else // membreak = sbrk( 0 );
{ // unaligned = _PDCLIB_PAGESIZE - (intptr_t)membreak % _PDCLIB_PAGESIZE;
/* out of memory */ // if ( unaligned < _PDCLIB_PAGESIZE )
membreak = oldbreak; // {
return NULL; // /* end-of-heap not page-aligned - adjust */
} // if ( sbrk( unaligned ) != membreak )
// {
// /* error */
// return NULL;
// }
// membreak = (char *)membreak + unaligned;
// }
// }
// /* increasing or decreasing heap - standard operation */
// oldbreak = membreak;
// membreak = (void *)( (char *)membreak + ( n * _PDCLIB_PAGESIZE ) );
//
// if ( sbrk( (char*)membreak - (char*)oldbreak ) == membreak )
// {
// /* successful */
// return oldbreak;
// }
// else
// {
// /* out of memory */
// membreak = oldbreak;
// return NULL;
// }
} }
#endif #endif

@ -19,24 +19,42 @@
descriptors 0, 1, and 2 respectively. descriptors 0, 1, and 2 respectively.
*/ */
/* TODO: This is proof-of-concept, requires finetuning. */ /* TODO: This is proof-of-concept, requires finetuning. */
static char _PDCLIB_sin_buffer[BUFSIZ]; /*static char _PDCLIB_serr_buf[BUFSIZ];
static char _PDCLIB_sout_buffer[BUFSIZ]; static char _PDCLIB_sout_buf[BUFSIZ];
static char _PDCLIB_serr_buffer[BUFSIZ]; static char _PDCLIB_sin_buf[BUFSIZ];
static unsigned char _PDCLIB_serr_unget[_PDCLIB_UNGETCBUFSIZE];
static unsigned char _PDCLIB_sout_unget[_PDCLIB_UNGETCBUFSIZE];
static unsigned char _PDCLIB_sin_unget[_PDCLIB_UNGETCBUFSIZE];
static unsigned char _PDCLIB_sin_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; static struct _PDCLIB_file_t _PDCLIB_serr = {
static unsigned char _PDCLIB_sout_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; 2,
static unsigned char _PDCLIB_serr_ungetbuf[_PDCLIB_UNGETCBUFSIZE]; _PDCLIB_serr_buf, BUFSIZ, 0, 0,{ 0, 0 },
0, _PDCLIB_serr_unget,
static struct _PDCLIB_file_t _PDCLIB_serr = { 2, _PDCLIB_serr_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_serr_ungetbuf, _IONBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, NULL }; _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC,
static struct _PDCLIB_file_t _PDCLIB_sout = { 1, _PDCLIB_sout_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sout_ungetbuf, _IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC, NULL, &_PDCLIB_serr }; NULL, NULL
static struct _PDCLIB_file_t _PDCLIB_sin = { 0, _PDCLIB_sin_buffer, BUFSIZ, 0, 0, { 0, 0 }, 0, _PDCLIB_sin_ungetbuf, _IOLBF | _PDCLIB_FREAD | _PDCLIB_STATIC, NULL, &_PDCLIB_sout }; };
static struct _PDCLIB_file_t _PDCLIB_sout = {
1,
_PDCLIB_sout_buf, BUFSIZ, 0, 0,{ 0, 0 },
0, _PDCLIB_sout_unget,
_IOLBF | _PDCLIB_FWRITE | _PDCLIB_STATIC,
NULL, &_PDCLIB_serr
};
static struct _PDCLIB_file_t _PDCLIB_sin = {
0,
_PDCLIB_sin_buf, BUFSIZ, 0, 0,{ 0, 0 },
0, _PDCLIB_sin_unget,
_IOLBF | _PDCLIB_FREAD | _PDCLIB_STATIC,
NULL, &_PDCLIB_sout
};*/
struct _PDCLIB_file_t * stdin = &_PDCLIB_sin; struct _PDCLIB_file_t *stdin = 0;//&_PDCLIB_sin;
struct _PDCLIB_file_t * stdout = &_PDCLIB_sout; struct _PDCLIB_file_t *stdout = 0;//&_PDCLIB_sout;
struct _PDCLIB_file_t * stderr = &_PDCLIB_serr; struct _PDCLIB_file_t *stderr = 0;//&_PDCLIB_serr;
/* FIXME: This approach is a possible attack vector. */ /* FIXME: This approach is a possible attack vector. */
struct _PDCLIB_file_t * _PDCLIB_filelist = &_PDCLIB_sin; // TODO used by remove/tmpfile
struct _PDCLIB_file_t *_PDCLIB_filelist = 0;//&_PDCLIB_sin;
/* "C" locale - defaulting to ASCII-7. /* "C" locale - defaulting to ASCII-7.
1 kByte (+ 4 byte) of <ctype.h> data. 1 kByte (+ 4 byte) of <ctype.h> data.

@ -39,7 +39,7 @@ int getpid(void)
void *sbrk(unsigned int bytes) void *sbrk(unsigned int bytes)
{ {
void *ret = 0; uint32_t ret = 0;
register uint32_t r1 __asm("r1") = bytes; register uint32_t r1 __asm("r1") = bytes;
register uint32_t r2 __asm("r2") = (uint32_t)&ret; register uint32_t r2 __asm("r2") = (uint32_t)&ret;
__asm("\ __asm("\
@ -48,7 +48,30 @@ void *sbrk(unsigned int bytes)
mov r2, %1; \ mov r2, %1; \
svc 0; \ svc 0; \
" :: "r" (r1), "r" (r2)); " :: "r" (r1), "r" (r2));
return ret; __asm("mov %0, r2" : "=r" (ret));
return *((void **)ret);
}
int execve(const char *file, char * const argv[], char * const envp[])
{
volatile uint32_t ret = 0;
register uint32_t r1 __asm("r1") = (uint32_t)file;
register uint32_t r2 __asm("r2") = (uint32_t)argv;
register uint32_t r3 __asm("r3") = (uint32_t)envp;
register uint32_t r12 __asm("r12") = (uint32_t)&ret;
__asm("\
mov r0, 5; \
mov r1, %0; \
mov r2, %1; \
mov r3, %2; \
mov r12, %3; \
svc 0; \
" :: "r" (r1), "r" (r2), "r" (r3), "r" (r12));
if (ret == (uint32_t)-1)
return ret;
((void (*)(void))ret)();
} }
// //
@ -131,15 +154,15 @@ int read(int fd, uint32_t count, uint8_t *buffer)
register uint32_t r1 __asm("r1") = fd; register uint32_t r1 __asm("r1") = fd;
register uint32_t r2 __asm("r2") = count; register uint32_t r2 __asm("r2") = count;
register uint32_t r3 __asm("r3") = (uint32_t)buffer; register uint32_t r3 __asm("r3") = (uint32_t)buffer;
register uint32_t r4 __asm("r4") = (uint32_t)&ret; register uint32_t r12 __asm("r12") = (uint32_t)&ret;
__asm("\ __asm("\
mov r0, 3; \ mov r0, 3; \
mov r1, %0; \ mov r1, %0; \
mov r2, %1; \ mov r2, %1; \
mov r3, %2; \ mov r3, %2; \
mov r4, %3; \ mov r12, %3; \
svc 3; \ svc 3; \
" :: "r" (r1), "r" (r2), "r" (r3), "r" (r4)); " :: "r" (r1), "r" (r2), "r" (r3), "r" (r12));
return ret; return ret;
} }
@ -149,15 +172,15 @@ int write(int fd, uint32_t count, const uint8_t *buffer)
register uint32_t r1 __asm("r1") = fd; register uint32_t r1 __asm("r1") = fd;
register uint32_t r2 __asm("r2") = count; register uint32_t r2 __asm("r2") = count;
register uint32_t r3 __asm("r3") = (uint32_t)buffer; register uint32_t r3 __asm("r3") = (uint32_t)buffer;
register uint32_t r4 __asm("r4") = (uint32_t)&ret; register uint32_t r12 __asm("r12") = (uint32_t)&ret;
__asm("\ __asm("\
mov r0, 4; \ mov r0, 4; \
mov r1, %0; \ mov r1, %0; \
mov r2, %1; \ mov r2, %1; \
mov r3, %2; \ mov r3, %2; \
mov r4, %3; \ mov r12, %3; \
svc 3; \ svc 3; \
" :: "r" (r1), "r" (r2), "r" (r3), "r" (r4)); " :: "r" (r1), "r" (r2), "r" (r3), "r" (r12));
return ret; return ret;
} }

@ -16,6 +16,7 @@ void _exit(int code);
int fork(void); int fork(void);
int getpid(void); int getpid(void);
void *sbrk(unsigned int bytes); void *sbrk(unsigned int bytes);
int execve(const char *file, char * const argv[], char * const envp[]);
// //
// Clock-related calls // Clock-related calls

@ -1,9 +1,29 @@
##
# @file Makefile
# Script to build folder of source files
#
# Copyright (C) 2018 Clyne Sullivan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
CFILES = $(wildcard *.c) CFILES = $(wildcard *.c)
AFILES = $(wildcard *.s) AFILES = $(wildcard *.s)
OFILES = $(patsubst %.c, %.o, $(CFILES)) \ OFILES = $(patsubst %.c, %.o, $(CFILES)) \
$(patsubst %.s, %.asm.o, $(AFILES)) $(patsubst %.s, %.asm.o, $(AFILES))
CFLAGS += -I.. -I../arch/cmsis CFLAGS += -ffreestanding -nostdlib -I.. -I../arch/cmsis
all: $(OFILES) all: $(OFILES)

@ -1,58 +0,0 @@
/**
* @file priv_gpio.h
* GPIO access for unpriviledged processes
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PRIV_GPIO_H_
#define PRIV_GPIO_H_
// For value flags
#include <kernel/gpio.h>
/**
* Possible GPIO calls.
*/
enum GPIO_CALLS {
GPIO_MODE = 0, /**< Change GPIO mode */
GPIO_TYPE, /**< Change GPIO type (PuPd/ODrain) */
GPIO_PUPD, /**< Set/clear pullup/pulldown */
GPIO_SPEED, /**< Set GPIO speed */
GPIO_OUT, /**< Set GPIO output state */
};
/**
* Provides unpriviledged GPIO access.
* @param call The type of GPIO call to make
* @param pin The pin to modify (0-15 = A, 16-31 = B, ...)
* @param value The value to pass to the call
*/
void gpio(uint32_t call, uint32_t pin, uint32_t value)
{
register uint32_t r0 asm("r0") = call;
register uint32_t r1 asm("r1") = pin;
register uint32_t r2 asm("r2") = value;
asm("\
mov r0, %0; \
mov r1, %1; \
mov r2, %2; \
svc 1; \
" :: "r" (r0), "r" (r1), "r" (r2));
}
#endif // PRIV_GPIO_H_

@ -1,41 +1,29 @@
#include "priv_gpio.h" /**
* @file user.c
* Userspace entry
*
* Copyright (C) 2018 Clyne Sullivan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <kernel/clock.h> #include <syscalls.h>
#include <kernel/heap.h> #include <stdio.h>
#include <kernel/vfs.h>
void user_delay(uint32_t ms)
{
register uint32_t r1 asm("r1") = ms;
asm("\
mov r0, 0; \
mov r1, %0; \
svc 2; \
" :: "r" (r1));
}
void user_main(void) void user_main(void)
{ {
gpio(GPIO_MODE, 5, OUTPUT); //gpio(GPIO_MODE, 5, OUTPUT);
execve("B:/init", 0, 0);
int test = vfs_open("B:/hello", VFS_FILE_READ);
char *buf = malloc(20);
int count = vfs_read(test, 20, (uint8_t *)buf);
buf[count] = '\0';
vfs_close(test);
// if (fork() == 0) {
// while (1) {
// gpio(GPIO_OUT, 5, 1);
// user_delay(2000);
// }
// } else {
// while (1) {
// user_delay(1000);
// gpio(GPIO_OUT, 5, 0);
// user_delay(1000);
// }
// }
} }

Loading…
Cancel
Save