Compare commits

...

10 Commits

Author SHA1 Message Date
d873ee19c1 example project file 2024-05-02 07:37:26 +05:00
6fe1d5a511 CamelCase 2023-11-19 22:52:26 +06:00
ab2f7b14a1 include fix 2023-11-19 22:42:53 +06:00
91b5eef3dc Process.h implementations for unix and windows 2023-11-19 22:36:02 +06:00
1b5efdb146 vscode debug 2023-11-19 22:35:22 +06:00
16f86ce592 kprintf calls 2023-10-12 13:53:32 +06:00
c53500d6ac languages and tools declaration 2023-09-05 12:17:53 +03:00
15085957fc new project file structure 2023-08-10 19:27:55 +03:00
a2fc40b006 process.c 2023-08-10 19:24:39 +03:00
44ee9e210f kerep sources 2023-07-12 14:08:26 +03:00
95 changed files with 3832 additions and 167 deletions

35
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Debug",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}/bin",
"windows": {
"program": "${workspaceFolder}\\bin\\cbuild.exe",
},
"linux": {
"program": "${workspaceFolder}/bin/cbuild",
},
"args": [ "-p", "../example.proj.dtsod", "exe"],
"preLaunchTask": "build",
"stopAtEntry": false,
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

24
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,24 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "build",
"command": "bash",
"args": [
"${workspaceRoot}/build.sh",
"debug"
],
"options": {
"cwd": "${workspaceRoot}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

77
TODO.md Normal file
View File

@@ -0,0 +1,77 @@
## cbuild logic description
+ verify cbuild version
+ foreach dep in import
+ if dep starts with "./"
+ import local file
+ else
+ if find(dep in ./cbuild)
+ else if find (dep in global_config_dir/**)
+ else error: "import target 'dep' not found, try 'fluzm find dep'"
+ apply proj settings
+ apply platform settings
+ apply configuration settings
+ apply platform settings
+ foreach task in tasks
+ apply platform settings
+ foreach tool in tool_order
+ apply task settings
+ foreach src in find(dir, langs)
+ if platform, settings, src or src_deps (included headers) were changed
+ src -> src_to_process
+ if parallel
+ foreach src in src_to_process
+ run tool on src
+ else
+ run tool on src_to_process
## Example of project.dtsod:
```yml
cbuild_version: 0;
import: [ "c", "c++", "gcc", "./some_local_file.dtsod" ];
gcc: {
src_languages: [ "c" ],
src_dirs: [ "src" ],
};
configurations: {
release: {
preprocess_sources: {
src_languages: [ "c", "c++" ],
src_dirs: [ "src" ],
},
gcc: {
pre_args: [ "-O2" ],
post_args: [ "-Wl,--gc-sections" ],
};
};
}
tasks: {
exe: {
pre_tasks: [ ],
tool_order: [ "preprocess_sources", "gcc", "g++", "g++-link" ],
g++: [ ... ],
};
};
languages: [
{
aliases: [ "c" ],
file_extensions: [ "c" ],
},
{
aliases: [ "c-header" ],
file_extensions: [ "h" ],
}
];
tools: [
{
aliases: [ "gcc" ],
exe_file: [ "gcc" ],
supported_languages: [ "c" ]; # set to "any" to use with any lang
parallel: true,
}
];
```

View File

@@ -1,31 +1,47 @@
#!/bin/bash
set -eo pipefail
CONFIG_DIR="/etc/cbuild"
CMP="gcc"
ARGS="-Wall -Wno-discarded-qualifiers -O2"
SRC="$(find . -name '*.c')"
LINK="-L. -lkerep"
WARN="-Wall -Wextra -Wno-discarded-qualifiers -Wno-unused-parameter"
OS=$(./detect_os.sh)
ARCH=$(./detect_arch.sh)
ARGS_DEBUG="-O0 -g"
ARGS_RELEASE="-O2 -flto=auto -fdata-sections -ffunction-sections -Wl,--gc-sections"
if [[ "$1" = "debug" ]]; then
ARGS=$ARGS_DEBUG
else
ARGS=$ARGS_RELEASE
fi
if [[ OS == "windows" ]]; then
SRC="$(find src -name '*.c')"
OS="$(./detect_os.sh)"
ARCH="$(./detect_arch.sh)"
LINK="-Lkerep/bin -lkerep-$OS-$ARCH"
if [ "$OS" = "windows" ]; then
OUT_FILE="cbuild.exe"
else
OUT_FILE="cbuild"
fi
command="$CMP $ARGS
-DOS=$OS -DARCH=$ARCH
$WARN
-DOS=\"$OS\" -DARCH=\"$ARCH\" -DCONFIG_DIR=\"$CONFIG_DIR\"
$SRC
$LINK
-o bin/$OUT_FILE"
if [ ! -f "kerep/bin/libkerep-$OS-$ARCH.a" ]; then
echo "libkerep-$OS-$ARCH.a not found"
cd kerep
./build.sh
cd ..
fi
rm -rf bin
mkdir bin
mkdir -p bin
echo "----------------[cbuild]----------------"
echo "$command"
tar xJf libkerep.a.tar.xz
$($command)
rm libkerep.a

View File

@@ -20,4 +20,4 @@ case "$uname_rezult" in
;;
esac
echo "\"$ARCH\""
echo "$ARCH"

View File

@@ -23,4 +23,4 @@ case "$uname_rezult" in
;;
esac
echo "\"$OS\""
echo "$OS"

48
example.proj.dtsod Normal file
View File

@@ -0,0 +1,48 @@
cbuild_version: 0;
import: [ "c", "c++", "gcc", "./some_local_file.dtsod" ];
gcc: {
src_languages: [ "c" ],
src_dirs: [ "src" ],
};
configurations: {
release: {
preprocess_sources: {
src_languages: [ "c", "c++" ],
src_dirs: [ "src" ],
},
gcc: {
pre_args: [ "-O2" ],
post_args: [ "-Wl,--gc-sections" ],
};
};
};
tasks: {
exe: {
pre_tasks: [ ],
tool_order: [ "preprocess_sources", "gcc", "g++", "g++-link" ],
#g++: [ ... ],
};
};
languages: [
{
aliases: [ "c" ],
file_extensions: [ "c" ],
},
{
aliases: [ "c-header" ],
file_extensions: [ "h" ],
}
];
tools: [
{
aliases: [ "gcc" ],
exe_file: "gcc",
supported_languages: [ "c" ]; # set to "any" to use with any lang
parallel: false,
}
];

View File

@@ -1,32 +0,0 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../Hashtable/Hashtable.h"
// parses text to binary values
Maybe DtsodV24_deserialize(char* text);
// creates text representation of dtsod
Maybe DtsodV24_serialize(Hashtable* dtsod);
// returns value or UniNull if key not found
Unitype DtsodV24_get(Hashtable* dtsod, char* key);
// adds or sets value
void DtsodV24_addOrSet(Hashtable* dtsod, char* key, Unitype value);
// checks for dtsod contains value or dont
bool DtsodV24_contains(Hashtable* dtsod, char* key);
// replaces value with UniNull if key exists in dtsod
bool DtsodV24_remove(Hashtable* dtsod, char* key);
// frees memory including memory of elements (hashtables, autoarrs, etc.)
void DtsodV24_free(Hashtable* dtsod);
#if __cplusplus
}
#endif

2
kerep/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
obj/
libkerep.*

41
kerep/build.sh Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
set -eo pipefail
CMP="gcc"
WARN="-std=c11 -Wall -Wno-discarded-qualifiers -Wno-unused-parameter"
ARGS="-O2 -flto=auto -fpic -fdata-sections -ffunction-sections"
SRC="$(find src -name '*.c')"
OS=$(../detect_os.sh)
ARCH=$(../detect_arch.sh)
OUTFILE="bin/libkerep-$OS-$ARCH.a"
rm -rf obj
mkdir obj
mkdir -p bin
echo "----------------[kerep]-----------------"
compiler_call="$CMP $WARN $ARGS -c"
echo "$compiler_call"
OBJECTS=
for srcfile in $SRC
do
echo " $srcfile"
object="obj/$(basename $srcfile).o"
OBJECTS="$OBJECTS
$object"
command="$compiler_call $srcfile -o $object"
if ! $($command); then
exit 1
fi
done
command="ar rcs $OUTFILE $OBJECTS"
echo "$command"
if $($command)
then
echo "static lib $OUTFILE created"
rm -r obj
else
exit 1
fi

View File

@@ -0,0 +1,17 @@
#include "Autoarr.h"
Autoarr_define(Pointer, true)
Autoarr_define(char, false)
Autoarr_define(bool, false)
Autoarr_define(f32, false)
Autoarr_define(f64, false)
Autoarr_define(u8, false)
Autoarr_define(i8, false)
Autoarr_define(u16, false)
Autoarr_define(i16, false)
Autoarr_define(u32, false)
Autoarr_define(i32, false)
Autoarr_define(u64, false)
Autoarr_define(i64, false)
Autoarr_define(Unitype, false)

View File

@@ -0,0 +1,17 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../Hashtable/Hashtable.h"
// parses text to binary values
Maybe DtsodV24_deserialize(char* text);
// creates text representation of dtsod
Maybe DtsodV24_serialize(Hashtable* dtsod);
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,344 @@
#include "DtsodV24.h"
#include "../String/StringBuilder.h"
#define ARR_BC 64
#define ARR_BL 1024
typedef struct DeserializeSharedData{
const char* sh_text_first;
char* sh_text;
bool sh_partOfDollarList;
bool sh_calledRecursively;
} DeserializeSharedData;
#define text shared->sh_text
#define partOfDollarList shared->sh_partOfDollarList
#define calledRecursively shared->sh_calledRecursively
// special func for throwing error messages about wrong characters in deserializing text
Maybe ERROR_WRONGCHAR(const char c, char* _text, char* text_first, const char* srcfile, i32 line, const char* funcname){
char errBuf[68];
for(u8 n=0; n<sizeof(errBuf);n++)
errBuf[n]='\0';
char* errText=_text-32;
u8 cplace=32;
if(errText<text_first) {
cplace=_text-text_first;
errText=text_first;
}
u8 i=0;
for(; i<cplace; i++){
// writes 32 chars before the wrongchar
errBuf[i]=errText[i];
}
//prints wrongchar in braces
errBuf[i++]='<';
errBuf[i++]=c;
errBuf[i++]='>';
for(; i<cplace+3+32; i++){
// writes 32 chars after the wrongchar
char _c=errText[i-2];
errBuf[i]=_c;
if(!_c) break;
}
char errmsg[1024];
IFMSC(
sprintf_s(errmsg,1024, "unexpected <%c> at:\n"
" \"%s\"\n"
"\\___[%s:%d] %s()",
c,errBuf, srcfile,line,funcname),
sprintf(errmsg, "unexpected <%c> at:\n"
" \"%s\"\n"
" \\___[%s:%d] %s()",
c,errBuf, srcfile,line,funcname)
);
safethrow(errmsg,;);
}
#define safethrow_wrongchar(C, freeMem) { freeMem; return ERROR_WRONGCHAR(C, text, shared->sh_text_first, __FILE__,__LINE__,__func__); }
Maybe __SkipComment(DeserializeSharedData* shared) {
char c;
while ((c=*++text) != '\n')
if (!c) safethrow(ERR_ENDOFSTR,;);
return MaybeNull;
}
#define SkipComment() __SkipComment(shared)
Maybe __ReadName(DeserializeSharedData* shared){
char c;
string nameStr={text+1,0};
while ((c=*++text)) switch (c){
case ' ': case '\t':
case '\r': case '\n':
if(nameStr.length!=0)
safethrow_wrongchar(c,;);
nameStr.ptr++;
break;
case '=': case ';':
case '\'': case '"':
case '[': case ']':
case '{':
safethrow_wrongchar(c,;);
case '#': ;
char _c=c;
char* _text=text;
try(SkipComment(),_,;);
if(nameStr.length!=0){
text=_text;
safethrow_wrongchar(_c,;);
}
nameStr.ptr=text+1; // skips '\n'
break;
case '}':
if(!calledRecursively || nameStr.length!=0)
safethrow_wrongchar(c,;);
return SUCCESS(UniHeapPtr(char,NULL));
case ':':
return SUCCESS(UniHeapPtr(char,string_extract(nameStr)));
case '$':
if(nameStr.length!=0)
safethrow_wrongchar(c,;);
nameStr.ptr++;
partOfDollarList=true;
break;
default:
nameStr.length++;
break;
}
if(nameStr.length>0) safethrow(ERR_ENDOFSTR,;);
return SUCCESS(UniHeapPtr(char,NULL));
}
#define ReadName() __ReadName(shared)
Maybe __deserialize(char** _text, bool _calledRecursively);
Maybe __ReadValue(DeserializeSharedData* shared, bool* readingList);
#define ReadValue(rL) __ReadValue(shared, rL)
// returns part of <text> without quotes
Maybe __ReadString(DeserializeSharedData* shared){
char c;
bool prevIsBackslash=false;
StringBuilder* b=StringBuilder_create();
while ((c=*++text)){
if(c=='"') {
if(prevIsBackslash) {
// replacing <\"> with <">
StringBuilder_rmchar(b);
StringBuilder_append_char(b,c);
prevIsBackslash=false;
}
else {
char* str=StringBuilder_build(b).ptr;
return SUCCESS(UniHeapPtr(char,str));
}
}
else {
prevIsBackslash= c=='\\' && !prevIsBackslash;
StringBuilder_append_char(b,c);
}
}
safethrow(ERR_ENDOFSTR, StringBuilder_free(b));
}
#define ReadString() __ReadString(shared)
Maybe __ReadList(DeserializeSharedData* shared){
Autoarr(Unitype)* list=Autoarr_create(Unitype,ARR_BC,ARR_BL);
bool readingList=true;
while (true){
try(ReadValue((&readingList)), m_val, Autoarr_free(list, true))
Autoarr_add(list,m_val.value);
if (!readingList){
if(Unitype_isUniNull(m_val.value))
Autoarr_pop(list);
break;
}
}
return SUCCESS(UniHeapPtr(Autoarr_Unitype,list));
};
#define ReadList() __ReadList(shared)
Maybe __ParseValue(DeserializeSharedData* shared, string str){
const string trueStr={"true",4};
const string falseStr={"false",5};
switch(str.ptr[str.length-1]){
// Bool
case 'e':
if(string_compare(str,trueStr))
return SUCCESS(UniTrue);
else if(string_compare(str,falseStr))
return SUCCESS(UniFalse);
else safethrow_wrongchar(*str.ptr,;);
// Float64
case 'f': {
char* _c=string_extract(str);
Unitype rez=UniFloat64(strtod(_c,NULL));
free(_c);
return SUCCESS(rez);
}
// UInt64
case 'u': {
u64 lu=0;
char* _c=string_extract(str);
if(sscanf(_c, IFWIN("%llu", "%lu"), &lu)!=1){
char err[64];
IFMSC(
sprintf_s(err,64,"can't parse to int: <%s>",_c),
sprintf(err,"can't parse to int: <%s>",_c)
);
safethrow(err,free(_c));
}
free(_c);
return SUCCESS(UniUInt64(lu));
}
// Int64
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
i64 li=0;
char* _c=string_extract(str);
if(sscanf(_c, IFWIN("%lli", "%li"), &li)!=1){
char err[64];
IFMSC(
sprintf_s(err,64,"can't parse to int: <%s>",_c),
sprintf(err,"can't parse to int: <%s>",_c)
);
safethrow(err,free(_c));
}
free(_c);
return SUCCESS(UniInt64(li));
}
// wrong type
default:
safethrow_wrongchar(str.ptr[str.length-1],;);
}
safethrow(ERR_ENDOFSTR,;);
};
#define ParseValue(str) __ParseValue(shared, str)
Maybe __ReadValue(DeserializeSharedData* shared, bool* readingList){
char c;
string valueStr={text+1,0};
Unitype value=UniNull;
bool spaceAfterVal=false;
while ((c=*++text)) switch (c){
case ' ': case '\t':
case '\r': case '\n':
if(valueStr.length!=0)
spaceAfterVal=true;
else valueStr.ptr++;
break;
case '=': case ':':
case '}': case '$':
case '\'':
safethrow_wrongchar(c,Unitype_free(value));
case '#':;
char _c=c;
char* _text=text;
try(SkipComment(),_,;);
if(valueStr.length!=0){
text=_text;
safethrow_wrongchar(_c,Unitype_free(value));
}
valueStr.ptr=text+1; // skips '\n'
break;
case '"':
if(valueStr.length!=0) safethrow_wrongchar(c,Unitype_free(value));
try(ReadString(),maybeString,;)
value=maybeString.value;
break;
case '{':
if(valueStr.length!=0) safethrow_wrongchar(c,Unitype_free(value));
++text; // skips '{'
try(__deserialize(&text,true), val,Unitype_free(value))
value=val.value;
break;
case '[':
if(valueStr.length!=0) safethrow_wrongchar(c,Unitype_free(value));
try(ReadList(),maybeList,Unitype_free(value))
value=maybeList.value;
break;
case ']':
if(!readingList) safethrow_wrongchar(c,Unitype_free(value));
*readingList=false;
goto return_value;
case ';':
case ',':
return_value:
if(valueStr.length!=0){
if(!Unitype_isUniNull(value))
safethrow_wrongchar(c,Unitype_free(value));
try(ParseValue(valueStr),maybeParsed,;)
value=maybeParsed.value;
}
return SUCCESS(value);
default:
if(spaceAfterVal)
safethrow_wrongchar(c,Unitype_free(value));
valueStr.length++;
break;
}
safethrow(ERR_ENDOFSTR,;);
}
Maybe __deserialize(char** _text, bool _calledRecursively) {
DeserializeSharedData _shared={
.sh_text_first=*_text,
.sh_text=*_text,
.sh_partOfDollarList=false,
.sh_calledRecursively=_calledRecursively
};
DeserializeSharedData* shared=&_shared;
Hashtable* dict=Hashtable_create();
text--;
while(true){
try(ReadName(), maybeName, Hashtable_free(dict))
if(!maybeName.value.VoidPtr) // end of file or '}' in recursive call
goto END;
char* nameCPtr=maybeName.value.VoidPtr;
try(ReadValue(NULL), val, {
Hashtable_free(dict);
free(nameCPtr);
}) {
if(partOfDollarList){
partOfDollarList=false;
Autoarr(Unitype)* list;
Unitype lu;
if(Hashtable_tryGet(dict,nameCPtr, &lu)){
list=(Autoarr(Unitype)*)lu.VoidPtr;
// Key is not used in that case, because it is already added
// to the table with the first dollar list item.
free(nameCPtr);
}
else{
list=Autoarr_create(Unitype,ARR_BC,ARR_BL);
Hashtable_add(dict,nameCPtr,UniHeapPtr(Autoarr_Unitype,list));
}
Autoarr_add(list,val.value);
}
else Hashtable_add(dict,nameCPtr,val.value);
}
}
END:
*_text=text;
return SUCCESS(UniHeapPtr(Hashtable,dict));
}
Maybe DtsodV24_deserialize(char* _text) {
return __deserialize(&_text, false);
}

View File

@@ -0,0 +1,130 @@
#include "DtsodV24.h"
#include "../String/StringBuilder.h"
STRUCT(SerializeSharedData,
StringBuilder* sh_builder;
u8 sh_tabs;
)
#define b shared->sh_builder
#define tabs shared->sh_tabs
Maybe __serialize(StringBuilder* _b, u8 _tabs, Hashtable* dtsod);
#define addc(C) StringBuilder_append_char(b,C)
void __AppendTabs(SerializeSharedData* shared) {
for (u8 t = 0; t < tabs; t++)
addc( '\t');
};
#define AppendTabs() __AppendTabs(shared)
Maybe __AppendValue(SerializeSharedData* shared, Unitype u);
#define AppendValue(UNI) __AppendValue(shared, UNI)
Maybe __AppendValue(SerializeSharedData* shared, Unitype u){
if(u.typeId==ktid_name(i64)){
StringBuilder_append_i64(b,u.Int64);
}
else if(u.typeId==ktid_name(u64)){
StringBuilder_append_u64(b,u.UInt64);
addc('u');
}
else if(u.typeId==ktid_name(f64)){
StringBuilder_append_f64(b,u.Float64);
addc('f');
}
else if(u.typeId==ktid_ptrName(char)){
addc('"');
char c;
while((c=*(char*)(u.VoidPtr++))){
if(c=='\"') addc('\\');
addc(c);
}
addc('"');
}
else if(u.typeId==ktid_name(bool)){
StringBuilder_append_cptr(b, u.Bool ? "true" : "false");
}
else if(Unitype_isUniNull(u)){
safethrow("Null isn't supported in DtsodV24",;);
}
else if(u.typeId==ktid_ptrName(Autoarr_Unitype)){
if(Autoarr_length(((Autoarr_Unitype*)(u.VoidPtr)))){
addc('\n');
AppendTabs();
addc('[');
tabs++;
Autoarr_foreach(((Autoarr_Unitype*)(u.VoidPtr)), e,
addc('\n');
AppendTabs();
try(AppendValue(e),__,;);
addc(',');
);
StringBuilder_rmchar(b);
addc('\n');
tabs--;
AppendTabs();
addc(']');
}
else {
addc('[');
addc(']');
}
}
else if(u.typeId==ktid_ptrName(Hashtable)){
// check hashtable is blank
bool hashtableNotBlank=false;
Hashtable_foreach(((Hashtable*)u.VoidPtr), __,
hashtableNotBlank=true;
if(__.key) {} // weird way to disable warning
break;
);
if(hashtableNotBlank){
addc('\n');
AppendTabs();
addc('{');
addc('\n');
try(__serialize(b,tabs+1,u.VoidPtr),___,;);
AppendTabs();
addc('}');
}
else {
addc('{');
addc('}');
}
}
else {
dbg((u.typeId));
safethrow(ERR_WRONGTYPE,;);
}
return MaybeNull;
};
Maybe __serialize(StringBuilder* _b, u8 _tabs, Hashtable* dtsod){
SerializeSharedData _shared={
.sh_builder=_b,
.sh_tabs=_tabs
};
SerializeSharedData* shared=&_shared;
Hashtable_foreach(dtsod, p,
AppendTabs();
StringBuilder_append_cptr(b,p.key);
addc(':');
addc(' ');
try(AppendValue(p.value),__,;);
addc(';');
addc('\n');
);
return MaybeNull;
}
Maybe DtsodV24_serialize(Hashtable* dtsod){
StringBuilder* sb=StringBuilder_create();
try(__serialize(sb,0,dtsod),__, StringBuilder_free(sb));
char* str=StringBuilder_build(sb).ptr;
return SUCCESS(UniHeapPtr(char, str));
}

View File

@@ -0,0 +1,69 @@
#include "filesystem.h"
#include "io_includes.h"
#include "../kprint/kprint.h"
bool dir_exists(const char* path){
if(path[0]=='.'){
if(path[1]==0 || (path[1]==path_sep && path[1]==0))
return true; // dir . or ./ always exists
// else if(path[1]=='.' && path[2]==path_sep)
//TODO path_resolve because windows doesnt recognize .\ pattern
}
#if KFS_USE_WINDOWS_H
DWORD dwAttrib = GetFileAttributes(path);
return (bool)(
(dwAttrib != INVALID_FILE_ATTRIBUTES) && // file exists
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); // file is a directory
#else
struct stat stats;
i32 rez=stat(path, &stats);
return (bool)(
(rez!=-1) && // file exists
(S_ISDIR(stats.st_mode))); // file is a directory
#endif
}
Maybe dir_create(const char* path){
if (dir_exists(path))
return MaybeNull;
char* parentDir=path_parentDir(path);
dir_create(parentDir);
free(parentDir);
#if KFS_USE_WINDOWS_H
if(!CreateDirectory(path, NULL))
#else
if(mkdir(path, 0777) == -1)
#endif
{
char err[512];
IFWIN(
sprintf_s(err, 512, "can't create dicectory <%s>", path),
sprintf(err, "can't create dicectory <%s>", path));
safethrow(err,;);
}
return MaybeNull;
}
Maybe dir_delete(const char* path){
throw(ERR_NOTIMPLEMENTED);
return MaybeNull;
}
Maybe dir_getFiles(const char* path, bool recursive){
throw(ERR_NOTIMPLEMENTED);
return MaybeNull;
}
Maybe dir_getDirs(const char* path, bool recursive){
throw(ERR_NOTIMPLEMENTED);
return MaybeNull;
}
Maybe dir_findFiles(const char* path, char* searchPattern, bool recursive){
throw(ERR_NOTIMPLEMENTED);
return MaybeNull;
}
Maybe dir_findDirs(const char* path, char* searchPattern, bool recursive){
throw(ERR_NOTIMPLEMENTED);
return MaybeNull;
}

View File

@@ -13,14 +13,14 @@ Maybe dir_create(const char* path);
///@return Maybe<void>
Maybe dir_delete(const char* path);
///@return Maybe<Array_string>
///@return Maybe<char**>
Maybe dir_getFiles(const char* path, bool recursive);
///@return Maybe<Array_string>
///@return Maybe<char**>
Maybe dir_getDirs(const char* path, bool recursive);
///@return Maybe<Array_string>
///@return Maybe<char**>
Maybe dir_findFiles(const char* path, char* searchPattern, bool recursive);
///@return Maybe<Array_string>
///@return Maybe<char**>
Maybe dir_findDirs(const char* path, char* searchPattern, bool recursive);
#if __cplusplus

138
kerep/src/Filesystem/file.c Normal file
View File

@@ -0,0 +1,138 @@
#include "filesystem.h"
#include "../String/StringBuilder.h"
#include "io_includes.h"
void __file_freeMembers(void* _f){ fclose((FileHandle)_f); }
kt_define(FileHandle, __file_freeMembers, NULL)
bool file_exists(const char* path){
if(path[0]=='.'){
if(path[1]==0 || (path[1]==path_sep && path[2]==0))
return false; // . or ./ is not a file
// else if(path[1]=='.' && path[2]==path_sep)
//TODO path_resolve because windows doesnt recognize .\ pattern
}
#if KFS_USE_WINDOWS_H
DWORD dwAttrib = GetFileAttributes(path);
return (bool)(
(dwAttrib != INVALID_FILE_ATTRIBUTES) && // file exists
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); // file is not directory
#else
struct stat stats;
i32 rez=stat(path, &stats);
return (bool)(
(rez!=-1) && // file exists
!(S_ISDIR(stats.st_mode))); // file is not directory
#endif
}
Maybe file_delete(const char* path, bool recursive){
throw(ERR_NOTIMPLEMENTED);
return MaybeNull;
}
char* FileOpenMode_toStr(FileOpenMode m){
char* p;
switch(m){
case FileOpenMode_Read: p="rb"; break;
case FileOpenMode_Write: p="wb"; break;
case FileOpenMode_Append: p="ab"; break;
case FileOpenMode_ReadWrite: p="wb+"; break;
case FileOpenMode_ReadAppend: p="ab+"; break;
default:
dbg(m);
throw(ERR_UNEXPECTEDVAL);
}
return p;
}
Maybe file_open(const char* path, FileOpenMode mode){
FileHandle file=fopen(path, FileOpenMode_toStr(mode));
if(!file)
safethrow(cptr_concat("can't open file ", (char*)path),;);
return SUCCESS(UniHeapPtr(FileHandle,file));
}
Maybe file_close(FileHandle file){
if(!file)
safethrow(ERR_NULLPTR,;);
if(fclose(file))
safethrow(ERR_IO,;);
return MaybeNull;
}
#define ioWriteCheck() \
if(rezult==EOF) \
safethrow(ERR_IO_EOF,;); \
if(rezult!=0) \
safethrow(ERR_IO,;);
Maybe file_writeChar(FileHandle file, char byte){
i32 rezult=fputc(byte, file);
ioWriteCheck();
return MaybeNull;
}
Maybe file_writeBuffer(FileHandle file, char* buffer, u64 length){
i32 rezult=0;
for(u64 i=0; i<length && !rezult; i++)
rezult=fputc(buffer[i], file);
ioWriteCheck();
return MaybeNull;
}
Maybe file_writeCptr(FileHandle file, char* cptr){
i32 rezult=fputs(cptr, file);
ioWriteCheck();
return MaybeNull;
}
Maybe file_readChar(FileHandle file){
i32 rezult=fgetc(file);
if(feof(file)) safethrow(ERR_IO_EOF,;);
if(ferror(file)) safethrow(ERR_IO,;);
return SUCCESS(UniUInt64(rezult));
}
Maybe file_readBuffer(FileHandle file, char* buffer, u64 length){
i32 rezult=0;
u64 i=0;
for(; i<length && rezult!=EOF; i++){
rezult=fgetc(file);
buffer[i]=(char)rezult;
}
if(ferror(file)) safethrow(ERR_IO,;);
return SUCCESS(UniUInt64(i));
}
Maybe file_readAll(FileHandle file, char** allBytes){
i32 rezult=0;
char buffer[256];
string bufStr={.ptr=buffer, .length=sizeof(buffer)};
StringBuilder* sb=StringBuilder_create();
u64 i=0;
while(true){
rezult=fgetc(file);
if(rezult==EOF){
if(ferror(file))
safethrow(ERR_IO, StringBuilder_free(sb));
break;
}
buffer[i%sizeof(buffer)]=(char)rezult;
i++;
if(!(i%sizeof(buffer)))
StringBuilder_append_string(sb,bufStr);
}
bufStr.length=i%sizeof(buffer);
if(bufStr.length!=0)
StringBuilder_append_string(sb,bufStr);
string str=StringBuilder_build(sb);
*allBytes=str.ptr;
// i dont know how can it happen, but if it will have, it will be very dangerous
if(i!=str.length)
throw(ERR_UNEXPECTEDVAL);
return SUCCESS(UniUInt64(i));
}

View File

@@ -0,0 +1,84 @@
#include "filesystem.h"
char* __path_concat(u32 n, ...){
char** parts=(char**)malloc(n*sizeof(char*));
u32* lengths=malloc(n*sizeof(u32));
u32 totalLength=0;
// reading args from va_list
va_list vl;
va_start(vl, n);
for(u16 i=0; i<n; i++){
char* part=va_arg(vl,char*);
i16 length=cptr_length(part);
parts[i]=part;
lengths[i]=length;
totalLength+=length;
}
va_end(vl);
// allocating memory for output value
char* totality=malloc(totalLength+1);
const char* output=totality;
totality[totalLength]=0;
// copying content of all strings to rezult
u16 k=0;
for(; k<n-1; k++){
memcopy(parts[k], totality, lengths[k]);
totality+=lengths[k];
*totality=path_sep;
totality++;
}
memcopy(parts[k], totality, lengths[k]);
free(parts);
free(lengths);
return output;
}
char* path_fixSeparators(const char* path){
char* pathCopy=cptr_copy(path);
char c;
while((c=*pathCopy)){
if(c==path_notSep)
*pathCopy=path_sep;
pathCopy++;
}
return pathCopy;
}
Maybe path_throwIfEscapes(const char* path){
if(cptr_contains(path,".."))
safethrow(cptr_concat("path <",path,"> uses <..>, that's not allowed"),);
return MaybeNull;
}
char* path_parentDir(char* dir){
char* copy=cptr_copy(dir);
i32 length=cptr_length(copy);
i32 i=cptr_lastIndexOfChar(copy,path_sep);
if(i!=-1 && i==length-1){
copy[length-1]=0;
i=cptr_lastIndexOfChar(copy,path_sep);
}
if(i==-1){
free(copy);
copy=malloc(2);
copy[0]='.';
copy[1]=0;
}
return copy;
}
char* path_basename(char* path, bool with_extension){
i32 nameIndex=cptr_lastIndexOfChar(path, path_sep)+1;
string rezult=string_fromCptr(path+nameIndex);
if(!with_extension){
i32 extIndex=cptr_lastIndexOfChar(rezult.ptr, '.');
if(extIndex!=0 && extIndex!=-1)
rezult.length=extIndex;
}
return string_extract(rezult);
}

View File

@@ -0,0 +1,111 @@
#include "hash.h"
u32 hash_sdbm32(u32 oldhash, void* buf, u32 len){
u8* ubuf=(u8*)buf;
register u32 hash=oldhash;
for (; len ; len--, ubuf++)
hash=(hash<<6)+(hash<<16)-hash+*ubuf;
return hash;
}
static const u32 crc_32_tab[]={
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
u32 hash_crc32(u32 oldhash, void* buf, u32 len){
u8* ubuf=(u8*)buf;
register u32 crc=oldhash;
for (; len; --len, ++ubuf)
crc=crc_32_tab[(crc^(*ubuf)) & 0xff] ^ (crc>>8);
return ~crc;
}
// bool hashf_crc32c(char *name, u32 *crc, long *charcnt) {
// register FILE *fin;
// register u32 oldcrc32;
// register i32 c;
// oldcrc32 = 0xFFFFFFFF; *charcnt = 0;
// if ((fin=fopen(name, "r"))==NULL) {
// perror(name);
// return false;
// }
// while ((c=getc(fin))!=EOF) {
// ++*charcnt;
// oldcrc32 = UPDC32(c, oldcrc32);
// }
// if (ferror(fin)) {
// perror(name);
// *charcnt = -1;
// }
// fclose(fin);
// *crc = oldcrc32 = ~oldcrc32;
// return true;
// }

View File

@@ -0,0 +1,133 @@
#include "Hashtable.h"
kt_define(Hashtable, __Hashtable_free, NULL);
// amount of rows
static const u16 HT_HEIGHTS[]={17,61,257,1021,4099,16381,65521};
#define HT_HEIN_MIN 0
#define HT_HEIN_MAX 6
#define ARR_BC 2
#define ARR_BL 8
Hashtable* Hashtable_create(){
Hashtable* ht=malloc(sizeof(Hashtable));
ht->hein=HT_HEIN_MIN;
ht->rows=malloc(HT_HEIGHTS[HT_HEIN_MIN]*sizeof(Autoarr(KVPair)*));
for(u16 i=0;i<HT_HEIGHTS[HT_HEIN_MIN];i++)
ht->rows[i]=Autoarr_create(KVPair,ARR_BC,ARR_BL);
return ht;
}
void __Hashtable_free(void* _ht){
Hashtable* ht=_ht;
for(u16 i=0;i<HT_HEIGHTS[ht->hein];i++)
Autoarr_free(ht->rows[i], true);
free(ht->rows);
}
void Hashtable_free(Hashtable* ht){
__Hashtable_free(ht);
free(ht);
}
u16 Hashtable_height(Hashtable* ht) { return HT_HEIGHTS[ht->hein]; }
void Hashtable_expand(Hashtable* ht){
if(ht->hein>=HT_HEIN_MAX) throw(ERR_MAXLENGTH);
Autoarr(KVPair)** newrows=malloc(HT_HEIGHTS[++ht->hein]*sizeof(Autoarr(KVPair)*));
for(u16 i=0;i<HT_HEIGHTS[ht->hein];i++)
newrows[i]=Autoarr_create(KVPair,ARR_BC,ARR_BL);
for(u16 i=0;i<HT_HEIGHTS[ht->hein-1];i++){
Autoarr(KVPair)* ar=ht->rows[i];
u32 arlen=Autoarr_length(ar);
for(u32 k=0;k<arlen;k++){
KVPair p=Autoarr_get(ar,k);
u16 newrown=hashs(hash_sdbm32, p.key)%HT_HEIGHTS[ht->hein];
Autoarr(KVPair)* newar=newrows[newrown];
Autoarr_add(newar,p);
}
// there is no need to free array values, because they are copied into new array
// so dont replace this incorrect auto-generated function
Autoarr_freeWithoutMembers(ar, true);
}
free(ht->rows);
ht->rows=newrows;
}
Autoarr(KVPair)* getrow(Hashtable* ht, char* key, bool can_expand){
u32 hash=hashs(hash_sdbm32, key);
Autoarr(KVPair)* ar=ht->rows[hash%HT_HEIGHTS[ht->hein]];
if(can_expand && Autoarr_length(ar)==Autoarr_max_length(ar))
Hashtable_expand(ht);
ar=ht->rows[hash%HT_HEIGHTS[ht->hein]];
return ar;
}
/// @param key must be heap allocated
/// Hashtable_free will free this pointer
void Hashtable_add(Hashtable* ht, char* key, Unitype u){
KVPair p={ .key=key, .value=u };
Autoarr_add(getrow(ht,key,true),p);
}
void Hashtable_addMany(Hashtable* ht, KVPair* pair_array, u32 count){
for(u32 i=0; i<count; i++){
Hashtable_add(ht, pair_array[i].key, pair_array[i].value);
}
}
// returns null or pointer to value in hashtable
Unitype* Hashtable_getPtr(Hashtable* ht, char* key){
Autoarr(KVPair)* ar=getrow(ht,key,false);
u32 arlen=Autoarr_length(ar);
for(u32 i=0;i<arlen;i++){
KVPair* p=Autoarr_getPtr(ar,i);
if(cptr_equals(key,p->key)) return &p->value;
}
return NULL;
}
Unitype Hashtable_get(Hashtable* ht, char* key){
Autoarr(KVPair)* ar=getrow(ht,key,false);
u32 arlen=Autoarr_length(ar);
for(u32 i=0;i<arlen;i++){
KVPair p=Autoarr_get(ar,i);
if(cptr_equals(key,p.key)) return p.value;
}
return UniNull;
}
bool Hashtable_tryGet(Hashtable* ht, char* key, Unitype* output){
Unitype u=Hashtable_get(ht,key);
*output=u;
return !Unitype_isUniNull(u);
}
bool Hashtable_trySet(Hashtable* ht, char* key, Unitype u){
Unitype* val=Hashtable_getPtr(ht,key);
if(val==NULL)
return false;
*val=u;
return true;
}
bool Hashtable_tryAdd(Hashtable* ht, char* key, Unitype u){
Unitype* val=Hashtable_getPtr(ht,key);
if(val==NULL){
Hashtable_add(ht, key, u);
return true;
}
return false;
}
void Hashtable_addOrSet(Hashtable* ht, char* key, Unitype u){
Unitype* val=Hashtable_getPtr(ht, key);
if(val==NULL)
Hashtable_add(ht, key, u); // add
else *val=u; // set
}

View File

@@ -0,0 +1,18 @@
#include "KeyValuePair.h"
kt_define(KVPair, __KVPair_free, NULL);
Autoarr_define(KVPair, false)
// proper way to clean a KVP
void KVPair_free(KVPair p){
free(p.key);
Unitype_free(p.value);
}
void __KVPair_free(void* p){ KVPair_free(*(KVPair*)p); }
void printkvp(KVPair p){
kprintf("{\"%s\", ",p.key);
printuni(p.value);
kprintf("}");
}

View File

@@ -0,0 +1,147 @@
#include "StringBuilder.h"
kt_define(StringBuilder, __StringBuilder_free, NULL);
#define BL_C 32
#define BL_L 1024
void complete_buf(StringBuilder* b){
if(!b->compl_bufs)
b->compl_bufs=Autoarr_create(string,BL_C,BL_L);
u32 len=Autoarr_length(b->curr_buf);
if(!len) return;
string str={.length=len, .ptr=malloc(len)};
u32 i=0;
Autoarr_foreach(b->curr_buf, c,
str.ptr[i++]=c;
);
Autoarr_add(b->compl_bufs,str);
Autoarr_free(b->curr_buf, true);
b->curr_buf=Autoarr_create(i8,BL_C,BL_L);
}
void try_complete_buf(StringBuilder* b){
if(b->curr_buf->blocks_count==BL_C)
complete_buf(b);
}
StringBuilder* StringBuilder_create(){
StringBuilder* b=malloc(sizeof(StringBuilder));
b->compl_bufs=NULL;
b->curr_buf=Autoarr_create(i8,BL_C,BL_L);
return b;
}
void __StringBuilder_free(void* _b){
StringBuilder* b=_b;
if(b->compl_bufs) Autoarr_free(b->compl_bufs, true);
Autoarr_free(b->curr_buf, true);
}
void StringBuilder_free(StringBuilder* b){
__StringBuilder_free(b);
free(b);
}
string StringBuilder_build(StringBuilder* b){
complete_buf(b);
u32 len=0;
Autoarr_foreach(b->compl_bufs, cs,
len+=cs.length;
);
string str= { .length=len, .ptr=malloc(len+1) };
str.ptr[len]='\0';
u32 i=0;
Autoarr_foreach(b->compl_bufs, cs,
for(u32 n=0;n<cs.length;n++)
str.ptr[i++]=cs.ptr[n];
free(cs.ptr);
);
StringBuilder_free(b);
return str;
}
void StringBuilder_rmchar(StringBuilder* b){
if(b->curr_buf->block_length!=0)
Autoarr_pop(b->curr_buf)
else {
if(!b->compl_bufs) throw(ERR_NULLPTR);
string* lastcb=Autoarr_getPtr(b->compl_bufs, (Autoarr_length(b->compl_bufs)-1));
lastcb->length--;
}
}
void StringBuilder_append_char(StringBuilder* b, char c){
try_complete_buf(b);
Autoarr_add(b->curr_buf,c);
}
void StringBuilder_append_string(StringBuilder* b, string s){
complete_buf(b);
Autoarr_add(b->compl_bufs, string_copy(s));
}
void StringBuilder_append_cptr(StringBuilder* b, char* s){
string str={
.ptr=s,
.length=cptr_length(s)
};
StringBuilder_append_string(b,str);
}
void curr_buf_add_string(StringBuilder* b, string s){
for(u32 i=0; i<s.length; i++)
Autoarr_add(b->curr_buf,s.ptr[i]);
}
void StringBuilder_append_i64(StringBuilder* b, i64 a){
try_complete_buf(b);
u8 i=0;
if(a==0){
Autoarr_add(b->curr_buf,'0');
return;
}
else if(a<0){
Autoarr_add(b->curr_buf,'-');
a=-a;
}
char buf[24];
while(a!=0){
buf[i++]='0'+a%10;
a/=10;
}
string rev=string_reverse((string){buf,i});
curr_buf_add_string(b,rev);
free(rev.ptr);
}
void StringBuilder_append_u64(StringBuilder* b, u64 a){
try_complete_buf(b);
u8 i=0;
if(a==0){
Autoarr_add(b->curr_buf,'0');
return;
}
char buf[24];
while(a!=0){
buf[i++]='0'+a%10;
a/=10;
}
string rev=string_reverse((string){buf,i});
curr_buf_add_string(b,rev);
free(rev.ptr);
}
void StringBuilder_append_f64(StringBuilder* b, f64 a){
try_complete_buf(b);
char buf[32];
IFMSC(
sprintf_s(buf,32,"%lf",a),
sprintf(buf,"%lf",a)
);
curr_buf_add_string(b, (string){.ptr=buf, .length=cptr_length(buf)});
}

47
kerep/src/String/string.c Normal file
View File

@@ -0,0 +1,47 @@
#include "string.h"
kt_define(string, NULL, NULL);
Autoarr_define(string, false);
// copies str content to new char pointer value (adding '\0' at the end)
char* string_extract(string str){
if(str.length==0) return NULL;
char* cptr=malloc(str.length*sizeof(char)+1);
cptr[str.length]=0;
while(str.length-->0)
cptr[str.length]=str.ptr[str.length];
return cptr;
}
// copies src.ptr content to new string and adds \0 at the end
string string_copy(string src){
if(!src.ptr)
return src;
string nstr;
nstr.length=src.length;
nstr.ptr=malloc(nstr.length+1);
for(u32 i=0;i<nstr.length;i++)
nstr.ptr[i]=src.ptr[i];
nstr.ptr[nstr.length]='\0';
return nstr;
}
// compares two strings, NullPtr-friendly
bool string_compare(string str0, string str1){
if(str0.length!=str1.length) return false;
if(!str0.ptr) return str1.ptr ? false : true;
else if(!str1.ptr) return false;
while(str0.length-->0)
if(*str0.ptr++ != *str1.ptr++)
return false;
return true;
}
// creates new string which is reversed variant of <s>
string string_reverse(string s){
if(s.length==0) return s;
string r={malloc(s.length), s.length};
for(u32 i=0; i<s.length; i++)
r.ptr[i]=s.ptr[s.length-i-1];
return r;
}

217
kerep/src/base/cptr.c Normal file
View File

@@ -0,0 +1,217 @@
#include "base.h"
#include "../String/StringBuilder.h"
#include <ctype.h>
// returns length of char buffer (without \0)
u32 cptr_length(const char* str){
const char *const str_first=str;
while(*str)
str++;
return str-str_first;
}
// allocates new char[] and copies src there
char* cptr_copy(const char* src){
u32 len=cptr_length(src)+1;
char* dst=malloc(len);
while(len--!=0)
dst[len]=src[len];
return dst;
}
// multiplies char n times
char* char_multiply(char c, u32 n){
char* rez=malloc(n+1);
rez[n]=0;
while(n--!=0)
rez[n]=c;
return rez;
}
bool cptr_equals(const char* key0, const char* key1){
char c0=*key0;
char c1=*key1;
bool eq=c0==c1;
while(c0 && c1 && eq) {
c0=*++key0;
c1=*++key1;
eq=c0==c1;
}
return eq;
}
bool cptr_startsWith(const char* src, const char* fragment){
char c0=*src;
char c1=*fragment;
bool eq=c0==c1 && c0 !=0 && c1!=0;
while(c0 && c1 && eq) {
c0=*++src;
c1=*++fragment;
eq=c0==c1;
if(c1==0)
return true;
}
return eq;
}
bool cptr_endsWith(const char* src, const char* fragment){
u32 src_len=cptr_length(src);
u32 fr_len=cptr_length(fragment);
if(src_len<fr_len || src_len==0 || fr_len==0)
return false;
src+=src_len-fr_len;
return cptr_equals(src, fragment);
}
i32 cptr_seek(const char* src, const char* fragment, u32 startIndex, u32 seekLength){
char sc=*src, fc=*fragment;
if(sc==0 || fc==0)
return -1;
u32 fr_start=startIndex;
for(u32 si=startIndex; si-startIndex<seekLength && sc!=0; si++){
sc=src[si];
fc=fragment[si-fr_start];
if(fc==0)
return fr_start;
if(sc!=fc)
fr_start++;
}
return -1;
}
i32 cptr_seekReverse(const char* src, const char* fragment, u32 startIndex, u32 seekLength){
char sc=*src, fc=*fragment;
if(sc==0 || fc==0)
return -1;
i32 len=cptr_length(src);
if(startIndex==(u32)-1)
startIndex=len-1;
u32 fr_len=cptr_length(fragment);
for(u32 si=startIndex; si<(u32)-1 && si!=len-1-seekLength; si--){
if(si+1<fr_len)
return -1;
sc=src[si];
fc=fragment[0];
u32 fr_start=si;
for(u32 fi=0; fc==sc ; fi++){
if(fi==fr_len)
return fr_start;
fc=fragment[fi];
sc=src[si--];
}
}
return -1;
}
i32 cptr_seekChar(const char* src, char fragment, u32 startIndex, u32 seekLength){
char sc=*src;
if(sc==0 || fragment==0)
return -1;
for(u32 si=startIndex; si-startIndex<seekLength && sc!=0; si++){
sc=src[si];
if(sc==fragment)
return si;
}
return -1;
}
i32 cptr_seekCharReverse(const char* src, char fragment, u32 startIndex, u32 seekLength){
char sc=*src;
if(sc==0 || fragment==0)
return -1;
i32 len=cptr_length(src);
if(startIndex==(u32)-1)
startIndex=len-1;
for(u32 si=startIndex; si<(u32)-1 && si!=len-1-seekLength; si--){
sc=src[si];
if(sc==fragment)
return si;
}
return -1;
}
void memcopy(void* from, void* to, u32 size){
if(from==NULL || to==NULL)
throw(ERR_NULLPTR);
for(u32 i=0; i<size; i++)
((char*)to)[i]=((char*)from)[i];
}
char* __cptr_concat(u32 n, ...){
char** strs=(char**)malloc(n*sizeof(char*));
u32* lengths=malloc(n*sizeof(u32));
u32 totalLength=0;
// reading args from va_list
va_list vl;
va_start(vl, n);
for(u16 i=0; i<n; i++){
char* str=va_arg(vl,char*);
i16 length=cptr_length(str);
strs[i]=str;
lengths[i]=length;
totalLength+=length;
}
va_end(vl);
// allocating memory for output value
char* totality=malloc(totalLength+1);
char* output=totality;
totality[totalLength]=0;
// copying content of all strings to rezult
for(u16 k=0; k<n; k++){
memcopy(strs[k], totality, lengths[k]);
totality+=lengths[k];
}
free(strs);
free(lengths);
return output;
}
char* cptr_toLower(const char* src) {
u32 length=cptr_length(src);
char *p=malloc(length+1);
p[length]=0;
for(u32 i=0; i<length; i++)
p[i]=tolower(src[i]);
return p;
}
char* cptr_toUpper(const char* src) {
u32 length=cptr_length(src);
char *p=malloc(length+1);
p[length]=0;
for(u32 i=0; i<length; i++)
p[i]=toupper(src[i]);
return p;
}
char* cptr_replaceCharIn(const char* src, char c_old, char c_new, u32 startIndex, u32 seekLength){
char* rzlt=cptr_copy(src);
for(u32 i=startIndex; i!=seekLength && src[i]!=0; i++){
if(src[i]==c_old)
rzlt[i]=c_new;
}
return rzlt;
}
char* cptr_replaceIn(const char* src, const char* str_old, const char* str_new, u32 startIndex, u32 seekLength){
StringBuilder* sb=StringBuilder_create();
const u32 str_old_len=cptr_length(str_old);
const u32 str_new_len=cptr_length(str_new);
i32 i=startIndex;
while( (i=cptr_seek(src, str_old, startIndex, seekLength)) !=-1 ){
if(i!=0)
StringBuilder_append_string(sb, (string){.ptr=(char*)src, .length=i});
StringBuilder_append_string(sb, (string){.ptr=str_new, .length=str_new_len});
src+=i+str_old_len;
}
u32 src_remains_len=cptr_length(src);
if(src_remains_len>0)
StringBuilder_append_string(sb, (string){.ptr=(char*)src, .length=src_remains_len});
string rezult=StringBuilder_build(sb);
return rezult.ptr;
}

13
kerep/src/base/endian.c Normal file
View File

@@ -0,0 +1,13 @@
#include "endian.h"
static const union
{
u16 number;
Endian bytes[2];
} _endian_union={ .number=0x0102 };
Endian getEndian(){
// if 0x0102 == { 1, 2 } then BigEndian
// if 0x0102 == { 2, 1 } then LittleEndian
return _endian_union.bytes[1];
}

59
kerep/src/base/errors.c Normal file
View File

@@ -0,0 +1,59 @@
#include "std.h"
#include "errors.h"
#include "cptr.h"
#include "../kprint/kprintf.h"
char* errname(ErrorId err){
switch(err){
case SUCCESS: return nameof(SUCCESS);
case ERR_MAXLENGTH: return nameof(ERR_MAXLENGTH);
case ERR_WRONGTYPE: return nameof(ERR_WRONGTYPE);
case ERR_WRONGINDEX: return nameof(ERR_WRONGINDEX);
case ERR_NOTIMPLEMENTED: return nameof(ERR_NOTIMPLEMENTED);
case ERR_NULLPTR: return nameof(ERR_NULLPTR);
case ERR_ENDOFSTR: return nameof(ERR_ENDOFSTR);
case ERR_KEYNOTFOUND: return nameof(ERR_KEYNOTFOUND);
case ERR_FORMAT: return nameof(ERR_FORMAT);
case ERR_UNEXPECTEDVAL: return nameof(ERR_UNEXPECTEDVAL);
case ERR_IO: return nameof(ERR_IO);
case ERR_IO_EOF: return nameof(ERR_IO_EOF);
default: return "UNKNOWN_ERROR";
}
}
#define ERRMSG_MAXLENGTH 1024
char* __genErrMsg(const char* errmsg, const char* srcfile, i32 line, const char* funcname){
size_t bufsize=ERRMSG_MAXLENGTH;
char* rezult=malloc(bufsize);
IFMSC(
sprintf_s(rezult,bufsize,"[%s:%d] %s() throwed error: %s",srcfile,line,funcname,errmsg),
sprintf(rezult,"[%s:%d] %s() throwed error: %s",srcfile,line,funcname,errmsg)
);
return rezult;
}
char* __extendErrMsg(const char* errmsg, const char* srcfile, i32 line, const char* funcname){
size_t bufsize=cptr_length(errmsg)+ERRMSG_MAXLENGTH;
char* rezult=malloc(bufsize);
IFMSC(
sprintf_s(rezult,bufsize,"%s\n \\___[%s:%d] %s()",errmsg,srcfile,line,funcname),
sprintf(rezult,"%s\n \\___[%s:%d] %s()",errmsg,srcfile,line,funcname)
);
free(errmsg);
return rezult;
}
void Maybe_free(Maybe e){
free(e.errmsg);
Unitype_free(e.value);
}
void printMaybe(Maybe e){
if(e.errmsg) kprintf("%s\n",e.errmsg);
else printuni(e.value);
}
char* __doNothing(char* a) {return a;}
char* __unknownErr() {return "UNKNOWN ERROR";}

View File

@@ -38,6 +38,10 @@ typedef u8 bool;
#define false 0
#endif
#ifndef typeof
#define typeof __typeof__
#endif
#define dbg(N) kprintf("\e[95m%d\n",N)
#define nameof(V) #V

View File

@@ -0,0 +1,238 @@
#include "base_toString.h"
#include "../base.h"
#include "../../kprint/kprint_format.h"
// accepts char* (ptr to char) and char* (ptr to string)
// uses format kp_s and kp_c to determine what type is <c> argument
char* __toString_char(void* c, u32 fmt) {
// *c=char*
if(kp_fmt_dataFormat(fmt)==kp_s){
return cptr_copy((char*)c); // to avoid segmentation fault on free() when *c allocalet on stack
}
// *c=char
if(kp_fmt_dataFormat(fmt)==kp_c){
char* cc=malloc(2);
cc[0]=*(char*)c;
cc[1]=0;
return cc;
}
else throw(ERR_FORMAT);
}
char* __toString_bool(void* c, u32 fmt) {
static const char _strbool[4][6]={ "false", "true\0", "False", "True\0" };
u8 strind=*(bool*)c==1 + kp_fmt_isUpper(fmt)*2;
char* rez=malloc(6);
rez[0]=_strbool[strind][0];
rez[1]=_strbool[strind][1];
rez[2]=_strbool[strind][2];
rez[3]=_strbool[strind][3];
rez[4]=_strbool[strind][4];
rez[5]=0;
return rez;
}
char* toString_i64(i64 n){
i64 d=n<0 ? -1*n : n;
char str[32];
u8 i=sizeof(str);
str[--i]=0;
if(d==0)
str[--i]='0';
else while(d!=0){
str[--i]='0' + d%10;
d/=10;
}
if(n<0)
str[--i]='-';
return cptr_copy((char*)str+i);
}
char* toString_u64(u64 n, bool withPostfix, bool uppercase){
char str[32];
u8 i=sizeof(str);
str[--i]=0;
if(withPostfix)
str[--i]= uppercase ? 'U' : 'u';
if(n==0)
str[--i]='0';
else while(n!=0){
str[--i]='0' + n%10;
n/=10;
}
return cptr_copy((char*)str+i);
}
#define _toString_float_impl(bufsize, maxPrecision) { \
char str[bufsize]; \
if(precision>maxPrecision) \
throw("too big precision"); \
if(precision==0) \
precision=toString_float_default_precision; \
i32 cn=IFMSC( \
sprintf_s(str, bufsize, "%.*f", precision, n), \
sprintf(str, "%.*f", precision, n) \
); \
/* remove trailing zeroes except .0*/ \
while(str[cn-1]=='0' && str[cn-2]!='.') \
cn--; \
if(withPostfix) \
str[cn++]= uppercase ? 'F' : 'f'; \
str[cn]='\0'; \
return cptr_copy(str); \
}
char* toString_f32(f32 n, u8 precision, bool withPostfix, bool uppercase)
_toString_float_impl(48, toString_f32_max_precision)
char* toString_f64(f64 n, u8 precision, bool withPostfix, bool uppercase)
_toString_float_impl(512, toString_f64_max_precision)
#define byte_to_bits(byte) { \
str[cn++]='0' + (u8)((byte>>7)&1); /* 8th bit */ \
str[cn++]='0' + (u8)((byte>>6)&1); /* 7th bit */ \
str[cn++]='0' + (u8)((byte>>5)&1); /* 6th bit */ \
str[cn++]='0' + (u8)((byte>>4)&1); /* 5th bit */ \
str[cn++]='0' + (u8)((byte>>3)&1); /* 4th bit */ \
str[cn++]='0' + (u8)((byte>>2)&1); /* 3th bit */ \
str[cn++]='0' + (u8)((byte>>1)&1); /* 2th bit */ \
str[cn++]='0' + (u8)((byte>>0)&1); /* 1th bit */ \
}
char* toString_bin(void* _bytes, u32 size, bool inverse, bool withPrefix){
char* bytes=_bytes;
char* str=malloc(size*8 + (withPrefix?2:0) +1);
u32 cn=0; // char number
if(withPrefix){
str[cn++]='0';
str[cn++]='b';
}
if(inverse){
// byte number
for(i32 bn=size-1; bn>=0; bn--)
byte_to_bits(bytes[bn])
} else {
for(u32 bn=0; bn<size; bn++)
byte_to_bits(bytes[bn])
}
str[cn]=0;
return str;
}
// converts number from 0 to F to char
char _4bitsHex(u8 u, bool uppercase){
switch(u){
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
return '0'+u;
case 0xA: case 0xB: case 0xC:
case 0xD: case 0xE: case 0xF:
return (uppercase ? 'A' : 'a') + u -10;
default:
dbg(u);
throw("incorrect number");
return 219;
}
}
char* toString_hex(void* _bytes, u32 size, bool inverse, bool withPrefix, bool uppercase){
char* bytes=_bytes;
char* str=malloc(size*2 + (withPrefix?2:0) + 1);
u32 cn=0; // char number
if(withPrefix){
str[cn++]='0';
str[cn++]='x';
}
// left to right
if(inverse){
// byte number
for(i32 bn=size-1; bn>=0; bn--){
unsigned char byte=bytes[bn];
str[cn++]=_4bitsHex(byte/16, uppercase);
str[cn++]=_4bitsHex(byte%16, uppercase);
}
}
// right to left
else {
for(u32 bn=0; bn<size; bn++){ // byte number
unsigned char byte=bytes[bn];
str[cn++]=_4bitsHex(byte/16, uppercase);
str[cn++]=_4bitsHex(byte%16, uppercase);
}
}
str[cn]=0;
return str;
}
#define __toString_i32_def(BITS) char* __toString_i##BITS(void* _n, u32 f){ \
switch(kp_fmt_dataFormat(f)){ \
case kp_i: ; \
i##BITS n=*(i##BITS*)_n; \
return toString_i64(n); \
case kp_b: \
return toString_bin(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f)); \
case kp_h: \
return toString_hex(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f)); \
default: \
kprintf("\n%u\n", kp_fmt_dataFormat(f)); \
throw(ERR_FORMAT); \
return NULL; \
} \
}
__toString_i32_def(8)
__toString_i32_def(16)
__toString_i32_def(32)
__toString_i32_def(64)
#define __toString_u_def(BITS) char* __toString_u##BITS(void* _n, u32 f){ \
switch(kp_fmt_dataFormat(f)){ \
case kp_u: ; \
u##BITS n=*(u##BITS*)_n; \
return toString_u64(n, kp_fmt_withPostfix(f), kp_fmt_isUpper(f)); \
case kp_b: \
return toString_bin(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f)); \
case kp_h: \
return toString_hex(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f)); \
default: \
kprintf("\n%u\n", kp_fmt_dataFormat(f)); \
throw(ERR_FORMAT); \
return NULL; \
} \
}
__toString_u_def(8)
__toString_u_def(16)
__toString_u_def(32)
// __toString_u_def(64)
char* __toString_u64(void* _n, u32 f){
switch(kp_fmt_dataFormat(f)){
case kp_u: ;
u64 n=*(u64*)_n;
return toString_u64(n, kp_fmt_withPostfix(f), kp_fmt_isUpper(f));
case kp_b:
return toString_bin(_n, 64/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f));
case kp_h:
return toString_hex(_n, 64/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f));
default:
kprintf("\n%u\n", kp_fmt_dataFormat(f)); throw(ERR_FORMAT); return NULL; }
}
#define __toString_float_def(BITS) char* __toString_f##BITS(void* _n, u32 f){ \
switch(kp_fmt_dataFormat(f)){ \
case kp_f: ; \
f##BITS n=*(f##BITS*)_n; \
return toString_f64(n, toString_float_default_precision, kp_fmt_withPostfix(f), kp_fmt_isUpper(f)); \
case kp_b: \
return toString_bin(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f)); \
case kp_h: \
return toString_hex(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f)); \
default: \
kprintf("\n%u\n", kp_fmt_dataFormat(f)); \
throw(ERR_FORMAT); \
return NULL; \
} \
}
__toString_float_def(32)
__toString_float_def(64)

View File

@@ -0,0 +1,65 @@
#include "../base.h"
#include "../../Autoarr/Autoarr.h"
#include "../../Hashtable/Hashtable.h"
#include "../../String/StringBuilder.h"
#include "../../Filesystem/filesystem.h"
#include "base_toString.h"
void kt_initKerepTypes(){
// base types
kt_register(Pointer);
if(ktid_Pointer!=0) // this can break UnitypeNull
throw("ktid_Pointer!=0, you must init kerep types before any other types");
kt_register(char);
kt_register(bool);
kt_register(f32);
kt_register(f64);
kt_register(i8);
kt_register(u8);
kt_register(i16);
kt_register(u16);
kt_register(i32);
kt_register(u32);
kt_register(i64);
kt_register(u64);
// ktDescriptor
kt_register(ktDescriptor);
// base type autoarrs
kt_register(Autoarr_Pointer);
kt_register(Autoarr_char);
kt_register(Autoarr_bool);
kt_register(Autoarr_f32);
kt_register(Autoarr_f64);
kt_register(Autoarr_i8);
kt_register(Autoarr_u8);
kt_register(Autoarr_i16);
kt_register(Autoarr_u16);
kt_register(Autoarr_i32);
kt_register(Autoarr_u32);
kt_register(Autoarr_i64);
kt_register(Autoarr_u64);
// Unitype
kt_register(Unitype);
kt_register(Autoarr_Unitype);
// KeyValuePair
kt_register(KVPair);
kt_register(Autoarr_KVPair);
// Hashtable
kt_register(Hashtable);
// string
kt_register(string);
kt_register(Autoarr_string);
// StringBuilder
kt_register(StringBuilder);
//File
kt_register(FileHandle);
}

View File

@@ -0,0 +1,90 @@
#include "../../Autoarr/Autoarr.h"
#include "type_system.h"
#include "base_toString.h"
kt_define(Pointer, NULL, __toString_u64);
kt_define(char,NULL, __toString_char);
kt_define(bool,NULL, __toString_bool);
kt_define(f32, NULL, __toString_f32);
kt_define(f64, NULL, __toString_f64);
kt_define(i8, NULL, __toString_i8);
kt_define(u8, NULL, __toString_u8);
kt_define(i16, NULL, __toString_i16);
kt_define(u16, NULL, __toString_u16);
kt_define(i32, NULL, __toString_i32);
kt_define(u32, NULL, __toString_u32);
kt_define(i64, NULL, __toString_i64);
kt_define(u64, NULL, __toString_u64);
char* ktDescriptor_toString(ktDescriptor* d){
const char* n="null";
char *s0 = toString_u64(d->id, 0,0);
char *s1 = toString_u64(d->size, 0,0);
char *s2 = d->toString ? toString_hex(d->toString, sizeof(void*), 0,1,0) : n;
char *s3 = d->freeMembers ? toString_hex(d->freeMembers, sizeof(void*), 0,1,0) : n;
char *rez=cptr_concat("ktDescriptor {"
" name:", d->name,
" id:",s0,
" size:",s1,
" toString:",s2,
" freeMembers:",s3,
" }");
free(s0);
free(s1);
if(s2!=n) free(s2);
if(s3!=n) free(s3);
return rez;
}
char* _ktDescriptor_toString(void* _d, u32 fmt) { return ktDescriptor_toString(_d); }
kt_define(ktDescriptor, NULL, _ktDescriptor_toString);
typedef ktDescriptor* ktDescriptor_Ptr;
// type descriptors are stored here during initialization
Autoarr(Pointer)* __descriptorPointers=NULL;
// here type descriptors are stored when initialization is complited
ktDescriptor** typeDescriptors=NULL;
ktid ktid_last=-1;
ENUM(ktDescriptorsState,
NotInitialized, Initializing, Initialized
)
ktDescriptorsState initState=NotInitialized;
void kt_beginInit(){
#if DEBUG
kprintf("\e[94mtype descriptors initializing...\n");
#endif
__descriptorPointers=Autoarr_create(Pointer, 256, 256);
}
void kt_endInit(){
if(__descriptorPointers==NULL)
throw(ERR_NULLPTR);
typeDescriptors=(ktDescriptor**)Autoarr_toArray(__descriptorPointers);
Autoarr_free(__descriptorPointers,true);
if(typeDescriptors==NULL) throw(ERR_NULLPTR);
#if DEBUG
kprintf("\e[92minitialized %u type descriptors\n", ktid_last);
#endif
}
void __kt_register(ktDescriptor* descriptor){
descriptor->id=++ktid_last;
Autoarr_add(__descriptorPointers, descriptor);
}
ktDescriptor* ktDescriptor_get(ktid id){
if(id>ktid_last || id==ktid_undefined) {
kprintf("\ntype id: %u\n",id);
throw("invalid type id");
}
return typeDescriptors[id];
}
void kt_free(){
free(typeDescriptors);
}

View File

@@ -0,0 +1,100 @@
#include "../../kprint/kprint_format.h"
#include "../base.h"
char *__Unitype_toString(void *_u, u32 fmt)
{
return Unitype_toString(*(Unitype *)_u, fmt);
}
kt_define(Unitype, __UnitypePtr_free, __Unitype_toString);
void Unitype_free(Unitype u)
{
if (u.typeId == ktid_undefined)
{
if (u.VoidPtr != NULL)
throw("unitype with undefined typeId has value");
return;
}
ktDescriptor *type = ktDescriptor_get(u.typeId);
if (type->freeMembers)
type->freeMembers(u.VoidPtr);
if (u.allocatedInHeap)
free(u.VoidPtr);
}
void __UnitypePtr_free(void *u)
{
Unitype_free(*(Unitype *)u);
}
char *Unitype_toString(Unitype u, u32 fmt)
{
if (u.typeId == ktid_undefined)
{
if (u.VoidPtr != NULL)
throw("unitype with undefined typeId has value");
return cptr_copy("{ERROR_TYPE}");
}
if (fmt == 0)
{
if (u.typeId == ktid_name(bool) || u.typeId == ktid_name(i8) || u.typeId == ktid_name(i16) ||
u.typeId == ktid_name(i32) || u.typeId == ktid_name(i64))
{
// auto format set
fmt = kp_i;
// replaces value with pointer to value to pass into toString_i64(void*, u32)
i64 value = u.Int64;
u.VoidPtr = &value;
}
else if (u.typeId == ktid_name(u8) || u.typeId == ktid_name(u16) || u.typeId == ktid_name(u32) ||
u.typeId == ktid_name(u64))
{
fmt = kp_u;
u64 value = u.UInt64;
u.VoidPtr = &value;
}
else if (u.typeId == ktid_name(f32) || u.typeId == ktid_name(f64))
{
fmt = kp_f;
f64 value = u.Float64;
u.VoidPtr = &value;
}
else if (u.typeId == ktid_name(char))
{
fmt = kp_c;
i64 value = u.Int64;
u.VoidPtr = &value;
}
else if (u.typeId == ktid_ptrName(char))
{
fmt = kp_s;
}
else if (u.typeId == ktid_name(Pointer))
{
if (u.VoidPtr == NULL)
return cptr_copy("{ UniNull }");
fmt = kp_h;
}
}
ktDescriptor *type = ktDescriptor_get(u.typeId);
char *valuestr;
if (type->toString)
valuestr = type->toString(u.VoidPtr, fmt);
else
valuestr = "ERR_NO_TOSTRING_FUNC";
char *rezult = cptr_concat("{ type: ", type->name, ", allocated on heap: ", (u.allocatedInHeap ? "true" : "false"),
", value:", valuestr, " }");
if (type->toString)
free(valuestr);
return rezult;
}
void printuni(Unitype v)
{
char *s = Unitype_toString(v, 0);
fputs(s, stdout);
free(s);
}

211
kerep/src/kprint/kprint.c Normal file
View File

@@ -0,0 +1,211 @@
#include "../String/StringBuilder.h"
#include "kprint.h"
ktid __typeFromFormat(kp_fmt f){
ktid typeId=kp_fmt_ktid(f);
if(typeId)
return typeId;
switch(kp_fmt_dataFormat(f)){
case kp_i:
case kp_h:
case kp_b:
return ktid_name(i64);
case kp_u:
return ktid_name(u64);
case kp_f:
return ktid_name(f64);
case kp_c:
return ktid_name(char);
case kp_s:
return ktid_ptrName(char);
default:
return ktid_undefined;
}
}
Maybe __next_toString(kp_fmt f, void* object){
// detecting type
ktid typeId=__typeFromFormat(f);
if(typeId==ktid_undefined)
safethrow("typeId is undefined, can't autodetect type",;);
if(typeId==ktid_ptrName(char))
object=*(char**)object; // dereferencing char** to char*
ktDescriptor* type=ktDescriptor_get(typeId);
if(!type->toString)
safethrow("type descriptor doesnt have toString() func",;);
return SUCCESS(UniHeapPtr(char, type->toString(object, f)));
}
Maybe check_argsN(u8 n){
if(n%2 != 0) safethrow("kprint recieved non-even number of arguments",;);
if(n > 32) safethrow("kprint recieved >32 number of arguments",;);
return MaybeNull;
}
Maybe __ksprint(u8 n, kp_fmt* formats, __kp_value_union* objects){
try(check_argsN(n), _,;);
n/=2;
StringBuilder* strb=StringBuilder_create();
for(u8 i=0; i<n; i++){
try(__next_toString(formats[i], &objects[i]),mStr,;);
StringBuilder_append_cptr(strb, mStr.value.VoidPtr);
Unitype_free(mStr.value);
}
char* rezult=StringBuilder_build(strb).ptr;
return SUCCESS(UniHeapPtr(char, rezult));
}
Maybe __kfprint(FILE* file, u8 n, kp_fmt* formats, __kp_value_union* objects){
try(check_argsN(n), _,;);
n/=2;
for(u8 i=0; i<n; i++){
try(__next_toString(formats[i], &objects[i]),maybeStr,;);
if(fputs(maybeStr.value.VoidPtr, file)==EOF)
safethrow("can't write string to file", Unitype_free(maybeStr.value));
Unitype_free(maybeStr.value);
}
fflush(file);
return MaybeNull;
}
void __kprint(u8 n, kp_fmt* formats, __kp_value_union* objects){
tryLast(check_argsN(n), _,;);
n/=2;
for(u8 i=0; i<n; i++){
kp_fmt fmt=formats[i];
kprint_setColor(fmt);
tryLast(__next_toString(fmt, &objects[i]),maybeStr, kprint_setColor(kp_bgBlack|kp_fgGray));
if(fputs(maybeStr.value.VoidPtr, stdout)==EOF) \
throw("can't write string to stdout");
//, Unitype_free(maybeStr.value)
Unitype_free(maybeStr.value);
}
fflush(stdout);
}
#if defined(_WIN32)|| defined(_WIN64)
#include <windows.h>
#define FOREGROUND_YELLOW FOREGROUND_GREEN | FOREGROUND_RED
DWORD kp_fgColor_toWin(kp_fgColor f){
//kprintf("fg: %x\n", f);
switch(f){
case kp_fgBlack: return 0;
case kp_fgRedD: return FOREGROUND_RED;
case kp_fgGreenD: return FOREGROUND_GREEN;
case kp_fgYellowD: return FOREGROUND_GREEN | FOREGROUND_RED;
case kp_fgBlueD: return FOREGROUND_BLUE;
case kp_fgMagentaD: return FOREGROUND_RED | FOREGROUND_BLUE;
case kp_fgCyanD: return FOREGROUND_BLUE | FOREGROUND_GREEN;
case kp_fgGray: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
case kp_fgGrayD: return FOREGROUND_INTENSITY;
case kp_fgRed: return FOREGROUND_RED | FOREGROUND_INTENSITY;
case kp_fgGreen: return FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case kp_fgYellow: return FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
case kp_fgBlue: return FOREGROUND_BLUE | FOREGROUND_INTENSITY;
case kp_fgMagenta: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
case kp_fgCyan: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case kp_fgWhite: return FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
default: throw(ERR_FORMAT);
}
}
DWORD kp_bgColor_toWin(kp_bgColor f){
//kprintf("bg: %x\n", f);
switch(f){
case kp_bgBlack: return 0;
case kp_bgRedD: return BACKGROUND_RED;
case kp_bgGreenD: return BACKGROUND_GREEN;
case kp_bgYellowD: return BACKGROUND_GREEN | BACKGROUND_RED;
case kp_bgBlueD: return BACKGROUND_BLUE;
case kp_bgMagentaD: return BACKGROUND_RED | BACKGROUND_BLUE;
case kp_bgCyanD: return BACKGROUND_BLUE | BACKGROUND_GREEN;
case kp_bgGray: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
case kp_bgGrayD: return BACKGROUND_INTENSITY;
case kp_bgRed: return BACKGROUND_RED | BACKGROUND_INTENSITY;
case kp_bgGreen: return BACKGROUND_GREEN | BACKGROUND_INTENSITY;
case kp_bgYellow: return BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
case kp_bgBlue: return BACKGROUND_BLUE | BACKGROUND_INTENSITY;
case kp_bgMagenta: return BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
case kp_bgCyan: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
case kp_bgWhite: return BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
default: throw(ERR_FORMAT);
}
}
void kprint_setColor(kp_fmt f){
DWORD color=0;
if(!kp_fmt_fgColorSet(f) & !kp_fmt_bgColorSet(f))
return;
if(kp_fmt_fgColorSet(f))
color+=kp_fgColor_toWin(kp_fmt_fgColor(f));
if(kp_fmt_bgColorSet(f))
color+=kp_bgColor_toWin(kp_fmt_bgColor(f));
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
}
#else
void kprint_setColor(kp_fmt f){
if(kp_fmt_fgColorSet(f)){
u8 fg=(f&0x0f000000)>>24;
if(fg<8) fg+=30;
else fg+=90-8;
printf("\e[%um", fg);
}
if(kp_fmt_bgColorSet(f)){
u8 bg=(f&0x00f00000)>>20;
if(bg<8) bg+=40;
else bg+=100-8;
printf("\e[%um", bg);
}
}
#endif
/* Maybe ksprint_ar(u32 count, kp_fmt format, ktid typeId, void* array){
ktDescriptor* type=ktDescriptor_get(format.typeId);
if(!type->toString)
safethrow("type descriptor doesnt have toString() func",;);
StringBuilder* strb=StringBuilder_create();
StringBuilder_append_char(strb, '[');
for (u16 e=1; e<count; e++){
StringBuilder_append_char(strb, ' ');
char* elStr=type->toString(array+type->size*e, &format);
StringBuilder_append_cptr(strb, elStr);
StringBuilder_append_char(strb, ',');
}
StringBuilder_rmchar(strb);
StringBuilder_append_char(strb, ' ');
StringBuilder_append_char(strb, ']');
} */
static const char* _kp_colorNames[16]={
"black",
"dark_red",
"dark_green",
"dark_yellow",
"dark_blue",
"dark_magenta",
"dark_cyan",
"gray",
"dark_gray",
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
"white"
};
char* kp_bgColor_toString(kp_bgColor c){
u32 color_index=(c&0x00f00000)>>20;
if(color_index>15) throw(ERR_WRONGINDEX);
return _kp_colorNames[color_index];
}
char* kp_fgColor_toString(kp_fgColor c){
u32 color_index=(c&0x00f00000)>>24;
if(color_index>15) throw(ERR_WRONGINDEX);
return _kp_colorNames[color_index];
}

155
kerep/src/kprint/kprintf.c Normal file
View File

@@ -0,0 +1,155 @@
#include "kprintf.h"
#include "../base/base.h"
#if defined(_WIN64) || defined(_WIN32)
#include <windows.h>
WORD unixColorToWin(u8 c){
switch(c){
//foreground
case 30: return 0;
case 31: return FOREGROUND_RED;
case 32: return FOREGROUND_GREEN;
case 33: return FOREGROUND_GREEN | FOREGROUND_RED;
case 34: return FOREGROUND_BLUE;
case 35: return FOREGROUND_RED | FOREGROUND_BLUE;
case 36: return FOREGROUND_BLUE | FOREGROUND_GREEN;
case 37: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
case 90: return FOREGROUND_INTENSITY;
case 91: return FOREGROUND_RED | FOREGROUND_INTENSITY;
case 92: return FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case 93: return FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
case 94: return FOREGROUND_BLUE | FOREGROUND_INTENSITY;
case 95: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
case 96: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case 97: return FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
//background
case 40: return 0;
case 41: return BACKGROUND_RED;
case 42: return BACKGROUND_GREEN;
case 43: return BACKGROUND_GREEN | BACKGROUND_RED;
case 44: return BACKGROUND_BLUE;
case 45: return BACKGROUND_RED | BACKGROUND_BLUE;
case 46: return BACKGROUND_BLUE | BACKGROUND_GREEN;
case 47: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
case 100: return BACKGROUND_INTENSITY;
case 101: return BACKGROUND_RED | BACKGROUND_INTENSITY;
case 102: return BACKGROUND_GREEN | BACKGROUND_INTENSITY;
case 103: return BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
case 104: return BACKGROUND_BLUE | BACKGROUND_INTENSITY;
case 105: return BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
case 106: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
case 107: return BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
default: return 0;
}
}
#endif
void kprintf(const char* format, ...){
va_list vl;
va_start(vl, format);
u32 i=0;
for(char c=format[i++]; c!=0; c=format[i++]){
// value format specifiers
if(c=='%'){
char* argstr=NULL;
bool l=false;
c=format[i++];
format_escape_seq:
switch (c) {
case 'u':
argstr=toString_u64(
l ? va_arg(vl, u64) : va_arg(vl, u32)
,0,0);
break;
case 'i': case 'd':
argstr=toString_i64(
l ? va_arg(vl, i64) : va_arg(vl, i32)
);
break;
case 'f':
// f32 is promoted to f64 when passed through '...'
argstr=toString_f64(va_arg(vl, f64), toString_float_default_precision,0,0);
break;
case 'l':
l=true;
if((c=format[i++]))
goto format_escape_seq;
break;
case 'p': ;
void* phex=va_arg(vl, void*);
argstr=toString_hex(&phex,getEndian()==LittleEndian,sizeof(phex),1,0);
break;
case 'x': ;
if(l){
u64 xhex=va_arg(vl, u64);
argstr=toString_hex(&xhex,getEndian()==LittleEndian,sizeof(xhex),0,1);
}
else {
u32 xhex=va_arg(vl, u32);
argstr=toString_hex(&xhex,getEndian()==LittleEndian,sizeof(xhex),0,1);
}
break;
case 's': ;
char* cptr=va_arg(vl,char*);
if(!cptr)
cptr="<nullstr>";
if(*cptr)
fputs(cptr, stdout);
break;
case 'c':
argstr=malloc(2);
argstr[0]=(char)va_arg(vl,int);
argstr[1]=0;
break;
default:
putc('\n',stdout);
putc('<',stdout);
putc(c,stdout);
putc('>',stdout);
throw(ERR_FORMAT);
}
if(argstr){
fputs(argstr, stdout);
free(argstr);
}
}
// escape sequences
else if(c=='\e'){
IFWIN(
/* WINDOWS */
({
if((c=format[i++])=='['){
u8 colorUnix=0;
for(i8 n=0; n<6 && c!=0; n++){
c=format[i++];
switch (c){
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
colorUnix=colorUnix*10+c-'0';
break;
case 'm': ;
WORD colorWin=unixColorToWin(colorUnix);
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, colorWin);
goto end_iteration;
default:
goto end_iteration;
}
}
}
}),
/* UNIX */
putc(c,stdout);
);
}
// common characters
else {
putc(c,stdout);
}
#if defined(_WIN64) || defined(_WIN32)
end_iteration:;
#endif
}
va_end(vl);
}

View File

@@ -0,0 +1,34 @@
#include "splitmix64.h"
/*
This is a fixed-increment version of Java 8's SplittableRandom generator
See http://dx.doi.org/10.1145/2714064.2660195 and
http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
It is a very fast generator passing BigCrush, and it can be useful if
for some reason you absolutely want 64 bits of state; otherwise, we
rather suggest to use a xoroshiro128+ (for moderately parallel
computations) or xorshift1024* (for massively parallel computations)
generator.
*/
// The state can be seeded with any (upto) 64 bit integer value.
void* splitmix64_init(u64 seed){
splitmix64_state* state=malloc(sizeof(splitmix64_state));
*state=seed;
return state;
}
u64 splitmix64_next(void* _state) {
splitmix64_state* state=_state;
// increment the state variable
*state += 0x9e3779b97f4a7c15;
// copy the state to a working variable
u64 z = *state;
// xor the variable with the variable right bit shifted 30 then multiply by a constant
z = (z ^ (z>>30)) * 0xbf58476d1ce4e5b9;
// xor the variable with the variable right bit shifted 27 then multiply by a constant
z = (z ^ (z>>27)) * 0x94d049bb133111eb;
// return the variable xored with itself right bit shifted 31
return z ^ (z>>31);
}

View File

@@ -0,0 +1,49 @@
/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoroshiro64.h"
/*
This is xoroshiro64* 1.0, our best and fastest 32-bit small-state
generator for 32-bit floating-poi32 numbers. We suggest to use its
upper bits for floating-poi32 generation, as it is slightly faster than
xoroshiro64**. It passes all tests we are aware of except for linearity
tests, as the lowest six bits have low linear complexity, so if low
linear complexity is not considered an issue (as it is usually the
case) it can be used to generate 32-bit outputs, too.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero.
*/
static inline u32 rotl(const u32 x, i32 k) {
return (x << k) | (x >> (32 - k));
}
u32 xoroshiro64star_next(void* _state) {
xoroshiro64_state* state=_state;
const u32 s0 = state->s[0];
u32 s1 = state->s[1];
const u32 result = s0 * 0x9E3779BB;
s1 ^= s0;
state->s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
state->s[1] = rotl(s1, 13); // c
return result;
}
void* xoroshiro64_init(u64 seed){
xoroshiro64_state* state=malloc(sizeof(xoroshiro64_state));
splitmix64_state* splitmix=splitmix64_init(seed);
state->merged=splitmix64_next(splitmix);
splitmix64_free(splitmix);
return state;
}

View File

@@ -0,0 +1,37 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoroshiro64.h"
/* This is xoroshiro64** 1.0, our 32-bit all-purpose, rock-solid,
small-state generator. It is extremely fast and it passes all tests we
are aware of, but its state space is not large enough for any parallel
application.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoroshiro64* is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline u32 rotl(const u32 x, i32 k) {
return (x << k) | (x >> (32 - k));
}
u32 xoroshiro64starstar_next(void* _state) {
xoroshiro64_state* state=_state;
const u32 s0 = state->s[0];
u32 s1 = state->s[1];
const u32 result = rotl(s0 * 0x9E3779BB, 5) * 5;
s1 ^= s0;
state->s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
state->s[1] = rotl(s1, 13); // c
return result;
}

View File

@@ -0,0 +1,59 @@
/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoroshiro128.h"
/* This is xoroshiro128+ 1.0, our best and fastest small-state generator
for floating-poi32 numbers, but its state space is large enough only
for mild parallelism. We suggest to use its upper bits for
floating-poi32 generation, as it is slightly faster than
xoroshiro128++/xoroshiro128**. It passes all tests we are aware of
except for the four lower bits, which might fail linearity tests (and
just those), so if low linear complexity is not considered an issue (as
it is usually the case) it can be used to generate 64-bit outputs, too;
moreover, this generator has a very mild Hamming-weight dependency
making our test (http://prng.di.unimi.it/hwd.php) fail after 5 TB of
output; we believe this slight bias cannot affect any application. If
you are concerned, use xoroshiro128++, xoroshiro128** or xoshiro256+.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s.
NOTE: the parameters (a=24, b=16, b=37) of this version give slightly
better results in our test than the 2016 version (a=55, b=14, c=36).
*/
static inline u64 rotl(const u64 x, i32 k) {
return (x << k) | (x >> (64 - k));
}
u64 xoroshiro128plus_next(void* _state){
xoroshiro128_state* state=_state;
const u64 s0 = state->s[0];
u64 s1 = state->s[1];
const u64 result = s0 + s1;
s1 ^= s0;
state->s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
state->s[1] = rotl(s1, 37); // c
return result;
}
void* xoroshiro128_init(u64 seed){
xoroshiro128_state* state=malloc(sizeof(xoroshiro128_state));
splitmix64_state* splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
splitmix64_free(splitmix);
return state;
}

View File

@@ -0,0 +1,39 @@
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoroshiro128.h"
/* This is xoroshiro128++ 1.0, one of our all-purpose, rock-solid,
small-state generators. It is extremely (sub-ns) fast and it passes all
tests we are aware of, but its state space is large enough only for
mild parallelism.
For generating just floating-poi32 numbers, xoroshiro128+ is even
faster (but it has a very mild bias, see notes in the comments).
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline u64 rotl(const u64 x, i32 k) {
return (x << k) | (x >> (64 - k));
}
u64 xoroshiro128plusplus_next(void* _state){
xoroshiro128_state* state=_state;
const u64 s0 = state->s[0];
u64 s1 = state->s[1];
const u64 result = rotl(s0 + s1, 17) + s0;
s1 ^= s0;
state->s[0] = rotl(s0, 49) ^ s1 ^ (s1 << 21); // a, b
state->s[1] = rotl(s1, 28); // c
return result;
}

View File

@@ -0,0 +1,39 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoroshiro128.h"
/* This is xoroshiro128** 1.0, one of our all-purpose, rock-solid,
small-state generators. It is extremely (sub-ns) fast and it passes all
tests we are aware of, but its state space is large enough only for
mild parallelism.
For generating just floating-poi32 numbers, xoroshiro128+ is even
faster (but it has a very mild bias, see notes in the comments).
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline u64 rotl(const u64 x, i32 k) {
return (x << k) | (x >> (64 - k));
}
u64 xoroshiro128starstar_next(void* _state){
xoroshiro128_state* state=_state;
const u64 s0 = state->s[0];
u64 s1 = state->s[1];
const u64 result = rotl(s0 * 5, 7) * 9;
s1 ^= s0;
state->s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
state->s[1] = rotl(s1, 37); // c
return result;
}

View File

@@ -0,0 +1,54 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoshiro128.h"
/* This is xoshiro128+ 1.0, our best and fastest 32-bit generator for 32-bit
floating-poi32 numbers. We suggest to use its upper bits for
floating-poi32 generation, as it is slightly faster than xoshiro128**.
It passes all tests we are aware of except for
linearity tests, as the lowest four bits have low linear complexity, so
if low linear complexity is not considered an issue (as it is usually
the case) it can be used to generate 32-bit outputs, too.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. */
static inline u32 rotl(const u32 x, i32 k) {
return (x << k) | (x >> (32 - k));
}
u32 xoshiro128plus_next(void* _state){
xoshiro128_state* state=_state;
const u32 result = state->s[0] + state->s[3];
const u32 t = state->s[1] << 9;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 11);
return result;
}
void* xoshiro128_init(u64 seed){
xoshiro128_state* state=malloc(sizeof(xoshiro128_state));
splitmix64_state* splitmix=splitmix64_init(seed);
state->merged[0]=splitmix64_next(splitmix);
state->merged[1]=splitmix64_next(splitmix);
splitmix64_free(splitmix);
return state;
}

View File

@@ -0,0 +1,42 @@
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoshiro128.h"
/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
generators. It has excellent speed, a state size (128 bits) that is
large enough for mild parallelism, and it passes all tests we are aware
of.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoshiro128+ is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline u32 rotl(const u32 x, i32 k) {
return (x << k) | (x >> (32 - k));
}
u32 xoshiro128plusplus_next(void* _state){
xoshiro128_state* state=_state;
const u32 result = rotl(state->s[0] + state->s[3], 7) + state->s[0];
const u32 t = state->s[1] << 9;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 11);
return result;
}

View File

@@ -0,0 +1,45 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoshiro128.h"
/* This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
generators. It has excellent speed, a state size (128 bits) that is
large enough for mild parallelism, and it passes all tests we are aware
of.
Note that version 1.0 had mistakenly state->s[0] instead of state->s[1] as state
word passed to the scrambler.
For generating just single-precision (i.e., 32-bit) floating-point
numbers, xoshiro128+ is even faster.
The state must be seeded so that it is not everywhere zero. */
static inline u32 rotl(const u32 x, i32 k) {
return (x << k) | (x >> (32 - k));
}
u32 xoshiro128starstar_next(void* _state){
xoshiro128_state* state=_state;
const u32 result = rotl(state->s[1] * 5, 7) * 9;
const u32 t = state->s[1] << 9;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 11);
return result;
}

View File

@@ -0,0 +1,58 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoshiro256.h"
/* This is xoshiro256+ 1.0, our best and fastest generator for floating-point
numbers. We suggest to use its upper bits for floating-point
generation, as it is slightly faster than xoshiro256++/xoshiro256**. It
passes all tests we are aware of except for the lowest three bits,
which might fail linearity tests (and just those), so if low linear
complexity is not considered an issue (as it is usually the case) it
can be used to generate 64-bit outputs, too.
We suggest to use a sign test to extract a random Boolean value, and
right shifts to extract subsets of bits.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline u64 rotl(const u64 x, i32 k) {
return (x << k) | (x >> (64 - k));
}
u64 xoshiro256plus_next(void* _state){
xoshiro256_state* state=_state;
const u64 result = state->s[0] + state->s[3];
const u64 t = state->s[1] << 17;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 45);
return result;
}
void* xoshiro256_init(u64 seed){
xoshiro256_state* state=malloc(sizeof(xoshiro256_state));
splitmix64_state* splitmix=splitmix64_init(seed);
state->s[0]=splitmix64_next(splitmix);
state->s[1]=splitmix64_next(splitmix);
state->s[2]=splitmix64_next(splitmix);
state->s[3]=splitmix64_next(splitmix);
splitmix64_free(splitmix);
return state;
}

View File

@@ -0,0 +1,37 @@
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoshiro256.h"
/* This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
It has excellent (sub-ns) speed, a state (256 bits) that is large
enough for any parallel application, and it passes all tests we are
aware of.
For generating just floating-poi32 numbers, xoshiro256+ is even faster.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline u64 rotl(const u64 x, i32 k) {
return (x << k) | (x>>(64 - k));
}
u64 xoshiro256plusplus_next(void* _state) {
xoshiro256_state* state=_state;
const u64 result=rotl(state->s[0] + state->s[3], 23) + state->s[0];
const u64 t=state->s[1] << 17;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3]=rotl(state->s[3], 45);
return result;
}

View File

@@ -0,0 +1,42 @@
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
#include "xoshiro256.h"
/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
generators. It has excellent (sub-ns) speed, a state (256 bits) that is
large enough for any parallel application, and it passes all tests we
are aware of.
For generating just floating-poi32 numbers, xoshiro256+ is even faster.
The state must be seeded so that it is not everywhere zero. If you have
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
output to fill s. */
static inline u64 rotl(const u64 x, i32 k) {
return (x << k) | (x >> (64 - k));
}
u64 xoshiro256starstar_next(void* _state){
xoshiro256_state* state=_state;
const u64 result = rotl(state->s[1] * 5, 7) * 9;
const u64 t = state->s[1] << 17;
state->s[2] ^= state->s[0];
state->s[3] ^= state->s[1];
state->s[1] ^= state->s[2];
state->s[0] ^= state->s[3];
state->s[2] ^= t;
state->s[3] = rotl(state->s[3], 45);
return result;
}

Binary file not shown.

View File

@@ -1,47 +1,108 @@
#include <unistd.h>
#include "CompilationScenario.h"
#include "unistd.h"
#include "../kerep/src/Filesystem/filesystem.h"
#include "process/Process.h"
kt_define(Language, NULL, NULL);
kt_define(Tool, NULL, NULL);
kt_define(CompilationScenario, (freeMembers_t)CompilationScenario_destruct, NULL);
void CompilationScenario_construct(CompilationScenario* ptr){
ptr->compiler = "UNDEFINED_COMPILER";
ptr->obj_dir = "obj";
ptr->out_file = "bin/out";
ptr->args = Autoarr_create(Pointer, 32, 32);
ptr->sources = Autoarr_create(Pointer, 32, 32);
ptr->languages = Hashtable_create();
ptr->tools = Hashtable_create();
ptr->tool_order = Autoarr_create(Pointer, 32, 32);
}
void CompilationScenario_destruct(CompilationScenario* ptr){
Autoarr_freeWithoutMembers(ptr->args, true);
Autoarr_freeWithoutMembers(ptr->sources, true);
// TODO
}
#define Dtsod_setStrField(FIELD) \
void Tool_construct(Tool* ptr, Autoarr(Pointer)* aliases, const char* exe_file, bool parallel, Autoarr(Pointer)* supported_languages){
ptr->aliases = aliases;
ptr->exe_file = exe_file;
ptr->parallel = parallel;
ptr->supported_languages = Hashtable_create();
Autoarr_foreach(supported_languages, _l,
Language* l = _l;
Autoarr_foreach(l->aliases, l_name,
Hashtable_add(ptr->supported_languages, l_name, UniHeapPtr(Language, l)));
)
ptr->src_languages = Hashtable_create();
ptr->src_dirs = Autoarr_create(Pointer, 32, 32);
ptr->pre_args = Autoarr_create(Pointer, 32, 32);
ptr->post_args = Autoarr_create(Pointer, 32, 32);
}
void Tool_destruct(Tool* ptr){
// TODO
}
void Language_construct(Language* ptr, Autoarr(Pointer)* aliases, Autoarr(Pointer)* file_extensions){
ptr->aliases = aliases;
ptr->file_extensions = file_extensions;
}
void Language_destruct(Language* ptr){
// TODO
}
#define Dtsod_getStrField(FIELD, OBJ) \
if(Hashtable_tryGet(dtsod, #FIELD, &val)){ \
if(val.typeId != ktid_char_Ptr) \
if(!UniCheckTypePtr(val, char)) \
safethrow(#FIELD " value expected to be string",;);\
sc->FIELD = val.VoidPtr; \
OBJ->FIELD = val.VoidPtr; \
}
#define Dtsod_addArrField(FIELD, ELEM_TYPE) \
#define Dtsod_addToStrAr(FIELD, OBJ) \
if(Hashtable_tryGet(dtsod, #FIELD, &val)){ \
if(val.typeId != ktid_Autoarr_Unitype_Ptr) \
safethrow(#FIELD " value expected to be array", ;); \
if(!UniCheckTypePtr(val, Autoarr(Unitype))) \
safethrow(#FIELD " value expected to be a string array", ;); \
Autoarr(Unitype)* ar = val.VoidPtr; \
Autoarr_foreach(ar, el, \
if(el.typeId != ktid_ptrName(ELEM_TYPE)) \
safethrow(#FIELD " array values expected to be " #ELEM_TYPE, ;); \
Autoarr_add(sc->FIELD, el.VoidPtr); \
if(!UniCheckTypePtr(el, char)) \
safethrow(#FIELD " array values expected to be string", ;); \
Autoarr_add(OBJ->FIELD, el.VoidPtr); \
) \
}
Maybe CompilationScenario_tryApplyOptions(CompilationScenario* sc, Hashtable* dtsod){
Maybe Tool_tryApplyOptions(Tool* t, Hashtable* dtsod){
Unitype val = UniNull;
Dtsod_setStrField(compiler);
Dtsod_setStrField(obj_dir);
Dtsod_setStrField(out_file);
Dtsod_addArrField(args, char);
Dtsod_addArrField(sources, char);
Dtsod_addToStrAr(src_dirs, t);
Dtsod_addToStrAr(pre_args, t);
Dtsod_addToStrAr(post_args, t);
if(Hashtable_tryGet(dtsod, "src_languages", &val)){
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow("src_languages value expected to be a string array", ;);
Autoarr(Unitype)* ar = val.VoidPtr;
Autoarr_foreach(ar, el,
if(!UniCheckTypePtr(el, char))
safethrow("src_languages array values expected to be string", ;);
const char* l_name = el.VoidPtr;
if(!Hashtable_tryGet(t->supported_languages, l_name, &val))
safethrow(cptr_concat("language '", l_name, "' isn't supported by tool '", Autoarr_get(t->aliases, 0), "'"), ;);
Hashtable_add(t->src_languages, l_name, val);
)
}
return MaybeNull;
}
Maybe CompilationScenario_tryApplyToolsOptions(CompilationScenario* sc, Hashtable* dtsod){
Unitype val = UniNull;
// adds tools to tool_order
Dtsod_addToStrAr(tool_order, sc);
// sets options for each tool
try(CompilationScenario_tryApplyPlatformSpecificOptions(sc, dtsod), _m0, ;);
Hashtable_foreach(sc->tools, _tool,
Tool* tool = _tool.value.VoidPtr;
if(Hashtable_tryGet(dtsod, _tool.key, &val)){
if(!UniCheckTypePtr(val, Hashtable))
safethrow(ERR_WRONGTYPE, ;);
Hashtable* tool_dtsod = val.VoidPtr;
try(Tool_tryApplyOptions(tool, tool_dtsod), _m1, ;);
}
)
return SUCCESS(UniBool(Unitype_isUniNull(val) || _m0.value.Bool));
}
@@ -49,10 +110,10 @@ Maybe CompilationScenario_tryApplyOptions(CompilationScenario* sc, Hashtable* dt
Maybe CompilationScenario_tryApplyConditionalOptions(CompilationScenario* sc, Hashtable* dtsod, const char* condition_name){
Unitype val = UniNull;
if(Hashtable_tryGet(dtsod, condition_name, &val)){
if(val.typeId != ktid_Hashtable_Ptr)
if(!UniCheckTypePtr(val, Hashtable))
safethrow(cptr_concat(condition_name, " expected to be key-value map"), ;);
Hashtable* conditional_options = val.VoidPtr;
try(CompilationScenario_tryApplyOptions(sc, conditional_options), _m0, ;);
try(CompilationScenario_tryApplyToolsOptions(sc, conditional_options), _m0, ;);
return SUCCESS(UniTrue);
}
else return SUCCESS(UniFalse);
@@ -87,9 +148,136 @@ Maybe CompilationScenario_applyTaskOptions(CompilationScenario* sc, Hashtable* d
return MaybeNull;
}
Maybe CompilationScenario_tryRegisterLanguages(CompilationScenario* sc, Hashtable* dtsod){
Unitype val = UniNull;
if(!Hashtable_tryGet(dtsod, "languages", &val))
return SUCCESS(UniFalse);
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow(ERR_WRONGTYPE, ;);
Autoarr(Unitype)* languages_serializad = val.VoidPtr;
Autoarr_foreach(languages_serializad, ldtsod,
if(!UniCheckTypePtr(ldtsod, Hashtable))
safethrow(ERR_WRONGTYPE, ;);
// reads aliases: string[] from dtsod
if(!Hashtable_tryGet(ldtsod.VoidPtr, "aliases", &val))
safethrow(ERR_FORMAT, ;);
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow(ERR_WRONGTYPE, ;);
Autoarr(Unitype)* aliases_uni = val.VoidPtr;
Autoarr(Pointer)* aliases = Autoarr_create(Pointer, 32, 32);
Autoarr_foreach(aliases_uni, au,
if(!UniCheckTypePtr(au, char))
safethrow(ERR_WRONGTYPE, ;);
Autoarr_add(aliases, au.VoidPtr);
)
// reads file_extensions: string[] from dtsod
if(!Hashtable_tryGet(ldtsod.VoidPtr, "file_extensions", &val))
safethrow(ERR_FORMAT, ;);
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow(ERR_WRONGTYPE, ;);
Autoarr(Unitype)* file_extensions_uni = val.VoidPtr;
Autoarr(Pointer)* file_extensions = Autoarr_create(Pointer, 32, 32);
Autoarr_foreach(file_extensions_uni, feu,
if(!UniCheckTypePtr(feu, char))
safethrow(ERR_WRONGTYPE, ;);
Autoarr_add(file_extensions, feu.VoidPtr);
)
Language* lang = malloc(sizeof(Language));
Language_construct(lang, aliases, file_extensions);
// registers each alias of the language
Autoarr_foreach(aliases, l_name,
if(!Hashtable_tryAdd(sc->languages, l_name, UniHeapPtr(Language, lang)))
safethrow(cptr_concat("language '", l_name, "has been already registered"), ;);
)
)
return SUCCESS(UniTrue);
}
Maybe CompilationScenario_tryRegisterTools(CompilationScenario* sc, Hashtable* dtsod){
Unitype val = UniNull;
if(!Hashtable_tryGet(dtsod, "tools", &val))
return SUCCESS(UniFalse);
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow(ERR_WRONGTYPE, ;);
Autoarr(Unitype)* tools_serializad = val.VoidPtr;
Autoarr_foreach(tools_serializad, tdtsod,
if(!UniCheckTypePtr(tdtsod, Hashtable))
safethrow(ERR_WRONGTYPE, ;);
// reads exe_file: string from dtsod
if(!Hashtable_tryGet(tdtsod.VoidPtr, "exe_file", &val))
safethrow(ERR_FORMAT, ;);
if(!UniCheckTypePtr(val, char))
safethrow(ERR_WRONGTYPE, ;);
char* exe_file = val.VoidPtr;
// reads parallel: bool from dtsod
if(!Hashtable_tryGet(tdtsod.VoidPtr, "parallel", &val))
safethrow(ERR_FORMAT, ;);
if(!UniCheckType(val, bool))
safethrow(ERR_WRONGTYPE, ;);
bool parallel = val.Bool;
// reads aliases: string[] from dtsod
if(!Hashtable_tryGet(tdtsod.VoidPtr, "aliases", &val))
safethrow(ERR_FORMAT, ;);
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow(ERR_WRONGTYPE, ;);
Autoarr(Unitype)* aliases_uni = val.VoidPtr;
Autoarr(Pointer)* aliases = Autoarr_create(Pointer, 32, 32);
Autoarr_foreach(aliases_uni, au,
if(!UniCheckTypePtr(au, char))
safethrow(ERR_WRONGTYPE, ;);
Autoarr_add(aliases, au.VoidPtr);
)
// reads supported_languages: string[] dtsod
if(!Hashtable_tryGet(tdtsod.VoidPtr, "supported_languages", &val))
safethrow(ERR_FORMAT, ;);
if(!UniCheckTypePtr(val, Autoarr(Unitype)))
safethrow(ERR_WRONGTYPE, ;);
Autoarr(Unitype)* supported_languages_uni = val.VoidPtr;
Autoarr(Pointer)* supported_languages = Autoarr_create(Pointer, 32, 32);
Autoarr_foreach(supported_languages_uni, lu,
if(!UniCheckTypePtr(lu, char))
safethrow(ERR_WRONGTYPE, ;);
char* l_name = lu.VoidPtr;
// gets language pointer from CompilationScenario regisgered languages
if(!Hashtable_tryGet(sc->languages, l_name, &val))
safethrow(ERR_KEYNOTFOUND, ;);
if(!UniCheckTypePtr(val, Language))
safethrow(ERR_WRONGTYPE, ;);
Language* lang = val.VoidPtr;
Autoarr_add(supported_languages, lang);
)
Tool* tool = malloc(sizeof(Tool));
Tool_construct(tool, aliases, exe_file, parallel, supported_languages);
// registers each alias of the tool
Autoarr_foreach(aliases, t_name,
if(!Hashtable_tryAdd(sc->tools, t_name, UniHeapPtr(Tool, tool)))
safethrow(cptr_concat("tool '", t_name, "has been already registered"), ;);
)
)
return SUCCESS(UniTrue);
}
Maybe CompilationScenario_applyProjectOptions(CompilationScenario* sc, Hashtable* dtsod, const char* configuration, const char* task){
// general options
try(CompilationScenario_tryApplyOptions(sc, dtsod), _m0, ;);
// TODO version check
// TODO import
try(CompilationScenario_tryRegisterLanguages(sc, dtsod), _m05, ;);
try(CompilationScenario_tryRegisterTools(sc, dtsod), _m06, ;);
// project-wide options
try(CompilationScenario_tryApplyToolsOptions(sc, dtsod), _m0, ;);
// configuration options
try(CompilationScenario_applyConfigurationOptions(sc, dtsod, configuration), _m1, ;);
// task options
@@ -97,33 +285,56 @@ Maybe CompilationScenario_applyProjectOptions(CompilationScenario* sc, Hashtable
return MaybeNull;
}
Maybe Tool_exec(Tool* tool){
Autoarr(Pointer)* args_ar = Autoarr_create(Pointer, 32, 32);
Autoarr_foreach(tool->pre_args, arg,
Autoarr_add(args_ar, arg));
/*
universal compilation:
pre-compilation tools
parallel foreach src
apply proj settings
apply lang settings
apply dir settings
if platform, settings or src were changed
compile object to onj/lang
concurrent add obj to obj_ar
post-compilation tools
example: if linkage enabled
apply proj linker settings
link
post-link tools
move files to general_out_dir
*/
Autoarr(Pointer)* sources = Autoarr_create(Pointer, 32, 32);
Autoarr_foreach(tool->src_dirs, dir,
try(dir_getFiles(dir, true), _m2, ;);
char** files = _m2.value.VoidPtr;
while(*files){
Autoarr_add(sources, *files);
files++;
}
);
if(tool->parallel){
safethrow(ERR_NOTIMPLEMENTED, ;);
}
else {
Autoarr_foreach(sources, file,
Autoarr_add(args_ar, file));
}
Autoarr_foreach(tool->post_args, arg,
Autoarr_add(args_ar, arg));
const char** args = (const char**)Autoarr_toArray(args_ar);
i32 argc = Autoarr_length(args_ar);
Autoarr_freeWithoutMembers(args_ar, true);
Process tool_proc;
try(Process_start(&tool_proc, tool->exe_file, args, argc, true), _m5512, Autoarr_freeWithoutMembers(sources, true))
// TODO wrap tool_proc->io
Process_waitForExit(&tool_proc);
Autoarr_freeWithoutMembers(sources, true);
return MaybeNull;
}
Maybe CompilationScenario_exec(CompilationScenario* sc){
/*const char ** compiler_args;
Autoarr_foreach(sc->sources, arg,
int rzlt = -1;
if(rzlt != 0){
kprintf("\nprocess exited with code %i\n", rzlt);
return false;
}
);*/
return true;
Autoarr_foreach(sc->tool_order, tool_name,
kprintf("tool: '%s'\n", tool_name);
Unitype uni;
if(!Hashtable_tryGet(sc->tools, tool_name, &uni))
safethrow(ERR_KEYNOTFOUND, ;);
if(!UniCheckTypePtr(uni, Tool))
safethrow(ERR_WRONGTYPE, ;);
Tool* tool = uni.VoidPtr;
try(Tool_exec(tool), _m1, ;);
)
return MaybeNull;
}

View File

@@ -1,16 +1,29 @@
#include "../kerep-headers/DtsodParser/DtsodV24.h"
#include "../kerep/src/DtsodParser/DtsodV24.h"
extern const char* os;
extern const char* arch;
typedef struct {
const char* language;
const char* compiler;
const char* obj_dir;
const char* out_file;
Autoarr(Pointer)* args;
Autoarr(Pointer)* sources;
} CompilationScenario;
STRUCT(Language,
Autoarr(Pointer)* aliases;
Autoarr(Pointer)* file_extensions;
)
STRUCT(Tool,
Autoarr(Pointer)* aliases;
const char* exe_file;
bool parallel;
Hashtable* supported_languages;
Hashtable* src_languages;
Autoarr(Pointer)* src_dirs;
Autoarr(Pointer)* pre_args;
Autoarr(Pointer)* post_args;
)
STRUCT(CompilationScenario,
Hashtable* tools; /* Hashtable<Tool> */
Hashtable* languages; /* Hashtable<Languages> */
Autoarr(Pointer)* tool_order; /* Autoarr(char[]) */
)
/* Public Functions */
@@ -29,13 +42,23 @@ Maybe CompilationScenario_exec(CompilationScenario* sc);
/* Internal Functions */
/// tries to register proramming languages from dtsod field "languages"
///@return Maybe<bool>
Maybe CompilationScenario_tryApplyOptions(CompilationScenario* sc, Hashtable* dtsod);
Maybe CompilationScenario_tryRegisterLanguages(CompilationScenario* sc, Hashtable* dtsod);
/// tries to register tools from dtsod field "tools"
///@return Maybe<bool>
Maybe CompilationScenario_tryRegisterTools(CompilationScenario* sc, Hashtable* dtsod);
/// tries to set options for tools registered in the project
///@return Maybe<bool>
Maybe CompilationScenario_tryApplyToolsOptions(CompilationScenario* sc, Hashtable* dtsod);
/// tries to get any options from field <condition_name>
///@return Maybe<bool>
Maybe CompilationScenario_tryApplyConditionalOptions(CompilationScenario* sc, Hashtable* dtsod, const char* condition_name);
/// tries to get options from dtsod fields named "windows", "linux", "android", "x64", "android-arm32", "windows_x86", etc.
/// tries to get options from dtsod fields named "windowss", "linux", "android", "x64", "android-arm32", "windows_x86", etc.
///@return Maybe<bool>
Maybe CompilationScenario_tryApplyPlatformSpecificOptions(CompilationScenario* sc, Hashtable* dtsod);

View File

@@ -1,23 +1,28 @@
#include "../kerep-headers/base/base.h"
#include "../kerep-headers/Filesystem/filesystem.h"
#include "../kerep-headers/DtsodParser/DtsodV24.h"
#include "../kerep/src/base/base.h"
#include "../kerep/src/Filesystem/filesystem.h"
#include "../kerep/src/DtsodParser/DtsodV24.h"
#include "CompilationScenario.h"
#include "process/Process.h"
#ifndef OS
#error undefined OS
#define OS "UNDEFINED"
#endif
#ifndef ARCH
#error undefined ARCH
#define ARCH "UNDEFINED"
#endif
#ifndef CONFIG_DIR
#error undefined CONFIG_DIR
#define CONFIG_DIR "UNDEFINED"
#endif
const char* os=OS;
const char* arch=ARCH;
const char* global_config_dir=CONFIG_DIR;
const char* global_out_dir="bin";
const char* configuration="release";
const char* task="exe";
const char** projects=NULL;
u16 project_count = 0;
const char* project_dir_or_file="./";
Autoarr(Pointer)* tasks;
int erri(ErrorId err_code){
throw(err_code);
@@ -35,74 +40,74 @@ char* projectFileFromDir(const char* dir){
int main(const int argc, const char** argv){
kt_beginInit();
kt_initKerepTypes();
kt_register(CompilationScenario);
kt_register(Language);
kt_register(Tool);
kt_register(Process);
kt_endInit();
if(cptr_equals(os, "UNDEFINED"))
throw("Operation system undefined. Recompile cbuild with flag -DOS=$(./detect_os.sh)");
if(cptr_equals(arch, "UNDEFINED"))
throw("CPU architecture undefined. Recompile cbuild with flag -DARCH=$(./detect_arch.sh)");
tasks = Autoarr_create(Pointer, 16, 32);
Autoarr(Pointer)* projects_ar = Autoarr_create(Pointer, 16, 32);
if(cptr_equals(os, "UNDEFINED"))
throw("Undefined operation system. Recompile cbuild with flag -DOS=\\\"$(./detect_os.sh)\\\"");
if(cptr_equals(arch, "UNDEFINED"))
throw("Undefined CPU architecture. Recompile cbuild with flag -DARCH=\\\"$(./detect_arch.sh)\\\"");
if(cptr_equals(global_config_dir, "UNDEFINED"))
throw("Undefined global config directory. Recompile cbuild with flag -DCONFIG_DIR=\\\"/etc/cbuild\\\"");
for(int argi = 1; argi < argc; argi++){
const char* arg = argv[argi];
kprintf("arg: %s\n", arg);
if(argIs("-h") || argIs("--help") || argIs("/?"))
kprintf("Usage: cbuild [options] [projects files/dirs]\n"
if(argIs("-h") || argIs("--help") || argIs("/?")){
kprintf("Usage: cbuild [options] [tasks0 task1...]\n"
" Options:\n"
" -h, --help, /? Display this message.\n"
" -o, --out-dir Set global output directory (default=bin).\n"
" -c, --configuration Select project configuration (default=release).\n"
" -t, --task Select build task from project.\n");
else if(argIs("-o") || argIs("--out-dir"))
global_out_dir = argNext();
" -p, --project Set project directory/file (default=./).\n");
return 0;
}
else if(argIs("-c") || argIs("--configuration"))
configuration = argNext();
else if(argIs("-t") || argIs("--task"))
task = argNext();
else if(argIs("-p") || argIs("--project"))
project_dir_or_file = argNext();
else {
if(arg[0] == '-')
throw(cptr_concat("invalid argument: ", arg));
Autoarr_add(projects_ar, arg);
Autoarr_add(tasks, arg);
}
}
project_count = Autoarr_length(projects_ar);
projects = (const char**)Autoarr_toArray(projects_ar);
Autoarr_freeWithoutMembers(projects_ar, true);
if(project_count == 0){
projects = malloc(sizeof(char*));
projects[0] = projectFileFromDir(".");
}
for(u16 i=0; i < project_count; i++){
const char* proj = projects[i];
const char* proj_file_path = NULL;
if(file_exists(proj))
proj_file_path = proj;
else if(dir_exists(proj))
proj_file_path = projectFileFromDir(proj);
if(file_exists(project_dir_or_file))
proj_file_path = project_dir_or_file;
else if(dir_exists(project_dir_or_file))
proj_file_path = projectFileFromDir(project_dir_or_file);
else throw(cptr_concat("can't find a project at path '", project_dir_or_file, "'"));
tryLast(file_open(proj_file_path, FileOpenMode_Read), _m1, ;);
FileHandle proj_file = _m1.value.VoidPtr;
char* proj_file_text;
char* proj_file_text = NULL;
tryLast(file_readAll(proj_file, &proj_file_text), _m2, file_close(proj_file));
file_close(proj_file);
tryLast(DtsodV24_deserialize(proj_file_text), _m3, free(proj_file_text));
Hashtable* proj_dtsod = _m3.value.VoidPtr;
char* platform = cptr_concat(os, "-", arch);
Autoarr_foreach(tasks, task,
kprintf("executing task '%s', configuration '%s', platform '%s'\n",
task, configuration, platform);
CompilationScenario proj_sc;
CompilationScenario_construct(&proj_sc);
tryLast(CompilationScenario_applyProjectOptions(&proj_sc, proj_dtsod, configuration, task), _m4, free(proj_file_text))
if(!CompilationScenario_exec(&proj_sc))
throw("compilation error");
tryLast(CompilationScenario_applyProjectOptions(&proj_sc, proj_dtsod, configuration, task), _m4, )
tryLast(CompilationScenario_exec(&proj_sc), _m5, ;)
CompilationScenario_destruct(&proj_sc);
)
#if DEBUG
Hashtable_free(proj_dtsod);
free(proj_file_text);
}
kt_free();
#endif
return 0;
}

33
src/process/Process.h Normal file
View File

@@ -0,0 +1,33 @@
#include "../../kerep/src/base/base.h"
#ifdef _WIN32
#define USE_WINDOWS_PROCESS_API
typedef void* PipeHandle;
#else
typedef int PipeHandle;
#endif
typedef struct Process {
int id;
const char* file_path;
const char** args;
PipeHandle input;
PipeHandle output;
PipeHandle error;
#ifdef USE_WINDOWS_PROCESS_API
void* _winProcHandle;
#endif
} Process;
kt_declare(Process);
///@param search_in_PATH if true and file_path doesn't contain path separator characters, will search in PATH for the file_path
///@return Maybe<void>
Maybe Process_start(Process* ptr, const char* file_path, const char** args, int argc, bool search_in_PATH);
///@return Maybe<void>
Maybe Process_waitForExit(Process* p);
///@return Maybe<void>
Maybe Process_stop(Process* p);
i32 PipeHandle_read(PipeHandle pipe, char* buf, i32 bufsize);

View File

@@ -0,0 +1,99 @@
#include "process.h"
#ifndef USE_WINDOWS_PROCESS_API
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
extern int kill (__pid_t __pid, int __sig) __THROW;
extern void * memset(void * __dst, int __val, size_t __n);
#define throw_if_negative(expr) if(expr < 0) throw(cptr_concat(#expr " exited with error ", toString_i64(errno)));
#define safethrow_if_negative(expr) if(expr < 0) safethrow(cptr_concat(#expr " exited with error ", toString_i64(errno)), ;);
Maybe Process_start(Process* p, const char* file_path, const char** args, int argc, bool search_in_PATH){
memset(p, 0, sizeof(Process));
int input_pipe[2];
int output_pipe[2];
int error_pipe[2];
safethrow_if_negative(pipe(input_pipe));
safethrow_if_negative(pipe(output_pipe));
safethrow_if_negative(pipe(error_pipe));
int pid = fork();
if(pid == -1)
safethrow("fork() error", ;);
// child process
if(pid == 0){
printf("child");
throw_if_negative(close(input_pipe[1])); // close writing
throw_if_negative(close(output_pipe[0])); // close reading
throw_if_negative(close(error_pipe[0])); // close reading
// redirect io streams to pipes
throw_if_negative(dup2(input_pipe[0], STDIN_FILENO));
throw_if_negative(dup2(output_pipe[1], STDOUT_FILENO));
throw_if_negative(dup2(error_pipe[1], STDERR_FILENO));
//
const char** argv = malloc(sizeof(char*) * (argc+2));
argv[0] = file_path;
for(int i=0; i<argc; i++){
argv[i+1] = args[i];
}
argv[argc+1] = NULL;
// start new process
int rzlt = search_in_PATH ? execvp(file_path, (char* const*)argv) : execv (file_path, (char* const*)argv);
exit(rzlt);
}
// parent process
safethrow_if_negative(close(input_pipe[0])); // close reading
safethrow_if_negative(close(output_pipe[1])); // close writing
safethrow_if_negative(close(error_pipe[1])); // close writing
p->file_path = file_path;
p->args = args;
p->id=pid;
p->input=input_pipe[1];
p->output=output_pipe[0];
p->error=error_pipe[0];
return MaybeNull;
}
Maybe Process_closeHandles(Process* p){
safethrow_if_negative(close(p->input));
safethrow_if_negative(close(p->output));
safethrow_if_negative(close(p->error));
p->id=0;
return MaybeNull;
}
Maybe Process_waitForExit(Process* p){
int wstatus=0;
if(waitpid(p->id, &wstatus, 0) == -1)
safethrow("waitpid() error", ;);
if(!WIFEXITED(wstatus))
safethrow(ERR_NOTIMPLEMENTED, ;)
int exitCode = WEXITSTATUS(wstatus);
if(exitCode != 0)
safethrow(cptr_concat("process ", toString_i64(p->id), " exited with code ", toString_i64(exitCode)), ;)
Process_closeHandles(p);
return MaybeNull;
}
Maybe Process_stop(Process* p){
safethrow_if_negative(kill(p->id, SIGINT));
try(Process_closeHandles(p), _m864, ;);
return MaybeNull;
}
kt_define(Process, (freeMembers_t)(void*)Process_stop, NULL)
i32 PipeHandle_read(PipeHandle pipe, char* buf, i32 bufsize){
return read(pipe, buf, bufsize);
}
#endif

View File

@@ -0,0 +1,141 @@
#include "process.h"
#ifdef USE_WINDOWS_PROCESS_API
#include <windows.h>
#include "../../kerep/src/String/StringBuilder.h"
#define safethrow_if_false(expr) if(!expr) safethrow(cptr_concat(#expr " exited with error ", toString_i64(GetLastError())), ;);
Maybe Process_start(Process* p, const char* file_path, const char** args, int argc, bool search_in_PATH){
memset(p, 0, sizeof(Process));
if(search_in_PATH && !cptr_contains(file_path, "\\")){
LPSTR lpFilePart;
char search_rezult[MAX_PATH];
safethrow_if_false(SearchPath( NULL, file_path, NULL, MAX_PATH, search_rezult, &lpFilePart))
file_path = cptr_copy(search_rezult);
}
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
// Set the bInheritHandle flag so pipe handles are inherited
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
HANDLE in_pipe_r = NULL;
HANDLE in_pipe_w = NULL;
HANDLE out_pipe_r = NULL;
HANDLE out_pipe_w = NULL;
HANDLE err_pipe_r = NULL;
HANDLE err_pipe_w = NULL;
// Create a pipe for the child process's STDIN.
safethrow_if_false( CreatePipe(&in_pipe_r, &in_pipe_w, &saAttr, 0));
// Ensure the write handle to the pipe for STDIN is not inherited.
safethrow_if_false( SetHandleInformation(in_pipe_w, HANDLE_FLAG_INHERIT, 0) );
// Create a pipe for the child process's STDOUT.
safethrow_if_false( CreatePipe(&out_pipe_r, &out_pipe_w, &saAttr, 0) )
// Ensure the read handle to the pipe for STDOUT is not inherited.
safethrow_if_false( SetHandleInformation(out_pipe_r, HANDLE_FLAG_INHERIT, 0) );
// Create a pipe for the child process's STDERR.
safethrow_if_false( CreatePipe(&err_pipe_r, &err_pipe_w, &saAttr, 0) );
// Ensure the read handle to the pipe for STDERR is not inherited.
safethrow_if_false( SetHandleInformation(err_pipe_r, HANDLE_FLAG_INHERIT, 0) )
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.hStdInput = in_pipe_r;
si.hStdOutput = out_pipe_w;
si.hStdError = err_pipe_w;
si.dwFlags |= STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
StringBuilder* b = StringBuilder_create();
StringBuilder_append_char(b, '"');
StringBuilder_append_cptr(b, file_path);
StringBuilder_append_char(b, '"');
StringBuilder_append_char(b, ' ');
for(int i = 0; i < argc; i++) {
StringBuilder_append_char(b, '"');
StringBuilder_append_cptr(b, args[i]);
StringBuilder_append_char(b, '"');
StringBuilder_append_char(b, ' ');
}
string args_str = StringBuilder_build(b);
// Start the child process.
if( !CreateProcess(
file_path, // Program executable path (optional)
args_str.ptr, // Command line args
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Inherit IO handles
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
) {
safethrow(cptr_concat("process_start(", file_path, ", ", args_str, ", ", search_in_PATH ? "true" : "false",
") error: CreateProcess() failed with error code ", toString_i64(GetLastError())), ;)
}
// Close thread handle and child process pipe ends
safethrow_if_false(CloseHandle(in_pipe_r));
safethrow_if_false(CloseHandle(out_pipe_w));
safethrow_if_false(CloseHandle(err_pipe_w));
safethrow_if_false(CloseHandle(pi.hThread));
p->file_path = file_path;
p->args = args;
p->id=pi.dwProcessId;
p->_winProcHandle = pi.hProcess;
p->input = in_pipe_w;
p->output= out_pipe_r;
p->error = err_pipe_r;
return MaybeNull;
}
Maybe Process_closeHandles(Process* p){
safethrow_if_false(CloseHandle(p->_winProcHandle));
safethrow_if_false(CloseHandle(p->input));
safethrow_if_false(CloseHandle(p->output));
safethrow_if_false(CloseHandle(p->error));
p->id=0;
return MaybeNull;
}
Maybe Process_waitForExit(Process* p){
if(WaitForSingleObject(p->_winProcHandle, INFINITE) != 0)
safethrow("WaitForSingleObject() failed", ;);
DWORD exitCode = 0;
safethrow_if_false(GetExitCodeProcess(p->_winProcHandle, &exitCode));
if(exitCode != 0)
safethrow(cptr_concat("process ", toString_i64(p->id), " exited with code ", toString_i64(exitCode)), ;)
Process_closeHandles(p);
return MaybeNull;
}
Maybe Process_stop(Process* p){
safethrow_if_false(TerminateProcess(p->_winProcHandle, 1));
try(Process_closeHandles(p), _m864, ;);
return MaybeNull;
}
kt_define(Process, (freeMembers_t)(void*)Process_stop, NULL)
i32 PipeHandle_read(PipeHandle pipe, char* buf, i32 bufsize){
DWORD bytesRead = 0;
if(!ReadFile(pipe, buf, bufsize, &bytesRead, NULL))
return -1;
return bytesRead;
}
#endif