commit 4a29a444306dedb59eab2b0510a6bc2e66520c7b
parent ecca78319fea82a868e9ef745d8c13168b2e8a29
Author: Erik Agsjö <erik.agsjo@gmail.com>
Date: Wed, 10 Nov 2021 23:42:30 +0100
Amalgamation
Diffstat:
12 files changed, 400 insertions(+), 92 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,16 +0,0 @@
-CFLAGS = -g -Wall -pedantic -Wno-gnu-zero-variadic-macro-arguments
-#CFLAGS = -O2
-
-ifeq ($(OS),Windows_NT)
-
-else
- UNAME_S := $(shell uname -s)
- ifeq ($(UNAME_S),Darwin)
- LDFLAGS = -framework Cocoa
- else ifeq ($(UNAME_S),Linux)
- #LDFLAGS = -s -lGLU -lGL -lX11
- endif
-endif
-
-naett: main.c naett.c naett_osx.c
- gcc $^ -o $@ $(CFLAGS) $(LDFLAGS)
diff --git a/example/Makefile b/example/Makefile
@@ -0,0 +1,16 @@
+CFLAGS = -I.. -g -Wall -pedantic -Wno-gnu-zero-variadic-macro-arguments
+#CFLAGS = -O2
+
+ifeq ($(OS),Windows_NT)
+
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LDFLAGS = -framework Cocoa
+ else ifeq ($(UNAME_S),Linux)
+ #LDFLAGS = -s -lGLU -lGL -lX11
+ endif
+endif
+
+naett: main.c ../naett.c
+ gcc $^ -o $@ $(CFLAGS) $(LDFLAGS)
diff --git a/main.c b/example/main.c
diff --git a/naett.c b/naett.c
@@ -1,4 +1,82 @@
-#include "naett_internal.h"
+// Inlined amalgam.h: //
+#include "naett.h"
+// Inlined naett_core.c: //
+// Inlined naett_internal.h: //
+#ifndef NAETT_INTERNAL_H
+#define NAETT_INTERNAL_H
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define __WINDOWS__ 1
+#endif
+
+#if __linux__ && !__ANDROID__
+#define __LINUX__ 1
+#endif
+
+#ifdef __APPLE__
+#include "TargetConditionals.h"
+#include <objc/objc.h>
+#if TARGET_OS_IPHONE
+#define __IOS__ 1
+#else
+#define __MACOS__ 1
+#endif
+#endif
+
+#define naettAlloc(TYPE, VAR) TYPE* VAR = (TYPE*)calloc(1, sizeof(TYPE))
+
+typedef struct KVLink {
+ const char* key;
+ const char* value;
+ struct KVLink* next;
+} KVLink;
+
+typedef struct Buffer {
+ void* data;
+ int size;
+ int capacity;
+} Buffer;
+
+typedef struct {
+ const char* method;
+ int timeoutMS;
+ naettReadFunc bodyReader;
+ void* bodyReaderData;
+ naettWriteFunc bodyWriter;
+ void* bodyWriterData;
+ KVLink* headers;
+ Buffer body;
+} RequestOptions;
+
+typedef struct {
+ RequestOptions options;
+ const char* url;
+#if __APPLE__
+ id urlRequest;
+#endif
+} InternalRequest;
+
+typedef struct {
+ InternalRequest* request;
+ int complete;
+ int code;
+ KVLink* headers;
+ Buffer body;
+#if __APPLE__
+ id session;
+#endif
+} InternalResponse;
+
+void naettPlatformInitRequest(InternalRequest* req);
+void naettPlatformMakeRequest(InternalRequest* req, InternalResponse* res);
+void naettPlatformFreeRequest(InternalRequest* req);
+void naettPlatformCloseResponse(InternalResponse* res);
+
+#endif // NAETT_INTERNAL_H
+// End of inlined naett_internal.h //
+
#include <stdarg.h>
#include <stdlib.h>
#include <stddef.h>
@@ -263,3 +341,191 @@ void naettClose(naettRes* response) {
naettPlatformCloseResponse(res);
free(response);
}
+// End of inlined naett_core.c //
+
+// Inlined naett_osx.c: //
+//#include "naett_internal.h"
+
+#ifdef __MACOS__
+
+// Inlined naett_objc.h: //
+#ifndef NAETT_OBJC_H
+#define NAETT_OBJC_H
+
+#if defined(__IOS__) || defined (__MACOS__)
+#include <assert.h>
+#include <math.h>
+
+#include <objc/NSObjCRuntime.h>
+#include <objc/message.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+#if defined(__OBJC__) && __has_feature(objc_arc)
+#error "ARC is not supported"
+#endif
+
+// ABI is a bit different between platforms
+#ifdef __arm64__
+#define abi_objc_msgSend_stret objc_msgSend
+#else
+#define abi_objc_msgSend_stret objc_msgSend_stret
+#endif
+#ifdef __i386__
+#define abi_objc_msgSend_fpret objc_msgSend_fpret
+#else
+#define abi_objc_msgSend_fpret objc_msgSend
+#endif
+
+#define objc_msgSendSuper_t(RET, ...) ((RET(*)(struct objc_super*, SEL, ##__VA_ARGS__))objc_msgSendSuper)
+#define objc_msgSend_t(RET, ...) ((RET(*)(id, SEL, ##__VA_ARGS__))objc_msgSend)
+#define objc_msgSend_stret_t(RET, ...) ((RET(*)(id, SEL, ##__VA_ARGS__))abi_objc_msgSend_stret)
+#define objc_msgSend_id objc_msgSend_t(id)
+#define objc_msgSend_void objc_msgSend_t(void)
+#define objc_msgSend_void_id objc_msgSend_t(void, id)
+#define objc_msgSend_void_bool objc_msgSend_t(void, bool)
+
+#define sel(NAME) sel_registerName(NAME)
+#define class(NAME) ((id)objc_getClass(NAME))
+#define makeClass(NAME, SUPER) objc_allocateClassPair((Class)objc_getClass(SUPER), NAME, 0)
+
+// Check here to get the signature right: https://nshipster.com/type-encodings/
+#define addMethod(CLASS, NAME, IMPL, SIGNATURE) if (!class_addMethod(CLASS, sel(NAME), (IMP) (IMPL), (SIGNATURE))) assert(false)
+
+#define addIvar(CLASS, NAME, SIZE, SIGNATURE) if (!class_addIvar(CLASS, NAME, SIZE, rint(log2(SIZE)), SIGNATURE)) assert(false)
+
+#define objc_alloc(CLASS) objc_msgSend_id(class(CLASS), sel("alloc"))
+#define autorelease(OBJ) objc_msgSend_void(OBJ, sel("autorelease"))
+#define retain(OBJ) objc_msgSend_void(OBJ, sel("retain"))
+#define release(OBJ) objc_msgSend_void(OBJ, sel("release"))
+
+#if __LP64__ || NS_BUILD_32_LIKE_64
+#define NSIntegerEncoding "q"
+#define NSUIntegerEncoding "L"
+#else
+#define NSIntegerEncoding "i"
+#define NSUIntegerEncoding "I"
+#endif
+
+#endif // defined(__IOS__) || defined (__MACOS__)
+#endif // NAETT_OBJC_H
+// End of inlined naett_objc.h //
+
+#include <stdlib.h>
+#include <string.h>
+
+void naettPlatformInitRequest(InternalRequest* req) {
+ id urlString = objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), req->url);
+ id url = objc_msgSend_t(id, id)(class("NSURL"), sel("URLWithString:"), urlString);
+ release(urlString);
+
+ id request = objc_msgSend_t(id, id)(class("NSMutableURLRequest"), sel("requestWithURL:"), url);
+ release(url);
+
+ objc_msgSend_t(void, double)(request, sel("setTimeoutInterval:"), (double)(req->options.timeoutMS) / 1000.0);
+ id methodString =
+ objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), req->options.method);
+ objc_msgSend_t(void, id)(request, sel("setHTTPMethod:"), methodString);
+ release(methodString);
+
+ KVLink* header = req->options.headers;
+ while (header != NULL) {
+ id name = objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), header->key);
+ id value = objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), header->value);
+ objc_msgSend_t(void, id, id)(request, sel("setValue:forHTTPHeaderField:"), name, value);
+ release(name);
+ release(value);
+ header = header->next;
+ }
+
+ if (req->options.body.data) {
+ Buffer* body = &req->options.body;
+
+ id bodyData = objc_msgSend_t(id, void*, NSUInteger, BOOL)(
+ class("NSData"), sel("dataWithBytesNoCopy:length:freeWhenDone:"), body->data, body->size, NO);
+ objc_msgSend_t(void, id)(request, sel("setHTTPBody:"), bodyData);
+ release(bodyData);
+ }
+
+ req->urlRequest = request;
+}
+
+void didReceiveData(id self, SEL _sel, id session, id dataTask, id data) {
+ InternalResponse* res = NULL;
+ object_getInstanceVariable(self, "response", (void**)&res);
+
+ if (res->headers == NULL) {
+ id response = objc_msgSend_t(id)(dataTask, sel("response"));
+ id allHeaders = objc_msgSend_t(id)(response, sel("allHeaderFields"));
+
+ NSUInteger headerCount = objc_msgSend_t(NSUInteger)(allHeaders, sel("count"));
+ id headerNames[headerCount];
+ id headerValues[headerCount];
+
+ objc_msgSend_t(NSInteger, id*, id*, NSUInteger)(
+ allHeaders, sel("getObjects:andKeys:count:"), headerValues, headerNames, headerCount);
+ for (int i = 0; i < headerCount; i++) {
+ naettAlloc(KVLink, node);
+ node->key = strdup(objc_msgSend_t(const char*)(headerNames[i], sel("UTF8String")));
+ node->value = strdup(objc_msgSend_t(const char*)(headerValues[i], sel("UTF8String")));
+ node->next = res->headers;
+ res->headers = node;
+ }
+ }
+
+ const void* bytes = objc_msgSend_t(const void*)(data, sel("bytes"));
+ NSUInteger length = objc_msgSend_t(NSUInteger)(data, sel("length"));
+ res->request->options.bodyWriter(bytes, length, res->request->options.bodyWriterData);
+}
+
+static void didComplete(id self, SEL _sel, id session, id dataTask, id error) {
+ InternalResponse* res = NULL;
+ object_getInstanceVariable(self, "response", (void**)&res);
+ res->complete = 1;
+}
+
+static id createDelegate() {
+ Class TaskDelegateClass = nil;
+
+ if (!TaskDelegateClass) {
+ TaskDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "naettTaskDelegate", 0);
+ addMethod(TaskDelegateClass, "URLSession:dataTask:didReceiveData:", didReceiveData, "v@:@@@");
+ addMethod(TaskDelegateClass, "URLSession:task:didCompleteWithError:", didComplete, "v@:@@@");
+ addIvar(TaskDelegateClass, "response", sizeof(void*), "^v");
+ }
+
+ id delegate = objc_msgSend_id((id)TaskDelegateClass, sel("alloc"));
+ delegate = objc_msgSend_id(delegate, sel("init"));
+
+ return delegate;
+}
+
+void naettPlatformMakeRequest(InternalRequest* req, InternalResponse* res) {
+ id config = objc_msgSend_id(class("NSURLSessionConfiguration"), sel("ephemeralSessionConfiguration"));
+ id delegate = createDelegate();
+
+ id session = objc_msgSend_t(id, id, id, id)(
+ class("NSURLSession"), sel("sessionWithConfiguration:delegate:delegateQueue:"), config, delegate, nil);
+
+ res->session = session;
+ release(delegate);
+
+ id task = objc_msgSend_t(id, id)(session, sel("dataTaskWithRequest:"), req->urlRequest);
+ object_setInstanceVariable(delegate, "response", (void*)res);
+ objc_msgSend_void(task, sel("resume"));
+ release(task);
+}
+
+void naettPlatformFreeRequest(InternalRequest* req) {
+ release(req->urlRequest);
+ req->urlRequest = nil;
+}
+
+void naettPlatformCloseResponse(InternalResponse* res) {
+ release(res->session);
+}
+
+#endif // __MACOS__
+// End of inlined naett_osx.c //
+
+// End of inlined amalgam.h //
diff --git a/naett_internal.h b/naett_internal.h
@@ -1,75 +0,0 @@
-#ifndef NAETT_INTERNAL_H
-#define NAETT_INTERNAL_H
-
-#include "naett.h"
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#define __WINDOWS__ 1
-#endif
-
-#if __linux__ && !__ANDROID__
-#define __LINUX__ 1
-#endif
-
-#ifdef __APPLE__
-#include "TargetConditionals.h"
-#include <objc/objc.h>
-#if TARGET_OS_IPHONE
-#define __IOS__ 1
-#else
-#define __MACOS__ 1
-#endif
-#endif
-
-#define naettAlloc(TYPE, VAR) TYPE* VAR = (TYPE*)calloc(1, sizeof(TYPE))
-
-typedef struct KVLink {
- const char* key;
- const char* value;
- struct KVLink* next;
-} KVLink;
-
-typedef struct Buffer {
- void* data;
- int size;
- int capacity;
-} Buffer;
-
-typedef struct {
- const char* method;
- int timeoutMS;
- naettReadFunc bodyReader;
- void* bodyReaderData;
- naettWriteFunc bodyWriter;
- void* bodyWriterData;
- KVLink* headers;
- Buffer body;
-} RequestOptions;
-
-typedef struct {
- RequestOptions options;
- const char* url;
-#if __APPLE__
- id urlRequest;
-#endif
-} InternalRequest;
-
-typedef struct {
- InternalRequest* request;
- int complete;
- int code;
- KVLink* headers;
- Buffer body;
-#if __APPLE__
- id session;
-#endif
-} InternalResponse;
-
-void naettPlatformInitRequest(InternalRequest* req);
-void naettPlatformMakeRequest(InternalRequest* req, InternalResponse* res);
-void naettPlatformFreeRequest(InternalRequest* req);
-void naettPlatformCloseResponse(InternalResponse* res);
-
-#endif // NAETT_INTERNAL_H
diff --git a/src/Makefile b/src/Makefile
@@ -0,0 +1,4 @@
+all: ../naett.c
+
+../naett.c:
+ ./bundle.sh $@ amalgam.h
diff --git a/src/amalgam.h b/src/amalgam.h
@@ -0,0 +1,3 @@
+#include "naett.h"
+#include "naett_core.c"
+#include "naett_osx.c"
diff --git a/src/bundle.sh b/src/bundle.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+usage="Usage: $0 bundle.c amalgam.h"
+target=${1:?$usage}
+source=${2:?$usage}
+
+[[ -f $source ]] || (echo source missing && exit)
+
+declare -A seen
+
+cat /dev/null > "$target"
+
+bundle() {
+ local file=$1
+
+ [[ -z "${seen[$file]}" ]] || return 1
+ seen[$file]=1
+
+ echo "// Inlined $file: //" >> "$target"
+ IFS=""
+ while read line; do
+ if [[ $line =~ ^\#include\ \"(.+)\" && -f ${BASH_REMATCH[1]} ]]; then
+ include=${BASH_REMATCH[1]}
+ if bundle $include; then
+ echo "$line" >> "$target"
+ else
+ echo "//$line" >> "$target"
+ fi
+ else
+ echo "$line" >> "$target"
+ fi
+ done < $file
+ echo "// End of inlined $file //" >> "$target"
+ return 0
+}
+
+bundle "$source"
diff --git a/naett.c b/src/naett_core.c
diff --git a/src/naett_internal.h b/src/naett_internal.h
@@ -0,0 +1,73 @@
+#ifndef NAETT_INTERNAL_H
+#define NAETT_INTERNAL_H
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define __WINDOWS__ 1
+#endif
+
+#if __linux__ && !__ANDROID__
+#define __LINUX__ 1
+#endif
+
+#ifdef __APPLE__
+#include "TargetConditionals.h"
+#include <objc/objc.h>
+#if TARGET_OS_IPHONE
+#define __IOS__ 1
+#else
+#define __MACOS__ 1
+#endif
+#endif
+
+#define naettAlloc(TYPE, VAR) TYPE* VAR = (TYPE*)calloc(1, sizeof(TYPE))
+
+typedef struct KVLink {
+ const char* key;
+ const char* value;
+ struct KVLink* next;
+} KVLink;
+
+typedef struct Buffer {
+ void* data;
+ int size;
+ int capacity;
+} Buffer;
+
+typedef struct {
+ const char* method;
+ int timeoutMS;
+ naettReadFunc bodyReader;
+ void* bodyReaderData;
+ naettWriteFunc bodyWriter;
+ void* bodyWriterData;
+ KVLink* headers;
+ Buffer body;
+} RequestOptions;
+
+typedef struct {
+ RequestOptions options;
+ const char* url;
+#if __APPLE__
+ id urlRequest;
+#endif
+} InternalRequest;
+
+typedef struct {
+ InternalRequest* request;
+ int complete;
+ int code;
+ KVLink* headers;
+ Buffer body;
+#if __APPLE__
+ id session;
+#endif
+} InternalResponse;
+
+void naettPlatformInitRequest(InternalRequest* req);
+void naettPlatformMakeRequest(InternalRequest* req, InternalResponse* res);
+void naettPlatformFreeRequest(InternalRequest* req);
+void naettPlatformCloseResponse(InternalResponse* res);
+
+#endif // NAETT_INTERNAL_H
diff --git a/naett_objc.h b/src/naett_objc.h
diff --git a/naett_osx.c b/src/naett_osx.c