├── LICENSE ├── README.md ├── huffman ├── README.md ├── amd64 │ ├── platform.c │ ├── start.S │ └── syscalls.h ├── build.sh ├── i386 │ ├── flags.sh │ ├── platform.c │ ├── start.S │ └── syscalls.h └── main.c ├── jsonp ├── README.md ├── amd64 │ ├── platform.c │ ├── start.S │ └── syscalls.h ├── build.sh ├── i386 │ ├── flags.sh │ ├── platform.c │ ├── start.S │ └── syscalls.h ├── main.c ├── test.json └── test2.json ├── memealloc ├── README.md ├── amd64 │ ├── platform.c │ ├── start.S │ └── syscalls.h ├── build.sh ├── i386 │ ├── flags.sh │ ├── platform.c │ ├── start.S │ └── syscalls.h └── main.c ├── namae ├── README.md ├── amd64 │ ├── main.c │ ├── start.S │ └── syscalls.h ├── build.sh ├── i386 │ ├── flags.sh │ ├── main.c │ ├── start.S │ └── syscalls.h └── namae.c └── qsort ├── amd64 ├── platform.c ├── start.S └── syscalls.h ├── build.sh ├── i386 ├── flags.sh ├── platform.c ├── start.S └── syscalls.h └── main.c /LICENSE: -------------------------------------------------------------------------------- 1 | This code is public domain and comes with no warranty. 2 | You are free to do whatever you want with it. You can 3 | contact me at lolisamurai@tfwno.gf but don't expect any 4 | support. 5 | I hope you will find the code useful or at least 6 | interesting to read. Have fun! 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Collection of reusable libc-free code that I copypaste and tweak 2 | in every libc-free project. 3 | 4 | This is all linux-specific, amd64 and i386 only for now. 5 | 6 | # Disclaimer 7 | These snippets might be incomplete, broken or just plain wrong, 8 | as many of them haven't had the chance to be heavily tested yet. 9 | 10 | This is not meant to be a general purpose library. This is 11 | basically me backing up my code snippets on github. 12 | 13 | # License 14 | This code is public domain and comes with no warranty. 15 | You are free to do whatever you want with it. You can 16 | contact me at lolisamurai@tfwno.gf but don't expect any 17 | support. 18 | I hope you will find the code useful or at least 19 | interesting to read. Have fun! 20 | -------------------------------------------------------------------------------- /huffman/README.md: -------------------------------------------------------------------------------- 1 | This is an implementation of file compression using huffman coding. 2 | 3 | It's meant to be tiny and in-memory. It will some day be part of 4 | a small gzip deflate decompressor that I will use for http APIs 5 | that return gzipped data. 6 | 7 | The encode function is currently partially broken and will not work 8 | for fully binary files that generate too long codes. Text appears 9 | to be working fine 100% of the time. 10 | -------------------------------------------------------------------------------- /huffman/amd64/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | #define AMD64 22 | #include "syscalls.h" 23 | 24 | typedef unsigned long int u64; 25 | typedef unsigned int u32; 26 | typedef unsigned short int u16; 27 | typedef unsigned char u8; 28 | 29 | typedef long int i64; 30 | typedef int i32; 31 | typedef short int i16; 32 | typedef signed char i8; 33 | 34 | typedef i64 intptr; 35 | typedef u64 uintptr; 36 | 37 | #include "../main.c" 38 | -------------------------------------------------------------------------------- /huffman/amd64/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | #include "syscalls.h" 22 | 23 | .intel_syntax noprefix 24 | .text 25 | .globl _start, syscall, 26 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 27 | .globl syscall6 28 | 29 | _start: 30 | xor rbp,rbp 31 | pop rdi 32 | mov rsi,rsp 33 | and rsp,-16 34 | call main 35 | mov rdi,rax 36 | mov rax,SYS_exit 37 | syscall 38 | ret 39 | 40 | syscall: 41 | mov rax,rdi 42 | syscall 43 | ret 44 | 45 | syscall1: 46 | mov rax,rdi 47 | mov rdi,rsi 48 | syscall 49 | ret 50 | 51 | syscall2: 52 | mov rax,rdi 53 | mov rdi,rsi 54 | mov rsi,rdx 55 | syscall 56 | ret 57 | 58 | syscall3: 59 | mov rax,rdi 60 | mov rdi,rsi 61 | mov rsi,rdx 62 | mov rdx,rcx 63 | syscall 64 | ret 65 | 66 | syscall4: 67 | mov rax,rdi 68 | mov rdi,rsi 69 | mov rsi,rdx 70 | mov rdx,rcx 71 | mov r10,r8 72 | syscall 73 | ret 74 | 75 | syscall5: 76 | mov rax,rdi 77 | mov rdi,rsi 78 | mov rsi,rdx 79 | mov rdx,rcx 80 | mov r10,r8 81 | mov r8,r9 82 | syscall 83 | ret 84 | 85 | syscall6: 86 | mov rax,rdi 87 | mov rdi,rsi 88 | mov rsi,rdx 89 | mov rdx,rcx 90 | mov r10,r8 91 | mov r8,r9 92 | mov r9,[rsp+8] 93 | syscall 94 | ret 95 | -------------------------------------------------------------------------------- /huffman/amd64/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | #define SYS_read 0 22 | #define SYS_write 1 23 | #define SYS_open 2 24 | #define SYS_close 3 25 | #define SYS_exit 60 26 | #define SYS_mmap 9 27 | -------------------------------------------------------------------------------- /huffman/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # huffman: implementation of file compression using huffman 19 | # coding 20 | 21 | exename="huffman" 22 | archname=${1:-amd64} # if not specified, default to amd64 23 | 24 | if [ -e $archname/flags.sh ]; then 25 | source $archname/flags.sh 26 | fi 27 | 28 | shift 29 | 30 | gcc -std=c89 -pedantic -s -O2 -Wall -Werror \ 31 | -nostdlib \ 32 | -fno-unwind-tables \ 33 | -fno-asynchronous-unwind-tables \ 34 | -fdata-sections \ 35 | -Wl,--gc-sections \ 36 | -Wa,--noexecstack \ 37 | -fno-builtin \ 38 | -fno-stack-protector \ 39 | $COMPILER_FLAGS \ 40 | $@ \ 41 | $archname/start.S $archname/platform.c \ 42 | -o $exename \ 43 | \ 44 | && strip -R .comment $exename 45 | -------------------------------------------------------------------------------- /huffman/i386/flags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # huffman: implementation of file compression using huffman 19 | # coding 20 | 21 | export COMPILER_FLAGS="-m32 -Wno-long-long -DLEGACY_MMAP=1" 22 | -------------------------------------------------------------------------------- /huffman/i386/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | #define I386 22 | #include "syscalls.h" 23 | 24 | typedef unsigned long long int u64; 25 | typedef unsigned int u32; 26 | typedef unsigned short int u16; 27 | typedef unsigned char u8; 28 | 29 | typedef long long int i64; 30 | typedef int i32; 31 | typedef short int i16; 32 | typedef signed char i8; 33 | 34 | typedef i32 intptr; 35 | typedef u32 uintptr; 36 | 37 | #include "../main.c" 38 | -------------------------------------------------------------------------------- /huffman/i386/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | #include "syscalls.h" 22 | 23 | .intel_syntax noprefix 24 | .text 25 | .globl _start, syscall 26 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 27 | .globl syscall6 28 | 29 | _start: 30 | xor ebp,ebp 31 | pop esi 32 | mov ecx,esp 33 | and esp,-16 34 | push 0xb16b00b5 35 | push 0xb16b00b5 36 | push ecx 37 | push esi 38 | call main 39 | add esp,16 40 | mov ebx,eax 41 | mov eax,SYS_exit 42 | int 0x80 43 | ret 44 | 45 | syscall: 46 | mov eax,[esp+4] 47 | int 0x80 48 | ret 49 | 50 | syscall1: 51 | push ebx 52 | mov eax,[esp+4+4] 53 | mov ebx,[esp+8+4] 54 | int 0x80 55 | pop ebx 56 | ret 57 | 58 | syscall2: 59 | push ebx 60 | mov eax,[esp+4+4] 61 | mov ebx,[esp+8+4] 62 | mov ecx,[esp+12+4] 63 | int 0x80 64 | pop ebx 65 | ret 66 | 67 | syscall3: 68 | push ebx 69 | mov eax,[esp+4+4] 70 | mov ebx,[esp+8+4] 71 | mov ecx,[esp+12+4] 72 | mov edx,[esp+16+4] 73 | int 0x80 74 | pop ebx 75 | ret 76 | 77 | syscall4: 78 | push ebx 79 | push esi 80 | mov eax,[esp+4+8] 81 | mov ebx,[esp+8+8] 82 | mov ecx,[esp+12+8] 83 | mov edx,[esp+16+8] 84 | mov esi,[esp+20+8] 85 | int 0x80 86 | pop esi 87 | pop ebx 88 | ret 89 | 90 | syscall5: 91 | push ebx 92 | push esi 93 | push edi 94 | mov eax,[esp+4+12] 95 | mov ebx,[esp+8+12] 96 | mov ecx,[esp+12+12] 97 | mov edx,[esp+16+12] 98 | mov esi,[esp+20+12] 99 | mov edi,[esp+24+12] 100 | int 0x80 101 | pop edi 102 | pop esi 103 | pop ebx 104 | ret 105 | 106 | syscall6: 107 | push ebx 108 | push esi 109 | push edi 110 | push ebp 111 | mov eax,[esp+4+16] 112 | mov ebx,[esp+8+16] 113 | mov ecx,[esp+12+16] 114 | mov edx,[esp+16+16] 115 | mov esi,[esp+20+16] 116 | mov edi,[esp+24+16] 117 | mov ebp,[esp+28+16] 118 | int 0x80 119 | pop ebp 120 | pop edi 121 | pop esi 122 | pop ebx 123 | ret 124 | -------------------------------------------------------------------------------- /huffman/i386/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | #define SYS_read 3 22 | #define SYS_write 4 23 | #define SYS_open 5 24 | #define SYS_close 6 25 | #define SYS_exit 1 26 | #define SYS_mmap 90 27 | -------------------------------------------------------------------------------- /huffman/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | huffman: implementation of file compression using huffman 18 | coding 19 | */ 20 | 21 | typedef i32 b32; 22 | 23 | #define internal static 24 | #define globvar static 25 | 26 | #define min(a, b) ((a) < (b) ? (a) : (b)) 27 | 28 | void* syscall1(uintptr number, void* arg1); 29 | 30 | void* syscall3( 31 | uintptr number, 32 | void* arg1, 33 | void* arg2, 34 | void* arg3 35 | ); 36 | 37 | void* syscall6( 38 | uintptr number, 39 | void* arg1, 40 | void* arg2, 41 | void* arg3, 42 | void* arg4, 43 | void* arg5, 44 | void* arg6 45 | ); 46 | 47 | /* ------------------------------------------------------------- */ 48 | 49 | internal 50 | void memecpy(void* dst, void const* src, intptr nbytes) 51 | { 52 | intptr i; 53 | u8* dst_bytes; 54 | u8* src_bytes; 55 | 56 | if (nbytes / sizeof(intptr)) 57 | { 58 | intptr* dst_chunks = (intptr*)dst; 59 | intptr* src_chunks = (intptr*)src; 60 | 61 | for (i = 0; i < nbytes / sizeof(intptr); ++i) { 62 | dst_chunks[i] = src_chunks[i]; 63 | } 64 | 65 | nbytes %= sizeof(intptr); 66 | dst = &dst_chunks[i]; 67 | src = &src_chunks[i]; 68 | } 69 | 70 | dst_bytes = (u8*)dst; 71 | src_bytes = (u8*)src; 72 | 73 | for (i = 0; i < nbytes; ++i) { 74 | dst_bytes[i] = src_bytes[i]; 75 | } 76 | } 77 | 78 | internal 79 | void memeset(void* dst, u8 value, intptr nbytes) 80 | { 81 | intptr i; 82 | u8* dst_bytes; 83 | 84 | if (nbytes / sizeof(intptr)) 85 | { 86 | intptr* dst_chunks = (intptr*)dst; 87 | intptr chunk; 88 | u8* raw_chunk = (u8*)&chunk; 89 | 90 | for (i = 0; i < sizeof(intptr); ++i) { 91 | raw_chunk[i] = value; 92 | } 93 | 94 | for (i = 0; i < nbytes / sizeof(intptr); ++i) { 95 | dst_chunks[i] = chunk; 96 | } 97 | 98 | nbytes %= sizeof(intptr); 99 | dst = &dst_chunks[i]; 100 | } 101 | 102 | dst_bytes = (u8*)dst; 103 | 104 | for (i = 0; i < nbytes; ++i) { 105 | dst_bytes[i] = value; 106 | } 107 | } 108 | 109 | /* ------------------------------------------------------------- */ 110 | 111 | #define stdin 0 112 | 113 | internal 114 | intptr write(int fd, void const* data, uintptr nbytes) 115 | { 116 | return (uintptr) 117 | syscall3( 118 | SYS_write, 119 | (void*)(intptr)fd, 120 | (void*)data, 121 | (void*)nbytes 122 | ); 123 | } 124 | 125 | internal 126 | intptr read(int fd, void* data, intptr nbytes) 127 | { 128 | return (intptr) 129 | syscall3( 130 | SYS_read, 131 | (void*)(intptr)fd, 132 | data, 133 | (void*)nbytes 134 | ); 135 | } 136 | 137 | #define O_RDONLY 00 138 | 139 | typedef u32 mode_t; 140 | 141 | internal 142 | int open(char const* filename, u32 flags, mode_t mode) 143 | { 144 | return (int)(intptr) 145 | syscall3( 146 | SYS_open, 147 | (void*)filename, 148 | (void*)(intptr)flags, 149 | (void*)(intptr)mode 150 | ); 151 | } 152 | 153 | internal 154 | void close(int fd) { 155 | syscall1(SYS_close, (void*)(intptr)fd); 156 | } 157 | 158 | #define PROT_READ 0x1 159 | #define PROT_WRITE 0x2 160 | 161 | #define MAP_PRIVATE 0x02 162 | #define MAP_ANONYMOUS 0x20 163 | 164 | #ifndef PAGE_SIZE 165 | #define PAGE_SIZE 4096 166 | #endif 167 | 168 | internal 169 | void* mmap( 170 | void* addr, 171 | uintptr nbytes, 172 | int prot, 173 | int flags, 174 | int fd, 175 | u32 offset) 176 | { 177 | #ifdef LEGACY_MMAP 178 | void* params[7]; 179 | 180 | offset = (offset + PAGE_SIZE / 2) / PAGE_SIZE; 181 | offset *= PAGE_SIZE; 182 | nbytes = (nbytes + PAGE_SIZE / 2) / PAGE_SIZE; 183 | nbytes *= PAGE_SIZE; 184 | 185 | params[0] = addr; 186 | params[1] = (void*)(intptr)nbytes; 187 | params[2] = (void*)(intptr)prot; 188 | params[3] = (void*)(intptr)flags; 189 | params[4] = (void*)(intptr)fd; 190 | params[5] = (void*)(intptr)offset; 191 | params[6] = 0; 192 | 193 | return syscall1(SYS_mmap, (void*)params); 194 | #else 195 | return 196 | syscall6( 197 | SYS_mmap, 198 | addr, 199 | (void*)nbytes, 200 | (void*)(intptr)prot, 201 | (void*)(intptr)flags, 202 | (void*)(intptr)fd, 203 | (void*)(intptr)offset 204 | ); 205 | #endif 206 | } 207 | 208 | /* ------------------------------------------------------------- */ 209 | 210 | #define FD_BUFSIZE 8000 211 | 212 | typedef struct 213 | { 214 | int handle; 215 | b32 flush_every_line; 216 | uintptr buf_nbytes; 217 | char buf[FD_BUFSIZE]; 218 | } 219 | fd_t; 220 | 221 | /* 222 | internal 223 | int fopen(fd_t* fd, char const* filename, u32 flags, mode_t mode) 224 | { 225 | fd->handle = open(filename, flags, mode); 226 | fd->buf_nbytes = 0; 227 | fd->flush_every_line = 0; 228 | 229 | return fd->handle; 230 | } 231 | */ 232 | 233 | internal 234 | intptr fflush(fd_t* fd) 235 | { 236 | intptr res = 237 | fd->buf_nbytes ? write(fd->handle, fd->buf, fd->buf_nbytes) 238 | : 0; 239 | 240 | fd->buf_nbytes = 0; 241 | 242 | return res; 243 | } 244 | 245 | /* 246 | internal 247 | void fclose(fd_t* fd) 248 | { 249 | fflush(fd); 250 | close(fd->handle); 251 | fd->handle = 0; 252 | } 253 | */ 254 | 255 | internal 256 | intptr fwrite(fd_t* fd, void const* data, uintptr nbytes) 257 | { 258 | u8* p = (u8*)data; 259 | uintptr total = nbytes; 260 | 261 | while (nbytes) 262 | { 263 | intptr res; 264 | b32 should_flush = 0; 265 | 266 | uintptr to_write = 267 | min(nbytes, FD_BUFSIZE - fd->buf_nbytes); 268 | 269 | memecpy(fd->buf + fd->buf_nbytes, p, to_write); 270 | fd->buf_nbytes += to_write; 271 | 272 | if (fd->buf_nbytes >= FD_BUFSIZE) { 273 | should_flush = 1; 274 | } 275 | 276 | else if (fd->flush_every_line) 277 | { 278 | uintptr i; 279 | 280 | for (i = 0; i < to_write; ++i) 281 | { 282 | if (p[i] == '\n' || p[i] == '\r') { 283 | should_flush = 1; 284 | break; 285 | } 286 | } 287 | } 288 | 289 | if (should_flush) 290 | { 291 | uintptr to_flush = fd->buf_nbytes; 292 | 293 | res = fflush(fd); 294 | if (res != to_flush) { 295 | return res; 296 | } 297 | } 298 | 299 | nbytes -= to_write; 300 | p += to_write; 301 | } 302 | 303 | return total; 304 | } 305 | 306 | #define fread(fd, data, nbytes) read(fd->handle, data, nbytes) 307 | 308 | globvar fd_t stdout_; 309 | globvar fd_t* stdout = &stdout_; 310 | 311 | globvar fd_t stderr_; 312 | globvar fd_t* stderr = &stderr_; 313 | 314 | internal 315 | void stdinit() 316 | { 317 | stdout->handle = 1; 318 | stdout->flush_every_line = 1; 319 | stderr->handle = 2; 320 | stderr->flush_every_line = 1; 321 | } 322 | 323 | internal 324 | void stdfflush() 325 | { 326 | fflush(stdout); 327 | fflush(stderr); 328 | } 329 | 330 | /* ------------------------------------------------------------- */ 331 | 332 | internal 333 | uintptr strlen(char const* str) 334 | { 335 | char const* p; 336 | for (p = str; *p; ++p); 337 | return p - str; 338 | } 339 | 340 | #ifdef HUFFMAN_DEBUG 341 | intptr uitoa( 342 | u8 base, 343 | uintptr val, 344 | char* buf, 345 | intptr width, 346 | char filler) 347 | { 348 | char c; 349 | char* p = buf; 350 | intptr res; 351 | 352 | if (!base) { 353 | return 0; 354 | } 355 | 356 | if (base > 16) { 357 | return 0; 358 | } 359 | 360 | do 361 | { 362 | u8 digit = val % base; 363 | val /= base; 364 | *p++ = "0123456789abcdef"[digit]; 365 | } 366 | while(val); 367 | 368 | while (p - buf < width) { 369 | *p++ = filler; 370 | } 371 | 372 | res = p - buf; 373 | *p-- = 0; 374 | 375 | while (p > buf) 376 | { 377 | /* flip the string */ 378 | c = *p; 379 | *p-- = *buf; 380 | *buf++ = c; 381 | } 382 | 383 | return res; 384 | } 385 | #endif 386 | 387 | #define fputs(fd, str) fwrite(fd, str, strlen(str)) 388 | #define puts(str) fputs(stdout, str) 389 | #define errs(str) fputs(stderr, str) 390 | 391 | /* ------------------------------------------------------------- */ 392 | 393 | internal 394 | void swap_intptr(intptr* a, intptr* b) 395 | { 396 | intptr tmp = *a; 397 | *a = *b; 398 | *b = tmp; 399 | } 400 | 401 | typedef b32 qsort_intptr_cmp(intptr a, intptr b); 402 | 403 | internal 404 | uintptr qsort_intptr_partition( 405 | intptr* arr, 406 | qsort_intptr_cmp* cmp, 407 | uintptr lo, 408 | uintptr hi) 409 | { 410 | uintptr pivot = arr[hi]; 411 | uintptr i = lo - 1; 412 | uintptr j; 413 | 414 | for (j = lo; j <= hi - 1; ++j) 415 | { 416 | if (cmp(arr[j], pivot)) 417 | { 418 | ++i; 419 | swap_intptr(&arr[i], &arr[j]); 420 | } 421 | } 422 | 423 | swap_intptr(&arr[++i], &arr[hi]); 424 | 425 | return i; 426 | } 427 | 428 | internal 429 | void qsort_intptr( 430 | intptr* arr, 431 | qsort_intptr_cmp* cmp, 432 | uintptr lo, uintptr hi) 433 | { 434 | uintptr p; 435 | 436 | if (lo >= hi) { 437 | return; 438 | } 439 | 440 | p = qsort_intptr_partition(arr, cmp, lo, hi); 441 | qsort_intptr(arr, cmp, lo, p - 1); 442 | qsort_intptr(arr, cmp, p + 1, hi); 443 | } 444 | 445 | /* ------------------------------------------------------------- */ 446 | 447 | #define HUFFMAN_NULL_VAL 0x1000 448 | 449 | typedef struct huffman_node_ 450 | { 451 | u16 val; 452 | uintptr weight; 453 | struct huffman_node_* parent; 454 | struct huffman_node_* child[2]; 455 | } 456 | huffman_node; 457 | 458 | typedef struct 459 | { 460 | u16 value; 461 | u8 nbits; 462 | char character; 463 | } 464 | huffman_code; 465 | 466 | #ifdef HUFFMAN_DEBUG 467 | internal 468 | void huffman_print_tree( 469 | huffman_node const* n, 470 | uintptr level, 471 | uintptr code, 472 | u8 codelen) 473 | { 474 | uintptr i; 475 | char buf[21]; 476 | 477 | for (i = 0; i < level; ++i) { 478 | errs(" "); 479 | } 480 | 481 | errs("("); 482 | 483 | if (n->val != HUFFMAN_NULL_VAL) 484 | { 485 | errs("'"); 486 | 487 | if (n->val >= 0x20 && n->val <= 0x7E) { 488 | fwrite(stderr, &n->val, 1); 489 | } else { 490 | errs("\\x"); 491 | uitoa(16, n->val, buf, 2, '0'); 492 | errs(buf); 493 | } 494 | 495 | errs("' "); 496 | } 497 | 498 | errs("weight: "); 499 | uitoa(10, n->weight, buf, 0, 0); 500 | errs(buf); 501 | errs(")"); 502 | 503 | if (n->val != HUFFMAN_NULL_VAL) 504 | { 505 | errs(" <-- "); 506 | uitoa(2, code, buf, codelen, '0'); 507 | errs(buf); 508 | } 509 | 510 | errs("\n"); 511 | 512 | if (n->val != HUFFMAN_NULL_VAL) { 513 | return; 514 | } 515 | 516 | if (codelen >= 15) { 517 | errln("FUCK"); 518 | return; 519 | } 520 | 521 | /* !BRANCHING RECURSION! */ 522 | 523 | huffman_print_tree( 524 | n->child[0], 525 | level + 1, 526 | code << 1, 527 | codelen + 1 528 | ); 529 | 530 | huffman_print_tree( 531 | n->child[1], 532 | level + 1, 533 | (code << 1)|1, 534 | codelen + 1 535 | ); 536 | } 537 | #else 538 | #define huffman_print_tree(n, level, code, codelen) 539 | #endif 540 | 541 | internal 542 | void huffman_walk_tree( 543 | huffman_node const* n, 544 | huffman_code* codes, 545 | uintptr level, 546 | uintptr code, 547 | u8 codelen) 548 | { 549 | if (n->val != HUFFMAN_NULL_VAL) 550 | { 551 | huffman_code* c = &codes[n->val]; 552 | c->value = code; 553 | c->nbits = codelen; 554 | return; 555 | } 556 | 557 | /* !BRANCHING RECURSION! */ 558 | 559 | huffman_walk_tree( 560 | n->child[0], 561 | codes, 562 | level + 1, 563 | code << 1, 564 | codelen + 1 565 | ); 566 | 567 | huffman_walk_tree( 568 | n->child[1], 569 | codes, 570 | level + 1, 571 | (code << 1)|1, 572 | codelen + 1 573 | ); 574 | } 575 | 576 | internal 577 | b32 huffman(u8 const* data, intptr n, huffman_code* codes) 578 | { 579 | huffman_node tree[0x200]; 580 | huffman_node* nodes[2]; 581 | huffman_node* newnode = 0; 582 | huffman_node* root = 0; 583 | uintptr i, j; 584 | 585 | memeset(tree, 0, sizeof(tree)); 586 | 587 | /* frequencies */ 588 | for (i = 0; i < 0x100; ++i) { 589 | codes[i].character = (char)i; 590 | tree[i].val = i; 591 | } 592 | 593 | for (i = 0; i < n; ++i) { 594 | ++tree[data[i]].weight; 595 | } 596 | 597 | while (1) 598 | { 599 | /* 600 | find 2 lowest weight nodes 601 | also store the first uninitalized node 602 | */ 603 | memeset(nodes, 0, sizeof(nodes)); 604 | newnode = 0; 605 | 606 | for (j = 0; j < 2; ++j) 607 | { 608 | for (i = 0; i < 0x200; ++i) 609 | { 610 | huffman_node* n = &tree[i]; 611 | 612 | if (j && n == nodes[0]) { 613 | continue; 614 | } 615 | 616 | if (!n->weight) 617 | { 618 | /* uninitialized */ 619 | 620 | if (!newnode) 621 | { 622 | newnode = n; 623 | n->val = HUFFMAN_NULL_VAL; 624 | /* reuses nodes that had 0 frequency */ 625 | } 626 | 627 | continue; 628 | } 629 | 630 | if (n->parent) { 631 | /* already used */ 632 | continue; 633 | } 634 | 635 | if (!nodes[j] || n->weight < nodes[j]->weight) 636 | { 637 | /* store lowest weight node and make sure to 638 | not select the same node twice */ 639 | nodes[j] = n; 640 | } 641 | } 642 | 643 | if (!nodes[j]) { 644 | break; 645 | } 646 | } 647 | 648 | /* no more unused nodes? we're done */ 649 | if (!nodes[0] || !nodes[1]) { 650 | break; 651 | } 652 | 653 | if (!newnode) { 654 | return 0; 655 | } 656 | 657 | /* join the two lowest weight nodes with a new node */ 658 | newnode->weight = nodes[0]->weight + nodes[1]->weight; 659 | memecpy(newnode->child, nodes, sizeof(nodes)); 660 | nodes[0]->parent = newnode; 661 | nodes[1]->parent = newnode; 662 | 663 | root = newnode; 664 | } 665 | 666 | if (!root) { 667 | return 0; 668 | } 669 | 670 | huffman_print_tree(root, 0, 0, 0); 671 | huffman_walk_tree(root, codes, 0, 0, 0); 672 | 673 | return 1; 674 | } 675 | 676 | /* sort by code length first and by alphabetical order second */ 677 | b32 huffman_code_cmp(huffman_code* a, huffman_code* b) 678 | { 679 | if (a->nbits < b->nbits) { 680 | return 1; 681 | } 682 | 683 | return a->nbits == b->nbits && a->character <= b->character; 684 | } 685 | 686 | #ifdef HUFFMAN_DEBUG 687 | #define print_codes() \ 688 | for (i = 0; i < 0x100; ++i) \ 689 | { \ 690 | char buf[17]; \ 691 | huffman_code* c = index[i]; \ 692 | u8 ch = (u8)(c - codes); \ 693 | \ 694 | if (!c->nbits) { \ 695 | continue; \ 696 | } \ 697 | \ 698 | if (ch >= 0x20 && ch <= 0x7E) { \ 699 | errs(" "); \ 700 | } \ 701 | \ 702 | errs("'"); \ 703 | \ 704 | if (ch >= 0x20 && ch <= 0x7E) { \ 705 | fwrite(stderr, &ch, 1); \ 706 | } else { \ 707 | errs("\\x"); \ 708 | uitoa(16, (uintptr)ch, buf, 2, '0');\ 709 | errs(buf); \ 710 | } \ 711 | \ 712 | errs("': "); \ 713 | \ 714 | uitoa(2, c->value, buf, c->nbits, '0'); \ 715 | errs(buf); \ 716 | \ 717 | uitoa(10, c->nbits, buf, 0, 0); \ 718 | errs(" ("); \ 719 | errs(buf); \ 720 | errs(" bits)"); \ 721 | errs("\n"); \ 722 | } 723 | #endif 724 | 725 | internal 726 | void huffman_canonical_from_lengths( 727 | u8* lengths, 728 | huffman_code* codes) 729 | { 730 | uintptr i; 731 | huffman_code* index[0x100]; 732 | u16 curcode = 0; 733 | u8 curnbits; 734 | 735 | for (i = 0; i < 0x100; ++i) 736 | { 737 | codes[i].character = (char)i; 738 | codes[i].nbits = lengths[i]; 739 | index[i] = &codes[i]; 740 | } 741 | 742 | qsort_intptr( 743 | (intptr*)index, 744 | (qsort_intptr_cmp*)huffman_code_cmp, 745 | 0, 0xFE 746 | ); 747 | 748 | for (i = 0; !index[i]->nbits; ++i); 749 | 750 | curnbits = index[i]->nbits; 751 | 752 | for (; i < 0x100; ++i) 753 | { 754 | huffman_code* c = index[i]; 755 | 756 | if (c->nbits != curnbits) { 757 | curcode <<= c->nbits - curnbits; 758 | curnbits = c->nbits; 759 | } 760 | 761 | c->value = curcode; 762 | 763 | ++curcode; 764 | } 765 | 766 | #ifdef HUFFMAN_DEBUG 767 | errs("Reconstructed codes:\n"); 768 | print_codes() 769 | #endif 770 | } 771 | 772 | internal 773 | void huffman_canonical(huffman_code* codes) 774 | { 775 | u8 lengths[0x100]; 776 | uintptr i; 777 | 778 | for (i = 0; i < 0x100; ++i) { 779 | lengths[i] = codes[i].nbits; 780 | } 781 | 782 | huffman_canonical_from_lengths(lengths, codes); 783 | } 784 | 785 | internal 786 | b32 huffman_encode( 787 | u8 const* data, 788 | u8* compressed, 789 | uintptr n, 790 | huffman_code* codes, 791 | uintptr* pnbytes, 792 | u8* premainder_bits) 793 | { 794 | uintptr i; 795 | 796 | u8* p = compressed; 797 | u8 bits_left = 8; 798 | 799 | for (i = 0; i < n; ++i) 800 | { 801 | huffman_code* c = &codes[data[i]]; 802 | u8 code_len; 803 | u16 value; 804 | 805 | if (!c->nbits) { 806 | return 0; 807 | } 808 | 809 | code_len = c->nbits; 810 | 811 | /* move the value to the leftmost bit */ 812 | value = c->value << (16 - c->nbits); 813 | 814 | /* 815 | c->nbits = 4; 816 | c->value = 00000000_00001101 817 | value = 11010000_00000000 818 | ^--^ 819 | the actual code 820 | */ 821 | 822 | /* pack the bits disregarding byte alignment */ 823 | while (code_len) 824 | { 825 | u16 mask; 826 | u8 nbits; 827 | 828 | if (!bits_left) 829 | { 830 | ++p; 831 | bits_left = 8; 832 | } 833 | 834 | nbits = bits_left < code_len ? bits_left : code_len; 835 | 836 | /* set the first nbits of the mask */ 837 | mask = 0xFF00 >> nbits; 838 | mask &= 0xFF; 839 | mask <<= 8; 840 | 841 | /* 842 | example: 843 | 3 bits left 844 | mask = 11100000_00000000 845 | 846 | we need to encode the first nbits bits of 847 | the code into the next nbits bits of the 848 | current byte 849 | */ 850 | 851 | *p |= (value & mask) >> (16 - bits_left); 852 | 853 | value <<= nbits; 854 | code_len -= nbits; 855 | 856 | bits_left -= nbits; 857 | } 858 | } 859 | 860 | *pnbytes = p - compressed; 861 | *premainder_bits = 8 - bits_left; 862 | 863 | return 1; 864 | } 865 | 866 | internal 867 | b32 huffman_decode( 868 | u8 const* data, 869 | u8* uncompressed, 870 | uintptr n, 871 | huffman_code* codes) 872 | { 873 | uintptr i = 0, j; 874 | 875 | u8* p = uncompressed; 876 | u8 bits_offset = 0; 877 | 878 | while (p - uncompressed < n) 879 | { 880 | huffman_code* match = 0; 881 | u32* p32 = (u32*)&data[i]; 882 | u32 chunk; 883 | 884 | /* TODO: fix this endian-ness mess lol */ 885 | chunk = *p32 >> 24 | *p32 << 24 | 886 | ((*p32 >> 8) & 0x0000FF00) | 887 | ((*p32 << 8) & 0x00FF0000); 888 | 889 | for (j = 0; j < 0x100; ++j) 890 | { 891 | #ifdef HUFFMAN_DEBUG 892 | uintptr k; 893 | char buf[33]; 894 | #endif 895 | huffman_code* c = &codes[j]; 896 | u16 value = c->value << (16 - c->nbits); 897 | u32 mask = 0xFFFF0000 >> c->nbits; 898 | 899 | if (!c->nbits) { 900 | continue; 901 | } 902 | 903 | #ifdef HUFFMAN_DEBUG 904 | uitoa(2, chunk, buf, 32, '0'); 905 | errs(buf); 906 | errs("\n"); 907 | 908 | for (k = 0; k < bits_offset; ++k) { 909 | errs(" "); 910 | } 911 | 912 | errs("^"); 913 | 914 | for (k = 0; k < c->nbits - 2; ++k) { 915 | errs(" "); 916 | } 917 | 918 | errs("^\n"); 919 | 920 | uitoa(2, (u16)mask, buf, 16, '0'); 921 | errs(buf); 922 | errs("\n"); 923 | 924 | uitoa(2, value, buf, c->nbits, '0'); 925 | errs(buf); 926 | errs("\n"); 927 | 928 | errs("i = "); 929 | uitoa(10, i, buf, 0, '0'); 930 | errs(buf); 931 | errs("\n"); 932 | 933 | errs("written = "); 934 | uitoa(10, p - uncompressed, buf, 0, '0'); 935 | errs(buf); 936 | errs("\n\n"); 937 | #endif 938 | 939 | /* TODO: make this readable */ 940 | if ( 941 | ((u16)((chunk << bits_offset) >> 16) & mask) == 942 | (value & (u16)mask) 943 | ){ 944 | match = c; 945 | break; 946 | } 947 | } 948 | 949 | if (!match) { 950 | /* invalid code */ 951 | return 0; 952 | } 953 | 954 | *p++ = (u8)j; 955 | 956 | i += (match->nbits + bits_offset) / 8; 957 | bits_offset = (match->nbits + bits_offset) % 8; 958 | } 959 | 960 | return 1; 961 | } 962 | 963 | typedef struct 964 | { 965 | u8 buf [8000000]; 966 | u8 transformed[8000000]; 967 | huffman_code codes[0x100]; 968 | 969 | /* codes array is 1 bigger than it should because lengths are 970 | not aligned to byte boundary and the loop would end up 971 | accessing oob stuff for the last length */ 972 | } 973 | memory; 974 | 975 | int main(int argc, char const* argv[]) 976 | { 977 | int fd; 978 | char const* filename; 979 | 980 | memory* m = 981 | mmap( 982 | 0, 983 | sizeof(memory), 984 | PROT_READ | PROT_WRITE, 985 | MAP_ANONYMOUS | MAP_PRIVATE, 986 | 0, 0 987 | ); 988 | 989 | uintptr transformed_nbytes; 990 | u8 transformed_remainder_bits = 0; 991 | 992 | intptr n; 993 | b32 result; 994 | 995 | if ((intptr)m < 0 && (intptr)m > -100000) { 996 | errs("mmap failed\n"); 997 | return 1; 998 | } 999 | 1000 | stdinit(); 1001 | 1002 | memeset(m->codes, 0, sizeof(m->codes)); 1003 | 1004 | if (argc != 3) 1005 | { 1006 | usage: 1007 | errs("Usage: "); 1008 | errs(argv[0]); 1009 | errs(" \n"); 1010 | 1011 | return 1; 1012 | } 1013 | 1014 | filename = argv[2]; 1015 | 1016 | if (*filename == '-' && !filename[1]) { 1017 | fd = stdin; 1018 | } else { 1019 | fd = open(filename, O_RDONLY, 0); 1020 | if (fd < 0) { 1021 | errs("open\n"); 1022 | return 1; 1023 | } 1024 | } 1025 | 1026 | n = read(fd, m->buf, sizeof(m->buf)); 1027 | if (n <= 0) { 1028 | errs("read\n"); 1029 | return 1; 1030 | } 1031 | if (n >= sizeof(m->buf)) { 1032 | errs("too big\n"); 1033 | } 1034 | 1035 | if (fd != stdin) { 1036 | close(fd); 1037 | } 1038 | 1039 | switch (*argv[1]) 1040 | { 1041 | case 'c': 1042 | { 1043 | uintptr i; 1044 | u8 lengths[128]; 1045 | 1046 | if (!huffman(m->buf, n, m->codes)) { 1047 | errs("????????????????\n"); 1048 | return 1; 1049 | } 1050 | 1051 | huffman_canonical(m->codes); 1052 | 1053 | for (i = 0; i < 128; ++i) 1054 | { 1055 | lengths[i] = m->codes[i * 2 ].nbits << 4; 1056 | lengths[i] |= m->codes[i * 2 + 1].nbits & 0xF; 1057 | } 1058 | 1059 | /* TODO: support files bigger than 4GB? */ 1060 | fwrite(stdout, &n, 4); 1061 | fwrite(stdout, lengths, 128); 1062 | 1063 | result = 1064 | huffman_encode( 1065 | m->buf, 1066 | m->transformed, 1067 | n, 1068 | m->codes, 1069 | &transformed_nbytes, 1070 | &transformed_remainder_bits 1071 | ); 1072 | 1073 | if (!result) { 1074 | errs("????? invalid code??????\n"); 1075 | return 1; 1076 | } 1077 | break; 1078 | } 1079 | 1080 | case 'x': 1081 | { 1082 | uintptr i; 1083 | u8 unp_lengths[0x100]; 1084 | u32 original_size = 0; 1085 | u8* p = m->buf; 1086 | 1087 | transformed_nbytes = original_size = *(u32*)p; 1088 | p += 4; 1089 | 1090 | for (i = 0; i < 128; ++i) 1091 | { 1092 | unp_lengths[i * 2 ] = *p >> 4; 1093 | unp_lengths[i * 2 + 1] = *p++ & 0xF; 1094 | } 1095 | 1096 | huffman_canonical_from_lengths(unp_lengths, m->codes); 1097 | 1098 | result = 1099 | huffman_decode( 1100 | p, 1101 | m->transformed, 1102 | original_size, 1103 | m->codes 1104 | ); 1105 | 1106 | if (!result) { 1107 | errs("????? invalid code??????\n"); 1108 | return 1; 1109 | } 1110 | break; 1111 | } 1112 | 1113 | default: 1114 | goto usage; 1115 | } 1116 | 1117 | fwrite( 1118 | stdout, 1119 | m->transformed, 1120 | transformed_nbytes + (transformed_remainder_bits ? 1 : 0) 1121 | ); 1122 | 1123 | stdfflush(); 1124 | 1125 | return 0; 1126 | } 1127 | -------------------------------------------------------------------------------- /jsonp/README.md: -------------------------------------------------------------------------------- 1 | C89 json parser that doesn't depend on the standard C library. 2 | 3 | It includes a rudimentary error system that shows part of the json 4 | and points at the bad character. 5 | 6 | This isn't meant to be used as a library or stand-alone tool. 7 | It's reusable code that I copypaste into my projects and tweak as 8 | needed so that I don't have to add an entire library to my codebase 9 | . The example in this repo simply prints the generated tree 10 | structure for reference and debugging. 11 | 12 | tl;dr I'm using github to back-up my code snippets, but if you like 13 | this you are free to use it for your projects. 14 | 15 | This example project is linux only, but it should easily plug into 16 | a windows project as long as you define a windows version of write 17 | to let it output errors and debug info or simply remove error 18 | output. 19 | 20 | # Linux 32-bit 21 | ``` 22 | $ git clone https://github.com/Francesco149/jsonp.git 23 | $ cd jsonp 24 | $ chmod +x ./build.sh 25 | $ ./build.sh i386 26 | $ ./jsonp test.json 27 | $ ./jsonp test2.json 28 | ``` 29 | 30 | # Linux 64-bit 31 | ``` 32 | $ git clone https://github.com/Francesco149/jsonp.git 33 | $ cd jsonp 34 | $ chmod +x ./build.sh 35 | $ ./build.sh 36 | $ ./jsonp test.json 37 | $ ./jsonp test2.json 38 | ``` 39 | 40 | # Performance 41 | I quickly tested 1million iterations on the two test json files 42 | and compared them to 1million iterations of node's ```JSON.parse``` 43 | and it's roughly 30% slower on larger objects (first file) and 44 | twice as fast on small objects (second files). 45 | 46 | I didn't try to optimise this, in fact this is the first time I 47 | even write a non-trivial parser and I didn't really look at any 48 | examples so it's likely far from optimal. 49 | 50 | However, I'm very happy with how it turned out and I will use and 51 | tweak it in my future projects that happen to require json parsing. 52 | 53 | # License 54 | This code is public domain and comes with no warranty. 55 | You are free to do whatever you want with it. You can 56 | contact me at lolisamurai@tfwno.gf but don't expect any 57 | support. 58 | I hope you will find the code useful or at least 59 | interesting to read. Have fun! 60 | -------------------------------------------------------------------------------- /jsonp/amd64/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | #define AMD64 21 | #include "syscalls.h" 22 | 23 | typedef unsigned long int u64; 24 | typedef unsigned int u32; 25 | typedef unsigned short int u16; 26 | typedef unsigned char u8; 27 | 28 | typedef long int i64; 29 | typedef int i32; 30 | typedef short int i16; 31 | typedef signed char i8; 32 | 33 | typedef i64 intptr; 34 | typedef u64 uintptr; 35 | 36 | #include "../main.c" 37 | -------------------------------------------------------------------------------- /jsonp/amd64/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | #include "syscalls.h" 21 | 22 | .intel_syntax noprefix 23 | .text 24 | .globl _start, syscall, 25 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 26 | 27 | _start: 28 | xor rbp,rbp 29 | pop rdi 30 | mov rsi,rsp 31 | and rsp,-16 32 | call main 33 | mov rdi,rax 34 | mov rax,SYS_exit 35 | syscall 36 | ret 37 | 38 | syscall: 39 | mov rax,rdi 40 | syscall 41 | ret 42 | 43 | syscall1: 44 | mov rax,rdi 45 | mov rdi,rsi 46 | syscall 47 | ret 48 | 49 | syscall2: 50 | mov rax,rdi 51 | mov rdi,rsi 52 | mov rsi,rdx 53 | syscall 54 | ret 55 | 56 | syscall3: 57 | mov rax,rdi 58 | mov rdi,rsi 59 | mov rsi,rdx 60 | mov rdx,rcx 61 | syscall 62 | ret 63 | 64 | syscall4: 65 | mov rax,rdi 66 | mov rdi,rsi 67 | mov rsi,rdx 68 | mov rdx,rcx 69 | mov r10,r8 70 | syscall 71 | ret 72 | 73 | syscall5: 74 | mov rax,rdi 75 | mov rdi,rsi 76 | mov rsi,rdx 77 | mov rdx,rcx 78 | mov r10,r8 79 | mov r8,r9 80 | syscall 81 | ret 82 | -------------------------------------------------------------------------------- /jsonp/amd64/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | #define SYS_read 0 21 | #define SYS_write 1 22 | #define SYS_open 2 23 | #define SYS_close 3 24 | #define SYS_exit 60 25 | -------------------------------------------------------------------------------- /jsonp/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # jsonp: a tiny standalone json parser written in C89 19 | 20 | exename="jsonp" 21 | archname=${1:-amd64} # if not specified, default to amd64 22 | 23 | if [ -e $archname/flags.sh ]; then 24 | source $archname/flags.sh 25 | fi 26 | 27 | gcc -std=c89 -pedantic -s -O2 -Wall -Werror \ 28 | -nostdlib \ 29 | -fno-unwind-tables \ 30 | -fno-asynchronous-unwind-tables \ 31 | -fdata-sections \ 32 | -Wl,--gc-sections \ 33 | -Wa,--noexecstack \ 34 | -fno-builtin \ 35 | -fno-stack-protector \ 36 | $COMPILER_FLAGS \ 37 | $archname/start.S $archname/platform.c \ 38 | -o $exename \ 39 | \ 40 | && strip -R .comment $exename 41 | -------------------------------------------------------------------------------- /jsonp/i386/flags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export COMPILER_FLAGS="-m32 -Wno-long-long" 4 | -------------------------------------------------------------------------------- /jsonp/i386/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | #define I386 21 | #include "syscalls.h" 22 | 23 | typedef unsigned long long int u64; 24 | typedef unsigned int u32; 25 | typedef unsigned short int u16; 26 | typedef unsigned char u8; 27 | 28 | typedef long long int i64; 29 | typedef int i32; 30 | typedef short int i16; 31 | typedef signed char i8; 32 | 33 | typedef i32 intptr; 34 | typedef u32 uintptr; 35 | 36 | #include "../main.c" 37 | -------------------------------------------------------------------------------- /jsonp/i386/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | #include "syscalls.h" 21 | 22 | .intel_syntax noprefix 23 | .text 24 | .globl _start, syscall 25 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 26 | 27 | _start: 28 | xor ebp,ebp 29 | pop esi 30 | mov ecx,esp 31 | and esp,-16 32 | push 0xb16b00b5 33 | push 0xb16b00b5 34 | push ecx 35 | push esi 36 | call main 37 | add esp,16 38 | mov ebx,eax 39 | mov eax,SYS_exit 40 | int 0x80 41 | ret 42 | 43 | syscall: 44 | mov eax,[esp+4] 45 | int 0x80 46 | ret 47 | 48 | syscall1: 49 | push ebx 50 | mov eax,[esp+4+4] 51 | mov ebx,[esp+8+4] 52 | int 0x80 53 | pop ebx 54 | ret 55 | 56 | syscall2: 57 | push ebx 58 | mov eax,[esp+4+4] 59 | mov ebx,[esp+8+4] 60 | mov ecx,[esp+12+4] 61 | int 0x80 62 | pop ebx 63 | ret 64 | 65 | syscall3: 66 | push ebx 67 | mov eax,[esp+4+4] 68 | mov ebx,[esp+8+4] 69 | mov ecx,[esp+12+4] 70 | mov edx,[esp+16+4] 71 | int 0x80 72 | pop ebx 73 | ret 74 | 75 | syscall4: 76 | push ebx 77 | push esi 78 | mov eax,[esp+4+8] 79 | mov ebx,[esp+8+8] 80 | mov ecx,[esp+12+8] 81 | mov edx,[esp+16+8] 82 | mov esi,[esp+20+8] 83 | int 0x80 84 | pop esi 85 | pop ebx 86 | ret 87 | 88 | syscall5: 89 | push ebx 90 | push esi 91 | push edi 92 | mov eax,[esp+4+12] 93 | mov ebx,[esp+8+12] 94 | mov ecx,[esp+12+12] 95 | mov edx,[esp+16+12] 96 | mov esi,[esp+20+12] 97 | mov edi,[esp+24+12] 98 | int 0x80 99 | pop edi 100 | pop esi 101 | pop ebx 102 | ret 103 | -------------------------------------------------------------------------------- /jsonp/i386/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | #define SYS_read 3 21 | #define SYS_write 4 22 | #define SYS_open 5 23 | #define SYS_close 6 24 | #define SYS_exit 1 25 | -------------------------------------------------------------------------------- /jsonp/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | jsonp: a tiny standalone json parser written in C89 18 | */ 19 | 20 | typedef i32 b32; 21 | 22 | #define internal static 23 | #define globvar static 24 | 25 | #define min(a, b) ((a) < (b) ? (a) : (b)) 26 | #define max(a, b) ((a) > (b) ? (a) : (b)) 27 | 28 | internal 29 | void memeset(void* dst, u8 value, intptr nbytes) 30 | { 31 | intptr i; 32 | 33 | if (nbytes % sizeof(intptr) == 0) 34 | { 35 | intptr* dst_chunks = (intptr*)dst; 36 | intptr chunk; 37 | u8* chunk_raw = (u8*)&chunk; 38 | 39 | for (i = 0; i < sizeof(intptr); ++i) { 40 | chunk_raw[i] = value; 41 | } 42 | 43 | for (i = 0; i < nbytes / sizeof(intptr); ++i) { 44 | dst_chunks[i] = chunk; 45 | } 46 | } 47 | else 48 | { 49 | u8* dst_bytes = (u8*)dst; 50 | 51 | for (i = 0; i < nbytes; ++i) { 52 | dst_bytes[i] = value; 53 | } 54 | } 55 | } 56 | 57 | /* ------------------------------------------------------------- */ 58 | 59 | void* syscall1(uintptr number, void* arg1); 60 | 61 | void* syscall3( 62 | uintptr number, 63 | void* arg1, 64 | void* arg2, 65 | void* arg3 66 | ); 67 | 68 | #define stdin 0 69 | #define stdout 1 70 | 71 | #define O_RDONLY 00 72 | 73 | typedef u32 mode_t; 74 | 75 | internal 76 | int open(char const* filename, u32 flags, mode_t mode) 77 | { 78 | return (int)(intptr) 79 | syscall3( 80 | SYS_open, 81 | (void*)filename, 82 | (void*)(intptr)flags, 83 | (void*)(intptr)mode 84 | ); 85 | } 86 | 87 | internal 88 | void close(int fd) { 89 | syscall1(SYS_close, (void*)(intptr)fd); 90 | } 91 | 92 | internal 93 | intptr write(int fd, void const* data, uintptr nbytes) 94 | { 95 | return (uintptr) 96 | syscall3( 97 | SYS_write, 98 | (void*)(intptr)fd, 99 | (void*)data, 100 | (void*)nbytes 101 | ); 102 | } 103 | 104 | internal 105 | intptr read(int fd, void* data, intptr nbytes) 106 | { 107 | return (intptr) 108 | syscall3( 109 | SYS_read, 110 | (void*)(intptr)fd, 111 | data, 112 | (void*)nbytes 113 | ); 114 | } 115 | 116 | /* ------------------------------------------------------------- */ 117 | 118 | internal 119 | uintptr strlen(char const* str) 120 | { 121 | char const* p; 122 | for (p = str; *p; ++p); 123 | return p - str; 124 | } 125 | 126 | internal 127 | uintptr puts(char const* str) { 128 | return write(stdout, str, strlen(str)); 129 | } 130 | 131 | #define STRINGIFY_(x) #x 132 | #define STRINGIFY(x) STRINGIFY_(x) 133 | 134 | #define log(type, msg) \ 135 | puts(type "|"), \ 136 | puts(__FUNCTION__), \ 137 | puts("|" __FILE__ ":" STRINGIFY(__LINE__) "|" msg) 138 | 139 | #define err(msg) log("ERR", msg) 140 | #define info(msg) log("INFO", msg) 141 | 142 | #if LOG_DEBUG 143 | #define debug(msg) log("DEBUG", msg) 144 | #else 145 | #define debug(msg) 146 | #endif 147 | 148 | internal 149 | b32 strneq(char const* a, char const* b, intptr len) 150 | { 151 | intptr i; 152 | 153 | for (i = 0; i < len; ++i) 154 | { 155 | if (a[i] != b[i]) { 156 | return 0; 157 | } else if (!a[i]) { 158 | return 1; 159 | } 160 | } 161 | 162 | return 1; 163 | } 164 | 165 | internal 166 | b32 is_whitespace(char c) 167 | { 168 | return c == ' ' || 169 | c == '\r' || 170 | c == '\n' || 171 | c == '\t' || 172 | c == '\f' || 173 | c == '\v'; 174 | } 175 | 176 | /* ------------------------------------------------------------- 177 | UTILITY FUNCS 178 | ------------------------------------------------------------- */ 179 | 180 | typedef struct 181 | { 182 | char const* start; 183 | char const* end; 184 | } 185 | string_t; 186 | 187 | #if !BENCHMARK 188 | internal 189 | uintptr string_len(string_t const str) { 190 | return str.end - str.start; 191 | } 192 | 193 | internal 194 | uintptr string_put(string_t const str) { 195 | return write(stdout, str.start, string_len(str)); 196 | } 197 | #endif 198 | 199 | internal 200 | b32 string_valid(string_t const str) { 201 | return str.start && str.end && str.end >= str.start; 202 | } 203 | 204 | internal 205 | b32 string_neq(string_t const a, char const* b, uintptr n) { 206 | return strneq(a.start, b, n); 207 | } 208 | 209 | internal 210 | void string_put_nows(string_t const s) 211 | { 212 | char const* p; 213 | char buf[64]; 214 | char* pbuf = buf; 215 | 216 | for (p = s.start; p < s.end; ++p) 217 | { 218 | if (!is_whitespace(*p)) { 219 | *pbuf++ = *p; 220 | } 221 | 222 | if (pbuf >= buf + 64) { 223 | write(stdout, buf, 64); 224 | pbuf = buf; 225 | } 226 | } 227 | 228 | write(stdout, buf, pbuf - buf); 229 | } 230 | 231 | internal 232 | void string_print_indicator( 233 | string_t const str, 234 | char const* p, 235 | uintptr n) 236 | { 237 | string_t s; 238 | 239 | s.start = s.end = p; 240 | 241 | s.start = max(str.start, p - n); 242 | s.end = min(str.end, p + n); 243 | 244 | string_put_nows(s); 245 | puts("\n"); 246 | 247 | for (; s.start < s.end; ++s.start) 248 | { 249 | if (s.start == p) { 250 | puts("^"); 251 | break; 252 | } 253 | 254 | if (!is_whitespace(*s.start)) { 255 | puts(" "); 256 | } 257 | } 258 | } 259 | 260 | /* ------------------------------------------------------------- 261 | MEMORY MANAGEMENT 262 | ------------------------------------------------------------- */ 263 | 264 | typedef struct 265 | { 266 | u8* start; 267 | u8* end; 268 | u8* p; 269 | } 270 | allocator_t; 271 | 272 | internal 273 | void* allocator_push(allocator_t* alloc, uintptr nbytes) 274 | { 275 | u8* res; 276 | 277 | if (alloc->p + nbytes >= alloc->end) 278 | { 279 | err("out of memory! please recompile with more memory " 280 | "reserved or check your code for misbehaving " 281 | "allocator usage."); 282 | 283 | return 0; 284 | } 285 | 286 | res = alloc->p; 287 | alloc->p += nbytes; 288 | 289 | return res; 290 | } 291 | 292 | /* 293 | internal 294 | void allocator_pop(allocator_t* alloc, uintptr nbytes) 295 | { 296 | if (alloc->p - nbytes < alloc->start) 297 | { 298 | err("misbehaving deallocation tried to free past the start" 299 | " of the memory buffer"); 300 | 301 | return; 302 | } 303 | 304 | alloc->p -= nbytes; 305 | } 306 | */ 307 | 308 | /* ------------------------------------------------------------- */ 309 | 310 | globvar u8 memory[0xFFFF]; 311 | 312 | globvar allocator_t alloc = { 313 | memory, memory + sizeof(memory), memory 314 | }; 315 | 316 | /* ------------------------------------------------------------- 317 | JSONP 318 | ------------------------------------------------------------- */ 319 | 320 | #define JSON_INVALID 0 321 | #define JSON_ROOT 1 322 | 323 | #define JSON_ARRAY 2 324 | #define JSON_OBJECT 3 325 | #define JSON_PAIR 4 326 | #define JSON_ARRAY_ELEMENT 5 327 | 328 | #define JSON_STRING 6 329 | #define JSON_NUMBER 7 330 | #define JSON_TRUE 8 331 | #define JSON_FALSE 9 332 | #define JSON_NULL 10 333 | 334 | typedef struct _json_node 335 | { 336 | u8 type; 337 | string_t raw; 338 | struct _json_node* child; 339 | struct _json_node* next; 340 | } 341 | json_node; 342 | 343 | #if JSON_DEBUG 344 | internal 345 | void print_json_node(json_node const* n) 346 | { 347 | puts("-------------------------------------------------------" 348 | "------------\n"); 349 | switch(n->type) 350 | { 351 | #define t(x) case x: puts(#x "\n"); break; 352 | t(JSON_INVALID) 353 | t(JSON_ROOT) 354 | t(JSON_ARRAY) 355 | t(JSON_OBJECT) 356 | t(JSON_PAIR) 357 | t(JSON_ARRAY_ELEMENT) 358 | t(JSON_STRING) 359 | t(JSON_NUMBER) 360 | t(JSON_TRUE) 361 | t(JSON_FALSE) 362 | t(JSON_NULL) 363 | #undef t 364 | } 365 | 366 | string_put(n->raw); 367 | puts("\n"); 368 | } 369 | #endif 370 | 371 | internal 372 | void jsonp_init(json_node* tree, string_t str) 373 | { 374 | memeset(tree, 0, sizeof(json_node)); 375 | tree->raw = str; 376 | tree->type = JSON_ROOT; 377 | } 378 | 379 | internal 380 | char jsonp_peekch(string_t* p) 381 | { 382 | for (; is_whitespace(*p->start); ++p->start) 383 | { 384 | if (!string_valid(*p)) { 385 | debug("string not valid (reached end?)"); 386 | return 0; 387 | } 388 | } 389 | 390 | return *p->start; 391 | } 392 | 393 | internal 394 | char jsonp_nextch(string_t* p) 395 | { 396 | char c = jsonp_peekch(p); 397 | ++p->start; 398 | return c; 399 | } 400 | 401 | internal 402 | b32 jsonp_string(string_t* p, string_t* pstr) 403 | { 404 | b32 escaped = 0; 405 | 406 | if (jsonp_nextch(p) != '"') { 407 | debug("didn't find opening double quote\n"); 408 | return 0; 409 | } 410 | 411 | pstr->start = p->start; 412 | 413 | while (string_valid(*p)) 414 | { 415 | char c = jsonp_nextch(p); 416 | 417 | if (!escaped && c == '"') { 418 | pstr->end = p->start - 1; 419 | return 1; 420 | } 421 | 422 | if (escaped) 423 | { 424 | escaped = 0; 425 | 426 | if (c == 'u') { 427 | p->start += 4; 428 | /* TODO: validate hex and remaining size */ 429 | } 430 | } else { 431 | escaped = c == '\\'; 432 | } 433 | } 434 | 435 | debug("didn't find closing double quote\n"); 436 | 437 | return 0; 438 | } 439 | 440 | #define indicator(p) \ 441 | string_print_indicator(parent->raw, p, 33), puts("\n") 442 | 443 | #if LOG_DEBUG 444 | #define jdebug(msg) debug(msg), debug_indicator(pc) 445 | #else 446 | #define jdebug(msg) 447 | #endif 448 | 449 | #define jerr(msg) err(msg), indicator(it.start - 1) 450 | 451 | internal 452 | b32 jsonp_walk(json_node* parent) 453 | { 454 | string_t it = parent->raw; 455 | json_node* node; 456 | 457 | /* TODO: pull the allocator calls into a generic func */ 458 | node = (json_node*)allocator_push(&alloc, sizeof(json_node)); 459 | memeset(node, 0, sizeof(node)); 460 | node->raw = parent->raw; 461 | parent->child = node; 462 | 463 | switch (parent->type) 464 | { 465 | case JSON_ROOT: 466 | switch (jsonp_nextch(&it)) 467 | { 468 | case '{': node->type = JSON_OBJECT; break; 469 | case '[': node->type = JSON_ARRAY; break; 470 | 471 | default: 472 | jerr("expected object or array\n"); 473 | return 0; 474 | } 475 | 476 | if (!jsonp_walk(node)) { /* RECURSION */ 477 | return 0; 478 | } 479 | it.start = node->raw.end; 480 | break; 481 | 482 | case JSON_OBJECT: 483 | case JSON_ARRAY: 484 | { 485 | json_node* prev = parent->child; 486 | char delim; 487 | u8 type; 488 | 489 | if (parent->type == JSON_OBJECT) 490 | { 491 | delim = '}'; 492 | type = JSON_PAIR; 493 | } 494 | else 495 | { 496 | delim = ']'; 497 | type = JSON_ARRAY_ELEMENT; 498 | } 499 | 500 | jsonp_nextch(&it); /* skip opening bracket */ 501 | 502 | while (1) 503 | { 504 | char c; 505 | 506 | node->type = type; 507 | 508 | node->raw = it; 509 | if (!jsonp_walk(node)) { /* BRANCHING RECURSION */ 510 | return 0; 511 | } 512 | 513 | it.start = node->raw.end; 514 | c = jsonp_nextch(&it); 515 | 516 | if (c == delim) { 517 | break; 518 | } 519 | 520 | if (c != ',') { 521 | jerr("expected ','\n"); 522 | return 0; 523 | } 524 | 525 | node = (json_node*) 526 | allocator_push( 527 | &alloc, 528 | sizeof(json_node) 529 | ); 530 | 531 | memeset(node, 0, sizeof(node)); 532 | prev->next = node; 533 | prev = node; 534 | 535 | node->raw.start = it.start; 536 | node->raw.end = parent->raw.end; 537 | } 538 | 539 | parent->raw.end = it.start; 540 | break; 541 | } 542 | 543 | /* TODO: I'd like to be able to fit this switch case in 544 | one screenful. shorten this code, maybe pull 545 | stuff out? */ 546 | case JSON_PAIR: 547 | case JSON_ARRAY_ELEMENT: 548 | { 549 | char const* pc; 550 | 551 | /* TODO: pull number checking into a separate func */ 552 | /* TODO: use a bitmask? */ 553 | b32 has_dot = 0; 554 | b32 has_e = 0; 555 | b32 has_number = 0; 556 | b32 no_more_numbers = 0; 557 | 558 | if (parent->type == JSON_PAIR) 559 | { 560 | node->type = JSON_STRING; 561 | 562 | if (!jsonp_string(&it, &node->raw)) { 563 | jerr("expected string\n"); 564 | return 0; 565 | } 566 | 567 | node = (json_node*) 568 | allocator_push(&alloc, sizeof(json_node)); 569 | 570 | memeset(node, 0, sizeof(node)); 571 | node->raw = parent->raw; 572 | parent->child->next = node; 573 | 574 | if (jsonp_nextch(&it) != ':') { 575 | jerr("expected ':'\n"); 576 | return 0; 577 | } 578 | } 579 | 580 | /* skip whitespace so we can strcmp */ 581 | jsonp_peekch(&it); 582 | 583 | /* parse value */ 584 | node->raw.start = it.start; 585 | 586 | if (jsonp_peekch(&it) == '{') 587 | { 588 | node->type = JSON_OBJECT; 589 | 590 | if (!jsonp_walk(node)) { /* RECURSION */ 591 | return 0; 592 | } 593 | 594 | parent->raw.end = node->raw.end; 595 | break; 596 | } 597 | 598 | if (jsonp_peekch(&it) == '[') 599 | { 600 | node->type = JSON_ARRAY; 601 | 602 | if (!jsonp_walk(node)) { /* RECURSION */ 603 | return 0; 604 | } 605 | 606 | parent->raw.end = node->raw.end; 607 | break; 608 | } 609 | 610 | /* TODO: reduce redundancy? */ 611 | if (string_neq(it, "true", 4)) 612 | { 613 | node->type = JSON_TRUE; 614 | parent->raw.end = node->raw.end = it.start + 4; 615 | break; 616 | } 617 | 618 | if (string_neq(it, "false", 5)) { 619 | node->type = JSON_FALSE; 620 | parent->raw.end = node->raw.end = it.start + 5; 621 | break; 622 | } 623 | 624 | if (string_neq(it, "null", 4)) { 625 | node->type = JSON_NULL; 626 | parent->raw.end = node->raw.end = it.start + 4; 627 | break; 628 | } 629 | 630 | /* this is too much indentation. I need to pull 631 | this out into a function */ 632 | for (pc = it.start; pc != it.end; ++pc) 633 | { 634 | if (*pc == '.') 635 | { 636 | /* TODO: don't accept 123. */ 637 | 638 | if (has_dot) { 639 | /* 123.123. */ 640 | jdebug("multiple dots\n"); 641 | break; 642 | } 643 | 644 | if (has_e) { 645 | /* 123e1.23 */ 646 | jdebug("dot after e\n"); 647 | break; 648 | } 649 | 650 | if (!has_number) { 651 | /* .123 */ 652 | jdebug("dot before number\n"); 653 | break; 654 | } 655 | 656 | has_dot = 1; 657 | continue; 658 | } 659 | 660 | if (*pc == 'e' || *pc == 'E') 661 | { 662 | if (has_e) { 663 | /* 123e123e */ 664 | jdebug("multiple e's\n"); 665 | break; 666 | } 667 | 668 | if (!has_number) { 669 | /* e123 */ 670 | jdebug("e before number\n"); 671 | break; 672 | } 673 | 674 | if (pc + 1 != it.end) 675 | { 676 | if (pc[1] == '+' || pc[1] == '-') { 677 | ++pc; 678 | } 679 | } 680 | 681 | has_e = 1; 682 | continue; 683 | } 684 | 685 | if (*pc < '0' || *pc > '9') 686 | { 687 | b32 is_terminator = 688 | *pc == ',' || *pc == '}' || *pc == ']'; 689 | 690 | if (is_whitespace(*pc)) 691 | { 692 | no_more_numbers = has_number; 693 | continue; 694 | } 695 | 696 | if (!is_terminator) 697 | { 698 | jdebug("invalid char within number\n"); 699 | break; 700 | } 701 | 702 | if (!has_number) { 703 | jdebug("terminator with no number\n"); 704 | break; 705 | } 706 | 707 | node->type = JSON_NUMBER; 708 | parent->raw.end = node->raw.end = pc; 709 | goto done; 710 | } 711 | 712 | if (no_more_numbers) { 713 | jdebug("number broken by whitespace\n"); 714 | break; 715 | } 716 | 717 | has_number = 1; 718 | } 719 | 720 | if (jsonp_string(&it, &node->raw)) 721 | { 722 | node->type = JSON_STRING; 723 | parent->raw.end = node->raw.end + 1; 724 | break; 725 | } 726 | 727 | jerr("invalid pair value\n"); 728 | return 0; 729 | } 730 | 731 | default: 732 | jerr("this type of node can't have children, wtf?\n"); 733 | return 0; 734 | } 735 | 736 | done: 737 | #if JSON_DEBUG 738 | print_json_node(node); 739 | print_json_node(parent); 740 | #endif 741 | 742 | return 1; 743 | } 744 | 745 | #undef jdebug 746 | #undef jerr 747 | 748 | #if !BENCHMARK 749 | internal 750 | b32 jsonp_print(json_node const* parent, u32 level) 751 | { 752 | u32 i; 753 | json_node const* child; 754 | 755 | for (i = 0; i < level; ++i) { 756 | puts(" "); 757 | } 758 | 759 | switch (parent->type) 760 | { 761 | case JSON_INVALID: 762 | err("found node with invalid type"); 763 | return 0; 764 | 765 | case JSON_ROOT: puts("(root node)"); break; 766 | case JSON_ARRAY: puts("array"); break; 767 | case JSON_OBJECT: puts("object"); break; 768 | case JSON_PAIR: puts("pair"); break; 769 | case JSON_ARRAY_ELEMENT: puts("(array element)"); break; 770 | 771 | case JSON_STRING: 772 | puts("string: "); 773 | goto truefalsenull; 774 | 775 | case JSON_NUMBER: 776 | puts("number: "); 777 | 778 | case JSON_TRUE: 779 | case JSON_FALSE: 780 | case JSON_NULL: 781 | truefalsenull: 782 | string_put(parent->raw); 783 | break; 784 | } 785 | 786 | puts("\n"); 787 | 788 | for (child = parent->child; child; child = child->next) 789 | { 790 | if (!jsonp_print(child, level + 1)) { 791 | return 0; 792 | } 793 | } 794 | 795 | return 1; 796 | } 797 | #endif 798 | 799 | /* ------------------------------------------------------------- */ 800 | 801 | #define JSON_MAX_SIZE 0xFFFF 802 | 803 | internal 804 | b32 jsonp_test(char const* file_name) 805 | { 806 | int fd; 807 | intptr nread; 808 | char json_buf[JSON_MAX_SIZE]; 809 | string_t tok; 810 | json_node root; 811 | #if BENCHMARK 812 | int i; 813 | #endif 814 | 815 | if (*file_name == '-' && !file_name[1]) { 816 | fd = stdin; 817 | } else { 818 | fd = open(file_name, O_RDONLY, 0); 819 | if (fd < 0) { 820 | err("open"); 821 | return 0; 822 | } 823 | } 824 | 825 | nread = read(fd, json_buf, JSON_MAX_SIZE - 1); 826 | 827 | if (nread == JSON_MAX_SIZE - 1) { 828 | err("file too big"); 829 | return 0; 830 | } 831 | else if (nread < 0) { 832 | err("read"); 833 | return 0; 834 | } 835 | 836 | if (fd) { 837 | close(fd); 838 | } 839 | 840 | fd = 1; 841 | 842 | tok.start = json_buf; 843 | tok.end = json_buf + nread; 844 | 845 | jsonp_init(&root, tok); 846 | 847 | #if BENCHMARK 848 | for (i = 0; i < 1000000; ++i) 849 | { 850 | alloc.p = alloc.start; 851 | #endif 852 | 853 | if (!jsonp_walk(&root)) { 854 | puts("failed to parse\n"); 855 | return 0; 856 | } 857 | 858 | #if !BENCHMARK 859 | jsonp_print(&root, 0); 860 | #else 861 | } 862 | #endif 863 | 864 | return 1; 865 | } 866 | 867 | int main(int argc, char const* argv[]) 868 | { 869 | int i; 870 | 871 | for (i = 0; i < argc; ++i) { 872 | puts(argv[i]); 873 | puts(" "); 874 | } 875 | 876 | puts("\n\n"); 877 | 878 | if (argc != 2) 879 | { 880 | puts("Usage: "); 881 | puts(argv[0]); 882 | puts(" "); 883 | 884 | return 1; 885 | } 886 | 887 | if (!jsonp_test(argv[1])) { 888 | return 1; 889 | } 890 | 891 | return 0; 892 | } 893 | -------------------------------------------------------------------------------- /jsonp/test.json: -------------------------------------------------------------------------------- 1 | [{"user_id":"124493","username":"Cookiezi","count300":"6213098","count100":"259442","count50":"21920","playcount":"15540","ranked_score":"22636787609","total_score":"135794987960","pp_rank":"1","level":"101.089","pp_raw":"13519.2","accuracy":"98.87391662597656","count_rank_ss":"56","count_rank_s":"461","count_rank_a":"332","country":"KR","pp_country_rank":"1","events":[{"display_html":" Cookiezi<\/a><\/b> achieved rank #805 on 96neko - Uso no Hibana [Hanabi]<\/a> (osu!)","beatmap_id":"1184220","beatmapset_id":"559978","date":"2017-04-02 07:04:50","epicfactor":"1"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #1<\/b> on cYsmix - Moonlight Sonata [Expert]<\/a> (osu!)","beatmap_id":"1037478","beatmapset_id":"486535","date":"2017-04-02 06:38:55","epicfactor":"8"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #45<\/b> on cYsmix - Moonlight Sonata [Expert]<\/a> (osu!)","beatmap_id":"1037478","beatmapset_id":"486535","date":"2017-04-02 06:24:20","epicfactor":"1"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #185 on cYsmix - Moonlight Sonata [Expert]<\/a> (osu!)","beatmap_id":"1037478","beatmapset_id":"486535","date":"2017-04-02 06:20:06","epicfactor":"1"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #1<\/b> on Himeno Kotori (cv. Tamura Yukari) - Koi no Hime Hime Pettanko [Insane]<\/a> (osu!)","beatmap_id":"1101356","beatmapset_id":"518377","date":"2017-04-02 06:01:46","epicfactor":"8"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #3<\/b> on Himeno Kotori (cv. Tamura Yukari) - Koi no Hime Hime Pettanko [Insane]<\/a> (osu!)","beatmap_id":"1101356","beatmapset_id":"518377","date":"2017-04-02 05:59:50","epicfactor":"4"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #1<\/b> on BABYMETAL - Gimme Chocolate!! [Extreme]<\/a> (osu!)","beatmap_id":"922600","beatmapset_id":"162368","date":"2017-04-02 05:57:40","epicfactor":"4"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #1<\/b> on Remo Prototype[CV: Hanamori Yumiri] - Sendan Life [Melia]<\/a> (osu!)","beatmap_id":"939072","beatmapset_id":"394834","date":"2017-04-02 05:45:36","epicfactor":"8"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #5<\/b> on Remo Prototype[CV: Hanamori Yumiri] - Sendan Life [Melia]<\/a> (osu!)","beatmap_id":"939072","beatmapset_id":"394834","date":"2017-04-02 05:41:09","epicfactor":"4"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #1<\/b> on BABYMETAL - Tales of The Destinies [Predator]<\/a> (osu!)","beatmap_id":"1131424","beatmapset_id":"534115","date":"2017-04-02 05:28:55","epicfactor":"8"},{"display_html":" Cookiezi<\/a><\/b> achieved rank #1<\/b> on toby fox - ASGORE (Metal Cover by RichaadEB) [DETERMINATION]<\/a> (osu!)","beatmap_id":"902888","beatmapset_id":"416857","date":"2017-04-02 04:26:45","epicfactor":"8"}]}] -------------------------------------------------------------------------------- /jsonp/test2.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": null, 3 | "b": 123, 4 | "c": 123.123, 5 | "d": 123.123e123, 6 | "e": true, 7 | "f": false, 8 | "g": [ 1, 2, 3, 4, 5, [ "a", "b", "c" ], [ true, false, null ] ], 9 | "h": { "foo": "bar", "bar": 123e10 }, 10 | "i": "abcd\u1234cock\"hehe\"\\" 11 | } 12 | -------------------------------------------------------------------------------- /memealloc/README.md: -------------------------------------------------------------------------------- 1 | A resizable and relocatable memory pool/allocator that uses 2 | relative pointers. 3 | 4 | All allocations are crammed into a single mmap'd memory block. 5 | 6 | Resizes are slow, as everything needs to be copied over to the 7 | re-allocated block, so it's recommended to reserve memory in 8 | advance. 9 | -------------------------------------------------------------------------------- /memealloc/amd64/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #define AMD64 23 | #include "syscalls.h" 24 | 25 | typedef unsigned long int u64; 26 | typedef unsigned int u32; 27 | typedef unsigned short int u16; 28 | typedef unsigned char u8; 29 | 30 | typedef long int i64; 31 | typedef int i32; 32 | typedef short int i16; 33 | typedef signed char i8; 34 | 35 | typedef i64 intptr; 36 | typedef u64 uintptr; 37 | 38 | #include "../main.c" 39 | -------------------------------------------------------------------------------- /memealloc/amd64/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #include "syscalls.h" 23 | 24 | .intel_syntax noprefix 25 | .text 26 | .globl _start, syscall 27 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 28 | .globl syscall6 29 | 30 | _start: 31 | xor rbp,rbp 32 | pop rdi 33 | mov rsi,rsp 34 | and rsp,-16 35 | call main 36 | mov rdi,rax 37 | mov rax,SYS_exit 38 | syscall 39 | ret 40 | 41 | syscall: 42 | mov rax,rdi 43 | syscall 44 | ret 45 | 46 | syscall1: 47 | mov rax,rdi 48 | mov rdi,rsi 49 | syscall 50 | ret 51 | 52 | syscall2: 53 | mov rax,rdi 54 | mov rdi,rsi 55 | mov rsi,rdx 56 | syscall 57 | ret 58 | 59 | syscall3: 60 | mov rax,rdi 61 | mov rdi,rsi 62 | mov rsi,rdx 63 | mov rdx,rcx 64 | syscall 65 | ret 66 | 67 | syscall4: 68 | mov rax,rdi 69 | mov rdi,rsi 70 | mov rsi,rdx 71 | mov rdx,rcx 72 | mov r10,r8 73 | syscall 74 | ret 75 | 76 | syscall5: 77 | mov rax,rdi 78 | mov rdi,rsi 79 | mov rsi,rdx 80 | mov rdx,rcx 81 | mov r10,r8 82 | mov r8,r9 83 | syscall 84 | ret 85 | 86 | syscall6: 87 | mov rax,rdi 88 | mov rdi,rsi 89 | mov rsi,rdx 90 | mov rdx,rcx 91 | mov r10,r8 92 | mov r8,r9 93 | mov r9,[rsp+8] 94 | syscall 95 | ret 96 | -------------------------------------------------------------------------------- /memealloc/amd64/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #define SYS_read 0 23 | #define SYS_write 1 24 | #define SYS_open 2 25 | #define SYS_close 3 26 | #define SYS_exit 60 27 | #define SYS_mmap 9 28 | #define SYS_munmap 11 29 | -------------------------------------------------------------------------------- /memealloc/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # memealloc: 19 | # A resizable and relocatable memory pool/allocator that uses 20 | # relative pointers. 21 | 22 | exename="memealloc" 23 | archname=${1:-amd64} # if not specified, default to amd64 24 | shift 25 | 26 | if [ -e $archname/flags.sh ]; then 27 | source $archname/flags.sh 28 | fi 29 | 30 | gcc -std=c89 -pedantic -s -O2 -Wall -Werror \ 31 | -nostdlib \ 32 | -fno-unwind-tables \ 33 | -fno-asynchronous-unwind-tables \ 34 | -fdata-sections \ 35 | -Wl,--gc-sections \ 36 | -Wa,--noexecstack \ 37 | -fno-builtin \ 38 | -fno-stack-protector \ 39 | $COMPILER_FLAGS \ 40 | $@ \ 41 | $archname/start.S $archname/platform.c \ 42 | -o $exename \ 43 | \ 44 | && strip -R .comment $exename 45 | -------------------------------------------------------------------------------- /memealloc/i386/flags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # memealloc: 19 | # A resizable and relocatable memory pool/allocator that uses 20 | # relative pointers. 21 | 22 | export COMPILER_FLAGS="-m32 -Wno-long-long -DLEGACY_MMAP=1" 23 | -------------------------------------------------------------------------------- /memealloc/i386/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #define I386 23 | #include "syscalls.h" 24 | 25 | typedef unsigned int u32; 26 | typedef unsigned short int u16; 27 | typedef unsigned char u8; 28 | 29 | typedef int i32; 30 | typedef short int i16; 31 | typedef signed char i8; 32 | 33 | typedef i32 intptr; 34 | typedef u32 uintptr; 35 | 36 | #include "../main.c" 37 | -------------------------------------------------------------------------------- /memealloc/i386/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #include "syscalls.h" 23 | 24 | .intel_syntax noprefix 25 | .text 26 | .globl _start, syscall 27 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 28 | .globl syscall6 29 | 30 | _start: 31 | xor ebp,ebp 32 | pop esi 33 | mov ecx,esp 34 | and esp,-16 35 | push 0xb16b00b5 36 | push 0xb16b00b5 37 | push ecx 38 | push esi 39 | call main 40 | add esp,16 41 | mov ebx,eax 42 | mov eax,SYS_exit 43 | int 0x80 44 | ret 45 | 46 | syscall: 47 | mov eax,[esp+4] 48 | int 0x80 49 | ret 50 | 51 | syscall1: 52 | push ebx 53 | mov eax,[esp+4+4] 54 | mov ebx,[esp+8+4] 55 | int 0x80 56 | pop ebx 57 | ret 58 | 59 | syscall2: 60 | push ebx 61 | mov eax,[esp+4+4] 62 | mov ebx,[esp+8+4] 63 | mov ecx,[esp+12+4] 64 | int 0x80 65 | pop ebx 66 | ret 67 | 68 | syscall3: 69 | push ebx 70 | mov eax,[esp+4+4] 71 | mov ebx,[esp+8+4] 72 | mov ecx,[esp+12+4] 73 | mov edx,[esp+16+4] 74 | int 0x80 75 | pop ebx 76 | ret 77 | 78 | syscall4: 79 | push ebx 80 | push esi 81 | mov eax,[esp+4+8] 82 | mov ebx,[esp+8+8] 83 | mov ecx,[esp+12+8] 84 | mov edx,[esp+16+8] 85 | mov esi,[esp+20+8] 86 | int 0x80 87 | pop esi 88 | pop ebx 89 | ret 90 | 91 | syscall5: 92 | push ebx 93 | push esi 94 | push edi 95 | mov eax,[esp+4+12] 96 | mov ebx,[esp+8+12] 97 | mov ecx,[esp+12+12] 98 | mov edx,[esp+16+12] 99 | mov esi,[esp+20+12] 100 | mov edi,[esp+24+12] 101 | int 0x80 102 | pop edi 103 | pop esi 104 | pop ebx 105 | ret 106 | 107 | syscall6: 108 | push ebx 109 | push esi 110 | push edi 111 | push ebp 112 | mov eax,[esp+4+16] 113 | mov ebx,[esp+8+16] 114 | mov ecx,[esp+12+16] 115 | mov edx,[esp+16+16] 116 | mov esi,[esp+20+16] 117 | mov edi,[esp+24+16] 118 | mov ebp,[esp+28+16] 119 | int 0x80 120 | pop ebp 121 | pop edi 122 | pop esi 123 | pop ebx 124 | ret 125 | -------------------------------------------------------------------------------- /memealloc/i386/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #define SYS_read 3 23 | #define SYS_write 4 24 | #define SYS_open 5 25 | #define SYS_close 6 26 | #define SYS_exit 1 27 | #define SYS_mmap 90 28 | #define SYS_munmap 91 29 | -------------------------------------------------------------------------------- /memealloc/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | memealloc: 18 | A resizable and relocatable memory pool/allocator that uses 19 | relative pointers. 20 | */ 21 | 22 | #define internalfn static 23 | #define globvar static 24 | 25 | #define min(a, b) ((a) < (b) ? (a) : (b)) 26 | 27 | typedef i32 b32; 28 | typedef float f32; 29 | 30 | /* ------------------------------------------------------------- */ 31 | 32 | void* syscall1(uintptr number, void* arg1); 33 | void* syscall2(uintptr number, void* arg1, void* arg2); 34 | void* syscall3(uintptr number, void* arg1, void* arg2, void* arg3); 35 | 36 | void* syscall6( 37 | uintptr number, 38 | void* arg1, 39 | void* arg2, 40 | void* arg3, 41 | void* arg4, 42 | void* arg5, 43 | void* arg6 44 | ); 45 | 46 | /* ------------------------------------------------------------- */ 47 | 48 | internalfn 49 | void memecpy(void* dst, void const* src, intptr nbytes) 50 | { 51 | intptr i; 52 | u8* dst_bytes; 53 | u8* src_bytes; 54 | 55 | if (nbytes / sizeof(intptr)) 56 | { 57 | intptr* dst_chunks = (intptr*)dst; 58 | intptr* src_chunks = (intptr*)src; 59 | 60 | for (i = 0; i < nbytes / sizeof(intptr); ++i) { 61 | dst_chunks[i] = src_chunks[i]; 62 | } 63 | 64 | nbytes %= sizeof(intptr); 65 | dst = &dst_chunks[i]; 66 | src = &src_chunks[i]; 67 | } 68 | 69 | dst_bytes = (u8*)dst; 70 | src_bytes = (u8*)src; 71 | 72 | for (i = 0; i < nbytes; ++i) { 73 | dst_bytes[i] = src_bytes[i]; 74 | } 75 | } 76 | 77 | /* ------------------------------------------------------------- */ 78 | 79 | #define stdin 0 80 | 81 | internalfn 82 | intptr write(int fd, void const* data, uintptr nbytes) 83 | { 84 | return (uintptr) 85 | syscall3( 86 | SYS_write, 87 | (void*)(intptr)fd, 88 | (void*)data, 89 | (void*)nbytes 90 | ); 91 | } 92 | 93 | #define PROT_READ 0x1 94 | #define PROT_WRITE 0x2 95 | 96 | #define MAP_PRIVATE 0x02 97 | #define MAP_ANONYMOUS 0x20 98 | 99 | #ifndef PAGE_SIZE 100 | #define PAGE_SIZE 4096 101 | #endif 102 | 103 | internalfn 104 | void* mmap( 105 | void* addr, 106 | uintptr nbytes, 107 | int prot, 108 | int flags, 109 | int fd, 110 | u32 offset) 111 | { 112 | #ifdef LEGACY_MMAP 113 | void* params[7]; 114 | 115 | offset = (offset + PAGE_SIZE / 2) / PAGE_SIZE; 116 | offset *= PAGE_SIZE; 117 | nbytes = (nbytes + PAGE_SIZE / 2) / PAGE_SIZE; 118 | nbytes *= PAGE_SIZE; 119 | 120 | params[0] = addr; 121 | params[1] = (void*)(intptr)nbytes; 122 | params[2] = (void*)(intptr)prot; 123 | params[3] = (void*)(intptr)flags; 124 | params[4] = (void*)(intptr)fd; 125 | params[5] = (void*)(intptr)offset; 126 | params[6] = 0; 127 | 128 | return syscall1(SYS_mmap, (void*)params); 129 | #else 130 | return 131 | syscall6( 132 | SYS_mmap, 133 | addr, 134 | (void*)nbytes, 135 | (void*)(intptr)prot, 136 | (void*)(intptr)flags, 137 | (void*)(intptr)fd, 138 | (void*)(intptr)offset 139 | ); 140 | #endif 141 | } 142 | 143 | internalfn 144 | int munmap(void* addr, uintptr nbytes) 145 | { 146 | return (int)(intptr) 147 | syscall2( 148 | SYS_munmap, 149 | addr, 150 | (void*)nbytes 151 | ); 152 | } 153 | 154 | /* ------------------------------------------------------------- */ 155 | 156 | #define FD_BUFSIZE 8000 157 | 158 | typedef struct 159 | { 160 | int handle; 161 | b32 flush_every_line; 162 | uintptr buf_nbytes; 163 | char buf[FD_BUFSIZE]; 164 | } 165 | fd_t; 166 | 167 | /* 168 | internalfn 169 | int fopen(fd_t* fd, char const* filename, u32 flags, mode_t mode) 170 | { 171 | fd->handle = open(filename, flags, mode); 172 | fd->buf_nbytes = 0; 173 | fd->flush_every_line = 0; 174 | 175 | return fd->handle; 176 | } 177 | */ 178 | 179 | internalfn 180 | intptr fflush(fd_t* fd) 181 | { 182 | intptr res = 183 | fd->buf_nbytes ? write(fd->handle, fd->buf, fd->buf_nbytes) 184 | : 0; 185 | 186 | fd->buf_nbytes = 0; 187 | 188 | return res; 189 | } 190 | 191 | /* 192 | internalfn 193 | void fclose(fd_t* fd) 194 | { 195 | fflush(fd); 196 | close(fd->handle); 197 | fd->handle = 0; 198 | } 199 | */ 200 | 201 | internalfn 202 | intptr fwrite(fd_t* fd, void const* data, uintptr nbytes) 203 | { 204 | u8* p = (u8*)data; 205 | uintptr total = nbytes; 206 | 207 | while (nbytes) 208 | { 209 | intptr res; 210 | b32 should_flush = 0; 211 | 212 | uintptr to_write = 213 | min(nbytes, FD_BUFSIZE - fd->buf_nbytes); 214 | 215 | memecpy(fd->buf + fd->buf_nbytes, p, to_write); 216 | fd->buf_nbytes += to_write; 217 | 218 | if (fd->buf_nbytes >= FD_BUFSIZE) { 219 | should_flush = 1; 220 | } 221 | 222 | else if (fd->flush_every_line) 223 | { 224 | uintptr i; 225 | 226 | for (i = 0; i < to_write; ++i) 227 | { 228 | if (p[i] == '\n' || p[i] == '\r') { 229 | should_flush = 1; 230 | break; 231 | } 232 | } 233 | } 234 | 235 | if (should_flush) 236 | { 237 | uintptr to_flush = fd->buf_nbytes; 238 | 239 | res = fflush(fd); 240 | if (res != to_flush) { 241 | return res; 242 | } 243 | } 244 | 245 | nbytes -= to_write; 246 | p += to_write; 247 | } 248 | 249 | return total; 250 | } 251 | 252 | #define fread(fd, data, nbytes) read(fd->handle, data, nbytes) 253 | 254 | globvar fd_t stdout_; 255 | globvar fd_t* stdout = &stdout_; 256 | 257 | internalfn 258 | void stdinit() 259 | { 260 | stdout->handle = 1; 261 | stdout->flush_every_line = 1; 262 | } 263 | 264 | internalfn 265 | void stdfflush() 266 | { 267 | fflush(stdout); 268 | } 269 | 270 | /* ------------------------------------------------------------- */ 271 | 272 | #define puts(s) fwrite(stdout, s, strlen(s)) 273 | 274 | #ifdef _DEBUG 275 | #define dbgputs puts 276 | #else 277 | #define dbgputs(str) 278 | #endif 279 | 280 | /* ------------------------------------------------------------- */ 281 | 282 | #define strcpy(dst, src) memecpy(dst, src, strlen(src) + 1) 283 | 284 | internalfn 285 | uintptr strlen(char const* str) 286 | { 287 | char const* p; 288 | for (p = str; *p; ++p); 289 | return p - str; 290 | } 291 | 292 | intptr uitoa( 293 | u8 base, 294 | uintptr val, 295 | char* buf, 296 | intptr width, 297 | char filler) 298 | { 299 | char c; 300 | char* p = buf; 301 | intptr res; 302 | 303 | if (!base) { 304 | return 0; 305 | } 306 | 307 | if (base > 16) { 308 | return 0; 309 | } 310 | 311 | do 312 | { 313 | u8 digit = val % base; 314 | val /= base; 315 | *p++ = "0123456789abcdef"[digit]; 316 | } 317 | while(val); 318 | 319 | while (p - buf < width) { 320 | *p++ = filler; 321 | } 322 | 323 | res = p - buf; 324 | *p-- = 0; 325 | 326 | while (p > buf) 327 | { 328 | /* flip the string */ 329 | c = *p; 330 | *p-- = *buf; 331 | *buf++ = c; 332 | } 333 | 334 | return res; 335 | } 336 | 337 | /* ------------------------------------------------------------- 338 | MEMEALLOC 339 | ------------------------------------------------------------- */ 340 | 341 | globvar u8* memory = 0; 342 | globvar uintptr memory_size = 0; 343 | 344 | globvar u8* pmemory = 0; 345 | 346 | /* TODO: use macro trickery to add caller to each allocation */ 347 | typedef struct 348 | { 349 | uintptr size; 350 | uintptr offset_to_next; 351 | } 352 | allocation_t; 353 | 354 | internalfn 355 | void memeinit(uintptr size) 356 | { 357 | u8* new_memory = (u8*) 358 | mmap( 359 | 0, 360 | size, 361 | PROT_READ | PROT_WRITE, 362 | MAP_ANONYMOUS | MAP_PRIVATE, 363 | 0, 0 364 | ); 365 | 366 | if (memory) 367 | { 368 | uintptr offset = (uintptr)(pmemory - memory); 369 | #ifdef _DEBUG 370 | char buf[21]; 371 | 372 | uitoa(10, size, buf, 0, 0); 373 | #endif 374 | 375 | dbgputs("**** reallocating memory pool with size="); 376 | dbgputs(buf); 377 | dbgputs("\n"); 378 | 379 | memecpy(new_memory, memory, offset); 380 | pmemory = new_memory + offset; 381 | 382 | munmap(memory, memory_size); 383 | } 384 | 385 | else if (!pmemory) { 386 | pmemory = new_memory; 387 | } 388 | 389 | memory = new_memory; 390 | memory_size = size; 391 | } 392 | 393 | internalfn 394 | uintptr memealloc(uintptr size) 395 | { 396 | allocation_t* new_alloc = 0; 397 | u8* p = memory; 398 | intptr total_size = size + sizeof(allocation_t); 399 | #ifdef _DEBUG 400 | char buf[21]; 401 | 402 | uitoa(10, size, buf, 0, 0); 403 | #endif 404 | 405 | while (p < pmemory - 1) 406 | { 407 | allocation_t* alloc = (allocation_t*)p; 408 | intptr space_left; 409 | 410 | /* NOTE: gcc silently casts signed to unsigned in 411 | unsigned - signed comparisons, and we don't 412 | want that, that's why I made space_left signed. */ 413 | 414 | if (!alloc->offset_to_next) { 415 | break; 416 | } 417 | 418 | space_left = 419 | (intptr)alloc->offset_to_next - 420 | alloc->size - 421 | sizeof(allocation_t) * 422 | (alloc->size ? 2 : 1); 423 | 424 | /* if alloc is not freed, we will have to create a new 425 | allocation in the empty space after it, so there will be 426 | two allocation_t structs */ 427 | 428 | if (space_left >= total_size) 429 | { 430 | uintptr next = alloc->offset_to_next; 431 | 432 | if (alloc->size) 433 | { 434 | alloc->offset_to_next = 435 | sizeof(allocation_t) + alloc->size; 436 | 437 | next -= alloc->offset_to_next; 438 | 439 | p += alloc->offset_to_next; 440 | } 441 | 442 | new_alloc = (allocation_t*)p; 443 | new_alloc->offset_to_next = next; 444 | 445 | dbgputs("**** reusing free'd memory to allocate "); 446 | dbgputs(buf); 447 | dbgputs(" bytes\n"); 448 | 449 | break; 450 | } 451 | 452 | p = (u8*)alloc + alloc->offset_to_next; 453 | } 454 | 455 | if (!new_alloc) 456 | { 457 | allocation_t* prev = (allocation_t*)p; 458 | 459 | if (pmemory + total_size >= memory + memory_size) 460 | { 461 | return 0; /* out of memory */ 462 | } 463 | 464 | new_alloc = (allocation_t*)pmemory; 465 | prev->offset_to_next = prev->size + sizeof(allocation_t); 466 | new_alloc->offset_to_next = 0; 467 | 468 | pmemory += total_size; 469 | 470 | dbgputs("**** allocating "); 471 | dbgputs(buf); 472 | dbgputs(" bytes at the end of the memory pool\n"); 473 | } 474 | 475 | new_alloc->size = size; 476 | 477 | return (uintptr) 478 | ((u8*)new_alloc + sizeof(allocation_t) - memory); 479 | } 480 | 481 | internalfn 482 | void memefree(uintptr off) 483 | { 484 | u8* addr = memory + off; 485 | 486 | allocation_t* alloc = 487 | (allocation_t*)(addr - sizeof(allocation_t)); 488 | 489 | #ifdef _DEBUG 490 | char buf[21]; 491 | 492 | dbgputs("**** freeing "); 493 | 494 | uitoa(10, alloc->size, buf, 0, 0); 495 | dbgputs(buf); 496 | 497 | dbgputs(" bytes at 0x"); 498 | 499 | uitoa(16, (uintptr)addr, buf, sizeof(uintptr) * 2, '0'); 500 | dbgputs(buf); 501 | 502 | dbgputs("\n"); 503 | #endif 504 | 505 | alloc->size = 0; 506 | } 507 | 508 | /* ------------------------------------------------------------- */ 509 | 510 | /* dummy struct purely to get compiler warnings when I try to use 511 | a pointer to the wrong type */ 512 | 513 | #define ptr_type(type) \ 514 | typedef struct { uintptr off; } p##type; \ 515 | \ 516 | type* p##type##_get(p##type p) { return (type*)&memory[p.off]; } 517 | 518 | ptr_type(char) 519 | ptr_type(u32) 520 | 521 | globvar char buf[21]; 522 | 523 | internalfn 524 | void print_ptr(void const* addr) 525 | { 526 | puts("<"); 527 | uitoa(16, (uintptr)addr, buf, sizeof(uintptr) * 2, '0'); 528 | puts(buf); 529 | puts(">"); 530 | } 531 | 532 | internalfn 533 | void print_var_name(char const* name, void const* pvar) 534 | { 535 | puts(name); 536 | puts(" "); 537 | print_ptr(pvar); 538 | puts(" = "); 539 | } 540 | 541 | internalfn 542 | void print_str_(char const* name, pchar const pstr) 543 | { 544 | char const* str = pchar_get(pstr); 545 | print_var_name(name, str); 546 | puts(str); 547 | puts("\n"); 548 | } 549 | 550 | internalfn 551 | void print_u32_array_(char const* name, pu32 const parr, uintptr n) 552 | { 553 | u32 const* arr = pu32_get(parr); 554 | 555 | print_var_name(name, arr); 556 | 557 | for (; n; --n, ++arr) 558 | { 559 | uitoa(10, (uintptr)*arr, buf, 0, 0); 560 | puts(buf); 561 | puts(" "); 562 | } 563 | 564 | puts("\n"); 565 | } 566 | 567 | #define print_str(str) print_str_(#str, str) 568 | #define print_u32_array(arr, n) print_u32_array_(#arr, arr, n) 569 | 570 | int main() 571 | { 572 | pchar a; 573 | pchar b; 574 | pu32 c; 575 | pu32 d; 576 | pu32 e; 577 | int i; 578 | 579 | stdinit(); 580 | memeinit(1000000); /* 1mb memory pool */ 581 | 582 | a.off = memealloc(128); 583 | b.off = memealloc(400); 584 | c.off = memealloc(sizeof(u32) * 10); 585 | 586 | for (i = 0; i < 10; ++i) { 587 | pu32_get(c)[i] = i; 588 | } 589 | 590 | strcpy(pchar_get(a), "this is a small string"); 591 | strcpy( 592 | pchar_get(b), 593 | "this is a long string this is a long string " 594 | "this is a long string this is a long string" 595 | ); 596 | 597 | /* print stuff ---------------- */ 598 | print_str(a); 599 | print_str(b); 600 | print_u32_array(c, 10); 601 | /* ---------------------------- */ 602 | 603 | memefree(a.off); 604 | 605 | /* resize pool test */ 606 | memeinit(2000000); 607 | 608 | d.off = memealloc(sizeof(u32) * 10); 609 | a.off = memealloc(600); 610 | e.off = memealloc(sizeof(u32) * 2); 611 | 612 | pu32_get(e)[0] = 1337; 613 | pu32_get(e)[1] = 111111; 614 | 615 | strcpy( 616 | pchar_get(a), 617 | "this is an even longer string " 618 | "this is an even longer string " 619 | "this is an even longer string " 620 | "this is an even longer string " 621 | "this is an even longer string " 622 | "this is an even longer string" 623 | ); 624 | 625 | for (i = 0; i < 10; ++i) { 626 | pu32_get(d)[i] = pu32_get(c)[i] * 2; 627 | } 628 | 629 | /* print stuff ---------------- */ 630 | print_str(a); 631 | print_str(b); 632 | print_u32_array(c, 10); 633 | print_u32_array(d, 10); 634 | print_u32_array(e, 2); 635 | /* ---------------------------- */ 636 | 637 | /* no need to free the rest since the program is terminating */ 638 | stdfflush(); 639 | 640 | return 0; 641 | } 642 | 643 | -------------------------------------------------------------------------------- /namae/README.md: -------------------------------------------------------------------------------- 1 | This is a partial implementation of a DNS client that doesn't 2 | depend on libc or any third party library. It builds to a rather 3 | small < 4kb executable. The codebase is C89 and should build even 4 | on old compilers. 5 | 6 | The main purpose of this project is having libc-free code that I 7 | can copypaste in projects that need to resolve domains. 8 | 9 | Currently supported architectures are amd64 and i386. 10 | 11 | It queries the A record for a given hostname, using a hardcoded 12 | dns server (currently 185.121.177.177, one of opennic's servers). 13 | 14 | No ipv6 support until I actually need it. 15 | 16 | Note that this does not check for /etc/hosts or any config file at 17 | all. 18 | 19 | # Linux 32-bit 20 | ``` 21 | $ git clone https://github.com/Francesco149/namae.git 22 | $ cd namae 23 | $ chmod +x ./build.sh 24 | $ ./build.sh i386 25 | $ ./namae sdf.org 26 | ``` 27 | 28 | # Linux 64-bit 29 | ``` 30 | $ git clone https://github.com/Francesco149/namae.git 31 | $ cd namae 32 | $ chmod +x ./build.sh 33 | $ ./build.sh 34 | $ ./namae sdf.org 35 | ``` 36 | 37 | # License 38 | This code is public domain and comes with no warranty. You are free 39 | to do whatever you want with it. 40 | 41 | You can contact me at 42 | [lolisamurai@tfwno.gf](mailto:lolisamurai@tfwno.gf) but don't 43 | expect any support. 44 | 45 | I hope you will find the code useful or at least interesting to 46 | read. Have fun! 47 | -------------------------------------------------------------------------------- /namae/amd64/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #define AMD64 22 | #include "syscalls.h" 23 | 24 | typedef unsigned long int u64; 25 | typedef unsigned int u32; 26 | typedef unsigned short int u16; 27 | typedef unsigned char u8; 28 | 29 | typedef long int i64; 30 | typedef int i32; 31 | typedef short int i16; 32 | typedef signed char i8; 33 | 34 | typedef i64 intptr; 35 | typedef u64 uintptr; 36 | 37 | #include "../namae.c" 38 | 39 | int main(int argc, char const* argv[]) { 40 | return namae_run(argc, argv); 41 | } 42 | -------------------------------------------------------------------------------- /namae/amd64/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #include "syscalls.h" 22 | 23 | .intel_syntax noprefix 24 | .text 25 | .globl _start, syscall, 26 | .globl syscall1, syscall2, syscall3 27 | 28 | _start: 29 | xor rbp,rbp 30 | pop rdi 31 | mov rsi,rsp 32 | and rsp,-16 33 | call main 34 | mov rdi,rax 35 | mov rax,SYS_exit 36 | syscall 37 | ret 38 | 39 | syscall: 40 | mov rax,rdi 41 | syscall 42 | ret 43 | 44 | syscall1: 45 | mov rax,rdi 46 | mov rdi,rsi 47 | syscall 48 | ret 49 | 50 | syscall2: 51 | mov rax,rdi 52 | mov rdi,rsi 53 | mov rsi,rdx 54 | syscall 55 | ret 56 | 57 | syscall3: 58 | mov rax,rdi 59 | mov rdi,rsi 60 | mov rsi,rdx 61 | mov rdx,rcx 62 | syscall 63 | ret 64 | -------------------------------------------------------------------------------- /namae/amd64/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #define SYS_read 0 22 | #define SYS_write 1 23 | #define SYS_close 3 24 | #define SYS_getpid 39 25 | #define SYS_socket 41 26 | #define SYS_connect 42 27 | #define SYS_exit 60 28 | -------------------------------------------------------------------------------- /namae/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # namae: a tiny libc-free partial implementation of a dns 19 | # client for Linux. 20 | 21 | exename="namae" 22 | archname=${1:-amd64} 23 | 24 | if [ -e $archname/flags.sh ]; then 25 | source $archname/flags.sh 26 | fi 27 | 28 | gcc -std=c89 -pedantic -s -O2 -Wall -Werror \ 29 | -nostdlib \ 30 | -fno-unwind-tables \ 31 | -fno-asynchronous-unwind-tables \ 32 | -fdata-sections \ 33 | -Wl,--gc-sections \ 34 | -Wa,--noexecstack \ 35 | -fno-builtin \ 36 | -fno-stack-protector \ 37 | $COMPILER_FLAGS \ 38 | $archname/start.S $archname/main.c \ 39 | -o $exename \ 40 | \ 41 | && strip -R .comment $exename 42 | -------------------------------------------------------------------------------- /namae/i386/flags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # namae: a tiny libc-free partial implementation of a dns 19 | # client for Linux. 20 | 21 | export COMPILER_FLAGS="-m32 -Wno-long-long" 22 | -------------------------------------------------------------------------------- /namae/i386/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #define I386 22 | #include "syscalls.h" 23 | 24 | typedef unsigned long long int u64; 25 | typedef unsigned int u32; 26 | typedef unsigned short int u16; 27 | typedef unsigned char u8; 28 | 29 | typedef long long int i64; 30 | typedef int i32; 31 | typedef short int i16; 32 | typedef signed char i8; 33 | 34 | typedef i32 intptr; 35 | typedef u32 uintptr; 36 | 37 | #include "../namae.c" 38 | 39 | int main(int argc, char const* argv[]) { 40 | return namae_run(argc, argv); 41 | } 42 | -------------------------------------------------------------------------------- /namae/i386/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #include "syscalls.h" 22 | 23 | .intel_syntax noprefix 24 | .text 25 | .globl _start, syscall 26 | .globl syscall1, syscall2, syscall3 27 | 28 | _start: 29 | xor ebp,ebp 30 | pop esi 31 | mov ecx,esp 32 | and esp,-16 33 | push 0xb16b00b5 34 | push 0xb16b00b5 35 | push ecx 36 | push esi 37 | call main 38 | add esp,16 39 | mov ebx,eax 40 | mov eax,SYS_exit 41 | int 0x80 42 | ret 43 | 44 | syscall: 45 | mov eax,[esp+4] 46 | int 0x80 47 | ret 48 | 49 | syscall1: 50 | push ebx 51 | mov eax,[esp+4+4] 52 | mov ebx,[esp+8+4] 53 | int 0x80 54 | pop ebx 55 | ret 56 | 57 | syscall2: 58 | push ebx 59 | mov eax,[esp+4+4] 60 | mov ebx,[esp+8+4] 61 | mov ecx,[esp+12+4] 62 | int 0x80 63 | pop ebx 64 | ret 65 | 66 | syscall3: 67 | push ebx 68 | mov eax,[esp+4+4] 69 | mov ebx,[esp+8+4] 70 | mov ecx,[esp+12+4] 71 | mov edx,[esp+16+4] 72 | int 0x80 73 | pop ebx 74 | ret 75 | -------------------------------------------------------------------------------- /namae/i386/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #define SYS_read 3 22 | #define SYS_write 4 23 | #define SYS_close 6 24 | #define SYS_getpid 20 25 | #define SYS_exit 1 26 | #define SYS_socketcall 102 27 | -------------------------------------------------------------------------------- /namae/namae.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | namae: a tiny libc-free partial implementation of a dns 18 | client for Linux. 19 | */ 20 | 21 | #define NAMAE_VER "namae v1.0" 22 | #define DNS_SERVER 0xB1B179B9 /* in big endian */ 23 | 24 | #define internal static 25 | 26 | typedef u32 b32; 27 | 28 | void* syscall(uintptr number); 29 | void* syscall1(uintptr number, void* arg1); 30 | void* syscall2(uintptr number, void* arg1, void* arg2); 31 | void* syscall3(uintptr number, void* arg1, void* arg2, void* arg3); 32 | 33 | /* ------------------------------------------------------------- */ 34 | 35 | internal 36 | void memeset(void* dst, u8 value, intptr nbytes) 37 | { 38 | intptr i; 39 | 40 | if (nbytes % sizeof(intptr) == 0) 41 | { 42 | intptr* dst_chunks = (intptr*)dst; 43 | intptr chunk; 44 | u8* chunk_raw = (u8*)&chunk; 45 | 46 | for (i = 0; i < sizeof(intptr); ++i) { 47 | chunk_raw[i] = value; 48 | } 49 | 50 | for (i = 0; i < nbytes / sizeof(intptr); ++i) { 51 | dst_chunks[i] = chunk; 52 | } 53 | } 54 | else 55 | { 56 | u8* dst_bytes = (u8*)dst; 57 | 58 | for (i = 0; i < nbytes; ++i) { 59 | dst_bytes[i] = value; 60 | } 61 | } 62 | } 63 | 64 | /* ------------------------------------------------------------- */ 65 | 66 | internal 67 | int getpid() { 68 | return (int)(intptr)syscall(SYS_getpid); 69 | } 70 | 71 | #define stdout 1 72 | #define stderr 2 73 | 74 | internal 75 | void close(int fd) { 76 | syscall1(SYS_close, (void*)(intptr)fd); 77 | } 78 | 79 | internal 80 | intptr write(int fd, void const* data, uintptr nbytes) 81 | { 82 | return (uintptr) 83 | syscall3( 84 | SYS_write, 85 | (void*)(intptr)fd, 86 | (void*)data, 87 | (void*)nbytes 88 | ); 89 | } 90 | 91 | internal 92 | intptr read(int fd, void* data, intptr nbytes) 93 | { 94 | return (intptr) 95 | syscall3( 96 | SYS_read, 97 | (void*)(intptr)fd, 98 | data, 99 | (void*)nbytes 100 | ); 101 | } 102 | 103 | #define AF_INET 2 104 | #define SOCK_DGRAM 2 105 | #define IPPROTO_UDP 17 106 | 107 | typedef struct 108 | { 109 | u16 family; 110 | u16 port; /* NOTE: this is big endian!!!!!!! use flip16u */ 111 | u32 addr; /* this is also big endian */ 112 | u8 zero[8]; 113 | } 114 | sockaddr_in; 115 | 116 | #ifdef SYS_socketcall 117 | /* i386 multiplexes socket calls through socketcall */ 118 | #define SYS_SOCKET 1 119 | #define SYS_CONNECT 3 120 | 121 | internal 122 | int socketcall(u32 call, void* args) 123 | { 124 | return (int)(intptr) 125 | syscall2( 126 | SYS_socketcall, 127 | (void*)(intptr)call, 128 | args 129 | ); 130 | } 131 | #endif 132 | 133 | internal 134 | int socket(u16 family, i32 type, i32 protocol) 135 | { 136 | #ifndef SYS_socketcall 137 | return (int)(intptr) 138 | syscall3( 139 | SYS_socket, 140 | (void*)(intptr)family, 141 | (void*)(intptr)type, 142 | (void*)(intptr)protocol 143 | ); 144 | #else 145 | void* args[3]; 146 | args[0] = (void*)(intptr)family; 147 | args[1] = (void*)(intptr)type; 148 | args[2] = (void*)(intptr)protocol; 149 | 150 | return socketcall(SYS_SOCKET, args); 151 | #endif 152 | } 153 | 154 | internal 155 | int connect(int sockfd, sockaddr_in const* addr) 156 | { 157 | #ifndef SYS_socketcall 158 | return (int)(intptr) 159 | syscall3( 160 | SYS_connect, 161 | (void*)(intptr)sockfd, 162 | (void*)addr, 163 | (void*)sizeof(sockaddr_in) 164 | ); 165 | #else 166 | void* args[3]; 167 | args[0] = (void*)(intptr)sockfd; 168 | args[1] = (void*)addr; 169 | args[2] = (void*)sizeof(sockaddr_in); 170 | 171 | return socketcall(SYS_CONNECT, args); 172 | #endif 173 | } 174 | 175 | /* ------------------------------------------------------------- */ 176 | 177 | internal 178 | intptr strlen(char const* str) 179 | { 180 | char const* p; 181 | for(p = str; *p; ++p); 182 | return p - str; 183 | } 184 | 185 | internal 186 | b32 streq(char const* a, char const* b) 187 | { 188 | for (; *a && *b; ++a, ++b) 189 | { 190 | if (*a != *b) { 191 | return 0; 192 | } 193 | } 194 | 195 | return *a == *b; 196 | } 197 | 198 | internal 199 | intptr fputs(int fd, char const* str) { 200 | return write(fd, str, strlen(str)); 201 | } 202 | 203 | internal 204 | intptr puts(char const* str) { 205 | return fputs(stdout, str); 206 | } 207 | 208 | internal 209 | intptr uitoa( 210 | u8 base, 211 | uintptr val, 212 | char* buf, 213 | intptr width, 214 | char filler) 215 | { 216 | char c; 217 | char* p = buf; 218 | intptr res; 219 | 220 | if (!base) { 221 | return 0; 222 | } 223 | 224 | if (base > 16) { 225 | return 0; 226 | } 227 | 228 | do 229 | { 230 | u8 digit = val % base; 231 | val /= base; 232 | *p++ = "0123456789abcdef"[digit]; 233 | } 234 | while(val); 235 | 236 | while (p - buf < width) { 237 | *p++ = filler; 238 | } 239 | 240 | res = p - buf; 241 | *p-- = 0; 242 | 243 | while (p > buf) 244 | { 245 | /* flip the string */ 246 | c = *p; 247 | *p-- = *buf; 248 | *buf++ = c; 249 | } 250 | 251 | return res; 252 | } 253 | 254 | 255 | internal 256 | void print_ipv4(u8 const* bytes) 257 | { 258 | static char buf[16]; 259 | char* p = buf; 260 | 261 | p += uitoa(10, (uintptr)bytes[0], p, 0, '0'); 262 | *p++ = '.'; 263 | 264 | p += uitoa(10, (uintptr)bytes[1], p, 0, '0'); 265 | *p++ = '.'; 266 | 267 | p += uitoa(10, (uintptr)bytes[2], p, 0, '0'); 268 | *p++ = '.'; 269 | 270 | uitoa(10, (uintptr)bytes[3], p, 0, '0'); 271 | 272 | puts(buf); 273 | } 274 | 275 | /* reverses byte order of a 16-bit integer (0x1234 -> 0x3412) */ 276 | internal 277 | u16 flip16u(u16 v) { 278 | return (v << 8) | (v >> 8); 279 | } 280 | 281 | /* ------------------------------------------------------------- */ 282 | 283 | /* primitive encoding functions used to build the packets. 284 | this is all big endian */ 285 | 286 | internal 287 | uintptr encode2(u8* p, u16 v) 288 | { 289 | u8 const* s = p; 290 | *p++ = (u8)(v >> 8); 291 | *p++ = (u8)(v & 0x00FF); 292 | return p - s; 293 | } 294 | 295 | internal 296 | uintptr decode2(u8 const* p, u16* v) 297 | { 298 | u8 const* s = p; 299 | *v = *p++ << 8; 300 | *v |= *p++; 301 | return p - s; 302 | } 303 | 304 | internal 305 | uintptr decode4(u8 const* p, u32* v) 306 | { 307 | u8 const* s = p; 308 | p += decode2(p, (u16*)v + 1); 309 | p += decode2(p, (u16*)v); 310 | return p - s; 311 | } 312 | 313 | #define MAX_STR 63 314 | 315 | /* len will be truncated to MAX_STR if higher */ 316 | internal 317 | uintptr encode_str(u8* p, char const* str, u8 len) 318 | { 319 | u8 const* s = p; 320 | len &= MAX_STR; 321 | 322 | *p++ = len; 323 | 324 | for (; len; --len) { 325 | *p++ = (u8)*str++; 326 | } 327 | 328 | return p - s; 329 | } 330 | 331 | internal 332 | uintptr decode_str(u8 const* p, char* str) 333 | { 334 | u8 const* s = p; 335 | u8 len = *p++; 336 | 337 | for (; len; --len) { 338 | *str++ = (char)*p++; 339 | } 340 | 341 | *str++ = 0; 342 | 343 | return p - s; 344 | } 345 | 346 | /* ------------------------------------------------------------- */ 347 | 348 | #define RCODE_OK 0 349 | #define RCODE_EFMT 1 350 | #define RCODE_ESERV 2 351 | #define RCODE_ENAME 3 352 | #define RCODE_EIMPL 4 353 | #define RCODE_EREFUSED 5 354 | 355 | char const* rcode(u8 code) 356 | { 357 | switch (code) 358 | { 359 | case RCODE_EFMT: 360 | return "Format error: the name server was unable to " 361 | "interpret the query"; 362 | case RCODE_ESERV: 363 | return "Server failure: The name server was unable to " 364 | "process this query due to a problem with the " 365 | "name server"; 366 | case RCODE_ENAME: 367 | return "Name error: the domain name referenced in the " 368 | " query does not exist"; 369 | case RCODE_EIMPL: 370 | return "Not implemented: the name server does not " 371 | "support the requested kind of query"; 372 | case RCODE_EREFUSED: 373 | return "Refused: the name server refuses to perform " 374 | "the specified operation for policy reasons"; 375 | } 376 | 377 | return "Unknown error"; 378 | } 379 | 380 | /* 381 | Section 4.1.3 of https://www.ietf.org/rfc/rfc1035.txt 382 | 383 | 1 1 1 1 1 1 384 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 385 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 386 | | ID | 387 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 388 | |QR| Opcode |AA|TC|RD|RA| Z | RCODE | <- mask 389 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 390 | | QDCOUNT | 391 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 392 | | ANCOUNT | 393 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 394 | | NSCOUNT | 395 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 396 | | ARCOUNT | 397 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 398 | */ 399 | 400 | #define QR_QUERY 0x0000 401 | #define QR_RESP 0x8000 /* 1 0000 0 0 0 0 000 0000 */ 402 | #define OPCODE_QUERY 0x0000 403 | #define OPCODE_STATUS 0x1000 /* 0 0010 0 0 0 0 000 0000 */ 404 | #define DNS_RD 0x0100 /* 0 0000 0 0 1 0 000 0000 */ 405 | #define DNS_AA 0x0400 /* 0 0000 1 0 0 0 000 0000 */ 406 | #define RCODE_MASK 0x000F /* 0 0000 0 0 0 0 000 1111 */ 407 | 408 | typedef struct 409 | { 410 | u16 id; 411 | u16 mask; 412 | u16 qd_count; 413 | u16 an_count; 414 | u16 ns_count; 415 | u16 ar_count; 416 | } 417 | dns_hdr; 418 | 419 | internal 420 | uintptr encode_dns_hdr(u8* p, dns_hdr const* hdr) 421 | { 422 | u8 const* s = p; 423 | 424 | p += encode2(p, hdr->id); 425 | p += encode2(p, hdr->mask); 426 | p += encode2(p, hdr->qd_count); 427 | p += encode2(p, hdr->an_count); 428 | p += encode2(p, hdr->ns_count); 429 | p += encode2(p, hdr->ar_count); 430 | 431 | return p - s; 432 | } 433 | 434 | internal 435 | uintptr decode_dns_hdr(u8 const* p, dns_hdr* hdr) 436 | { 437 | u8 const* s = p; 438 | 439 | p += decode2(p, &hdr->id); 440 | p += decode2(p, &hdr->mask); 441 | p += decode2(p, &hdr->qd_count); 442 | p += decode2(p, &hdr->an_count); 443 | p += decode2(p, &hdr->ns_count); 444 | p += decode2(p, &hdr->ar_count); 445 | 446 | return p - s; 447 | } 448 | 449 | #define TYPE_A 1 450 | #define CLASS_IN 1 451 | 452 | internal 453 | uintptr encode_dns_question( 454 | u8* p, 455 | char const* qname, 456 | u16 qtype, 457 | u16 qclass) 458 | { 459 | u8 const* s = p; 460 | char const* label = qname; 461 | 462 | for (; 1; ++label) 463 | { 464 | char c = *label; 465 | 466 | if (c != '.' && c) { 467 | continue; 468 | } 469 | 470 | p += encode_str(p, qname, label - qname); 471 | qname = label + 1; 472 | 473 | if (!c) { 474 | break; 475 | } 476 | } 477 | 478 | *p++ = 0; 479 | 480 | p += encode2(p, qtype); 481 | p += encode2(p, qclass); 482 | 483 | return p - s; 484 | } 485 | 486 | /* 487 | Section 4.1.4 of https://www.ietf.org/rfc/rfc1035.txt 488 | 489 | To avoid duplicate strings, an entire domain name or a list of 490 | labels at the end of a domain name is replaced with a pointer 491 | to a prior occurance of the same name. 492 | 493 | The pointer takes the form of a two octet sequence: 494 | 495 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 496 | | 1 1| OFFSET | 497 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 498 | 499 | The first two bits are ones. This allows a pointer to be 500 | distinguished from a label, since the label must begin with two 501 | zero bits because labels are restricted to 63 octets or less. 502 | */ 503 | 504 | #define MAX_HOST 0xFF 505 | #define STR_POINTER 0xC0 506 | 507 | /* qname is expected to be of size MAX_HOST */ 508 | internal 509 | uintptr decode_name(u8 const* p, char* qname, u8 const* data_begin) 510 | { 511 | u8 const* s = p; 512 | 513 | if ((*p & STR_POINTER) == STR_POINTER) 514 | { 515 | /* a pointer basically redirects the parsing of the entire 516 | name to another location in the packet */ 517 | u16 offset; 518 | p += decode2(p, &offset); 519 | offset &= ~(STR_POINTER << 8); 520 | decode_name(data_begin + offset, qname, data_begin); 521 | return p - s; 522 | } 523 | 524 | while (p - s + *p < MAX_HOST - 1) 525 | { 526 | p += decode_str(p, qname); 527 | if (!*p) { 528 | break; 529 | } 530 | 531 | for (; *qname; ++qname); 532 | *qname++ = '.'; 533 | } 534 | 535 | for (; *p; ++p); /* skip rest in case of truncation */ 536 | 537 | return ++p - s; 538 | } 539 | 540 | /* qname is expected to be of size MAX_HOST */ 541 | internal 542 | uintptr decode_dns_question( 543 | u8 const* p, 544 | char* qname, 545 | u16* qtype, 546 | u16* qclass, 547 | u8 const* data_begin) 548 | { 549 | u8 const* s = p; 550 | 551 | p += decode_name(p, qname, data_begin); 552 | p += decode2(p, qtype); 553 | p += decode2(p, qclass); 554 | 555 | return p - s; 556 | } 557 | 558 | typedef struct 559 | { 560 | char* name; 561 | u16 type; 562 | u16 class; 563 | u32 ttl; 564 | u16 rd_length; 565 | void const* data; 566 | } 567 | dns_resource; 568 | 569 | /* res->name is expected to be set to a buffer of size MAX_HOST. 570 | res->data will point to data in p, and will only be valid as 571 | long as p is valid */ 572 | internal 573 | uintptr decode_dns_resource( 574 | u8 const* p, 575 | dns_resource* res, 576 | u8 const* data_begin) 577 | { 578 | u8 const* s = p; 579 | 580 | p += decode_dns_question( 581 | p, 582 | res->name, 583 | &res->type, 584 | &res->class, 585 | data_begin 586 | ); 587 | 588 | p += decode4(p, &res->ttl); 589 | p += decode2(p, &res->rd_length); 590 | 591 | res->data = p; 592 | p += res->rd_length; 593 | 594 | return p - s; 595 | } 596 | 597 | /* note: ip is in big endian */ 598 | internal 599 | int dns_dial(u32 ip) 600 | { 601 | int fd, err; 602 | sockaddr_in a; 603 | 604 | memeset(&a, 0, sizeof(sockaddr_in)); 605 | a.family = AF_INET; 606 | a.port = flip16u(53); 607 | a.addr = ip; 608 | 609 | fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 610 | if (fd < 0) { 611 | return fd; 612 | } 613 | 614 | err = connect(fd, &a); 615 | if (err < 0) { 616 | close(fd); 617 | return err; 618 | } 619 | 620 | return fd; 621 | } 622 | 623 | /* ------------------------------------------------------------- */ 624 | 625 | #define BUFSIZE 0xFFFF 626 | 627 | #define error(msg) fputs(stderr, msg) 628 | #define die(msg) \ 629 | error(msg); \ 630 | return 1; 631 | 632 | #define die_cleanup(msg) \ 633 | error(msg); \ 634 | code = 1; \ 635 | goto cleanup; 636 | 637 | internal 638 | int namae_run(int argc, char const* argv[]) 639 | { 640 | int code = 0; 641 | int fd; 642 | 643 | /* query and response */ 644 | u8 buf[BUFSIZE]; 645 | u8* p; 646 | dns_hdr hdr; 647 | 648 | /* response */ 649 | char namebuf[MAX_HOST]; 650 | u16 qtype, qclass; 651 | u16 i; 652 | 653 | /* ----------------------------------------------------- */ 654 | 655 | fputs(stderr, "(" NAMAE_VER ")\n\n"); 656 | 657 | if (argc < 2) 658 | { 659 | fputs(stderr, "Usage: "); 660 | fputs(stderr, argv[0]); 661 | fputs(stderr, " domain\n"); 662 | 663 | return 1; 664 | } 665 | 666 | /* ----------------------------------------------------- */ 667 | 668 | fd = dns_dial(DNS_SERVER); 669 | if (fd < 0) { 670 | die("Failed to connect to DNS server") 671 | } 672 | 673 | /* ----------------------------------------------------- */ 674 | 675 | memeset(&hdr, 0, sizeof(dns_hdr)); 676 | hdr.id = (u16)getpid(); 677 | hdr.mask = QR_QUERY | OPCODE_QUERY | DNS_RD; 678 | hdr.qd_count = 1; 679 | 680 | p = buf; 681 | p += encode_dns_hdr(p, &hdr); 682 | p += encode_dns_question(p, argv[1], TYPE_A, CLASS_IN); 683 | 684 | if (write(fd, buf, p - buf) != p - buf) { 685 | die_cleanup("write failed\n") 686 | } 687 | 688 | /* ----------------------------------------------------- */ 689 | 690 | if (read(fd, buf, BUFSIZE) < 0) { 691 | die_cleanup("read failed\n") 692 | } 693 | 694 | cleanup: 695 | close(fd); 696 | 697 | if (code) { 698 | return code; 699 | } 700 | 701 | p = buf; 702 | p += decode_dns_hdr(p, &hdr); 703 | 704 | if (hdr.id != getpid()) { 705 | die("ID mismatch\n") 706 | } 707 | 708 | if (!(hdr.mask & QR_RESP)) { 709 | die("Expected response, got query\n") 710 | } 711 | 712 | if ((hdr.mask & RCODE_MASK) != RCODE_OK) { 713 | die(rcode(hdr.mask & RCODE_MASK)) 714 | } 715 | 716 | if (hdr.qd_count != 1) { 717 | die("Question count mismatch\n") 718 | } 719 | 720 | p += decode_dns_question(p, namebuf, &qtype, &qclass, buf); 721 | 722 | if (!streq(namebuf, argv[1])) { 723 | die("Query hostname mismatch\n") 724 | } 725 | 726 | if (qtype != TYPE_A) { 727 | die("Query type mismatch\n") 728 | } 729 | 730 | if (qclass != CLASS_IN) { 731 | die("Query class mimatch\n") 732 | } 733 | 734 | for (i = 0; 735 | i < hdr.an_count + hdr.ns_count + hdr.ar_count; 736 | ++i) 737 | { 738 | dns_resource r; 739 | 740 | r.name = namebuf; 741 | p += decode_dns_resource(p, &r, buf); 742 | 743 | puts(r.name); 744 | puts(" -> "); 745 | 746 | switch (r.type) 747 | { 748 | case TYPE_A: 749 | if (r.rd_length != 4) { 750 | die("Invalid length for ipv4 A record\n") 751 | } 752 | 753 | print_ipv4(r.data); 754 | break; 755 | 756 | default: 757 | { 758 | u8 const* pdata = r.data; 759 | 760 | puts("(unknown resource type "); 761 | uitoa(10, (uintptr)r.type, namebuf, 0, '0'); 762 | puts(namebuf); 763 | puts(") "); 764 | 765 | for (; r.rd_length; --r.rd_length) 766 | { 767 | uitoa(16, (uintptr)*pdata++, namebuf, 2, '0'); 768 | puts(namebuf); 769 | puts(" "); 770 | } 771 | } 772 | } 773 | 774 | puts("\n"); 775 | } 776 | 777 | return 0; 778 | } 779 | -------------------------------------------------------------------------------- /qsort/amd64/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | #define AMD64 21 | #include "syscalls.h" 22 | 23 | typedef unsigned long int u64; 24 | typedef unsigned int u32; 25 | typedef unsigned short int u16; 26 | typedef unsigned char u8; 27 | 28 | typedef long int i64; 29 | typedef int i32; 30 | typedef short int i16; 31 | typedef signed char i8; 32 | 33 | typedef i64 intptr; 34 | typedef u64 uintptr; 35 | 36 | #include "../main.c" 37 | -------------------------------------------------------------------------------- /qsort/amd64/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | #include "syscalls.h" 21 | 22 | .intel_syntax noprefix 23 | .text 24 | .globl _start, syscall, 25 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 26 | 27 | _start: 28 | xor rbp,rbp 29 | pop rdi 30 | mov rsi,rsp 31 | and rsp,-16 32 | call main 33 | mov rdi,rax 34 | mov rax,SYS_exit 35 | syscall 36 | ret 37 | 38 | syscall: 39 | mov rax,rdi 40 | syscall 41 | ret 42 | 43 | syscall1: 44 | mov rax,rdi 45 | mov rdi,rsi 46 | syscall 47 | ret 48 | 49 | syscall2: 50 | mov rax,rdi 51 | mov rdi,rsi 52 | mov rsi,rdx 53 | syscall 54 | ret 55 | 56 | syscall3: 57 | mov rax,rdi 58 | mov rdi,rsi 59 | mov rsi,rdx 60 | mov rdx,rcx 61 | syscall 62 | ret 63 | 64 | syscall4: 65 | mov rax,rdi 66 | mov rdi,rsi 67 | mov rsi,rdx 68 | mov rdx,rcx 69 | mov r10,r8 70 | syscall 71 | ret 72 | 73 | syscall5: 74 | mov rax,rdi 75 | mov rdi,rsi 76 | mov rsi,rdx 77 | mov rdx,rcx 78 | mov r10,r8 79 | mov r8,r9 80 | syscall 81 | ret 82 | -------------------------------------------------------------------------------- /qsort/amd64/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | #define SYS_read 0 21 | #define SYS_write 1 22 | #define SYS_open 2 23 | #define SYS_close 3 24 | #define SYS_exit 60 25 | -------------------------------------------------------------------------------- /qsort/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # qsort: just a basic implementation of qsort 19 | 20 | exename="qsort" 21 | archname=${1:-amd64} # if not specified, default to amd64 22 | shift 23 | 24 | if [ -e $archname/flags.sh ]; then 25 | source $archname/flags.sh 26 | fi 27 | 28 | gcc -std=c89 -pedantic -s -O2 -Wall -Werror \ 29 | -nostdlib \ 30 | -fno-unwind-tables \ 31 | -fno-asynchronous-unwind-tables \ 32 | -fdata-sections \ 33 | -Wl,--gc-sections \ 34 | -Wa,--noexecstack \ 35 | -fno-builtin \ 36 | -fno-stack-protector \ 37 | $COMPILER_FLAGS \ 38 | $@ \ 39 | $archname/start.S $archname/platform.c \ 40 | -o $exename \ 41 | \ 42 | && strip -R .comment $exename 43 | -------------------------------------------------------------------------------- /qsort/i386/flags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This code is public domain and comes with no warranty. 4 | # You are free to do whatever you want with it. You can 5 | # contact me at lolisamurai@tfwno.gf but don't expect any 6 | # support. 7 | # I hope you will find the code useful or at least 8 | # interesting to read. Have fun! 9 | # ----------------------------------------------------------- 10 | # This file is part of "nolibc", a compilation of reusable 11 | # code snippets I copypaste and tweak for my libc-free 12 | # linux software. 13 | # 14 | # DISCLAIMER: these snippets might be incomplete, broken or 15 | # just plain wrong, as many of them haven't had 16 | # the chance to be heavily tested yet. 17 | # ----------------------------------------------------------- 18 | # qsort: just a basic implementation of qsort 19 | 20 | export COMPILER_FLAGS="-m32 -Wno-long-long" 21 | -------------------------------------------------------------------------------- /qsort/i386/platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | #define I386 21 | #include "syscalls.h" 22 | 23 | typedef unsigned long long int u64; 24 | typedef unsigned int u32; 25 | typedef unsigned short int u16; 26 | typedef unsigned char u8; 27 | 28 | typedef long long int i64; 29 | typedef int i32; 30 | typedef short int i16; 31 | typedef signed char i8; 32 | 33 | typedef i32 intptr; 34 | typedef u32 uintptr; 35 | 36 | #include "../main.c" 37 | -------------------------------------------------------------------------------- /qsort/i386/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | #include "syscalls.h" 21 | 22 | .intel_syntax noprefix 23 | .text 24 | .globl _start, syscall 25 | .globl syscall1, syscall2, syscall3, syscall4, syscall5 26 | 27 | _start: 28 | xor ebp,ebp 29 | pop esi 30 | mov ecx,esp 31 | and esp,-16 32 | push 0xb16b00b5 33 | push 0xb16b00b5 34 | push ecx 35 | push esi 36 | call main 37 | add esp,16 38 | mov ebx,eax 39 | mov eax,SYS_exit 40 | int 0x80 41 | ret 42 | 43 | syscall: 44 | mov eax,[esp+4] 45 | int 0x80 46 | ret 47 | 48 | syscall1: 49 | push ebx 50 | mov eax,[esp+4+4] 51 | mov ebx,[esp+8+4] 52 | int 0x80 53 | pop ebx 54 | ret 55 | 56 | syscall2: 57 | push ebx 58 | mov eax,[esp+4+4] 59 | mov ebx,[esp+8+4] 60 | mov ecx,[esp+12+4] 61 | int 0x80 62 | pop ebx 63 | ret 64 | 65 | syscall3: 66 | push ebx 67 | mov eax,[esp+4+4] 68 | mov ebx,[esp+8+4] 69 | mov ecx,[esp+12+4] 70 | mov edx,[esp+16+4] 71 | int 0x80 72 | pop ebx 73 | ret 74 | 75 | syscall4: 76 | push ebx 77 | push esi 78 | mov eax,[esp+4+8] 79 | mov ebx,[esp+8+8] 80 | mov ecx,[esp+12+8] 81 | mov edx,[esp+16+8] 82 | mov esi,[esp+20+8] 83 | int 0x80 84 | pop esi 85 | pop ebx 86 | ret 87 | 88 | syscall5: 89 | push ebx 90 | push esi 91 | push edi 92 | mov eax,[esp+4+12] 93 | mov ebx,[esp+8+12] 94 | mov ecx,[esp+12+12] 95 | mov edx,[esp+16+12] 96 | mov esi,[esp+20+12] 97 | mov edi,[esp+24+12] 98 | int 0x80 99 | pop edi 100 | pop esi 101 | pop ebx 102 | ret 103 | -------------------------------------------------------------------------------- /qsort/i386/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | #define SYS_read 3 21 | #define SYS_write 4 22 | #define SYS_open 5 23 | #define SYS_close 6 24 | #define SYS_exit 1 25 | -------------------------------------------------------------------------------- /qsort/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This code is public domain and comes with no warranty. 3 | You are free to do whatever you want with it. You can 4 | contact me at lolisamurai@tfwno.gf but don't expect any 5 | support. 6 | I hope you will find the code useful or at least 7 | interesting to read. Have fun! 8 | ----------------------------------------------------------- 9 | This file is part of "nolibc", a compilation of reusable 10 | code snippets I copypaste and tweak for my libc-free 11 | linux software. 12 | 13 | DISCLAIMER: these snippets might be incomplete, broken or 14 | just plain wrong, as many of them haven't had 15 | the chance to be heavily tested yet. 16 | ----------------------------------------------------------- 17 | qsort: just a basic implementation of qsort 18 | */ 19 | 20 | /* TODO: change pivot to middle to improve efficiency for nearly 21 | sorted arrays */ 22 | 23 | typedef i32 b32; 24 | 25 | #define internal static 26 | #define globvar static 27 | 28 | #define arr_count(a) (sizeof(a) / sizeof((a)[0])) 29 | 30 | /* ------------------------------------------------------------- */ 31 | 32 | void* syscall1(uintptr number, void* arg1); 33 | 34 | void* syscall3( 35 | uintptr number, 36 | void* arg1, 37 | void* arg2, 38 | void* arg3 39 | ); 40 | 41 | /* ------------------------------------------------------------- */ 42 | 43 | #define stdin 0 44 | #define stdout 1 45 | 46 | internal 47 | intptr write(int fd, void const* data, uintptr nbytes) 48 | { 49 | return (uintptr) 50 | syscall3( 51 | SYS_write, 52 | (void*)(intptr)fd, 53 | (void*)data, 54 | (void*)nbytes 55 | ); 56 | } 57 | 58 | internal 59 | intptr read(int fd, void* data, intptr nbytes) 60 | { 61 | return (intptr) 62 | syscall3( 63 | SYS_read, 64 | (void*)(intptr)fd, 65 | data, 66 | (void*)nbytes 67 | ); 68 | } 69 | 70 | #define O_RDONLY 00 71 | 72 | typedef u32 mode_t; 73 | 74 | internal 75 | int open(char const* filename, u32 flags, mode_t mode) 76 | { 77 | return (int)(intptr) 78 | syscall3( 79 | SYS_open, 80 | (void*)filename, 81 | (void*)(intptr)flags, 82 | (void*)(intptr)mode 83 | ); 84 | } 85 | 86 | internal 87 | void close(int fd) { 88 | syscall1(SYS_close, (void*)(intptr)fd); 89 | } 90 | 91 | /* ------------------------------------------------------------- */ 92 | 93 | internal 94 | uintptr strlen(char const* str) 95 | { 96 | char const* p; 97 | for (p = str; *p; ++p); 98 | return p - str; 99 | } 100 | 101 | internal 102 | uintptr puts(char const* str) { 103 | return write(stdout, str, strlen(str)); 104 | } 105 | 106 | /* ------------------------------------------------------------- */ 107 | 108 | internal 109 | void swap_u32(u32* a, u32* b) 110 | { 111 | u32 tmp = *a; 112 | *a = *b; 113 | *b = tmp; 114 | } 115 | 116 | typedef b32 qsort32_cmp(u32 a, u32 b); 117 | 118 | internal 119 | uintptr qsort32_partition( 120 | u32* arr, 121 | qsort32_cmp* cmp, 122 | uintptr lo, 123 | uintptr hi) 124 | { 125 | uintptr pivot = arr[hi]; 126 | uintptr i = lo - 1; 127 | uintptr j; 128 | 129 | for (j = lo; j <= hi - 1; ++j) 130 | { 131 | if (cmp(arr[j], pivot)) 132 | { 133 | ++i; 134 | swap_u32(&arr[i], &arr[j]); 135 | } 136 | } 137 | 138 | swap_u32(&arr[++i], &arr[hi]); 139 | 140 | return i; 141 | } 142 | 143 | internal 144 | void qsort32(u32* arr, qsort32_cmp* cmp, uintptr lo, uintptr hi) 145 | { 146 | uintptr p; 147 | 148 | if (lo >= hi) { 149 | return; 150 | } 151 | 152 | p = qsort32_partition(arr, cmp, lo, hi); 153 | qsort32(arr, cmp, lo, p - 1); 154 | qsort32(arr, cmp, p + 1, hi); 155 | } 156 | 157 | /* ------------------------------------------------------------- */ 158 | 159 | internal 160 | intptr uitoa( 161 | u8 base, 162 | uintptr val, 163 | char* buf, 164 | intptr width, 165 | char filler) 166 | { 167 | char c; 168 | char* p = buf; 169 | intptr res; 170 | 171 | if (!base) { 172 | return 0; 173 | } 174 | 175 | if (base > 16) { 176 | return 0; 177 | } 178 | 179 | do 180 | { 181 | u8 digit = val % base; 182 | val /= base; 183 | *p++ = "0123456789abcdef"[digit]; 184 | } 185 | while(val); 186 | 187 | while (p - buf < width) { 188 | *p++ = filler; 189 | } 190 | 191 | res = p - buf; 192 | *p-- = 0; 193 | 194 | while (p > buf) 195 | { 196 | /* flip the string */ 197 | c = *p; 198 | *p-- = *buf; 199 | *buf++ = c; 200 | } 201 | 202 | return res; 203 | } 204 | 205 | /* ------------------------------------------------------------- */ 206 | 207 | void print_u32_array(u32* v, uintptr n) 208 | { 209 | uintptr i; 210 | 211 | for (i = 0; i < n; ++i) 212 | { 213 | char buf[11]; 214 | uitoa(10, v[i], buf, 0, 0); 215 | puts(buf); 216 | puts("\n"); 217 | } 218 | } 219 | 220 | #define FNAME "/dev/urandom" 221 | #define NVALUES 10 222 | 223 | internal 224 | b32 cmp_u32(u32 a, u32 b) { 225 | return a <= b; 226 | } 227 | 228 | globvar u32 numbers[NVALUES]; 229 | 230 | int main(int argc, char const* argv[]) 231 | { 232 | int fd; 233 | intptr n; 234 | u8* p = (u8*)numbers; 235 | 236 | fd = open(FNAME, O_RDONLY, 0); 237 | if (fd < 0) { 238 | puts("Failed to open " FNAME "\n"); 239 | return 1; 240 | } 241 | 242 | while (p <= (u8*)&numbers[NVALUES - 1]) 243 | { 244 | n = read(fd, &numbers[0], sizeof(numbers)); 245 | if (n < 0) { 246 | puts("Failed to read from " FNAME "\n"); 247 | return 1; 248 | } 249 | 250 | p += n; 251 | } 252 | 253 | close(fd); 254 | 255 | puts("Unsorted:\n"); 256 | print_u32_array(numbers, arr_count(numbers)); 257 | 258 | qsort32(numbers, cmp_u32, 0, arr_count(numbers) - 1); 259 | 260 | puts("\nSorted:\n"); 261 | print_u32_array(numbers, arr_count(numbers)); 262 | 263 | return 0; 264 | } 265 | --------------------------------------------------------------------------------