From cb86d3213519727a7fecd05b18b6a8adff230976 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sat, 6 Jan 2024 11:15:57 +0200 Subject: (src) Moved source files to a src folder --- .gitmodules | 4 +- browser-cli.c | 183 ----------------------------------------------- browser-cli.h | 12 ---- browser.c | 99 -------------------------- sds | 1 - server-cli.c | 46 ------------ server-cli.h | 8 --- server-connection.c | 133 ---------------------------------- server-connection.h | 12 ---- server.c | 185 ------------------------------------------------ src/browser-cli.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++ src/browser-cli.h | 12 ++++ src/browser.c | 99 ++++++++++++++++++++++++++ src/server-cli.c | 46 ++++++++++++ src/server-cli.h | 8 +++ src/server-connection.c | 133 ++++++++++++++++++++++++++++++++++ src/server-connection.h | 12 ++++ src/server.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++ src/util.h | 29 ++++++++ util.c | 180 ---------------------------------------------- util.h | 29 -------- 22 files changed, 889 insertions(+), 890 deletions(-) delete mode 100644 browser-cli.c delete mode 100644 browser-cli.h delete mode 100644 browser.c delete mode 160000 sds delete mode 100644 server-cli.c delete mode 100644 server-cli.h delete mode 100644 server-connection.c delete mode 100644 server-connection.h delete mode 100644 server.c create mode 100644 src/browser-cli.c create mode 100644 src/browser-cli.h create mode 100644 src/browser.c create mode 100644 src/server-cli.c create mode 100644 src/server-cli.h create mode 100644 src/server-connection.c create mode 100644 src/server-connection.h create mode 100644 src/server.c create mode 100644 src/util.c create mode 100644 src/util.h delete mode 100644 util.c delete mode 100644 util.h diff --git a/.gitmodules b/.gitmodules index d12d74d..071acbc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "sds"] - path = sds +[submodule "src/sds"] + path = src/sds url = https://github.com/antirez/sds.git diff --git a/browser-cli.c b/browser-cli.c deleted file mode 100644 index 3bea4ba..0000000 --- a/browser-cli.c +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -struct md_syntax { - regex_t anchor; -}; - -struct md_syntax syntax = { - .anchor = NULL, -}; - -int* anchorsIndecies; -int anchorsCount = 0; - -void initRendering() { - /* - * Compile regexes used in rendering - */ - - herr(regcomp(&syntax.anchor, "\\[\\([^]]*\\)\\](\\([^)]*\\))", 0), "regcomp"); -} - -void freeRendering() { - regfree(&syntax.anchor); - - free(anchorsIndecies); -} - -void renderPage(const sds page) { - if (sdslen(page) == 0) { - printf("Server didn't return page!\n"); - return; - } - - sds toPrint = sdsdup(page); - - /* - * Parse Markdown constructs - */ - - /* Substitute and store anchorsIndecies */ - if (anchorsIndecies != NULL) { - free(anchorsIndecies); - anchorsCount = 0; - anchorsIndecies = NULL; - } - toPrint = gsub_getm(toPrint, &syntax.anchor, "\16\033[4m\1\033[0m", &anchorsIndecies, &anchorsCount); - - sds newPrint; - for (int i = 0, anchorInd = 0; i < anchorsCount; i++) { - anchorInd = strchr(toPrint, '\16') - toPrint; - - /* In toPrint, replace '\16' with "\033[30;46m%d\033[0m", where %d is the variable i */ - toPrint[anchorInd] = '\0'; - newPrint = sdsgrowzero(sdsempty(), sdslen(toPrint) + digits(i) + 8 + 4); - sprintf(newPrint, "%s\033[30;46m%d\033[0m%s", toPrint, i, toPrint + anchorInd + 1); - - sdsfree(toPrint); - toPrint = newPrint; - } - - /* - * Print page on stdout - */ - write(1, toPrint, sdslen(toPrint)); - - sdsfree(toPrint); -} - -#define MAX_LEN_COMMAND 16 -#define COMMAND_FORMAT ": %16s" - -int portLen(char* start) { - int count = 0; - while ('0' <= *start && *start <= '9') { - count++; - start++; - } - return count; -} - -int hostLen(char* start) { - int count = 0; - while (*start == '.' || ('0' <= *start && *start <= '9')) { - count++; - start++; - } - return count; -} - -char* findBeginningOfPath(char* uri) { - char* startPath = strchr(uri, '/'); - while (startPath != uri && startPath != NULL) { - if (*(startPath - 1) == '.') startPath--; - else break; - } - return startPath; -} - -int handleCLI(sds *host, sds *port, sds *uri, const sds page) { - // Get a line - char line[1024]; - fgets(line, 1024, stdin); - - // Nothing - if (line[0] == '\0') { - printf("Please enter a valid command!\n"); - return 0; - } - - // Number or URL - if (line[0] != ':') { - sds newURI; - - // Index of anchor - if (isNumber(line)) { - int gotoIndex = 0; - sscanf(line, "%d", &gotoIndex); - - if (gotoIndex < 0 || gotoIndex >= anchorsCount) { - printf("Invalid anchor index!\n"); - return 0; - } - - char* start = strchr(page + anchorsIndecies[gotoIndex], '(') + 1; - newURI = sdsnewlen(start, strchr(start, ')') - start); - } - // New address - else { - newURI = sdsnewlen(line, strlen(line)-1); // skip newline - } - - char* startPath = findBeginningOfPath(newURI); - - // Handle relative URLs - if (startPath == newURI) { - sds beforePath = sdscatsds(sdsnewlen(*uri, findBeginningOfPath(*uri) - *uri), newURI); - sdsfree(newURI); - newURI = beforePath; - startPath = findBeginningOfPath(newURI); - } - - if (*uri != NULL) sdsfree(*uri); - *uri = newURI; - - char* startHost = strchr(newURI, '@'); - char* startPort = strchr(newURI, ':'); - - // Update host - if (startHost != NULL && startHost < startPath) { - if (host != NULL) sdsfree(*host); - *host = sdsnewlen(startHost + 1, hostLen(startHost + 1)); - } - - // Update port - if (startPort != NULL && startPort < startPath) { - if (port != NULL) sdsfree(*port); - *port = sdsnewlen(startPort + 1, portLen(startPort + 1)); - } - - return 0; - } - - // Special command - - // Get command name and it's arguments - // Currently no command takes arguments - char name[MAX_LEN_COMMAND+1] = { '\0' }; - int argsAssigned = sscanf(line, COMMAND_FORMAT, name); - - if (streq(name, "q") || streq(name, "e") || streq(name, "quit") || streq(name, "exit")) { - return 1; - } - - printf("Invalid command %s!\n", name); - return 0; -} diff --git a/browser-cli.h b/browser-cli.h deleted file mode 100644 index 1837c6a..0000000 --- a/browser-cli.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef BROWSER_CLI -#define BROWSER_CLI - -#include - -void initRendering(); -void freeRendering(); - -void renderPage(const sds page); -int handleCLI(sds *host, sds *port, sds *uri, const sds page); - -#endif diff --git a/browser.c b/browser.c deleted file mode 100644 index 7268831..0000000 --- a/browser.c +++ /dev/null @@ -1,99 +0,0 @@ -/* Receives a markdown file and "renders" it - */ -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#define READ_BUFFER_SIZE 512 - -sds get_page(const char* ip, const char* port, const char* URL) { - if (streq(URL, "blank")) return sdsnew("\n"); - - /* - * Create socket for connecting with server - */ - int fd_socket = socket(AF_INET, SOCK_STREAM, 0); - herrc(fd_socket, "socket"); - - int aton_status = 0; - struct sockaddr_in sa_server = { - .sin_family = AF_INET, - .sin_port = atop(port), - .sin_addr = aton(ip, &aton_status), - }; - herrc(aton_status, "inet_aton"); - - /* - * Request page - */ - - int connectStatus = connect(fd_socket, (struct sockaddr*)&sa_server, sizeof(struct sockaddr_in)); - herrc(connectStatus, "connect"); - if (connectStatus < 0) return sdsnew("Couldn't connect to server!\n"); - - write(fd_socket, URL, strlen(URL)); - - /* - * Receive page - */ - - sds page = sdsempty(); - - char buff[READ_BUFFER_SIZE]; - clear_arr(buff); - while (read(fd_socket, buff, READ_BUFFER_SIZE)) { - page = sdscat(page, buff); - clear_arr(buff); - } - - /* - * Final - */ - - close(fd_socket); - return page; -} - -int main(int argc, char* argv[]) { - initRendering(); - - /* - * Server-client communication - */ - - sds page; - sds host = sdsnew("127.0.0.1"); - sds port = sdsnew("8080"); - sds uri = sdsnew("blank"); - - int stopProgram = 0; - while (!stopProgram) { - /* - * Get the page - */ - - printf("\033[30;107m%s\033[0m\n", uri); - page = get_page(host, port, uri); - renderPage(page); - - /* - * Handle user input - */ - stopProgram = handleCLI(&host, &port, &uri, page); - sdsfree(page); - } - - freeRendering(); - sdsfree(host); - sdsfree(port); - sdsfree(uri); -} diff --git a/sds b/sds deleted file mode 160000 index a9a03bb..0000000 --- a/sds +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a9a03bb3304030bb8a93823a9aeb03c157831ba9 diff --git a/server-cli.c b/server-cli.c deleted file mode 100644 index 58e5ea4..0000000 --- a/server-cli.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#include - -#define MAX_LEN_COMMAND 16 -#define COMMAND_FORMAT ": %16s" - -void handleCLI(sds **vhosts, int vhostsc) { - // Get a line - char line[256]; - fgets(line, 256, stdin); - - // Get command name and it's arguments - // Currently no command takes arguments - char name[MAX_LEN_COMMAND+1]; - int argsAssigned = sscanf(line, COMMAND_FORMAT, name); - - while (!streq(name, "q") && !streq(name, "e") && !streq(name, "quit") && !streq(name, "exit")) { - if (argsAssigned < 1) { - printf("Bad command syntax!\n"); - } - else if (streq(name, "vhosts")) { - for (int i = 0; i < vhostsc; i++) { - printf("Name: \"%s\" Root dir: \"%s\" Error file: \"%s\"\n", - vhosts[i][vh_user], - vhosts[i][vh_path], - vhosts[i][vh_error]); - } - } - else if (streq(name, "help") || streq(name, "h") || streq(name, "?")) { - printf("help,h,?\tPrints this message\nvhosts\t\tPrints all registered virtual hosts\nquit,exit,q,e\tExits the program\n"); - } - else { - printf("Unknown command %s!\n", name); - } - - // Get line and divided it into command name and arguments - fgets(line, 256, stdin); - argsAssigned = sscanf(line, COMMAND_FORMAT, name); - } - - printf("Exiting...\n"); - kill(getppid(), SIGTERM); -} diff --git a/server-cli.h b/server-cli.h deleted file mode 100644 index b5b5875..0000000 --- a/server-cli.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef H_SERVER_CLI -#define H_SERVER_CLI - -#include - -void handleCLI(sds **vhosts, int vhostsc); - -#endif diff --git a/server-connection.c b/server-connection.c deleted file mode 100644 index 285cc1d..0000000 --- a/server-connection.c +++ /dev/null @@ -1,133 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -sds constructFilePath(const sds root, const char* file); -void sanitizeAddress(char* address); -sds* findVhost(char* address, sds** vhosts, const int vhostsc); -int openError(sds* filePath, int* fd, const sds* vhost, const char* client, const int fd_client); - -void on_connection(const char* client, const int fd_client, sds **vhosts, const int vhostsc) { - printf("[%s@%d] Connected successfully!\n", client, fd_client); - - /* Get address request */ - char address[256]; - memset(address, 0, 256); - - read(fd_client, address, 256); - sanitizeAddress(address); - printf("[%s@%d] Requested %s\n", client, fd_client, address); - - /* Is the username connected with any file path? */ - const sds *vhost = findVhost(address, vhosts, vhostsc); - if (vhost == NULL) { - fprintf(stderr, "[%s@%d] Unknown username in address %s\n", client, fd_client, address); - return; - } - - /* Try to open the requested file or the error file */ - sds filePath = constructFilePath(vhost[vh_path], strchr(address, '@') + 1); - - int fd = 0; - - /* Check if file is directory */ - struct stat buf; - if (stat(filePath, &buf) == 0) { - if (S_ISDIR(buf.st_mode)) { - filePath = sdscat(filePath, "/index.md"); - } - else if (!(S_ISREG(buf.st_mode))) { - fprintf(stderr, "[%s@%d] %s is not a regular file!\n", client, fd_client, filePath); - - if (openError(&filePath, &fd, vhost, client, fd_client)) - return; - } - } - - if (fd <= 0) - fd = open(filePath, O_RDONLY); - - if (fd < 0) { - fprintf(stderr, "[%s@%d] Error opening %s\n", client, fd_client, filePath); - - if (openError(&filePath, &fd, vhost, client, fd_client)) - return; - } - - /* Send the file to the client */ - printf("[%s@%d] Serving %s\n", client, fd_client, filePath); - sdsfree(filePath); - - char buff[256]; - memset(buff, 0, sizeof(buff)); - while (read(fd, buff, 256)) { - write(fd_client, buff, strlen(buff)); - memset(buff, 0, sizeof(buff)); - } - - /* Finalize */ - close(fd); - printf("[%s@%d] Served!\n", client, fd_client); -} - -sds constructFilePath(const sds root, const char* file) { - sds path = sdsdup(root); - if (root[sdslen(root)-1] != '/' && file[0] != '/') - path = sdscat(path, "/"); - path = sdscat(path, file); - if (file[strlen(file)-1] == '/') - path = sdscat(path, "index.md"); - return path; -} - -void sanitizeAddress(char* address) { - /* Remove host and port */ - char* startPath = strchr(address, '/'); - if (startPath == NULL) - startPath = strchr(address, '\0'); - - char* startHost = strchr(address, '@'); - shiftLeft(startHost + 1, address - startHost, startPath - startHost - 1); - - /* Remove ../ */ - for (char* prev = startHost+1, *i = startHost+1; i != NULL && *i != '\0';) { - if (i[1] == '.' && i[2] == '.' && i[3] == '/') { - shiftLeft(prev, strlen(prev), i - prev + 3); - i = prev; - } - else { - prev = i; - i = strchr(i+1, '/'); - } - } -} - -sds* findVhost(char* address, sds** vhosts, const int vhostsc) { - sds* vhost = NULL; - int usernameLen = strchr(address, '@') - address; - for (int i = 0; i < vhostsc; i++) { - if (strncmp(vhosts[i][vh_user], address, usernameLen) == 0) { - vhost = *vhosts + i; - break; - } - } - return vhost; -} - -int openError(sds* filePath, int* fd, const sds* vhost, const char* client, const int fd_client) { - sdsfree(*filePath); - *filePath = constructFilePath(vhost[vh_path], vhost[vh_error]); - *fd = open(*filePath, O_RDONLY); - if (*fd < 0) { - fprintf(stderr, "[%s@%d] Error opening %s\n", client, fd_client, *filePath); - sdsfree(*filePath); - return 1; - } - return 0; -} diff --git a/server-connection.h b/server-connection.h deleted file mode 100644 index 71447ff..0000000 --- a/server-connection.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef H_SERVER_CONNECTION -#define H_SERVER_CONNECTION - -#include - -#define vh_user 0 -#define vh_path 1 -#define vh_error 2 - -void on_connection(const char* client, const int fd_client, sds **vhosts, const int vhostsc); - -#endif diff --git a/server.c b/server.c deleted file mode 100644 index aeff800..0000000 --- a/server.c +++ /dev/null @@ -1,185 +0,0 @@ -/* The server recieves connections and passes files to the clients - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -int createCommunicationSocket(const char* ip, const char* port) { - int fd_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - herr(fd_socket, "socket"); - - int aton_status = 0; - struct sockaddr_in sa_socket = { - .sin_family = AF_INET, - .sin_port = atop(port), - .sin_addr = aton(ip, &aton_status), - }; - herr(aton_status, "inet_aton"); - - // Reuse address when in TIME_WAIT state, after listening socket was closed - // https://stackoverflow.com/a/10651048/12036073 - // https://superuser.com/questions/173535/what-are-close-wait-and-time-wait-states#comment951880_173543 - int true = 1; - herr(setsockopt(fd_socket, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(int)), "setsockopt"); - - herr(bind(fd_socket, (struct sockaddr*)&sa_socket, sizeof(struct sockaddr_in)), "bind"); - - herr(listen(fd_socket, 50), "listen"); - - return fd_socket; -} - -void freeVhosts(sds **vhosts, int vhostsc) { - for (int i = 0; i < vhostsc; i++) { - sdsfreesplitres(vhosts[i], 3); - } - free(vhosts); -} - -int acceptConnections = 1; - -void handler_refuseConnections(int signum) { - acceptConnections = 0; -} - -int main(int argc, char* argv[]) { - /* - * Get server parameters - */ - - sds host = sdsnew("127.0.0.1"); - sds port = sdsnew("8080"); - - int argvOffset = 1; - if (argc > 1 && charCount(argv[1], ',') == 1) { - argvOffset++; - char* sep = strchr(argv[1], ','); - sdsfree(host); - host = sdsnewlen(argv[1], sep - argv[1]); - sdsfree(port); - port = sdsnew(sep + 1); - } - - /* - * Get hosts - */ - - int vhostsc = argc - argvOffset; - sds **vhosts = malloc(vhostsc * sizeof(sds*)); - for (int i = 0, temp = 0; i < vhostsc; i++) { - vhosts[i] = sdssplitlen(argv[i+argvOffset], strlen(argv[i+argvOffset]), ",", 1, &temp); - } - - /* - * Create socket for accepting connections - */ - - int fd_socket = createCommunicationSocket(host, port); - printf("Listening on %s:%s\n", host, port); - - /* - * Server command-line interface - */ - - int pid_cli = fork(); - if (pid_cli == 0) { - close(fd_socket); - handleCLI(vhosts, vhostsc); - freeVhosts(vhosts, vhostsc); - sdsfree(host); - sdsfree(port); - return 0; - } - - /* - * Define variables - */ - - // Client address - struct sockaddr_in sa_client = { - .sin_family = AF_INET, - .sin_port = 0, - .sin_addr.s_addr = 0, - }; - socklen_t sa_client_size = sizeof(struct sockaddr_in); - - int fd_client; - int count = 0; - int pselectStat = 0; - - /* - * Handle connection requests - */ - - // Data for pselect - fd_set rfds; - struct timespec tv = { - /* How long should we block (wait) for fd_socket to have a request */ - .tv_sec = 0, - .tv_nsec = 100000, - }; - - // Stop accepting connections on SIGTERM - signal(SIGTERM, handler_refuseConnections); - - while (acceptConnections) { - /* - * Check if fd_socket has something we can read - */ - - FD_ZERO(&rfds); - FD_SET(fd_socket, &rfds); - - herrc(pselect(fd_socket + 1, &rfds, NULL, NULL, &tv, NULL), "pselect"); - if (!FD_ISSET(fd_socket, &rfds)) continue; - - /* - * Accept the connection - */ - - fd_client = accept(fd_socket, (struct sockaddr*)&sa_client, &sa_client_size); - if (acceptConnections) herrc(fd_client, "accept"); - if (fd_client < 0) continue; - - char* strAddr = inet_ntoa(sa_client.sin_addr); - count++; - - /* - * Logic when connected with client - */ - - int fp = fork(); - if (fp == 0) { - close(fd_socket); - on_connection(strAddr, fd_client, vhosts, argc - 1); - close(fd_client); - freeVhosts(vhosts, vhostsc); - sdsfree(host); - sdsfree(port); - return 0; - } - close(fd_client); - } - - while(wait(NULL) > 0); - freeVhosts(vhosts, vhostsc); - close(fd_socket); - sdsfree(host); - sdsfree(port); -} diff --git a/src/browser-cli.c b/src/browser-cli.c new file mode 100644 index 0000000..3bea4ba --- /dev/null +++ b/src/browser-cli.c @@ -0,0 +1,183 @@ +#include +#include +#include + +#include +#include +#include +#include + +struct md_syntax { + regex_t anchor; +}; + +struct md_syntax syntax = { + .anchor = NULL, +}; + +int* anchorsIndecies; +int anchorsCount = 0; + +void initRendering() { + /* + * Compile regexes used in rendering + */ + + herr(regcomp(&syntax.anchor, "\\[\\([^]]*\\)\\](\\([^)]*\\))", 0), "regcomp"); +} + +void freeRendering() { + regfree(&syntax.anchor); + + free(anchorsIndecies); +} + +void renderPage(const sds page) { + if (sdslen(page) == 0) { + printf("Server didn't return page!\n"); + return; + } + + sds toPrint = sdsdup(page); + + /* + * Parse Markdown constructs + */ + + /* Substitute and store anchorsIndecies */ + if (anchorsIndecies != NULL) { + free(anchorsIndecies); + anchorsCount = 0; + anchorsIndecies = NULL; + } + toPrint = gsub_getm(toPrint, &syntax.anchor, "\16\033[4m\1\033[0m", &anchorsIndecies, &anchorsCount); + + sds newPrint; + for (int i = 0, anchorInd = 0; i < anchorsCount; i++) { + anchorInd = strchr(toPrint, '\16') - toPrint; + + /* In toPrint, replace '\16' with "\033[30;46m%d\033[0m", where %d is the variable i */ + toPrint[anchorInd] = '\0'; + newPrint = sdsgrowzero(sdsempty(), sdslen(toPrint) + digits(i) + 8 + 4); + sprintf(newPrint, "%s\033[30;46m%d\033[0m%s", toPrint, i, toPrint + anchorInd + 1); + + sdsfree(toPrint); + toPrint = newPrint; + } + + /* + * Print page on stdout + */ + write(1, toPrint, sdslen(toPrint)); + + sdsfree(toPrint); +} + +#define MAX_LEN_COMMAND 16 +#define COMMAND_FORMAT ": %16s" + +int portLen(char* start) { + int count = 0; + while ('0' <= *start && *start <= '9') { + count++; + start++; + } + return count; +} + +int hostLen(char* start) { + int count = 0; + while (*start == '.' || ('0' <= *start && *start <= '9')) { + count++; + start++; + } + return count; +} + +char* findBeginningOfPath(char* uri) { + char* startPath = strchr(uri, '/'); + while (startPath != uri && startPath != NULL) { + if (*(startPath - 1) == '.') startPath--; + else break; + } + return startPath; +} + +int handleCLI(sds *host, sds *port, sds *uri, const sds page) { + // Get a line + char line[1024]; + fgets(line, 1024, stdin); + + // Nothing + if (line[0] == '\0') { + printf("Please enter a valid command!\n"); + return 0; + } + + // Number or URL + if (line[0] != ':') { + sds newURI; + + // Index of anchor + if (isNumber(line)) { + int gotoIndex = 0; + sscanf(line, "%d", &gotoIndex); + + if (gotoIndex < 0 || gotoIndex >= anchorsCount) { + printf("Invalid anchor index!\n"); + return 0; + } + + char* start = strchr(page + anchorsIndecies[gotoIndex], '(') + 1; + newURI = sdsnewlen(start, strchr(start, ')') - start); + } + // New address + else { + newURI = sdsnewlen(line, strlen(line)-1); // skip newline + } + + char* startPath = findBeginningOfPath(newURI); + + // Handle relative URLs + if (startPath == newURI) { + sds beforePath = sdscatsds(sdsnewlen(*uri, findBeginningOfPath(*uri) - *uri), newURI); + sdsfree(newURI); + newURI = beforePath; + startPath = findBeginningOfPath(newURI); + } + + if (*uri != NULL) sdsfree(*uri); + *uri = newURI; + + char* startHost = strchr(newURI, '@'); + char* startPort = strchr(newURI, ':'); + + // Update host + if (startHost != NULL && startHost < startPath) { + if (host != NULL) sdsfree(*host); + *host = sdsnewlen(startHost + 1, hostLen(startHost + 1)); + } + + // Update port + if (startPort != NULL && startPort < startPath) { + if (port != NULL) sdsfree(*port); + *port = sdsnewlen(startPort + 1, portLen(startPort + 1)); + } + + return 0; + } + + // Special command + + // Get command name and it's arguments + // Currently no command takes arguments + char name[MAX_LEN_COMMAND+1] = { '\0' }; + int argsAssigned = sscanf(line, COMMAND_FORMAT, name); + + if (streq(name, "q") || streq(name, "e") || streq(name, "quit") || streq(name, "exit")) { + return 1; + } + + printf("Invalid command %s!\n", name); + return 0; +} diff --git a/src/browser-cli.h b/src/browser-cli.h new file mode 100644 index 0000000..1837c6a --- /dev/null +++ b/src/browser-cli.h @@ -0,0 +1,12 @@ +#ifndef BROWSER_CLI +#define BROWSER_CLI + +#include + +void initRendering(); +void freeRendering(); + +void renderPage(const sds page); +int handleCLI(sds *host, sds *port, sds *uri, const sds page); + +#endif diff --git a/src/browser.c b/src/browser.c new file mode 100644 index 0000000..7268831 --- /dev/null +++ b/src/browser.c @@ -0,0 +1,99 @@ +/* Receives a markdown file and "renders" it + */ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define READ_BUFFER_SIZE 512 + +sds get_page(const char* ip, const char* port, const char* URL) { + if (streq(URL, "blank")) return sdsnew("\n"); + + /* + * Create socket for connecting with server + */ + int fd_socket = socket(AF_INET, SOCK_STREAM, 0); + herrc(fd_socket, "socket"); + + int aton_status = 0; + struct sockaddr_in sa_server = { + .sin_family = AF_INET, + .sin_port = atop(port), + .sin_addr = aton(ip, &aton_status), + }; + herrc(aton_status, "inet_aton"); + + /* + * Request page + */ + + int connectStatus = connect(fd_socket, (struct sockaddr*)&sa_server, sizeof(struct sockaddr_in)); + herrc(connectStatus, "connect"); + if (connectStatus < 0) return sdsnew("Couldn't connect to server!\n"); + + write(fd_socket, URL, strlen(URL)); + + /* + * Receive page + */ + + sds page = sdsempty(); + + char buff[READ_BUFFER_SIZE]; + clear_arr(buff); + while (read(fd_socket, buff, READ_BUFFER_SIZE)) { + page = sdscat(page, buff); + clear_arr(buff); + } + + /* + * Final + */ + + close(fd_socket); + return page; +} + +int main(int argc, char* argv[]) { + initRendering(); + + /* + * Server-client communication + */ + + sds page; + sds host = sdsnew("127.0.0.1"); + sds port = sdsnew("8080"); + sds uri = sdsnew("blank"); + + int stopProgram = 0; + while (!stopProgram) { + /* + * Get the page + */ + + printf("\033[30;107m%s\033[0m\n", uri); + page = get_page(host, port, uri); + renderPage(page); + + /* + * Handle user input + */ + stopProgram = handleCLI(&host, &port, &uri, page); + sdsfree(page); + } + + freeRendering(); + sdsfree(host); + sdsfree(port); + sdsfree(uri); +} diff --git a/src/server-cli.c b/src/server-cli.c new file mode 100644 index 0000000..58e5ea4 --- /dev/null +++ b/src/server-cli.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +#define MAX_LEN_COMMAND 16 +#define COMMAND_FORMAT ": %16s" + +void handleCLI(sds **vhosts, int vhostsc) { + // Get a line + char line[256]; + fgets(line, 256, stdin); + + // Get command name and it's arguments + // Currently no command takes arguments + char name[MAX_LEN_COMMAND+1]; + int argsAssigned = sscanf(line, COMMAND_FORMAT, name); + + while (!streq(name, "q") && !streq(name, "e") && !streq(name, "quit") && !streq(name, "exit")) { + if (argsAssigned < 1) { + printf("Bad command syntax!\n"); + } + else if (streq(name, "vhosts")) { + for (int i = 0; i < vhostsc; i++) { + printf("Name: \"%s\" Root dir: \"%s\" Error file: \"%s\"\n", + vhosts[i][vh_user], + vhosts[i][vh_path], + vhosts[i][vh_error]); + } + } + else if (streq(name, "help") || streq(name, "h") || streq(name, "?")) { + printf("help,h,?\tPrints this message\nvhosts\t\tPrints all registered virtual hosts\nquit,exit,q,e\tExits the program\n"); + } + else { + printf("Unknown command %s!\n", name); + } + + // Get line and divided it into command name and arguments + fgets(line, 256, stdin); + argsAssigned = sscanf(line, COMMAND_FORMAT, name); + } + + printf("Exiting...\n"); + kill(getppid(), SIGTERM); +} diff --git a/src/server-cli.h b/src/server-cli.h new file mode 100644 index 0000000..b5b5875 --- /dev/null +++ b/src/server-cli.h @@ -0,0 +1,8 @@ +#ifndef H_SERVER_CLI +#define H_SERVER_CLI + +#include + +void handleCLI(sds **vhosts, int vhostsc); + +#endif diff --git a/src/server-connection.c b/src/server-connection.c new file mode 100644 index 0000000..285cc1d --- /dev/null +++ b/src/server-connection.c @@ -0,0 +1,133 @@ +#include + +#include +#include +#include +#include + +#include +#include + +sds constructFilePath(const sds root, const char* file); +void sanitizeAddress(char* address); +sds* findVhost(char* address, sds** vhosts, const int vhostsc); +int openError(sds* filePath, int* fd, const sds* vhost, const char* client, const int fd_client); + +void on_connection(const char* client, const int fd_client, sds **vhosts, const int vhostsc) { + printf("[%s@%d] Connected successfully!\n", client, fd_client); + + /* Get address request */ + char address[256]; + memset(address, 0, 256); + + read(fd_client, address, 256); + sanitizeAddress(address); + printf("[%s@%d] Requested %s\n", client, fd_client, address); + + /* Is the username connected with any file path? */ + const sds *vhost = findVhost(address, vhosts, vhostsc); + if (vhost == NULL) { + fprintf(stderr, "[%s@%d] Unknown username in address %s\n", client, fd_client, address); + return; + } + + /* Try to open the requested file or the error file */ + sds filePath = constructFilePath(vhost[vh_path], strchr(address, '@') + 1); + + int fd = 0; + + /* Check if file is directory */ + struct stat buf; + if (stat(filePath, &buf) == 0) { + if (S_ISDIR(buf.st_mode)) { + filePath = sdscat(filePath, "/index.md"); + } + else if (!(S_ISREG(buf.st_mode))) { + fprintf(stderr, "[%s@%d] %s is not a regular file!\n", client, fd_client, filePath); + + if (openError(&filePath, &fd, vhost, client, fd_client)) + return; + } + } + + if (fd <= 0) + fd = open(filePath, O_RDONLY); + + if (fd < 0) { + fprintf(stderr, "[%s@%d] Error opening %s\n", client, fd_client, filePath); + + if (openError(&filePath, &fd, vhost, client, fd_client)) + return; + } + + /* Send the file to the client */ + printf("[%s@%d] Serving %s\n", client, fd_client, filePath); + sdsfree(filePath); + + char buff[256]; + memset(buff, 0, sizeof(buff)); + while (read(fd, buff, 256)) { + write(fd_client, buff, strlen(buff)); + memset(buff, 0, sizeof(buff)); + } + + /* Finalize */ + close(fd); + printf("[%s@%d] Served!\n", client, fd_client); +} + +sds constructFilePath(const sds root, const char* file) { + sds path = sdsdup(root); + if (root[sdslen(root)-1] != '/' && file[0] != '/') + path = sdscat(path, "/"); + path = sdscat(path, file); + if (file[strlen(file)-1] == '/') + path = sdscat(path, "index.md"); + return path; +} + +void sanitizeAddress(char* address) { + /* Remove host and port */ + char* startPath = strchr(address, '/'); + if (startPath == NULL) + startPath = strchr(address, '\0'); + + char* startHost = strchr(address, '@'); + shiftLeft(startHost + 1, address - startHost, startPath - startHost - 1); + + /* Remove ../ */ + for (char* prev = startHost+1, *i = startHost+1; i != NULL && *i != '\0';) { + if (i[1] == '.' && i[2] == '.' && i[3] == '/') { + shiftLeft(prev, strlen(prev), i - prev + 3); + i = prev; + } + else { + prev = i; + i = strchr(i+1, '/'); + } + } +} + +sds* findVhost(char* address, sds** vhosts, const int vhostsc) { + sds* vhost = NULL; + int usernameLen = strchr(address, '@') - address; + for (int i = 0; i < vhostsc; i++) { + if (strncmp(vhosts[i][vh_user], address, usernameLen) == 0) { + vhost = *vhosts + i; + break; + } + } + return vhost; +} + +int openError(sds* filePath, int* fd, const sds* vhost, const char* client, const int fd_client) { + sdsfree(*filePath); + *filePath = constructFilePath(vhost[vh_path], vhost[vh_error]); + *fd = open(*filePath, O_RDONLY); + if (*fd < 0) { + fprintf(stderr, "[%s@%d] Error opening %s\n", client, fd_client, *filePath); + sdsfree(*filePath); + return 1; + } + return 0; +} diff --git a/src/server-connection.h b/src/server-connection.h new file mode 100644 index 0000000..71447ff --- /dev/null +++ b/src/server-connection.h @@ -0,0 +1,12 @@ +#ifndef H_SERVER_CONNECTION +#define H_SERVER_CONNECTION + +#include + +#define vh_user 0 +#define vh_path 1 +#define vh_error 2 + +void on_connection(const char* client, const int fd_client, sds **vhosts, const int vhostsc); + +#endif diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..aeff800 --- /dev/null +++ b/src/server.c @@ -0,0 +1,185 @@ +/* The server recieves connections and passes files to the clients + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +int createCommunicationSocket(const char* ip, const char* port) { + int fd_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + herr(fd_socket, "socket"); + + int aton_status = 0; + struct sockaddr_in sa_socket = { + .sin_family = AF_INET, + .sin_port = atop(port), + .sin_addr = aton(ip, &aton_status), + }; + herr(aton_status, "inet_aton"); + + // Reuse address when in TIME_WAIT state, after listening socket was closed + // https://stackoverflow.com/a/10651048/12036073 + // https://superuser.com/questions/173535/what-are-close-wait-and-time-wait-states#comment951880_173543 + int true = 1; + herr(setsockopt(fd_socket, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(int)), "setsockopt"); + + herr(bind(fd_socket, (struct sockaddr*)&sa_socket, sizeof(struct sockaddr_in)), "bind"); + + herr(listen(fd_socket, 50), "listen"); + + return fd_socket; +} + +void freeVhosts(sds **vhosts, int vhostsc) { + for (int i = 0; i < vhostsc; i++) { + sdsfreesplitres(vhosts[i], 3); + } + free(vhosts); +} + +int acceptConnections = 1; + +void handler_refuseConnections(int signum) { + acceptConnections = 0; +} + +int main(int argc, char* argv[]) { + /* + * Get server parameters + */ + + sds host = sdsnew("127.0.0.1"); + sds port = sdsnew("8080"); + + int argvOffset = 1; + if (argc > 1 && charCount(argv[1], ',') == 1) { + argvOffset++; + char* sep = strchr(argv[1], ','); + sdsfree(host); + host = sdsnewlen(argv[1], sep - argv[1]); + sdsfree(port); + port = sdsnew(sep + 1); + } + + /* + * Get hosts + */ + + int vhostsc = argc - argvOffset; + sds **vhosts = malloc(vhostsc * sizeof(sds*)); + for (int i = 0, temp = 0; i < vhostsc; i++) { + vhosts[i] = sdssplitlen(argv[i+argvOffset], strlen(argv[i+argvOffset]), ",", 1, &temp); + } + + /* + * Create socket for accepting connections + */ + + int fd_socket = createCommunicationSocket(host, port); + printf("Listening on %s:%s\n", host, port); + + /* + * Server command-line interface + */ + + int pid_cli = fork(); + if (pid_cli == 0) { + close(fd_socket); + handleCLI(vhosts, vhostsc); + freeVhosts(vhosts, vhostsc); + sdsfree(host); + sdsfree(port); + return 0; + } + + /* + * Define variables + */ + + // Client address + struct sockaddr_in sa_client = { + .sin_family = AF_INET, + .sin_port = 0, + .sin_addr.s_addr = 0, + }; + socklen_t sa_client_size = sizeof(struct sockaddr_in); + + int fd_client; + int count = 0; + int pselectStat = 0; + + /* + * Handle connection requests + */ + + // Data for pselect + fd_set rfds; + struct timespec tv = { + /* How long should we block (wait) for fd_socket to have a request */ + .tv_sec = 0, + .tv_nsec = 100000, + }; + + // Stop accepting connections on SIGTERM + signal(SIGTERM, handler_refuseConnections); + + while (acceptConnections) { + /* + * Check if fd_socket has something we can read + */ + + FD_ZERO(&rfds); + FD_SET(fd_socket, &rfds); + + herrc(pselect(fd_socket + 1, &rfds, NULL, NULL, &tv, NULL), "pselect"); + if (!FD_ISSET(fd_socket, &rfds)) continue; + + /* + * Accept the connection + */ + + fd_client = accept(fd_socket, (struct sockaddr*)&sa_client, &sa_client_size); + if (acceptConnections) herrc(fd_client, "accept"); + if (fd_client < 0) continue; + + char* strAddr = inet_ntoa(sa_client.sin_addr); + count++; + + /* + * Logic when connected with client + */ + + int fp = fork(); + if (fp == 0) { + close(fd_socket); + on_connection(strAddr, fd_client, vhosts, argc - 1); + close(fd_client); + freeVhosts(vhosts, vhostsc); + sdsfree(host); + sdsfree(port); + return 0; + } + close(fd_client); + } + + while(wait(NULL) > 0); + freeVhosts(vhosts, vhostsc); + close(fd_socket); + sdsfree(host); + sdsfree(port); +} diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..822a4d2 --- /dev/null +++ b/src/util.c @@ -0,0 +1,180 @@ +#include +#include +#include + +#include +#include +#include +#include + +/* + * Networking + */ + +uint16_t atop(const char *port) { + return htons(atoi(port)); +} + +struct in_addr aton(const char* cp, int* output) { + struct in_addr inp; + *output = inet_aton(cp, &inp); + return inp; +} + +/* + * Error handling + */ + +void herrc(int output, const char* funcName) { + if (output < 0 && errno != EINTR) { + perror(funcName); + } +} + +void herr(int output, const char* funcName) { + if (output < 0) { + perror(funcName); + exit(errno); + } +} + +/* + * sds string substitution + */ + +sds getMatch(const sds str, const regmatch_t match) { + return sdsnewlen(str + match.rm_so, match.rm_eo - match.rm_so); +} +int validMatch(const regmatch_t match) { + return match.rm_so > -1; +} + +void resizeMatches(int* *matches, int* size) { + if (*size == 0) { + *matches = malloc((*size = 8) * sizeof(int*)); + return; + } + + int* *biggerArr = malloc((*size * 2) * sizeof(int*)); + for (size_t i = 0; i < *size; i++) { + biggerArr[i] = matches[i]; + } + *size *= 2; + free(matches); + *matches = *biggerArr; +} +void pushBackMatch(int* *matches, int *matchesCount, int *matchesSize, int matchStart) { + if (*matchesCount >= *matchesSize) + resizeMatches(matches, matchesSize); + + (*matches)[*matchesCount] = matchStart; + *matchesCount += 1; +} + +#define MATCHSTART str + strInd +sds gsub_getm(sds str, const regex_t *regex, const char* repl, int* *matches, int *matchesCount) { + regmatch_t pmatch[10] = { + { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, + { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, + { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, + { .rm_so = 0, .rm_eo = 0, }, + }; + + int strInd = 0; + int matchesSize = (matchesCount != NULL) ? *matchesCount : 0; + size_t replLen = strlen(repl); + + sds ret = sdsempty(); + /* + * Substitute all occurences of regex with repl in str + */ + // sdslen is in O(1) time + while (strInd < sdslen(str)) { + /* Run regex */ + if (regexec(regex, MATCHSTART, 10, pmatch, 0) != 0) { + /* If there are no matches, return the rest of the string as-is */ + ret = sdscat(ret, MATCHSTART); + break; + } + + /* Store everything before the match as-is */ + ret = sdscatlen(ret, MATCHSTART, pmatch[0].rm_so); + + /* Replace match with repl + * repl can include matched subexpressions */ + for(size_t i = 0; i < replLen; i++) { + if (repl[i] <= '\10') { + if (pmatch[repl[i] % 10].rm_so > -1) { + sds match = getMatch(MATCHSTART, pmatch[repl[i] % 10]); + ret = sdscatsds(ret, match); + sdsfree(match); + } + } + else + ret = sdscatlen(ret, &repl[i], 1); + } + + /* Add index of current match to matches */ + if (matchesCount != NULL) { + pushBackMatch(matches, matchesCount, &matchesSize, strInd + pmatch[0].rm_so); + } + + /* Continute after the current match */ + strInd += pmatch[0].rm_eo; + } + + sdsfree(str); + return ret; +} + +sds gsub(sds str, const regex_t* regex, const char* repl) { + return gsub_getm(str, regex, repl, NULL, NULL); +} + +/* + * other + */ + +int digits(int num) { + if (num < 0) num *= -1; + // This is the fastest way to get the number of digits + if (num < 10) return 1; + if (num < 100) return 2; + if (num < 1000) return 3; + if (num < 10000) return 4; + if (num < 100000) return 5; + if (num < 1000000) return 6; + if (num < 10000000) return 7; + if (num < 100000000) return 8; + if (num < 1000000000) return 9; + // 2147483647 (2^31-1) is max value of int + return 10; +} + +int streq(const char* first, const char* second) { + return strcmp(first, second) == 0; +} + +void shiftLeft(char* str, size_t size, size_t shift) { + while (*(str + shift - 1) != '\0') { + *str = *(str + shift); + str++; + } +} + +int isNumber(char* str) { + while (*str >= ' ') { + if (*str < '0' || *str > '9') return 0; + str++; + } + return 1; +} + +int charCount(char* str, char cmp) { + int count = 0; + while (*str != '\0') { + count += *str == cmp; + str++; + } + return count; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..b2836eb --- /dev/null +++ b/src/util.h @@ -0,0 +1,29 @@ +#ifndef H_UTIL +#define H_UTIL + +#include +#include +#include +#include + +/* Networking */ +uint16_t atop(const char *port); +struct in_addr aton(const char* cp, int* output); + +/* Error handling */ +void herr(int output, const char* funcName); +void herrc(int output, const char* funcName); + +/* sds string substition */ +sds gsub(sds str, const regex_t* regex, const char* repl); +sds gsub_getm(sds str, const regex_t *regex, const char* repl, int* *matches, int *matchesCount); + +/* Other */ +#define clear_arr(arr) memset(arr, 0, sizeof(arr)/sizeof(*arr)) +int digits(int num); +int streq(const char* first, const char* second); +void shiftLeft(char* str, size_t size, size_t shift); +int isNumber(char* str); +int charCount(char* str, char cmp); + +#endif diff --git a/util.c b/util.c deleted file mode 100644 index 822a4d2..0000000 --- a/util.c +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -/* - * Networking - */ - -uint16_t atop(const char *port) { - return htons(atoi(port)); -} - -struct in_addr aton(const char* cp, int* output) { - struct in_addr inp; - *output = inet_aton(cp, &inp); - return inp; -} - -/* - * Error handling - */ - -void herrc(int output, const char* funcName) { - if (output < 0 && errno != EINTR) { - perror(funcName); - } -} - -void herr(int output, const char* funcName) { - if (output < 0) { - perror(funcName); - exit(errno); - } -} - -/* - * sds string substitution - */ - -sds getMatch(const sds str, const regmatch_t match) { - return sdsnewlen(str + match.rm_so, match.rm_eo - match.rm_so); -} -int validMatch(const regmatch_t match) { - return match.rm_so > -1; -} - -void resizeMatches(int* *matches, int* size) { - if (*size == 0) { - *matches = malloc((*size = 8) * sizeof(int*)); - return; - } - - int* *biggerArr = malloc((*size * 2) * sizeof(int*)); - for (size_t i = 0; i < *size; i++) { - biggerArr[i] = matches[i]; - } - *size *= 2; - free(matches); - *matches = *biggerArr; -} -void pushBackMatch(int* *matches, int *matchesCount, int *matchesSize, int matchStart) { - if (*matchesCount >= *matchesSize) - resizeMatches(matches, matchesSize); - - (*matches)[*matchesCount] = matchStart; - *matchesCount += 1; -} - -#define MATCHSTART str + strInd -sds gsub_getm(sds str, const regex_t *regex, const char* repl, int* *matches, int *matchesCount) { - regmatch_t pmatch[10] = { - { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, - { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, - { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, { .rm_so = 0, .rm_eo = 0, }, - { .rm_so = 0, .rm_eo = 0, }, - }; - - int strInd = 0; - int matchesSize = (matchesCount != NULL) ? *matchesCount : 0; - size_t replLen = strlen(repl); - - sds ret = sdsempty(); - /* - * Substitute all occurences of regex with repl in str - */ - // sdslen is in O(1) time - while (strInd < sdslen(str)) { - /* Run regex */ - if (regexec(regex, MATCHSTART, 10, pmatch, 0) != 0) { - /* If there are no matches, return the rest of the string as-is */ - ret = sdscat(ret, MATCHSTART); - break; - } - - /* Store everything before the match as-is */ - ret = sdscatlen(ret, MATCHSTART, pmatch[0].rm_so); - - /* Replace match with repl - * repl can include matched subexpressions */ - for(size_t i = 0; i < replLen; i++) { - if (repl[i] <= '\10') { - if (pmatch[repl[i] % 10].rm_so > -1) { - sds match = getMatch(MATCHSTART, pmatch[repl[i] % 10]); - ret = sdscatsds(ret, match); - sdsfree(match); - } - } - else - ret = sdscatlen(ret, &repl[i], 1); - } - - /* Add index of current match to matches */ - if (matchesCount != NULL) { - pushBackMatch(matches, matchesCount, &matchesSize, strInd + pmatch[0].rm_so); - } - - /* Continute after the current match */ - strInd += pmatch[0].rm_eo; - } - - sdsfree(str); - return ret; -} - -sds gsub(sds str, const regex_t* regex, const char* repl) { - return gsub_getm(str, regex, repl, NULL, NULL); -} - -/* - * other - */ - -int digits(int num) { - if (num < 0) num *= -1; - // This is the fastest way to get the number of digits - if (num < 10) return 1; - if (num < 100) return 2; - if (num < 1000) return 3; - if (num < 10000) return 4; - if (num < 100000) return 5; - if (num < 1000000) return 6; - if (num < 10000000) return 7; - if (num < 100000000) return 8; - if (num < 1000000000) return 9; - // 2147483647 (2^31-1) is max value of int - return 10; -} - -int streq(const char* first, const char* second) { - return strcmp(first, second) == 0; -} - -void shiftLeft(char* str, size_t size, size_t shift) { - while (*(str + shift - 1) != '\0') { - *str = *(str + shift); - str++; - } -} - -int isNumber(char* str) { - while (*str >= ' ') { - if (*str < '0' || *str > '9') return 0; - str++; - } - return 1; -} - -int charCount(char* str, char cmp) { - int count = 0; - while (*str != '\0') { - count += *str == cmp; - str++; - } - return count; -} diff --git a/util.h b/util.h deleted file mode 100644 index b2836eb..0000000 --- a/util.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef H_UTIL -#define H_UTIL - -#include -#include -#include -#include - -/* Networking */ -uint16_t atop(const char *port); -struct in_addr aton(const char* cp, int* output); - -/* Error handling */ -void herr(int output, const char* funcName); -void herrc(int output, const char* funcName); - -/* sds string substition */ -sds gsub(sds str, const regex_t* regex, const char* repl); -sds gsub_getm(sds str, const regex_t *regex, const char* repl, int* *matches, int *matchesCount); - -/* Other */ -#define clear_arr(arr) memset(arr, 0, sizeof(arr)/sizeof(*arr)) -int digits(int num); -int streq(const char* first, const char* second); -void shiftLeft(char* str, size_t size, size_t shift); -int isNumber(char* str); -int charCount(char* str, char cmp); - -#endif -- cgit v1.2.3