From: Soikk <76824648+Soikk@users.noreply.github.com> Date: Thu, 5 May 2022 16:45:45 +0000 (+0200) Subject: More quality of life changes X-Git-Url: https://git.xolatile.top/?a=commitdiff_plain;h=39c0dfbc9c4279e519841afae5c7413b1bdf56d8;p=soikk-DB.git More quality of life changes --- diff --git a/include/db.h b/include/db.h new file mode 100644 index 0000000..a5fca10 --- /dev/null +++ b/include/db.h @@ -0,0 +1,20 @@ +#ifndef DB_H +#define DB_H + +#include +#include +#include +#include +#include +#include + + +#include "strnatcmp.h" + +#include "repl.h" +#include "parser.h" +#include "storage.h" +#include "str.h" + + +#endif \ No newline at end of file diff --git a/include/parser.h b/include/parser.h new file mode 100644 index 0000000..2e46967 --- /dev/null +++ b/include/parser.h @@ -0,0 +1,17 @@ +#ifndef PARSER_H +#define PARSER_H + +#include "db.h" + + +typedef enum { + META_COMMAND_SUCCESS, + META_COMMAND_FAIL, +} metaCommandStatus; + + +int handleMetaCommand(inputBuffer *in); + +int handleInput(inputBuffer *in); + +#endif \ No newline at end of file diff --git a/include/repl.h b/include/repl.h new file mode 100644 index 0000000..9c9fb8e --- /dev/null +++ b/include/repl.h @@ -0,0 +1,20 @@ +#ifndef REPL_H +#define REPL_H + +#include "db.h" + +typedef struct { + char *buffer; + ssize_t inputSize; +} inputBuffer; + + +inputBuffer *newInputBuffer(void); + +void freeInputBuffer(inputBuffer *in); + +void getInput(inputBuffer *in); + +void prompt(void); + +#endif \ No newline at end of file diff --git a/include/storage.h b/include/storage.h new file mode 100644 index 0000000..507c733 --- /dev/null +++ b/include/storage.h @@ -0,0 +1,26 @@ +#ifndef STORAGE_H +#define STORAGE_H + +#include "db.h" + +#define MAXPATH 4096 +#define MAXTAGS 4096 + + +// When intializing the struct, it is recommended +// to also initialize numTags and lenTags +typedef struct{ + char path[MAXPATH]; + char tags[MAXTAGS]; + uint16_t numTags; + uint16_t lenTags; +} row; + + +row *newRow(const char *path); + +void insertTag(row *r, char *tag); + +void removeTag(row *r, char *tag); + +#endif \ No newline at end of file diff --git a/include/str.h b/include/str.h new file mode 100644 index 0000000..ffda145 --- /dev/null +++ b/include/str.h @@ -0,0 +1,14 @@ +#ifndef STRINGS_H +#define STRINGS_H + +#include "db.h" + + +uint16_t len(const char *s); + +bool sameStr(const char *s1, const char *s2); + +ssize_t strInTags(const char *tags, int n, const char *ndl, int m, char sep); + + +#endif \ No newline at end of file diff --git a/include/strnatcmp.h b/include/strnatcmp.h new file mode 100644 index 0000000..9d98198 --- /dev/null +++ b/include/strnatcmp.h @@ -0,0 +1,31 @@ +/* -*- mode: c; c-file-style: "k&r" -*- + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000, 2004 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +/* CUSTOMIZATION SECTION + * + * You can change this typedef, but must then also change the inline + * functions in strnatcmp.c */ +typedef char nat_char; + +int strnatcmp(nat_char const *a, nat_char const *b); +int strnatcasecmp(nat_char const *a, nat_char const *b); \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..c3b2a67 --- /dev/null +++ b/src/main.c @@ -0,0 +1,38 @@ +#include "db.h" + + +int main(){ + + inputBuffer *in = newInputBuffer(); + + + row r = {"C:/xd", "perro", 1, 5}; + printf("%s %d %d\n", r.tags, r.numTags, r.lenTags); + insertTag(&r, "caca"); + insertTag(&r, "mierda"); + insertTag(&r, "perra"); + insertTag(&r, "tu"); + printf("%s %d %d\n", r.tags, r.numTags, r.lenTags); + + printf("%d\n", strInTags(r.tags, r.lenTags, ";perro", 6, ';')); + + row *r2 = newRow("test1test2test3testtesttesttesttesttettesttestestest"); + + while(0){ + + prompt(); + getInput(in); + + insertTag(r2, in->buffer); + printf("Tags of row '%s': %s\n", r2->path, r2->tags); + + /*switch(handleInput(in)){ + case META_COMMAND_SUCCESS: + printf("we done it nigger\n"); + break; + case META_COMMAND_FAIL: + printf("uh-oh nigga i dunno what '%s' is!\n", in->buffer); + break; + }*/ + } +} \ No newline at end of file diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..f26a0cb --- /dev/null +++ b/src/parser.c @@ -0,0 +1,20 @@ +#include "db.h" + + +int handleMetaCommand(inputBuffer *in){ + if(sameStr(in->buffer, ".exit")){ + freeInputBuffer(in); + printf("EXIT M'NIGGA\n"); + exit(EXIT_SUCCESS); + }else{ + return META_COMMAND_FAIL; + } +} + +int handleInput(inputBuffer *in){ + if(in->buffer[0] == '.'){ + return handleMetaCommand(in); + }else{ + printf("normal command\n"); + } +} \ No newline at end of file diff --git a/src/repl.c b/src/repl.c new file mode 100644 index 0000000..c63ad44 --- /dev/null +++ b/src/repl.c @@ -0,0 +1,30 @@ +#include "db.h" + + +inputBuffer *newInputBuffer(void){ + inputBuffer *in = malloc(sizeof(inputBuffer)); + in->buffer = NULL; + in->inputSize = 0; + + return in; +} + +void freeInputBuffer(inputBuffer *in){ + free(in->buffer); + free(in); +} + +void getInput(inputBuffer *in){ + size_t n; + ssize_t r = getline(&(in->buffer), &n, stdin); + if(r <= 0){ + printf("Error\n"); + exit(r); + } + in->inputSize = r-1; + in->buffer[in->inputSize] = 0; +} + +void prompt(void){ + printf("db > "); +} \ No newline at end of file diff --git a/src/storage.c b/src/storage.c new file mode 100644 index 0000000..f934c4f --- /dev/null +++ b/src/storage.c @@ -0,0 +1,160 @@ +#include "db.h" + + +row *newRow(const char path[MAXPATH]){ + row *nr = malloc(sizeof(row)); + memcpy(nr->path, path, MAXPATH); + memcpy(nr->tags, "\0", MAXTAGS); + nr->numTags = 0; + nr->lenTags = 0; + + return nr; +} + +// Splits src into words based on a separator character (sep) and stores them in arr, +// and the length in len. Inspired by https://github.com/joshdk/tag/blob/master/src/dsv.c's split +static void split(const char *src, char sep, char ***arr, int *len){ + int slen = 0, ai = 0, wnum = 0, wlen = 0; + + while(src[slen] != '\0'){ + if(src[slen] == sep){ + ++wnum; + } + ++slen; + } + if(slen != 0 && src[slen-1] != sep){ + ++wnum; + } + ++slen; + + *arr = calloc((wnum+1), sizeof(char*)); + for(int i = 0; i < slen; ++i){ + if(src[i] == sep || src[i] == '\0'){ + (*arr)[ai] = calloc(wlen+1, sizeof(char)); + for(int j = i-wlen, k = 0; j < i; ++j, ++k){ + (*arr)[ai][k] = src[j]; + } + ++ai; + wlen = 0; + }else{ + ++wlen; + } + } + *len = wnum; +} + +static void swapWords(char ***arr, int a, int b){ + char *tmp = (*arr)[a]; + (*arr)[a] = (*arr)[b]; + (*arr)[b] = tmp; +} + +static char *normalizeTag(char *tag){ + uint16_t l = len(tag); + char *ntag = calloc(l+1, sizeof(char)); + for(int i = 0; i < l; ++i){ + ntag[i] = tolower(tag[i]); + } + return ntag; +} + +// Adds a tag in the tags array in the row r, sorted by natural string +// comparison with strnatcmp. We assume that when adding a tag all other +// tags are already sorted. Nothing is done if the tag is already in the tags +void insertTag(row *r, char *tag){ + int l, ltag = len(tag); + if(ltag == 0){ + return; + } + + tag = normalizeTag(tag); + + // Dump tags into array of strings and add tag + char **arr, **tmp; + split(r->tags, ';', &arr, &l); + + if((tmp = realloc(arr, (l+1)*sizeof(char*))) != NULL){ + arr = tmp; + tmp = NULL; + }else{ + fprintf(stderr, "Error reallocating array (insertTag)"); + exit(EXIT_FAILURE); + } + arr[l] = malloc((len(tag)+1)*sizeof(char)); + strcpy(arr[l], tag); + + // Sort tag by natural string comparison, starting from the last element (the new tag) + for(int i = l; i > 0; --i){ + switch(strnatcmp(arr[i-1], arr[i])){ + case 1: + // arr[i-1] is higher than arr[i]; swap them + swapWords(&arr, i, i-1); + break; + case -1: + // arr[i-1] is lower than arr[i]; exit loop + i = 0; + break; + case 0: + // The tag already exists, no need to alter anything + free(arr); + return; + } + } + ++l; // Succesfully added new tag + + // Insert tags back into tags member of row structure with the ';' separator in between them + int tagnum = 0; + for(int i = 0; i < l; ++i){ + int j = 0; + while(arr[i][j] != '\0'){ + r->tags[tagnum] = arr[i][j]; + ++j; + ++tagnum; + } + r->tags[tagnum++] = ';'; + } + r->tags[tagnum] = '\0'; + r->numTags = l; + r->lenTags = tagnum; +} + +// Remove a tag from the tags array in the row r +// Nothing is done if the tag isnt in the tags +void removeTag(row *r, char *tag){ + int l, ltag = len(tag); + if(ltag == 0){ + return; + } + + tag = normalizeTag(tag); + + // Dump tags into array of strings + char **arr; + split(r->tags, ';', &arr, &l); + + // Search for tag and remove it + for(int i = 0; i <= l; ++i){ + if(sameStr(arr[i], tag)){ + for(int j = i; j < l; ++j){ + arr[j] = arr[j+1]; + } + --l; + break; + } + } + + // Insert tags back into tags member of row structure with the ';' separator in between them + int tagnum = 0; + for(int i = 0; i < l; ++i){ + int j = 0; + while(arr[i][j] != '\0'){ + r->tags[tagnum] = arr[i][j]; + ++j; + ++tagnum; + } + r->tags[tagnum++] = ';'; + } + r->tags[tagnum] = '\0'; + r->numTags = l; + r->lenTags = tagnum; +} \ No newline at end of file diff --git a/src/str.c b/src/str.c new file mode 100644 index 0000000..9cf5685 --- /dev/null +++ b/src/str.c @@ -0,0 +1,59 @@ +#include "db.h" + + +uint16_t len(const char *s){ + uint16_t l = -1; + while(s[++l]); + return l; +} + +bool sameStr(const char *s1, const char *s2){ + uint16_t i1 = 0, i2 = 0; + while(s1[i1] && s2[i2] && s1[i1] == s2[i2]) + ++i1, ++i2; + return !s1[i1] && !s2[i2]; +} + +// Auxiliary function for creating a lookup table of the haystack +// table[i] will be the number of shifts right until the next +// separator when checking position i +// Only really useful for this implementation of tags +static int *table(const char *y, int n, char sep){ + int *tb = calloc(n, sizeof(int)); + if(tb == NULL){ + fprintf(stderr, "Error callocating array (table)"); + exit(EXIT_FAILURE); + } + + int lSep = n-1; + for(int i = n-1; i >= 0; --i){ + if(y[i] == sep){ + tb[i] = 1; + lSep = i; + }else if(y[i] != '\0'){ + tb[i] = lSep-i; + } + } + return tb; +} + +// Returns the position of ndl in tags, -1 if its not found +// A return of 0 means ndl occurs in tags starting in position 0 +// Use 'if(strInTags(...) != -1)' when using this function +ssize_t strInTags(const char *tags, int n, const char *ndl, int m, char sep){ + int *tb = table(tags, n, sep); + + for(int i = 0; i < n; ){ + int j = 0; + while(j < m && tags[i+j] == ndl[j]){ + ++j; + } + if(j == m){ + return i; + } + if(tags[i+j] != ndl[j]){ + i += tb[i]; + } + } + return -1; +} \ No newline at end of file diff --git a/src/strnatcmp.c b/src/strnatcmp.c new file mode 100644 index 0000000..46b7946 --- /dev/null +++ b/src/strnatcmp.c @@ -0,0 +1,187 @@ +/* -*- mode: c; c-file-style: "k&r" -*- + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000, 2004 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +/* partial change history: + * + * 2004-10-10 mbp: Lift out character type dependencies into macros. + * + * Eric Sosman pointed out that ctype functions take a parameter whose + * value must be that of an unsigned int, even on platforms that have + * negative chars in their default char type. + */ + +#include +#include +#include +#include + +#include "strnatcmp.h" + + +/* These are defined as macros to make it easier to adapt this code to + * different characters types or comparison functions. */ +static inline int +nat_isdigit(nat_char a) +{ + return isdigit((unsigned char) a); +} + + +static inline int +nat_isspace(nat_char a) +{ + return isspace((unsigned char) a); +} + + +static inline nat_char +nat_toupper(nat_char a) +{ + return toupper((unsigned char) a); +} + + + +static int +compare_right(nat_char const *a, nat_char const *b) +{ + int bias = 0; + + /* The longest run of digits wins. That aside, the greatest + value wins, but we can't know that it will until we've scanned + both numbers to know that they have the same magnitude, so we + remember it in BIAS. */ + for (;; a++, b++) { + if (!nat_isdigit(*a) && !nat_isdigit(*b)) + return bias; + else if (!nat_isdigit(*a)) + return -1; + else if (!nat_isdigit(*b)) + return +1; + else if (*a < *b) { + if (!bias) + bias = -1; + } else if (*a > *b) { + if (!bias) + bias = +1; + } else if (!*a && !*b) + return bias; + } + + return 0; +} + + +static int +compare_left(nat_char const *a, nat_char const *b) +{ + /* Compare two left-aligned numbers: the first to have a + different value wins. */ + for (;; a++, b++) { + if (!nat_isdigit(*a) && !nat_isdigit(*b)) + return 0; + else if (!nat_isdigit(*a)) + return -1; + else if (!nat_isdigit(*b)) + return +1; + else if (*a < *b) + return -1; + else if (*a > *b) + return +1; + } + + return 0; +} + + +static int strnatcmp0(nat_char const *a, nat_char const *b, int fold_case) +{ + int ai, bi; + nat_char ca, cb; + int fractional, result; + + assert(a && b); + ai = bi = 0; + while (1) { + ca = a[ai]; cb = b[bi]; + + /* skip over leading spaces or zeros */ + while (nat_isspace(ca)) + ca = a[++ai]; + + while (nat_isspace(cb)) + cb = b[++bi]; + + /* process run of digits */ + if (nat_isdigit(ca) && nat_isdigit(cb)) { + /* + Modified by Soikk for the purpose of DB + To revert to original version, remove this comment, + the uncommented code inside this if statement and + uncomment the remaining piece of code inside this + if statement + */ + if ((result = compare_right(a+ai, b+bi)) != 0) + return result; + /*fractional = (ca == '0' || cb == '0'); + + if (fractional) { + if ((result = compare_left(a+ai, b+bi)) != 0) + return result; + } else { + if ((result = compare_right(a+ai, b+bi)) != 0) + return result; + }*/ + } + + if (!ca && !cb) { + /* The strings compare the same. Perhaps the caller + will want to call strcmp to break the tie. */ + return 0; + } + + if (fold_case) { + ca = nat_toupper(ca); + cb = nat_toupper(cb); + } + + if (ca < cb) + return -1; + else if (ca > cb) + return +1; + + ++ai; ++bi; + } +} + + + +int strnatcmp(nat_char const *a, nat_char const *b) { + return strnatcmp0(a, b, 0); +} + + +/* Compare, recognizing numeric string and ignoring case. */ +int strnatcasecmp(nat_char const *a, nat_char const *b) { + return strnatcmp0(a, b, 1); +} \ No newline at end of file