diff --git a/app.c b/app.c index 2c76fb2..a2bdfd4 100644 --- a/app.c +++ b/app.c @@ -1,65 +1,3 @@ -#define DJSTD_BASIC_ENTRY -#include "core.c" - -int djstd_entry(Arena *arena, StringList args) { - Socket sock = socketConnect(arena, (SocketConnectInfo){ .address="::1", .port=8080, .blocking=true }); - - string newLine = s("\r\n"); - string lines[] = { - s("GET / HTTP/1.1"), - s("Host: localhost"), - }; - - for (EachInArray(lines, i)) { - socketWriteStr(&sock, lines[i]); - socketWriteStr(&sock, newLine); - } - socketWriteStr(&sock, newLine); - - CharList body = EmptyList(); - bool streamingBody = false; - - Forever { - StringResult response = socketReadStr(arena, &sock); - if (response.valid) { - if (streamingBody) { - if (body.capacity - body.length >= response.result.length) { - memcpy(body.data + body.length, response.result.str, response.result.length); - body.length += response.result.length; - } - } else { - StringList lines = strSplit(arena, s("\r\n"), response.result); - for (EachEl(lines, string, line)) { - if (body.capacity > 0 && strEql(*line, s(""))) { - streamingBody = true; - } else if (streamingBody && (body.capacity - body.length) >= line->length) { - // TODO(dledda): append list to list, string to string, whatever - // TODO(dledda): `joinStringList` - memcpy(body.data + body.length, line->str, line->length); - body.length += line->length; - } else { - // TODO(dledda): `strContains` - // TODO(dledda): `stringContains` -> `strContainsChar` - StringList split = strSplit(arena, s("Content-Length: "), *line); - if (split.length > 1) { - Int32Result lengthResult = parsePositiveInt(split.data[1]); - if (lengthResult.valid) { - body = PushList(arena, CharList, lengthResult.result); - } - } - } - } - } - } - - if (streamingBody == true && body.length == body.capacity) { - break; - } - } - - // TODO(dledda): string from CharList/ByteList - // TODO(dledda): `printStr` - print("%S", (string){.str=body.data, .length=body.length}); - - return 0; -} +//#include "./scratchpad.c" +//#include "./server-chat.example.c" +#include "./http1-1.example.c" diff --git a/core.c b/core.c index d2e72e5..6894c14 100644 --- a/core.c +++ b/core.c @@ -176,6 +176,15 @@ string strSlice(string str, size_t start, size_t stop) { }; } +string strListJoin(Arena *arena, StringList list) { + string result = PushString(arena, 0); + for (EachEl(list, string, item)) { + PushString(arena, item->length); + memcpy(result.str + result.length, item->str, item->length); + } + return result; +} + string strSliceCStr(char *data, size_t start, size_t stop) { return (string){ data + start, @@ -183,7 +192,7 @@ string strSliceCStr(char *data, size_t start, size_t stop) { }; } -bool stringContains(string str, char c) { +bool strContainsChar(string str, char c) { for (size_t i = 0; i < str.length; i++) { if (str.str[i] == c) { return true; @@ -192,9 +201,24 @@ bool stringContains(string str, char c) { return false; } +bool strContains(string str, string search) { + if (search.length == 0) return true; + if (search.length <= str.length) { + for (size_t i = 0; i <= str.length - search.length; i++) { + for (size_t j = 0; j < search.length; j++) { + if (str.str[i + j] != search.str[j]) { + break; + } + if (j == search.length - 1) return true; + } + } + } + return false; +} + string NUMERIC_CHARS = s("0123456789"); -inline bool isNumeric(char c) { - return stringContains(NUMERIC_CHARS, c); +inline function bool isNumeric(char c) { + return strContainsChar(NUMERIC_CHARS, c); } StringList strSplit(Arena *arena, string splitStr, string inputStr) { @@ -288,7 +312,7 @@ Real32Result parsePositiveReal32(string str) { StringList getArgs(Arena *arena, int argc, char **argv) { StringList args = PushList(arena, StringList, (size_t)argc - 1); for (int i = 1; i < argc; i++) { - AppendList(&args, strFromCString(arena, argv[i])); + ListAppend(args, strFromCString(arena, argv[i])); } return args; } @@ -365,6 +389,10 @@ function void printlnStdout(const char *fmt, ...) { void (*print)(const char *fmt, ...) = &printStdout; void (*println)(const char *fmt, ...) = &printlnStdout; +void printStr(string str) { + print("%S\n", str); +} + void setStdout() { print = &printStdout; println = &printlnStdout; diff --git a/core.h b/core.h index 66df1bc..a9dfa52 100644 --- a/core.h +++ b/core.h @@ -5,6 +5,7 @@ #include "stdbool.h" #include "stdint.h" // necessary for int type sizes #include "time.h" // TODO(djledda): try not to depend on this one +#include // ### Misc macros ### #if DJSTDLIB_DEBUG @@ -151,6 +152,7 @@ inline function Vec4 vec4(real32 x, real32 y, real32 z, real32 w) { #define ListElementSize(list) MemberSizeUnderlying(list, data) DefineList(string, String); +DefineList(void, Void); #define PushList(arena, type, size) (type){ .data=pushSize(arena, ListElementSize(type)*(size)), .length=0, .capacity=(size) } #define PushListZero(arena, type, size) (type){ .data=pushSizeFill(arena, ListElementSize(type)*(size), 0), .length=0, .capacity=(size) } @@ -161,22 +163,37 @@ DefineList(string, String); #define __ArrayAsList(array) { .data=(array), .length=ArrayCount(array), .capacity=ArrayCount(array) } #define AsList(listtype, ...) (listtype)__ArrayAsList(((listtype##_underlying[])__VA_ARGS__)) -// TODO(dledda): clone list -// TODO(dledda): list back element accessor -#define AppendList(list, element) \ - if ((list)->length < (list)->capacity) { \ - (list)->data[(list)->length++] = (element); \ +#define ListAppend(list, element) \ + if ((list).length < (list).capacity) { \ + (list).data[(list).length++] = (element); \ } #define ZeroListFull(list) memset((list)->data, 0, (list)->length * sizeof((list)->data[0])) #define ZeroList(list) (list)->length = 0; \ memset((list)->data, 0, (list)->length * sizeof((list)->data[0])) +/** 1 indicates last element, 2 second last, etc. */ +#define ListGetFromEnd(list, count) ((list).data[(list).length - (count)]) +#define ListLast(list) ListGetFromEnd(list, 1) + +inline VoidList __cloneList(Arena *arena, VoidList list, size_t underlyingSize) { + byte *newData = PushArrayZero(arena, void, list.capacity*underlyingSize); + memcpy(newData, list.data, list.capacity*underlyingSize); + return (VoidList){ + .data=newData, + .capacity=list.capacity, + .length=list.length, + }; +} +#define CloneList(arena, type, list) (type)cloneList((arena), (VoidList)(list), (MemberSizeUnderlying(list))) +#define ListAppendList(appendee, list)\ + if ((appendee).capacity - (appendee).length >= list.length) {\ + memcpy((appendee).data + (appendee).length, (list).data, MemberSizeUnderlying(list)*(list).length);\ + (appendee).length += (list).length;\ + } + // Following two macros do not use pointers due to copying #define ListSlice(list, start, stop) {\ - .data= (stop > (list).length || start > stop) ? 0 : (list).data + start,\ - .length=(stop > (list).length || start > stop) ? 0 : stop - start,\ - .capacity=(stop > (list).length || start > stop) ? 0 : stop - start,\ -} + .data= (stop > (list).length || start > stop) ? 0 : (list).data + start,\} #define ListTail(list, start) ListSlice(list, start, (list).length) #define ListRemove(list, index)\ @@ -196,6 +213,7 @@ struct string { #define s(lit) ((string){(char *)(lit), sizeof(lit) - 1}) #define PushString(arena, length) ((string){ (char *)pushSize(arena, length), (length) }) #define PushStringFill(arena, length, characterByte) ((string){ (char *)pushSizeFill(arena, length, characterByte), (length) }) +#define StrFromList(list) ((string){.str=(list).data,.length=(list).length}) // C Strings DefineList(char, Char); @@ -206,7 +224,8 @@ string strFromCString(Arena *arena, const char *str); bool strEql(string s1, string s2); bool strStartsWith(string str, string testStr); -bool stringContains(string str, char c); +bool strContainChar(string str, char c); +bool strContains(string a, string b); string strReverse(Arena *arena, string str); string strSlice(string str, size_t start, size_t stop); @@ -215,6 +234,8 @@ StringList strSplit(Arena *arena, string splitStr, string inputStr); string strPrintfv(Arena *arena, const char *fmt, va_list args); string strPrintf(Arena *arena, const char *fmt, ...); +string strListJoin(Arena *arena, StringList list); + #define DefineResult(type, prefix) \ typedef struct prefix ## Result prefix ## Result;\ struct prefix ## Result {\ @@ -303,8 +324,10 @@ typedef enum { #define COLOR_TEXT_RGB(text, red, green, blue) ANSI_INSTRUCTION_STR("38;2;" #red ";" #green ";" #blue) text ANSI_RESET DefineList(int, Int); + void printIntList(IntList l); void printStrList(StringList l); +void printStr(string str); void setStdout(); void setStderr(); extern void (*print)(const char *fmt, ...); diff --git a/http1-1.example.c b/http1-1.example.c new file mode 100644 index 0000000..f86a6d0 --- /dev/null +++ b/http1-1.example.c @@ -0,0 +1,62 @@ +#define DJSTD_BASIC_ENTRY +#include "core.c" + +int djstd_entry(Arena *arena, StringList args) { + Socket sock = socketConnect(arena, (SocketConnectInfo){ + .address="dlh.mediasuite.zii.aero", + .port=443, + .blocking=true + }); + + println("%d", sock.closed); + string newLine = s("\r\n"); + string lines[] = { + s("GET / HTTP/1.1"), + s("Host: localhost"), + }; + + for (EachInArray(lines, i)) { + socketWriteStr(&sock, lines[i]); + socketWriteStr(&sock, newLine); + } + socketWriteStr(&sock, newLine); + + StringList body = EmptyList(); + bool streamingBody = false; + + Forever { + StringResult response = socketReadStr(arena, &sock); + if (response.valid) { + if (streamingBody) { + if (body.capacity - body.length >= response.result.length) { + ListAppend(body, response.result); + } + } else { + StringList lines = strSplit(arena, s("\r\n"), response.result); + for (EachEl(lines, string, line)) { + if (body.capacity > 0 && strEql(*line, s(""))) { + streamingBody = true; + } else if (streamingBody && (body.capacity - body.length) >= line->length) { + ListAppend(body, *line); + } else { + StringList split = strSplit(arena, s("Content-Length: "), *line); + if (split.length > 1) { + Int32Result lengthResult = parsePositiveInt(split.data[1]); + if (lengthResult.valid) { + body = PushList(arena, StringList, lengthResult.result); + } + } + } + } + } + } + + if (streamingBody == true && body.length == body.capacity) { + break; + } + } + + printStr(strListJoin(arena, body)); + + return 0; +} diff --git a/os_linux.c b/os_linux.c index d0a758e..e9c928d 100644 --- a/os_linux.c +++ b/os_linux.c @@ -14,6 +14,7 @@ #include "sys/epoll.h" #include "sys/socket.h" #include "arpa/inet.h" +#include void *os_alloc(uint64 capacity) { @@ -226,7 +227,7 @@ Socket *serverAccept(Server *s) { epoll_ctl(((EPollServerEvents *)s->events)->epollFd, EPOLL_CTL_ADD, clientSockHandle, &event); if (s->clients.length < s->clients.capacity) { - AppendList(&s->clients, ((Socket){ + ListAppend(s->clients, ((Socket){ .handle=(SocketHandle *)(uint64)clientSockHandle, .address=(Address *)clientAddr, })); @@ -280,7 +281,7 @@ ServerEvent *serverGetNextEvent(Server *s) { } if (serverEvents->userEvents.length == 0) { - AppendList(&serverEvents->userEvents, (ServerEvent){ .type=ServerEventType_None }); + ListAppend(serverEvents->userEvents, (ServerEvent){ .type=ServerEventType_None }); } // Pop next event @@ -354,10 +355,10 @@ Socket socketConnect(Arena *arena, SocketConnectInfo info) { Socket result = { .handle=(SocketHandle *)(uint64)socketFd, .address=(Address *)remoteAddr, - .closed=false, - //.closed=connectErr == -1, + .closed=connectErr == -1, // TODO(dledda): investigate error behaviour }; + perror("errconn"); return result; } diff --git a/scratchpad.c b/scratchpad.c new file mode 100644 index 0000000..fc9955d --- /dev/null +++ b/scratchpad.c @@ -0,0 +1,6 @@ +#define DJSTD_BASIC_ENTRY +#include "core.c" + +int djstd_entry(Arena *arena, StringList args) { + return 0; +} diff --git a/app2.c b/server-chat.example.c similarity index 100% rename from app2.c rename to server-chat.example.c