+1660409336 (Sat Aug 13 2022 18:48:56 GMT+0200 (Central European Summer Time))
+Added primitive repl, delete functions for database and remove tag from file function.
+
1660003394 (Tue Aug 09 2022 02:03:14 GMT+0200 (Central European Summer Time))
Improved database name system.
OBSERVATIONS
+Notation:
+ CREATE miDB -> creates new database called miDB.
+ CREATE miDB miDB2 -> creates two new databases
+ CREATE "miDB miDB2" -> creates a new database called "miDB miDB2" (without the quotation marks).
+
+ OPEN ..
+
+ TAG file WITH tag -> adds tag to file
+ TAG file1 file2 WITH tag -> adds tag to file1, file2
+ TAG file WITH tag1 tag2 -> adds tag1, tag2 to file
+
+
STORAGE
LTABLE
static void decreaseCount(ctable *ct, uint64_t i);
Auxiliary function that decreases the count of cell i at ct's table;
- static int addRelation(database *db, relation r);
- Auxiliary function that adds a relation to the mapping table in db.
- This function returns 0 if r was inserted correctly or -1 if r was already on the database.
-
- int addFileTag(database *db, char *file, char *tag);
- This function uses the auxiliary functions addRelation and increaseCount.
- Adds a file and a tag to the database, and its relation.
- If the file or the tag or both were already on the database, it still adds the relation.
- If the relation wasn't in the database, it adds one to the cfiles' table for the file index and another one to the ctags' table for the file index, and then returns 0.
- If the relation was in the database, it returns -1.
-
- int addFileTags(database *db, char *file, int ntags, ...);
- Adds multiple tags to a single file using addFileTag.
- Returns 0 upon completion.
-
- int addTagFiles(database *db, char *tag, int nfiles, ...);
- Adds the same tag to multiple files using addFileTag.
- Returns 0 upon completion.
-
static void decreaseHigherIndexNode(node *n, uint64_t i);
Auxiliary function that decreases the indexes in the node structure of n by one if they're bigger than i.
To counter this, we use the auxiliary functions decreaseHigherIndexNode and decreaseHigherTagIndexMap to update all the higher indexes in htags and map.
This function returns 0 upon completion or -1 if the tag is not in the database.
+ static int addRelation(database *db, relation r);
+ Auxiliary function that adds a relation to the mapping table in db.
+ This function returns 0 if r was inserted correctly or -1 if r was already on the database.
+
+ int addFileTag(database *db, char *file, char *tag);
+ This function uses the auxiliary functions addRelation and increaseCount.
+ Adds a file and a tag to the database, and its relation.
+ If the file or the tag or both were already on the database, it still adds the relation.
+ If the relation wasn't in the database, it adds one to the cfiles' table for the file index and another one to the ctags' table for the file index, and then returns 0.
+ If the relation was in the database, it returns -1.
+
+ int addFileTags(database *db, char *file, int ntags, ...);
+ Adds multiple tags to a single file using addFileTag.
+ Returns 0 upon completion.
+
+ int addTagFiles(database *db, char *tag, int nfiles, ...);
+ Adds the same tag to multiple files using addFileTag.
+ Returns 0 upon completion.
+
int searchFile(database *db, char *file, uint64_t n, uint64_t **r, uint64_t *rl);
Stores in r a list with the indexes of the first n tags that this file has.
If n is 0, it returns all of them. Stores in rl the length of r.
+TODO Show files with multiple tags & viceversa
+
TODO Get rid of old functionalities (strnatcmp, BM)
----------------------------------------------------------------
+DONE Add remove tag from file function
+
+DONE Add delete functions
+
DONE Must update all indexes in map when removing a file or a tag
DONE Standarize function names
database *newDatabase(char *name);
+int freeDatabase(database **db);
+
+int deleteDatabase(database **db);
+
uint64_t addFile(database *db, char *file);
uint64_t addTag(database *db, char *tag);
+int removeFile(database *db, char *file);
+
+int removeTag(database *db, char *tag);
+
int addFileTag(database *db, char *file, char *tag);
int addFileTags(database *db, char *file, int ntags, ...);
int addTagFiles(database *db, char *tag, int nfiles, ...);
-int removeFile(database *db, char *file);
-
-int removeTag(database *db, char *tag);
+int removeFileTag(database *db, char *file, char *tag);
int searchFile(database *db, char *file, uint64_t n, uint64_t **r, uint64_t *rl);
void printDatabase(database *db);
-void debugAVLtree(node *n);
-
void debugDatabase(database *db);
#endif
#include "strnatcmp.h"
#include "crc64.h"
-#include "repl.h"
-#include "parser.h"
+#include "str.h"
#include "storage.h"
#include "database.h"
-#include "str.h"
+#include "repl.h"
+#include "parser.h"
#include "bm.h"
#endif
#include "db.h"
-typedef enum {
+#define NKEYWORDS 16
+#define EXIT_CODE 1
+
+typedef enum{
+ COMMAND_EXIT, COMMAND_DEBUG,
+ COMMAND_CREATE, COMMAND_DELETE, COMMAND_OPEN, COMMAND_SAVE, COMMAND_CLOSE,
+ COMMAND_ADDF, COMMAND_ADDT, COMMAND_DELETEF, COMMAND_DELETET,
+ COMMAND_TAG, COMMAND_REMOVE,
+ COMMAND_SHOW, COMMAND_SHOWT, COMMAND_SHOWF,
+} COMMANDS;
+
+typedef enum{
META_COMMAND_SUCCESS,
META_COMMAND_FAIL,
} metaCommandStatus;
+typedef struct{
+ uint64_t argc;
+ char **argv;
+} argList;
+
+
+argList *newArgList(void);
+
+argList *splitInput(inputBuffer *in);
int handleMetaCommand(inputBuffer *in);
-int handleInput(inputBuffer *in);
+int handleInput(argList *args, database **db);
-#endif
\ No newline at end of file
+#endif
#include "db.h"
-typedef struct {
+typedef struct{
char *buffer;
- ssize_t inputSize;
+ int64_t inputSize;
} inputBuffer;
void getInput(inputBuffer *in);
-void prompt(void);
+void prompt(database *db);
#endif
ltable *newLtable(uint64_t size);
+int deleteLtable(ltable **lt);
+
int insertLtable(ltable *lt, char *str);
int removeLtable(ltable *lt, char *str);
ctable *newCtable(uint64_t size);
+int deleteCtable(ctable **ct);
+
int insertCtable(ctable *ct, uint64_t n);
int removeCtable(ctable *ct, uint64_t n);
mtable *newMtable(uint64_t size);
+int deleteMtable(mtable **mt);
+
int insertMtable(mtable *mt, relation r);
int removeMtable(mtable *mt, relation r);
node *newNode(uint64_t h, uint64_t i);
+int deleteTree(tree *root);
+
node *insertNode(node *r, uint64_t h, uint64_t i);
node *removeNode(node *r, uint64_t h);
return db;
}
+int freeDatabase(database **db){
+ deleteLtable(&(*db)->lfiles);
+ deleteLtable(&(*db)->ltags);
+ deleteCtable(&(*db)->cfiles);
+ deleteCtable(&(*db)->ctags);
+ deleteTree(&(*db)->hfiles);
+ deleteTree(&(*db)->htags);
+ deleteMtable(&(*db)->map);
+ free((*db)->name);
+ free(*db);
+ *db = NULL;
+ return 0;
+}
+
+int deleteDatabase(database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: can't delete NULL database\n");
+ return -1;
+ }
+ int r = remove((*db)->name);
+ if(r != 0){
+ fprintf(stderr, "Error deleting database '%s'\n", (*db)->name);
+ return -1;
+ }
+ freeDatabase(db);
+ return 0;
+}
+
uint64_t addFile(database *db, char *file){
uint32_t l;
file = normalizeStrLimit(file, &l, MAXPATH-1);
ct->table[i]--;
}
-static int addRelation(database *db, relation r){
- if(searchMtable(db->map, r) == UINTMAX_MAX){
- insertMtable(db->map, r);
- return 0;
- }
- return -1;
-}
-
-int addFileTag(database *db, char *file, char *tag){
- uint64_t fi = addFile(db, file), ti = addTag(db, tag);
- int r = addRelation(db, (relation){.file = fi, .tag = ti});
- if(r == 0){
- increaseCount(db->cfiles, fi);
- increaseCount(db->ctags, ti);
- return 0;
- }
- return -1;
-}
-
-int addFileTags(database *db, char *file, int ntags, ...){
- va_list tags;
- va_start(tags, ntags);
- for(uint64_t i = 0; i < ntags; ++i){
- char *tag = va_arg(tags, char*);
- addFileTag(db, file, tag);
- }
- va_end(tags);
- return 0;
-}
-
-int addTagFiles(database *db, char *tag, int nfiles, ...){
- va_list files;
- va_start(files, nfiles);
- for(uint64_t i = 0; i < nfiles; ++i){
- char *file = va_arg(files, char*);
- addFileTag(db, file, tag);
- }
- va_end(files);
- return 0;
-}
-
static void decreaseHigherIndexNode(node *n, uint64_t i){
if(n == NULL){
return;
return 0;
}
+static int addRelation(database *db, relation r){
+ if(searchMtable(db->map, r) == UINTMAX_MAX){
+ insertMtable(db->map, r);
+ return 0;
+ }
+ return -1;
+}
+
+int addFileTag(database *db, char *file, char *tag){
+ uint64_t fi = addFile(db, file), ti = addTag(db, tag);
+ int r = addRelation(db, (relation){.file = fi, .tag = ti});
+ if(r == 0){
+ increaseCount(db->cfiles, fi);
+ increaseCount(db->ctags, ti);
+ return 0;
+ }
+ return -1;
+}
+
+int addFileTags(database *db, char *file, int ntags, ...){
+ va_list tags;
+ va_start(tags, ntags);
+ for(uint64_t i = 0; i < ntags; ++i){
+ char *tag = va_arg(tags, char*);
+ addFileTag(db, file, tag);
+ }
+ va_end(tags);
+ return 0;
+}
+
+int addTagFiles(database *db, char *tag, int nfiles, ...){
+ va_list files;
+ va_start(files, nfiles);
+ for(uint64_t i = 0; i < nfiles; ++i){
+ char *file = va_arg(files, char*);
+ addFileTag(db, file, tag);
+ }
+ va_end(files);
+ return 0;
+}
+
+int removeFileTag(database *db, char *file, char *tag){
+ uint32_t lf, lt;
+ file = normalizeStrLimit(file, &lf, MAXPATH-1);
+ tag = normalizeStrLimit(tag, <, MAXPATH-1);
+ uint64_t hf = crc64(0, file, lf), ht = crc64(0, tag, lt);
+ uint64_t fi = searchNode(db->hfiles, hf), ti = searchNode(db->htags, ht);
+ if(fi == UINTMAX_MAX){
+ fprintf(stderr, "Error: no such file '%s'\n", file);
+ return -1;
+ }
+ if(ti == UINTMAX_MAX){
+ fprintf(stderr, "Error: no such tag '%s'\n", tag);
+ return -1;
+ }
+ int status = removeMtable(db->map, (relation){.file = fi, .tag = ti});
+ if(status == -1){
+ fprintf(stderr, "Error: tag '%s' not associated with file '%s'\n", tag, file);
+ return -1;
+ }
+ return 0;
+}
+
int searchFile(database *db, char *file, uint64_t n, uint64_t **r, uint64_t *rl){
uint32_t l;
file = normalizeStrLimit(file, &l, MAXPATH-1);
database *loadDatabase(const char* path){
FILE *fp = fopen(path, "rb");
+ if(fp == NULL){
+ fprintf(stderr, "Error: no such file (%s)\n", path);
+ return NULL;
+ }
char *header = calloc(2, sizeof(char));
fread(header, sizeof(char), 2, fp);
if(!sameStr(header, "DB")){
printf("\n");
}
-void debugAVLtree(node *n){
+static void debugAVLtree(node *n){
if(n != NULL){
printf("\t\t+ %" PRIu64 " -> %" PRIu64 "\n", n->h, n->i);
debugAVLtree(n->left);
}
void debugDatabase(database *db){
+ if(db == NULL){
+ fprintf(stderr, "Error: database is NULL\n");
+ return;
+ }
printf("\n");
printf("Name: %s\n", db->name);
printf("\t-lfiles: %d\n", db->lfiles->size);
int main(){
+
inputBuffer *in = newInputBuffer();
- database *db = newDatabase("miDB");
+ /*database *test = newDatabase("miDB");
- addFileTag(db, "vaca.png", "naturalezas");
- addFileTags(db, "terry-davis.jpg", 3, "holyC", "programmer", "very cool");
- addFileTag(db, "vaca.png", "lovely");
- addFileTags(db, "vaca.png", 3, "nature", "animal", "very cool");
- addFileTag(db, "terry-davis.jpg", "based");
+ addFileTag(test, "vaca.png", "naturalezas");
+ addFileTags(test, "terry-davis.jpg", 3, "holyC", "programmer", "very cool");
+ addFileTag(test, "vaca.png", "lovely");
+ addFileTags(test, "vaca.png", 3, "nature", "animal", "very cool");
+ addFileTag(test, "terry-davis.jpg", "based");
- storeDatabase(db, "db.db");
+ storeDatabase(test, "db.db");
printDatabase(db);
for(uint64_t j = 0; j < i; ++j){
printf("\t%s\n", db->ltags->table[l[j]]);
- }
-
-
-
- while(0){
+ }*/
- prompt();
+ database *db = NULL;
+ while(1){
+ prompt(db);
getInput(in);
-
- /*
- insertTag(r, in->buffer);
- printf("Tags of row '%s': %s\n", r->path, r->tags);
- printf("Number of tags: %u. Length of tags: %u\n", r->numTags, r->lenTags);
- */
-
- /*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;
- }*/
+ argList *args = splitInput(in);
+ int status = handleInput(args, &db);
+ if(status == EXIT_CODE){
+ printf("Exiting db\n");
+ break;
+ }
}
return 0;
#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;
+char *keywords[NKEYWORDS] = {"EXIT", "DEBUG",
+ "CREATE", "DELETE", "OPEN", "SAVE", "CLOSE",
+ "ADDF", "ADDT", "DELETEF", "DELETET",
+ "TAG", "REMOVE",
+ "SHOW", "SHOWT", "SHOWF"};
+
+argList *newArgList(void){
+ argList *args = malloc(sizeof(argList));
+ args->argc = 0;
+ args->argv = NULL;
+ return args;
+}
+
+argList *splitInput(inputBuffer *in){
+ if(in->inputSize == 0){
+ return NULL;
+ }
+ argList *args = newArgList();
+ uint64_t len = args->argc = 0;
+
+ // Remove leading spaces
+ while(isspace(in->buffer[len])){
+ ++len;
+ }
+ // Count words (alone or quoted)
+ while(in->buffer[len] != '\0'){
+ while(isspace(in->buffer[len])){
+ ++len;
+ }
+ if(in->buffer[len] == '"'){
+ do{
+ ++len;
+ }while(in->buffer[len] != '"');
+ ++args->argc;
+ }else if(in->buffer[len] == '\''){
+ do{
+ ++len;
+ }while(in->buffer[len] != '\'');
+ ++args->argc;
+ }else{
+ while(in->buffer[len] != '\0' && !isspace(in->buffer[len])){
+ ++len;
+ }
+ ++args->argc;
+ }
+ ++len;
+ }
+ uint64_t *wstarts = malloc(args->argc*sizeof(uint64_t)), *wlens = malloc(args->argc*sizeof(uint64_t));
+ len = args->argc = 0;
+ while(in->buffer[len] != '\0'){
+ while(isspace(in->buffer[len])){
+ ++len;
+ }
+ if(in->buffer[len] == '"'){
+ wstarts[args->argc] = len+1;
+ do{
+ ++len;
+ }while(in->buffer[len] != '"');
+ wlens[args->argc] = len - wstarts[args->argc];
+ ++args->argc;
+ }else if(in->buffer[len] == '\''){
+ wstarts[args->argc] = len+1;
+ do{
+ ++len;
+ }while(in->buffer[len] != '\'');
+ wlens[args->argc] = len -wstarts[args->argc];
+ ++args->argc;
+ }else{
+ wstarts[args->argc] = len;
+ while(in->buffer[len] != '\0' && !isspace(in->buffer[len])){
+ ++len;
+ }
+ wlens[args->argc] = len - wstarts[args->argc];
+ ++args->argc;
+ }
+ ++len;
+ }
+
+ args->argv = malloc(args->argc*sizeof(char*));
+ for(uint64_t i = 0; i < args->argc; ++i){
+ args->argv[i] = calloc(wlens[i]+1, sizeof(char));
+ memcpy(args->argv[i], &in->buffer[wstarts[i]], wlens[i]);
+ }
+ return args;
+}
+
+static int commandExit(argList *args, database **db){
+ // TODO: cleanup functions
+ return EXIT_CODE;
+}
+
+static int commandDebug(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to debug\n");
+ return -1;
+ }
+ debugDatabase(*db);
+ return 0;
+}
+
+static int commandCreate(argList *args, database **db){
+ if(args->argc < 2){
+ fprintf(stderr, "Error, not enough arguments for command '%s'\n", args->argv[0]);
+ return -1;
+ }
+ for(int i = 1; i < args->argc; ++i){
+ int status = storeDatabase(newDatabase(args->argv[i]), args->argv[i]);
+ if(status != 0){
+ fprintf(stderr, "Error creating and storing database '%s'\n", args->argv[i]);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int commandDelete(argList *args, database **db){
+ if(args->argc < 2){
+ fprintf(stderr, "Error, not enough arguments for command '%s'\n", args->argv[0]);
+ return -1;
+ }
+ for(int i = 1; i < args->argc; ++i){
+ database *t = loadDatabase(args->argv[i]);
+ int status = deleteDatabase(&t);
+ if(status != 0){
+ fprintf(stderr, "Error deleting database '%s'\n", args->argv[i]);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int commandOpen(argList *args, database **db){
+ if(args->argc < 2){
+ fprintf(stderr, "Error: not enough arguments for command '%s'\n", args->argv[0]);
+ return -1;
+ }else if(args->argc > 2){
+ fprintf(stderr, "Error: too many arguments for command 'OPEN'. Only opening first one ('%s')\n", args->argv[1]);
+ }
+ if(*db != NULL){
+ fprintf(stderr, "Error: database '%s' already opened. Close it before proceeding with \"CLOSE '%s'\"\n", (*db)->name, (*db)->name);
+ return -1;
}
+ *db = loadDatabase(args->argv[1]);
+ if(*db == NULL){
+ fprintf(stderr, "Error loading database '%s'\n", args->argv[1]);
+ return -1;
+ }
+ return 0;
}
-int handleInput(inputBuffer *in){
- if(in->buffer[0] == '.'){
- return handleMetaCommand(in);
- }else{
- printf("normal command\n");
+static int commandSave(argList *args, database **db){
+ if(args->argc > 1){
+ fprintf(stderr, "Error: too many arguments for function 'SAVE'. Only saving loaded database ('%s')\n", (*db)->name);
+ }
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to save\n");
+ return -1;
+ }
+ int status = storeDatabase(*db, (*db)->name);
+ if(status != 0){
+ fprintf(stderr, "Error storing database '%s'\n", (*db)->name);
+ return -1;
+ }
+ return 0;
+}
+
+static int commandClose(argList *args, database **db){
+ if(args->argc > 1){
+ fprintf(stderr, "Error: too many arguments for function 'CLOSE'. Only closing loaded database ('%s')\n", (*db)->name);
+ }
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to close\n");
+ return -1;
+ }
+ int status = storeDatabase(*db, (*db)->name);
+ if(status != 0){
+ fprintf(stderr, "Error storing database '%s' before closing it\n", (*db)->name);
+ return -1;
+ }
+ freeDatabase(db);
+ return 0;
+}
+
+static int commandAddf(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to add files to\n");
+ return -1;
+ }
+ char **files = malloc((args->argc-1)*sizeof(char*));
+ uint64_t fi = 0;
+ for(uint64_t i = 1; i < args->argc; ++i){
+ files[fi++] = args->argv[i];
+ }
+ if(fi == 0){
+ fprintf(stderr, "Error: no files given to add to database\n");
+ return -1;
+ }
+ for(uint64_t i = 0; i < fi; ++i){
+ addFile(*db, files[i]);
+ }
+ return 0;
+}
+
+static int commandAddt(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to add tags to\n");
+ return -1;
+ }
+ char **tags = malloc((args->argc-1)*sizeof(char*));
+ uint64_t ti = 0;
+ for(uint64_t i = 1; i < args->argc; ++i){
+ tags[ti++] = args->argv[i];
+ }
+ if(ti == 0){
+ fprintf(stderr, "Error: no tags given to add to database\n");
+ return -1;
+ }
+ for(uint64_t i = 0; i < ti; ++i){
+ addTag(*db, tags[i]);
+ }
+ return 0;
+}
+
+static int commandDeletef(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to delete files from\n");
+ return -1;
+ }
+ char **files = malloc((args->argc-1)*sizeof(char*));
+ uint64_t fi = 0;
+ for(uint64_t i = 1; i < args->argc; ++i){
+ files[fi++] = args->argv[i];
+ }
+ if(fi == 0){
+ fprintf(stderr, "Error: no files given to remove from database\n");
+ return -1;
}
-}
\ No newline at end of file
+ for(uint64_t i = 0; i < fi; ++i){
+ removeFile(*db, files[i]);
+ }
+ return 0;
+}
+
+static int commandDeletet(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to remove tags from\n");
+ return -1;
+ }
+ char **tags = malloc((args->argc-1)*sizeof(char*));
+ uint64_t ti = 0;
+ for(uint64_t i = 1; i < args->argc; ++i){
+ tags[ti++] = args->argv[i];
+ }
+ if(ti == 0){
+ fprintf(stderr, "Error: no tags given to remove from database\n");
+ return -1;
+ }
+ for(uint64_t i = 0; i < ti; ++i){
+ removeTag(*db, tags[i]);
+ }
+ return 0;
+}
+
+static int commandTag(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to add files and tags to\n");
+ return -1;
+ }
+ char **files = malloc((args->argc-1)*sizeof(char*));
+ uint64_t i, fi = 0, ti = 0;
+ bool with = false;
+ for(i = 1; i < args->argc; ++i){
+ uint32_t l1, l2;
+ if(sameStr(normalizeStr(args->argv[i], &l1), normalizeStr("WITH", &l2))){
+ with = true;
+ ++i;
+ break;
+ }
+ files[fi++] = args->argv[i];
+ }
+ if(fi == 0){
+ fprintf(stderr, "Error: no files given to tag\n");
+ return -1;
+ }
+ if(with == false){
+ fprintf(stderr, "Error: missing 'WITH' keyword on 'TAG' command\n");
+ return -1;
+ }
+ char **tags = malloc((args->argc-i)*sizeof(char*));
+ for(; i < args->argc; ++i){
+ tags[ti++] = args->argv[i];
+ }
+ if(ti == 0){
+ fprintf(stderr, "Error: no tags given to tag files\n");
+ return -1;
+ }
+
+ for(uint64_t f = 0; f < fi; ++f){
+ for(uint64_t t = 0; t < ti; ++t){
+ int status = addFileTag(*db, files[f], tags[t]);
+ if(status != 0){
+ fprintf(stderr, "Error: couldnt add tag '%s' to file '%s'\n", tags[t], files[f]);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int commandRemove(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to remove files and tags from\n");
+ return -1;
+ }
+ char **tags = malloc((args->argc-1)*sizeof(char*));
+ uint64_t i, ti = 0, fi = 0;
+ bool from = false;
+ for(i = 1; i < args->argc; ++i){
+ uint32_t l1, l2;
+ if(sameStr(normalizeStr(args->argv[i], &l1), normalizeStr("FROM", &l2))){
+ from = true;
+ ++i;
+ break;
+ }
+ tags[ti++] = args->argv[i];
+ }
+ if(ti == 0){
+ fprintf(stderr, "Error: no tags given to remove\n");
+ return -1;
+ }
+ if(from == false){
+ fprintf(stderr, "Error: missing 'FROM' keyword on 'REMOVE' command\n");
+ return -1;
+ }
+ char **files = malloc((args->argc-i)*sizeof(char*));
+ for(; i < args->argc; ++i){
+ files[fi++] = args->argv[i];
+ }
+ if(fi == 0){
+ fprintf(stderr, "Error: no files given to remove\n");
+ return -1;
+ }
+
+ for(uint64_t f = 0; f < fi; ++f){
+ for(uint64_t t = 0; t < ti; ++t){
+ int status = removeFileTag(*db, files[f], tags[t]);
+ if(status != 0){
+ fprintf(stderr, "Error: couldnt remove tag '%s' from file '%s'\n", tags[t], files[f]);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int commandShow(argList *args, database **db){
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to show\n");
+ return -1;
+ }
+ printDatabase(*db);
+ return 0;
+}
+
+static int commandShowt(argList *args, database **db){
+ // We only show the files of one tag
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to show tags of file\n");
+ return -1;
+ }
+ if(args->argc > 2){
+ fprintf(stderr, "Error: too many arguments for 'SHOWT', current support for only one file. Only showing tags of first file ('%s')\n", args->argv[1]);
+ }
+
+ uint64_t rl, *r;
+ int status = searchFile(*db, args->argv[1], 0, &r, &rl);
+ if(status == -1){
+ fprintf(stderr, "Error searching for file '%s'\n", args->argv[1]);
+ return -1;
+ }
+ printf("Tags of file '%s' (%"PRIu64"):\n", args->argv[1], rl);
+ for(uint64_t i = 0; i < rl; ++i){
+ printf("\t- %s\n", (*db)->ltags->table[r[i]]);
+ }
+ printf("\n");
+}
+
+static int commandShowf(argList *args, database **db){
+ // We only show the tags of one file
+ if(*db == NULL){
+ fprintf(stderr, "Error: no database to show files of tag\n");
+ return -1;
+ }
+ if(args->argc > 2){
+ fprintf(stderr, "Error: too many arguments for 'SHOWF', current support for only one tag. Only showing files of first tag ('%s')\n", args->argv[1]);
+ }
+
+ uint64_t rl, *r;
+ int status = searchTag(*db, args->argv[1], 0, &r, &rl);
+ if(status == -1){
+ fprintf(stderr, "Error searching for tag '%s'\n", args->argv[1]);
+ return -1;
+ }
+ printf("Files of tag '%s' (%"PRIu64"):\n", args->argv[1], rl);
+ for(uint64_t i = 0; i < rl; ++i){
+ printf("\t- %s\n", (*db)->lfiles->table[r[i]]);
+ }
+ printf("\n");
+}
+
+ int (*commands[])(argList*, database**) = {
+ commandExit, commandDebug,
+ commandCreate, commandDelete, commandOpen, commandSave, commandClose,
+ commandAddf, commandAddt, commandDeletef, commandDeletet,
+ commandTag, commandRemove,
+ commandShow, commandShowt, commandShowf
+ };
+
+int handleInput(argList *args, database **db){
+ if(args == NULL){
+ return 0;
+ }
+ int command = -1;
+ for(int i = 0; i < NKEYWORDS; ++i){
+ uint32_t l1, l2;
+ if(sameStr(normalizeStr(args->argv[0], &l1), normalizeStr(keywords[i], &l2))){
+ command = i;
+ break;
+ }
+ }
+ if(command == -1){
+ fprintf(stderr, "Error: command '%s' not found\n", args->argv[0]);
+ return -1;
+ }
+ return commands[command](args, db);
+}
inputBuffer *in = malloc(sizeof(inputBuffer));
in->buffer = NULL;
in->inputSize = 0;
-
return in;
}
size_t n;
ssize_t r = getline(&(in->buffer), &n, stdin);
if(r <= 0){
- printf("Error\n");
+ fprintf(stderr, "Error\n");
exit(r);
}
in->inputSize = r-1;
in->buffer[in->inputSize] = 0;
}
-void prompt(void){
- printf("db > ");
-}
\ No newline at end of file
+void prompt(database *db){
+ if(db == NULL){
+ printf("db > ");
+ }else{
+ printf("%s > ", db->name);
+ }
+}
return lt;
}
+int deleteLtable(ltable **lt){
+ free((*lt)->table);
+ free(*lt);
+ *lt = NULL;
+ return 0;
+}
+
int insertLtable(ltable *lt, char *str){
uint32_t ls;
str = normalizeStrLimit(str, &ls, MAXPATH-1);
return ct;
}
+int deleteCtable(ctable **ct){
+ free((*ct)->table);
+ free(*ct);
+ *ct = NULL;
+ return 0;
+}
+
int insertCtable(ctable *ct, uint64_t n){
uint64_t *nct = malloc((ct->size+1)*sizeof(uint64_t));
for(uint64_t i = 0; i < ct->size; ++i){
return mt;
}
+int deleteMtable(mtable **mt){
+ free((*mt)->table);
+ free(*mt);
+ *mt = NULL;
+ return 0;
+}
+
int insertMtable(mtable *mt, relation r){
relation *nmt = malloc((mt->size+1)*sizeof(relation));
for(uint64_t i = 0; i < mt->size; ++i){
return n;
}
+int deleteTree(tree *root){
+ if(*root == NULL){
+ return -1;
+ }
+ deleteTree(&(*root)->left);
+ deleteTree(&(*root)->right);
+ free(*root);
+ *root = NULL;
+ return 0;
+}
+
static node *rotateNodeRight(node *r){
node *nr = r->left;
node *nc = nr->right;