htmc is a tool that allows you to easily integrate C code in your HTML pages and vice versa. Files ending in .htmc can be used to describe the structure of a page statically in HTML and dynamically in C, much like other hypertex preprocessors such as PHP. Regular C source files can also be compiled with htmc and used to generate fully dynamic web pages.
htmc uses GCC and the GNU Linker to generate highly optimized native binaries that can be cached and run on demande via htmc. In theory, this allows for much faster execution* compared to many common interpreted languages like PHP, Python, and JavaScript.
Writing web code in C can also be a fun challenge or academic exercise. Given enough tinkering, you can get htmc to do everything you need in a dynamic web page or HTTP API endpoint.
* The performance of code executed through htmc has not been tested yet. Also, most important optimizations have yet to be implemented as they stricly require htmc to integrate a web server of its own.
htmc is built to support multiple usecases. As of now, htmc can be used:
include directory and libhtmc.a)The recommended mode for serving web content is CGI as it allows for easy integration with existing web software.
CGI is known to be old and slow, hence why htmc will get its own web server at some point. The integrated web server will use preallocated arenas, memory and network optimizations to maximize execution speed and minimize overhead, hopefully.
NOTE: As of now replacing GCC or GNU Linker with other software is not encouraged. Some commandline options specified by htmc may be different in other compilers/linkers.
libhtmc contains all htmc functions. The library can be used in other native programs to integrate htmc, but also includes an interface to interact with the htmc runtime and manipulate HTML code
| Function interface | Description |
|---|---|
void htmc_bind(htmc_handover_t *handover) |
Binds an htmc_handover_t pointer to the current htmc execution unit |
int htmc_printf(const char *fmt, ...) |
Writes a formatted string to the HTML page |
int htmc_vpprintf(const char *fmt, va_list args) |
Writes a formatted string to the HTML page |
int htmc_puts(const cahr *s) |
Write a plain-text string to the HTML page (faster than htmc_printf) |
int htmc_query_scanf(const char *fmt, ...) |
Reads values from HTTP query arguments |
int htmc_query_vscanf(const char *fmt, va_list args) |
Reads values from HTTP query arguments |
int htmc_form_scanf(const char *fmt, ...) |
Reads values from HTTP body arguments in POST requests |
int htmc_form_vscanf(const char *fmt, va_list args) |
Reads values from HTTP body arguments in POST requests |
int htmc_error(const char *fmt, ...) |
Throws a formatted error message |
void *htmc_alloc(size_t size) |
Returns a void * to a memory buffer of the requested size or NULL if it fails |
void htmc_free(void *ptr) |
Frees a memory buffer allocated with htmc_alloc
|
The easiest way to use htmc is to create a simple CGI web server in a high level language and invoke htmc when handling requests. In this example, Golang is used as it's one of the simplest native languages that supports these features out of the box. A Golang web server is included in this repository.
htmc-cgi-ws for Linux from herehtmc-cgi-ws into ithtmc-cgi-ws is recognized as an executablechmod +x ./htmc-cgi-ws
htmc-cgi-ws as super user (if needed) and follow the instructions on screen[alevm@alevm ws]$ sudo ./htmc-cgi-ws
You're missing some important htmc files, proceed with the download? [Y/n]: Y
Downloading <https://alessandro-salerno.github.io/htmc/bin/htmc> to ./bin/htmc ... Done!
Downloading <https://alessandro-salerno.github.io/htmc/bin/libhtmc.a> to ./bin/libhtmc.a ... Done!
Downloading <https://alessandro-salerno.github.io/htmc/include/libhtmc/libhtmc.h> to ./include/libhtmc/libhtmc.h ... Done!
Downloading <https://alessandro-salerno.github.io/htmc/examples/index.htmc> to ./index.htmc ... Done!
Listening on localhost:80
localhost/index.htmc
Compiling for linux
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/cli.c -o obj/common/cli.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/compile.c -o obj/common/compile.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/emit.c -o obj/common/emit.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/libhtmc/impl/base-impl.c -o obj/common/libhtmc/impl/base-impl.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/libhtmc/impl/debug-impl.c -o obj/common/libhtmc/impl/debug-impl.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/libhtmc/libhtmc.c -o obj/common/libhtmc/libhtmc.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/load.c -o obj/common/load.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/log.c -o obj/common/log.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/main.c -o obj/common/main.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/parse.c -o obj/common/parse.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -flto -c src/common/util.c -o obj/common/util.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/cli.c -o lib/common/cli.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/compile.c -o lib/common/compile.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/emit.c -o lib/common/emit.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/libhtmc/impl/base-impl.c -o lib/common/libhtmc/impl/base-impl.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/libhtmc/impl/debug-impl.c -o lib/common/libhtmc/impl/debug-impl.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/libhtmc/libhtmc.c -o lib/common/libhtmc/libhtmc.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/load.c -o lib/common/load.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/log.c -o lib/common/log.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/main.c -o lib/common/main.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/parse.c -o lib/common/parse.o
gcc -O2 -std=c2x -Wno-unused-parameter -Iinclude/ -DEXT_HTMC_BUILD=""24.10.09"" -fPIC -g -w -c src/common/util.c -o lib/common/util.o
gcc -flto obj/common/cli.o obj/common/compile.o obj/common/emit.o obj/common/libhtmc/impl/base-impl.o obj/common/libhtmc/impl/debug-impl.o obj/common/libhtmc/libhtmc.o obj/common/load.o obj/common/log.o obj/common/main.o obj/common/parse.o obj/common/util.o -o bin/htmc
ar rcs bin/libhtmc.a lib/common/cli.o lib/common/compile.o lib/common/emit.o lib/common/libhtmc/impl/base-impl.o lib/common/libhtmc/impl/debug-impl.o lib/common/libhtmc/libhtmc.o lib/common/load.o lib/common/log.o lib/common/main.o lib/common/parse.o lib/common/util.o
cd cgi-ws && go build -o ../bin/htmc-cgi-ws
Finished!
alessandrosalerno@MacBook-Pro-di-Alessandro-3 htmc %
git clone https://github.com/Alessandro-Salerno/htmc
cd htmc/
make
NOTE: The default make target is all. Alternative make targets are:
make htmc # Build ONLY the executable
make libhtmc # Build ONLY the library
make htmc-cgi-ws # Build ONLY the CGI Web Server
htmc is distributed under the terms of the MIT license. See LICENSE for more information.
This project was initially inspired by PKD667/cweb.