Compare commits

..

10 Commits

Author SHA1 Message Date
Krzosa Karol
7660402d08 Remove flags from build tool
Some checks failed
/ run-and-compile-ubuntu (push) Has been cancelled
/ run-and-compile-mac (push) Has been cancelled
/ run-and-compile-windows (push) Has been cancelled
2024-03-16 12:01:52 +01:00
Krzosa Karol
18100a87fb Fix const char 2024-03-16 11:55:44 +01:00
Krzosa Karol
da575e8877 Fix warnings 2024-03-16 11:51:13 +01:00
Krzosa Karol
1a1432592a Disable clang address sanitizer 2024-03-16 11:45:53 +01:00
Krzosa Karol
71d36352cb Fix memcpy in arena 2024-03-16 11:40:26 +01:00
Krzosa Karol
1b48585308 Add stubs, wanted to compile to wasm 2024-03-15 16:23:33 +01:00
Krzosa Karol
0c4d19c9b8 Add int cmd kind 2024-03-15 06:53:55 +01:00
Krzosa Karol
6c4c141344 Improve build tool 2024-03-14 11:20:30 +01:00
Krzosa Karol
c944ceac4b IO Thread local on callback, build system thread local on perm arena 2024-03-10 19:22:16 +01:00
Krzosa Karol
bc12273f2a CmdParser improvements 2024-03-04 17:28:57 +01:00
14 changed files with 258 additions and 187 deletions

View File

@@ -3,6 +3,4 @@ mkdir build
cd build
cl -Fe:bld.exe ../build_tool/main.cpp -FC -WX -W3 -wd4200 -diagnostics:column -nologo -Zi -D_CRT_SECURE_NO_WARNINGS
cd ..
rem build\bld.exe clear_cache
build\bld.exe
rem build\bld.exe cc=clang

View File

@@ -58,7 +58,6 @@ int main(int argc, char **argv) {
Array<S8_String> flags = {scratch};
flags += "-g -Wno-write-strings";
flags += "-fdiagnostics-absolute-paths";
flags += "-fsanitize=address";
if (is_cpp) flags += "-fno-exceptions";
if (is_cpp) flags += "-fno-rtti";
if (is_cpp) flags += "-std=c++11";

View File

@@ -12,9 +12,8 @@
#define AND_CL_STRING_TERMINATE_ON_NEW_LINE
#include "../standalone_libraries/clexer.c"
MA_Arena PernamentArena;
MA_Arena *Perm = &PernamentArena;
Table<S8_String> CMDLine;
thread_local MA_Arena PernamentArena;
thread_local MA_Arena *Perm = &PernamentArena;
#include "cache.cpp"
#include "easy_strings.cpp"

View File

@@ -7,15 +7,6 @@ int main(int argument_count, char **arguments) {
IO_Printf("WORKING DIR: %.*s\n", S8_Expand(working_dir));
Array<S8_String> cmd = CMD_Make(arguments, argument_count);
if (CMD_Match(cmd, "clear_cache")) {
for (OS_FileIter it = OS_IterateFiles(Perm, "./"); OS_IsValid(it); OS_Advance(&it)) {
if (!it.is_directory && S8_EndsWith(it.filename, ".cache", true)) {
OS_DeleteFile(it.absolute_path);
}
}
return 0;
}
S8_String cc = CMD_Get(cmd, "cc", IF_WINDOWS("cl") IF_MAC("clang") IF_LINUX("gcc"));
// Search for build file in the project directory
@@ -31,7 +22,6 @@ int main(int argument_count, char **arguments) {
IO_Printf("Couldnt find build file in current dir: %.*s, exiting ... \n", S8_Expand(working_dir));
IO_Printf("- Proper build file contains 'build_file.c' in it's name\n");
IO_Printf("- Alternative compiler can be chosen like this: bld cc=clang\n");
IO_Printf("- Cache can be cleared like this: bld clear_cache\n");
return 0;
}
}
@@ -48,28 +38,25 @@ int main(int argument_count, char **arguments) {
Array<S8_String> flags = {Perm};
flags += "-nologo -Zi";
flags += "-WX -W3 -wd4200 -diagnostics:column";
flags += Fmt("/Fe:%.*s", S8_Expand(exe_name));
flags += Fmt("/Fe:%.*s /Fd:%.*s.pdb", S8_Expand(exe_name), S8_Expand(exe_name));
result = Run(cc + build_file + flags);
}
else if (cc == "clang") {
} else if (cc == "clang") {
Array<S8_String> flags = {Perm};
cc = "clang++";
flags += "-std=c++11 -g";
flags += "-fdiagnostics-absolute-paths";
flags += "-Wno-writable-strings";
flags += "-fno-exceptions";
flags += "-fno-rtti";
flags += "-lm";
flags += Fmt("-o %.*s", S8_Expand(exe_name));
result = Run(cc + build_file + flags);
}
else {
} else {
IO_Assert(cc == "gcc");
cc = "g++";
Array<S8_String> flags = {Perm};
flags += "-std=c++11 -g";
flags += "-Wno-write-strings";
flags += "-fno-exceptions";
flags += "-fno-rtti";
flags += "-lm";
flags += Fmt("-o %.*s", S8_Expand(exe_name));
result = Run(cc + build_file + flags);
@@ -77,6 +64,7 @@ int main(int argument_count, char **arguments) {
if (result != 0) {
IO_Printf("FAILED compilation of the build file!\n");
OS_DeleteFile("build_tool.cache");
return 1;
}
time = OS_GetTime() - time;
@@ -90,6 +78,7 @@ int main(int argument_count, char **arguments) {
int result = Run(exe_name + cmd);
if (result != 0) {
IO_Printf("FAILED execution of the build file!\n");
OS_DeleteFile("build_tool.cache");
return 1;
}
}

View File

@@ -1,6 +1,6 @@
CmdParser MakeCmdParser(MA_Arena *arena, int argc, char **argv) {
CmdParser result = {argc, argv, arena};
CmdParser MakeCmdParser(MA_Arena *arena, int argc, char **argv, const char *custom_help) {
CmdParser result = {argc, argv, arena, custom_help};
return result;
}
@@ -13,6 +13,15 @@ void AddBool(CmdParser *p, bool *result, const char *name, const char *help) {
SLL_QUEUE_ADD(p->fdecl, p->ldecl, decl);
}
void AddInt(CmdParser *p, int *result, const char *name, const char *help) {
CmdDecl *decl = MA_PushStruct(p->arena, CmdDecl);
decl->kind = CmdDeclKind_Int;
decl->name = S8_MakeFromChar((char *)name);
decl->help = S8_MakeFromChar((char *)help);
decl->int_result = result;
SLL_QUEUE_ADD(p->fdecl, p->ldecl, decl);
}
void AddList(CmdParser *p, S8_List *result, const char *name, const char *help) {
CmdDecl *decl = MA_PushStruct(p->arena, CmdDecl);
decl->kind = CmdDeclKind_List;
@@ -54,8 +63,9 @@ S8_String StrEnumValues(MA_Arena *arena, CmdDecl *decl) {
}
void PrintCmdUsage(CmdParser *p) {
IO_Printf("\nhere are the supported commands:\n");
IO_Printf("%s\nCommands:\n", p->custom_help);
for (CmdDecl *it = p->fdecl; it; it = it->next) {
IO_Printf(" ");
if (it->kind == CmdDeclKind_List) {
S8_String example = S8_Format(p->arena, "-%.*s a b c", S8_Expand(it->name));
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
@@ -66,13 +76,15 @@ void PrintCmdUsage(CmdParser *p) {
S8_String enum_vals = StrEnumValues(p->arena, it);
S8_String example = S8_Format(p->arena, "-%.*s %.*s", S8_Expand(it->name), S8_Expand(enum_vals));
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
} else if (it->kind == CmdDeclKind_Int) {
S8_String example = S8_Format(p->arena, "-%.*s 8", S8_Expand(it->name));
IO_Printf("%-30.*s %.*s\n", S8_Expand(example), S8_Expand(it->help));
} else IO_Todo();
}
}
bool InvalidCmdArg(CmdParser *p, S8_String arg) {
IO_Printf("invalid command line argument: %.*s\n", S8_Expand(arg));
PrintCmdUsage(p);
return false;
}
@@ -96,8 +108,26 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
if (decl->kind == CmdDeclKind_Bool) {
*decl->bool_result = !*decl->bool_result;
} else if (decl->kind == CmdDeclKind_Int) {
if (i + 1 >= p->argc) {
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
return false;
}
S8_String num = S8_MakeFromChar(p->argv[++i]);
for (int i = 0; i < num.len; i += 1) {
if (!CHAR_IsDigit(num.str[i])) {
IO_Printf("expected argument to be a number, got instead: %.*s", S8_Expand(num));
return false;
}
}
int count = atoi(num.str);
decl->int_result[0] = count;
} else if (decl->kind == CmdDeclKind_Enum) {
if (i + 1 >= p->argc) { IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg)); PrintCmdUsage(p); return false; }
if (i + 1 >= p->argc) {
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
return false;
}
S8_String option_from_cmd = S8_MakeFromChar(p->argv[++i]);
bool found_option = false;
@@ -113,18 +143,23 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
if (!found_option) {
IO_Printf("expected one of the enum values: %.*s", S8_Expand(StrEnumValues(p->arena, decl)));
IO_Printf(" got instead: %.*s\n", S8_Expand(option_from_cmd));
PrintCmdUsage(p);
return false;
}
} else if (decl->kind == CmdDeclKind_List) {
if (i + 1 >= p->argc) { IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg)); PrintCmdUsage(p); return false; }
if (i + 1 >= p->argc) {
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
return false;
}
i += 1;
for (int counter = 0; i < p->argc; i += 1, counter += 1) {
S8_String arg = S8_MakeFromChar(p->argv[i]);
if (arg.str[0] == '-') {
if (counter == 0) { IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg)); PrintCmdUsage(p); return false; }
if (counter == 0) {
IO_Printf("expected at least 1 argument after %.*s\n", S8_Expand(arg));
return false;
}
i -= 1;
break;
}
@@ -133,48 +168,19 @@ bool ParseCmd(MA_Arena *arg_arena, CmdParser *p) {
}
} else IO_Todo();
} else {
if (p->require_one_standalone_arg && p->args.node_count == 0) {
S8_AddNode(arg_arena, &p->args, arg);
} else {
return InvalidCmdArg(p, arg);
}
else return InvalidCmdArg(p, arg);
}
}
if (p->require_one_standalone_arg && p->args.node_count == 0) {
PrintCmdUsage(p);
return false;
}
return true;
}
// ./a.exe -scratch
// ./a.exe -quick
// ./a.exe -run_tests a.test b.test c.test
// ./a.exe --break_on_error
// ./a.exe -build=release
// ./a.exe --help
//
void TestCmdParser() {
char *argv[] = {
"exe",
"--build_scratch",
"-tests",
"a", "b", "c",
"--things", "1234", "asdsa",
"-build", "release",
};
int argc = MA_Lengthof(argv);
MA_Checkpoint scratch = MA_GetScratch();
bool build_scratch = false;
S8_List test_list = {0};
S8_List test_things = {0};
int build_profile = 0;
const char *build_profiles[] = {"debug", "release"};
int build_profiles_count = MA_Lengthof(build_profiles);
CmdParser p = MakeCmdParser(scratch.arena, argc, argv);
AddBool(&p, &build_scratch, "build_scratch", "builds a sandbox where I experiment with things");
AddList(&p, &test_list, "tests", "list of specific tests to run");
AddList(&p, &test_things, "things", "list of things");
AddEnum(&p, &build_profile, "build", "choose build profile", build_profiles, build_profiles_count);
bool success = ParseCmd(scratch.arena, &p);
IO_Assertf(success, "failed to parse cmd");
IO_Assert(build_scratch);
IO_Assert(test_list.node_count == 3);
IO_Assert(test_things.node_count == 2);
IO_Assert(build_profile == 1);
MA_ReleaseScratch(scratch);
}

View File

@@ -1,6 +1,7 @@
typedef enum {
CmdDeclKind_Bool,
CmdDeclKind_Int,
CmdDeclKind_List,
CmdDeclKind_Enum,
} CmdDeclKind;
@@ -14,6 +15,7 @@ struct CmdDecl {
bool *bool_result;
S8_List *list_result;
int *int_result;
int *enum_result;
const char **enum_options;
@@ -25,7 +27,11 @@ struct CmdParser {
int argc;
char **argv;
MA_Arena *arena;
const char *custom_help;
CmdDecl *fdecl;
CmdDecl *ldecl;
bool require_one_standalone_arg;
S8_List args;
};

View File

@@ -20,11 +20,3 @@
#include "filesystem.c"
#include "cmd.c"
/*
- I think it's okay to say that strings being null terminated should be mostly treated as NOT terminated but leave some
leeway for big buffers and other such things. Just make sure to not relay on it because it's easier unless specified.
- Not sure if we should assume that strings should use allocators or arenas, for now it's arenas because I don't have other use cases
@todo
- Remove static buffers from filesystem, use scratch arenas, more secure, data corruption instead of control flow corruption
*/

View File

@@ -381,7 +381,7 @@ OS_API OS_Date OS_GetDate(void) {
return result;
}
#else
#elif __linux__ || __APPLE__ || __unix__
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
@@ -690,9 +690,9 @@ OS_API OS_Result OS_WriteFile(S8_String path, S8_String string) {
return result;
}
#endif
#endif
#if _WIN32 || __linux__ || __APPLE__ || __unix__
OS_API int OS_SystemF(const char *string, ...) {
MA_Checkpoint scratch = MA_GetScratch();
S8_FORMAT(scratch.arena, string, result);
@@ -746,3 +746,4 @@ OS_API S8_String OS_ExpandIncludes(MA_Arena *arena, S8_String filepath) {
}
return result;
}
#endif

View File

@@ -4,20 +4,6 @@
#define MA_Assertf(x, ...) assert(x)
#endif
#ifndef MA_MemoryZero
#include <string.h>
MA_API void MA_MemoryZero(void *p, size_t size) {
memset(p, 0, size);
}
#endif
#ifndef MA_MemoryCopy
#include <string.h>
MA_API void MA_MemoryCopy(void *dst, void *src, size_t size) {
memcpy(dst, src, size);
}
#endif
#ifndef MA_CMalloc
#include <stdlib.h>
#define MA_CMalloc(x) malloc(x)
@@ -434,7 +420,7 @@ MA_API bool MV_DecommitPos(MV_Memory *m, size_t pos) {
return false;
}
#else
#elif __unix__ || __linux__ || __APPLE__
#include <sys/mman.h>
#define MV__UNIX_PAGE_SIZE 4096
MA_API MV_Memory MV_Reserve(size_t size) {
@@ -465,4 +451,17 @@ MA_API void MV_Deallocate(MV_Memory *m) {
int result = munmap(m->data, m->reserve);
MA_Assertf(result == 0, "Failed to release virtual memory using munmap");
}
#else
MA_API MV_Memory MV_Reserve(size_t size) {
MV_Memory result = {0};
return result;
}
MA_API bool MV_Commit(MV_Memory *m, size_t commit) {
return false;
}
MA_API void MV_Deallocate(MV_Memory *m) {
}
#endif

View File

@@ -55,6 +55,16 @@ typedef struct MA_SourceLoc MA_SourceLoc;
#endif
#endif
#ifndef MA_MemoryZero
#include <string.h>
#define MA_MemoryZero(p, size) memset(p, 0, size)
#endif
#ifndef MA_MemoryCopy
#include <string.h>
#define MA_MemoryCopy(dst, src, size) memcpy(dst, src, size);
#endif
typedef enum M_AllocatorOp {
M_AllocatorOp_Invalid,
M_AllocatorOp_Allocate,
@@ -158,8 +168,6 @@ MA_API void MA_PopSize(MA_Arena *arena, size_t size);
MA_API void MA_DeallocateArena(MA_Arena *arena);
MA_API void MA_Reset(MA_Arena *arena);
MA_API void MA_MemoryZero(void *p, size_t size);
MA_API void MA_MemoryCopy(void *dst, void *src, size_t size);
MA_API size_t MA_GetAlignOffset(size_t size, size_t align);
MA_API size_t MA_AlignUp(size_t size, size_t align);
MA_API size_t MA_AlignDown(size_t size, size_t align);

View File

@@ -31,7 +31,7 @@ IO_StaticFunc int IO_Strlen(char *string) {
return len;
}
void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
IO_THREAD_LOCAL void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) {
va_list args1;
@@ -108,8 +108,7 @@ IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ..
if (IO_User_OutputMessage) {
IO_User_OutputMessage(kind, file, line, result, size);
}
else {
} else {
IO_OutputMessage(result, size);
}
@@ -118,9 +117,9 @@ IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ..
}
}
IO_API bool IO__FatalError(char *msg) {
int len = IO_Strlen(msg);
IO_ErrorResult result = IO_OutputError(msg, len);
IO_API bool IO__FatalError(const char *msg) {
int len = IO_Strlen((char *)msg);
IO_ErrorResult result = IO_OutputError((char *)msg, len);
if (result == IO_ErrorResult_Exit) {
IO_Exit(1);
}
@@ -130,8 +129,7 @@ IO_API bool IO__FatalError(char *msg) {
IO_API void IO_Print(int kind, const char *file, int line, char *msg, int len) {
if (IO_User_OutputMessage) {
IO_User_OutputMessage(kind, file, line, msg, len);
}
else {
} else {
IO_OutputMessage(msg, len);
}
}
@@ -188,8 +186,7 @@ IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
}
result = IO_ErrorResult_Exit;
}
else {
} else {
result = IO_ErrorResult_Break;
}
@@ -203,9 +200,8 @@ IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
IO_API void IO_Exit(int error_code) {
ExitProcess(error_code);
}
#else // _WIN32 else // LIBC
#elif __linux__ || __unix__ || __APPLE__
#include <stdio.h>
IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
fprintf(stderr, "%.*s", len, str);
return IO_ErrorResult_Exit;
@@ -222,4 +218,19 @@ IO_API void IO_Exit(int error_code) {
IO_API bool IO_IsDebuggerPresent(void) {
return false;
}
#else
IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
return IO_ErrorResult_Exit;
}
IO_API void IO_OutputMessage(char *str, int len) {
}
IO_API void IO_Exit(int error_code) {
}
IO_API bool IO_IsDebuggerPresent(void) {
return false;
}
#endif // LIBC

View File

@@ -22,6 +22,22 @@ typedef enum IO_ErrorResult {
#define IO_DebugBreak() (__builtin_trap(), 0)
#endif
#ifndef IO_THREAD_LOCAL
#if defined(__cplusplus) && __cplusplus >= 201103L
#define IO_THREAD_LOCAL thread_local
#elif defined(__GNUC__)
#define IO_THREAD_LOCAL __thread
#elif defined(_MSC_VER)
#define IO_THREAD_LOCAL __declspec(thread)
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
#define IO_THREAD_LOCAL _Thread_local
#elif defined(__TINYC__)
#define IO_THREAD_LOCAL _Thread_local
#else
#error Couldnt figure out thread local, needs to be provided manually
#endif
#endif
#if defined(__has_attribute)
#if __has_attribute(format)
#define IO__PrintfFormat(fmt, va) __attribute__((format(printf, fmt, va)))
@@ -33,13 +49,13 @@ typedef enum IO_ErrorResult {
#endif
typedef void IO_MessageHandler(int kind, const char *file, int line, char *str, int len);
extern void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
extern IO_THREAD_LOCAL void (*IO_User_OutputMessage)(int kind, const char *file, int line, char *str, int len);
#define IO__STRINGIFY(x) #x
#define IO__TOSTRING(x) IO__STRINGIFY(x)
#define IO_LINE IO__TOSTRING(__LINE__)
#define IO_Assert(x) !(x) && IO__FatalError((char *)(__FILE__ "(" IO_LINE "): " \
#define IO_Assert(x) !(x) && IO__FatalError((__FILE__ "(" IO_LINE "): " \
"error: " #x "\n")) && \
IO_DebugBreak()
#define IO_FatalErrorf(...) \
@@ -70,14 +86,14 @@ extern void (*IO_User_OutputMessage)(int kind, const char *file, int line, char
}
#define IO_InvalidCodepath() IO_FatalError("This codepath is invalid")
#define IO_InvalidDefaultCase() \
default: { \
default: { \
IO_FatalError("Entered invalid switch statement case"); \
}
}
#define IO_Todo() IO_FatalError("This codepath is not implemented yet")
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) IO__PrintfFormat(3, 4);
IO_API void IO__Printf(int kind, const char *file, int line, const char *msg, ...) IO__PrintfFormat(4, 5);
IO_API bool IO__FatalError(char *msg);
IO_API bool IO__FatalError(const char *msg);
IO_API void IO_Print(int kind, const char *file, int line, char *msg, int len);
IO_API void IO_OutputMessage(char *str, int len);
IO_API IO_ErrorResult IO_OutputError(char *str, int len);

View File

@@ -11,6 +11,7 @@
#elif defined(__linux__)
#define OS_POSIX 1
#define OS_LINUX 1
#elif OS_WASM
#else
#error Unsupported platform
#endif
@@ -109,6 +110,8 @@
#define OS_NAME "linux"
#elif OS_MAC
#define OS_NAME "mac_os"
#elif OS_WASM
#define OS_NAME "wasm"
#else
#error couldnt figure out OS
#endif

View File

@@ -4,6 +4,51 @@
#include "test_arena.cpp"
#include "test_lexer.cpp"
// ./a.exe -scratch
// ./a.exe -quick
// ./a.exe -run_tests a.test b.test c.test
// ./a.exe --break_on_error
// ./a.exe -build=release
// ./a.exe --help
//
void TestCmdParser() {
const char *argv[] = {
"exe",
"--build_scratch",
"-tests",
"a",
"b",
"c",
"--things",
"1234",
"asdsa",
"-build",
"release",
};
int argc = MA_Lengthof(argv);
MA_Checkpoint scratch = MA_GetScratch();
bool build_scratch = false;
S8_List test_list = {0};
S8_List test_things = {0};
int build_profile = 0;
const char *build_profiles[] = {"debug", "release"};
int build_profiles_count = MA_Lengthof(build_profiles);
CmdParser p = MakeCmdParser(scratch.arena, argc, (char **)argv, "this is a test");
AddBool(&p, &build_scratch, "build_scratch", "builds a sandbox where I experiment with things");
AddList(&p, &test_list, "tests", "list of specific tests to run");
AddList(&p, &test_things, "things", "list of things");
AddEnum(&p, &build_profile, "build", "choose build profile", build_profiles, build_profiles_count);
bool success = ParseCmd(scratch.arena, &p);
IO_Assertf(success, "failed to parse cmd");
IO_Assert(build_scratch);
IO_Assert(test_list.node_count == 3);
IO_Assert(test_things.node_count == 2);
IO_Assert(build_profile == 1);
MA_ReleaseScratch(scratch);
}
int main() {
TestSimpleInsertAndIntegrity();
TestStrings();
@@ -20,7 +65,6 @@ int main() {
TestBootstrapExclusive();
TestBootstrapArenaClear();
// @todo: github worker fails on this:
TestClexer();
// Unicode iteration over codepoints using For