chris256.com C. Lang July 2024 _ _ ____ ____ __ ___| |__ _ __(_)___|___ \| ___| / /_ ___ ___ _ __ ___ / __| '_ \| '__| / __| __) |___ \| '_ \ / __/ _ \| '_ ` _ \ | (__| | | | | | \__ \/ __/ ___) | (_) | (_| (_) | | | | | | \___|_| |_|_| |_|___/_____|____/ \___(_)___\___/|_| |_| |_| My Personal Website ________________________________________________________________________________ USEFULL LINKS , \`-._ __ Me \\ `-..____,.' `. gihub :`. / \`. linkedin : ) : : \ ;' ' ; | : This Site ).. .. .:.`.; : /::... .:::... ` ; documents ; _ ' __ /:\ jotto `:o> /\o_> ;:. `. rope drop puzzle `-`.__ ; __..--- /:. \ === \_/ ;=====_.':. ; Great Software ,/'`--'...`--.... ; ; ; void linux - linux distro .' ; kakoune - text editor .' ; dwm,dmenu,st - X applications .' .. , . ; tmux - terminal multiplexer : ::.. / ;::. | git - source control / `.;::. | ;:.. ; nmap - network scanner : |:. : ;:. ; : :: ;:.. |. ; : :; :::....| | /\ ,/ \ ;:::::; ; .:. \:..| : ; '.--| ; ::. :'' `-.,,; ;' ; ; .-'. _.'\ / `; \,__: \ `---' `----' ; / \,.,,,/ `----` ---------------------------------------------- / Dicipline is following your own rules, \ People and Groups \ obedience is following the rules of another. / --------------------------------------------- Protesilaos Stavrou \ ^__^ Luke Smith \ (oo)\_______ suckless.org (__)\ )\/\ John Baez ||----w | Dynamicland || || ________________________________________________________________________________
TABLE OF CONTENTS * PROJECTS * RP2*** Micropython Apriltag Detection Port * RP2*** Micropython OV7670 Camera Module Driver * Molecular Dynamics * MDL (Music Download) * clce (C Language Chess Engine) * DOS 16-bit Assembly Video Game ('Lazer Recoil') * ESP32-C3 Development Board * 6502 Computer * mysmtp * LIME Voxel Renderer * PIFS OS Compilation Guide * Typewriter PDF Typesetting * 28C256 EEPROM Programmer * x86_64 Assembly Pong * Billericay Food Bank App * Rust Chess Engine * ESSAYS * GUIDES * Polymorphism in C * How to Manually Link a C Program * Error Handling in C with the 'OR' Macro * LITERATURE ________________________________________________________________________________ PROJECTS ________________________________________________________________________________ RP2*** Micropython Apriltag Detection Port September 2024 Github ________________________________________________________________________________ RP2*** Micropython OV7670 Camera Module Driver September 2024 Github ________________________________________________________________________________ Molecular Dynamics July 2024 Github ________________________________________________________________________________ MDL (Music Download) July 2024 Python script for downloading music from streaming sites. Uses yt-dlp. Github ________________________________________________________________________________ clce (C Chess Engine) March 2024 **UNFINISHED** A better chess engine. Featuring magic bitboards and lichess api support. 'clce' stand for C language chess engine and Chris Lang's chess engine. Github ________________________________________________________________________________ Dos 16-bit Assembly Video Game ('Lazer Recoil') Febuary 2024 Made in 48 hours for the 2024 Cambridge University Game Jam. The theme was 'reflections'. Runs in dosbox emulator. Github ________________________________________________________________________________ ESP32-C3 Dev Board December 2023 Put together this development board for a RISC-V ESP32-C3 SOC. ________________________________________________________________________________ 6502 Computer September 2023 65C02 microprocessor reads instructions from 28C256 memory and writes draw instructions to an output interfaace register which connects to an LCD character display. Video ________________________________________________________________________________ mysmtp August 2023 Implemented SMTP client in C. Github ________________________________________________________________________________ LIME Voxel Renderer April 2021 - July 2023 Experiments with novel 3D rendering techniques. Written with Vulkan and C. Github ________________________________________________________________________________ PIFS OS Compilation Guide March 2023 Like LFS [1], but for cross-compiling a Raspberry-Pi OS. I wrote this guide for my second EPQ. * guide * report [1] LFS https://www.linuxfromscratch.org/lfs/ ________________________________________________________________________________ Typewriter PDF Typesetting December 2022 This project can't really decide what it whants to be. The general idea is that I want to convert text files to PDF files in some unspecified way but I keep on changing my mind on the best way to do this. At various points in time, my /bin/tw has been a symbolic link to: a C binary with no external dependencies, a python script, a pearl script, an OCaml binary and a Bash script. Github ________________________________________________________________________________ 28C256 EEPROM Programmer June 2022 Data sent to an Arduino over USB interface, which in turn copies the data onto the EEPROM. Made as part of my larger 6502 project. Github ________________________________________________________________________________ x86_64 Assembly Pong January 2022 Implementation of the video game 'Pong' in x86_64 assembly. Draws graphics directly to Linux framebuffer at /dev/fb0. Reads keyboard input directly from device files in /dev/input. Github ________________________________________________________________________________ Billericay Food Bank App April 2021 I wrote this app for my local food bank. It helps communicate to patrons which products are needed most. Due to flutter migration and App Store difficulties, it's no longer being updated. Google Play App Store ________________________________________________________________________________ Rust Chess Engine October 2020 I wrote this chess engine for my first EPQ (a graded school project usually done alongside A-Levels). Its chess.com elo is around 1300. Uses alpha-beta pruned minimax search and endgame tables. Github ________________________________________________________________________________ ESSAYS ________________________________________________________________________________ NA ________________________________________________________________________________ GUIDES ________________________________________________________________________________ Polymorphism in C December 2023 The other day I was reading the MuPDF source. I noticed an interesting implementation of polymorphism, so I wrote the following code to demonstrate. Notice that, using this method, no struct may implement more than one interface. When you use a polymorphic interface, you can't reason about the performance implications of your function calls, as you do not know what the underlying implementation is. In addition, polymorphic support makes the implementation of a datastructure more complex. Polymorphism is only a good idea when the flexibility granted outweighs the performance and complexity cost. #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <time.h> struct writer; typedef void (writer_put_char_fn)(struct writer *, char); typedef void (writer_printf_fn)(struct writer *, const char *format, va_list args); typedef void (writer_destroy_fn)(struct writer *); struct writer { /* Shared attributes can be declared here. */ writer_put_char_fn *put_char; writer_printf_fn *printf; writer_destroy_fn *destroy; }; struct file_writer { struct writer super; FILE *file; }; struct string_writer { struct writer super; long length, allocated; char *string; }; void writer_put_char(struct writer *writer, char c); void writer_printf(struct writer *writer, const char *format, ...); void writer_destroy(struct writer *writer); struct file_writer create_file_writer(const char *fname); void file_writer_put_char(struct file_writer *writer, char c); void file_writer_printf(struct file_writer *writer, const char *format, va_list args); void file_writer_destroy(struct file_writer *writer); struct string_writer create_string_writer(long allocate); void string_writer_put_char(struct string_writer *writer, char c); void string_writer_printf(struct string_writer *writer, const char *format, va_list args); void string_writer_destroy(struct string_writer *writer); void write_unix_time(struct writer *writer); void writer_put_char(struct writer *writer, char c) { writer->put_char(writer, c); } void writer_printf(struct writer *writer, const char *format, ...) { va_list args; va_start(args, format); writer->printf(writer, format, args); va_end(args); } void writer_destroy(struct writer *writer) { writer->destroy(writer); } struct file_writer create_file_writer(const char *fname) { struct file_writer writer; writer.super.put_char = (writer_put_char_fn *)file_writer_put_char; writer.super.printf = (writer_printf_fn *)file_writer_printf; writer.super.destroy = (writer_destroy_fn *)file_writer_destroy; writer.file = fopen(fname, "w"); return writer; } void file_writer_put_char(struct file_writer *writer, char c) { fputc(c, writer->file); } void file_writer_printf(struct file_writer *writer, const char *format, va_list args) { fprintf(writer->file, format, args); } void file_writer_destroy(struct file_writer *writer) { fclose(writer->file); } struct string_writer create_string_writer(long allocate) { struct string_writer writer; writer.super.put_char = (writer_put_char_fn *)string_writer_put_char; writer.super.printf = (writer_printf_fn *)string_writer_printf; writer.super.destroy = (writer_destroy_fn *)string_writer_destroy; writer.length = 0; writer.allocated = allocate; writer.string = malloc(allocate); return writer; } void string_writer_put_char(struct string_writer *writer, char c) { if (writer->allocated == writer->length) { writer->allocated *= 2; writer->string = realloc(writer->string, writer->allocated); } writer->string[writer->length++] = c; } void string_writer_printf(struct string_writer *writer, const char *format, va_list args) { int len; len = vsnprintf(writer->string + writer->length, writer->allocated - writer->length, format, args); if (len >= writer->allocated - writer->length) { writer->allocated += len; writer->allocated *= 2; writer->string = realloc(writer->string, writer->allocated); vsprintf(writer->string + writer->length, format, args); } writer->length += len; } void string_writer_destroy(struct string_writer *writer) { free(writer->string); } void write_unix_time(struct writer *writer) { int t; t = (int)time(NULL); writer_printf(writer, "seconds since Epoch: %d\n", t); } int main(int argc, char *argv[]) { struct file_writer file_writer; struct string_writer string_writer; file_writer = create_file_writer("time.txt"); string_writer = create_string_writer(1024); write_unix_time((struct writer *)&file_writer); write_unix_time((struct writer *)&string_writer); printf("%s", string_writer.string); writer_destroy((struct writer *)&file_writer); writer_destroy((struct writer *)&string_writer); } ________________________________________________________________________________ How to Manually Link a C Program February 2023 These are instruction to manually link object files to produce an executable. Usually, GCC links C programs by automatically invoking ld in response to a command such as gcc a.o b.o -o output. But this hides some interesting stuff about how programs are linked, so for some fun, lets link the object files ourselves. First, in an empty directory, create main.c: #include <stdio.h> int main(int argc, char **argv) { printf("hello world\n"); return 0; } Now compile the program to main.o. -c means not to run the linker: gcc -c main.c Lets try to (naively) link the program. ld is the name of the GNU linker and its what GCC uses to link: ld main.o -o output We get the error messages: ld: warning: cannot find entry symbol _start; defaulting to 000000000... ld: main.o: in function `main': main.c:(.text+0x1a): undefined reference to `puts' The entry point to an elf file is the _start symbol but our C program only has a main function. The solution is to link with the C runtime startup code object file. This provides a _start symbol which will, among other things, execute the main function. It is possible to avoid linking with the C runtime startup code by specifying a _start symbol in your program source, but that's beyond the scope of this guide. We are also informed of an undefined reference to `puts'. This is because we haven't linked with the standard C library which is used by the printf call. I don't know why we are told undefined reference to `puts' and not undefined reference to `printf'... Interesting, lets call it homework. Lets run the linker again to reflect what we have learnt. link main.o, the C runtime startup code and the C standard library. ld main.o /lib/Scrt1.o -lc -o output On your system, the path to the static C runtime startup code (Scrt) may be different. To find out, run gcc main.o -v and grep the standard error output for crt. This asks GCC to link for you in verbose mode so that you can see what C runtime startup it uses. The command should run without error. But when we try to execute ./output: bash: ./output: No such file or directory Weird, ./output definitely exists. Lets have a look at the headers of the elf: $ readelf ./output -e ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 ... INTERP 0x00000000000002e0 0x00000000004002e0 0x00000000004002e0 0x000000000000000f 0x000000000000000f R 0x1 [Requesting program interpreter: /lib/ld64.so.1] ... Ah Ha! That program interpreter doesn't look right! Look at the headers of a working binary on your system: readelf $(which bash) -e. You should see that it uses an interpreter like /lib64/ld-linux-x86-64.so.2. As far as I understand, ld-linux is like a newer version of ld64 and ld64 isn't installed on most systems. Now lets construct our final link command: $ ld main.o /lib/Scrt1.o -lc --dynamic-linker=/lib/ld-linux-x86-64.so.2 -o output $ ./output hello world Hooray it works! Further reading: How ELF binaries get run. ________________________________________________________________________________ Error Handling in C with the 'OR' Macro December 2022 I made this macro to make error handling code more readable. #define OR ? (errno = 0) : (errno = errno ? errno : -1); if (errno) Be sure to `#include <errno.h>` Usage Evaluate expression1, if equal to zero then set errno to 0 and execute statement1. Otherwise set errno to -1. expression1 OR statement1 Example Usage Here is a simple example that catches a memory error. int main(int argc, char **argv) { char *memory; (memory = malloc(10000)) OR goto memory_error; return 0; memory_error: perror("failed to allocate memory"); return 1; } The two following code extracts show the same function except that the first uses the OR macro and the second does not. This demonstrates how much more readable using the OR macro is. /* Error handling with 'OR' Macro. */ int read_font_file(const char *fname, struct font_info *info) { int ret = 0; long size; FILE *file = NULL; char *ttf = NULL; (file = fopen(fname, "r")) OR goto file_error; fseek(file, 0, SEEK_END) == 0 OR goto file_error; (size = ftell(file)) >= 0 OR goto file_error; fseek(file, 0, SEEK_SET) == 0 OR goto file_error; (ttf = malloc(size)) OR goto allocation_error; fread(ttf, 1, size, file) == size OR goto file_error; read_ttf(ttf, size, info) == 0 OR goto ttf_error; cleanup: free(ttf); if (file != NULL) fclose(file); return ret; file_error: fprintf(stderr, "file error in '%s': %s\n", fname, strerror(errno)); ret = 1; goto cleanup; allocation_error: perror("failed to allocate memory"); ret = 1; goto cleanup; ttf_error: fprintf(stderr, "failed to parse ttf '%s'\n", fname); ret = 1; goto cleanup; } /* Error Handling with IF statement. */ int read_font_file(const char *fname, struct font_info *info) { int ret = 0; long size; FILE *file = NULL; char *ttf = NULL; file = fopen(fname, "r"); if (file == NULL) { char *err = strerror(errno); fprintf(stderr, "failed to open font file '%s': %s\n", fname, err); ret = 1; goto cleanup; } errno = 0; fseek(file, 0, SEEK_END); size = ftell(file); fseek(file, 0, SEEK_SET); if (errno) { perror("failed to get length of file"); ret = 1; goto cleanup; } ttf = malloc(size); if (ttf == NULL) { perror("malloc failed"); ret = 1; goto cleanup; } if (fread(ttf, 1, size, file) != size) { fprintf(stderr, "failed to read all bytes from file\n"); ret = 1; goto cleanup; } if (read_ttf(ttf, size, info) != 0) { fprintf(stderr, "failed to parse ttf\n"); ret = 1; goto cleanup; } cleanup: free(ttf); if (file != NULL) fclose(file); return ret; } ________________________________________________________________________________ LITERATURE ________________________________________________________________________________ The bourgeoisie, wherever it has got the upper hand, has put an end to all feudal, patriarchal, idyllic relations. It has pitilessly torn asunder the motley feudal ties that bound man to his "natural superiors", and has left remaining no other nexus between man and man than naked selfinterest, than callous "cash payment". It has drowned the most heavenly ecstasies of religious fervour, of chivalrous enthusiasm, of philistine sentimentalism, in the icy water of egotistical calculation. It has resolved personal worth into exchange value, and in place of the numberless indefeasible chartered freedoms, has set up that single, unconscionable freedom - Free Trade. In one word, for exploitation, veiled by religious and political illusions, it has substituted naked, shameless, direct, brutal exploitation. - 1848, Karl Marx and Frederick Engels, translated by Samuel Moore, Manifesto of the Communist Party One of history's few iron laws is that luxuries tend to become necessities and to spawn new obligations. - 2015, Yuval Noah Harari, Sapiens ________________________________________________________________________________ christopher.lang.256@removethis.gmail.andthis.com