From 04e39575f548671906d9292cb0a02dbded3177e8 Mon Sep 17 00:00:00 2001 From: Tristan Riehs Date: Thu, 16 Jul 2026 12:01:38 +0200 Subject: Factorize edit commands There is probably still a lot of room for improvement though. --- src/main.c | 198 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 108 insertions(+), 90 deletions(-) diff --git a/src/main.c b/src/main.c index 4d2a185..8f221cf 100644 --- a/src/main.c +++ b/src/main.c @@ -612,11 +612,116 @@ step4: sqlite3_close(db); } +static void ftag_edit_usage(int file_or_tag) +{ + printf("Usage: ftag %s edit [-h] [-n] %s...\n", + file_or_tag ? "file" : "tag", + file_or_tag ? "FILE" : "TAG"); +} + +/* Check whether the entry we are querying exists or not. _SHALL_EXIST is a + * boolean indicating whether it is supposed to exist or not. If this callback + * is ever called, then the entry exists. */ +static int +ftag_shall_exist_callback(void *_shall_exist, int, char **cols, char **) +{ + int shall_exist = (intptr_t)_shall_exist; + assert(cols[0]); + if (!shall_exist) { + fprintf(stderr, + "ftag: error: entry \"%s\" already exists\n", cols[0]); + } + return !shall_exist; +} + +/* Callback for retrieving the description of an item and store it to *_OLD. */ +static int ftag_edit_desc_callback(void *_old, int, char **cols, char **) +{ + char **old = _old; + assert(cols); + assert(cols[0]); + *old = strdup(cols[0]); + return 0; +} + +/* Common core of "ftag file edit" and "ftag tag edit". If FILE_OR_TAG is + * non-zero, then "ftag file edit" is performed, else "ftag tag edit" is + * performed. */ +static void ftag_common_edit(int argc, char **argv, int file_or_tag) +{ + int opt; + int edit_name = 0; + char *table_name = file_or_tag ? "files" : "tags"; + char *name_column_name = file_or_tag ? "canonical_name" : "name"; + char *column_name; + char *optstring = "hn"; + char *name = NULL; + sqlite3 *db; + int rc; + char sql[512]; + char *old; + char *new; + optind = 1; + while ((opt = getopt(argc, argv, optstring)) != -1) { + switch (opt) { + case 'h': + ftag_edit_usage(file_or_tag); + exit(EXIT_SUCCESS); + case 'n': + edit_name = 1; + break; + case '?': + default: + ftag_edit_usage(file_or_tag); + exit(EXIT_FAILURE); + } + } + if (argc - optind != 1) { + ftag_edit_usage(file_or_tag); + exit(EXIT_FAILURE); + } + name = strdup(argv[optind]); + sanitize_sql_str(&name); + db = ftag_db_open(); + strbuild(sql, "SELECT %s FROM %s WHERE %s = '%s';", name_column_name, table_name, name_column_name, name); + rc = sqlite3_exec(db, sql, ftag_shall_exist_callback, (void *)1, NULL); + sqlite3_check(rc, db); + if (edit_name) { + column_name = name_column_name; + old = strdup(name); + } + else { + column_name = "description"; + strbuild(sql, "SELECT description FROM %s WHERE %s = '%s';", + table_name, name_column_name, name); + rc = sqlite3_exec(db, sql, ftag_edit_desc_callback, &old, NULL); + sqlite3_check(rc, db); + } + new = edit(old); + printf("%s: old content: %s\n", __func__, old); + printf("%s: new content: %s\n", __func__, new); + sanitize_sql_str(&new); + /* TODO: fix isse with UTF-8 and sanitize_sql_str */ + strbuild(sql, "UPDATE %s SET %s = '%s' WHERE %s = '%s';", table_name, column_name, new, name_column_name, name); + rc = sqlite3_exec(db, sql, NULL, NULL, NULL); + sqlite3_check(rc, db); + free(name); + free(old); + free(new); + sqlite3_close(db); +} + +static void ftag_file_edit(int argc, char **argv) +{ + ftag_common_edit(argc, argv, 1); +} + static void ftag_file_help(int, char **) { puts("Usage: ftag file COMMAND [ARG]..."); puts("Available values for COMMAND:"); puts(" add add files to the database"); + puts(" edit edit a file's entry in the database"); puts(" help print this help"); puts(" list list files in the database"); puts(" tag add tags to files"); @@ -681,10 +786,10 @@ static void ftag_file(int argc, char **argv) assert_db_exists(); const struct ftag_command file_commands[] = { {.name = "add", .func = ftag_file_add}, + {.name = "edit", .func = ftag_file_edit}, {.name = "help", .func = ftag_file_help}, {.name = "list", .func = ftag_file_list}, {.name = "tag", .func = ftag_file_tag} - /* TODO: add an edit command */ }; const int file_command_count = sizeof(file_commands)/ sizeof(struct ftag_command); parse_args(argc - 1, argv + 1, file_commands, file_command_count); @@ -967,21 +1072,6 @@ static void ftag_sync(int argc, char **argv) parse_args(argc - 1, argv + 1, sync_commands, sync_command_count); } -/* Check whether the entry we are querying exists or not. _SHALL_EXIST is a - * boolean indicating whether it is supposed to exist or not. If this callback - * is ever called, then the entry exists. */ -static int -ftag_tag_shall_exist_callback(void *_shall_exist, int, char **cols, char **) -{ - int shall_exist = (intptr_t)_shall_exist; - assert(cols[0]); - if (!shall_exist) { - fprintf(stderr, - "ftag: error: entry \"%s\" already exists\n", cols[0]); - } - return !shall_exist; -} - static void ftag_tag_add(int argc, char **argv) { if (argc != 3) { @@ -1001,7 +1091,7 @@ static void ftag_tag_add(int argc, char **argv) strbuild(sql, "SELECT name FROM tags WHERE name = '%s';", new_tag_name); rc = sqlite3_exec(db, sql, - ftag_tag_shall_exist_callback, (void *)0, NULL); + ftag_shall_exist_callback, (void *)0, NULL); sqlite3_check(rc, db); int next_id = table_next_id(db, "tags"); char *new_tag_desc = strdup(argv[2]); @@ -1016,81 +1106,9 @@ static void ftag_tag_add(int argc, char **argv) free(new_tag_desc); } -static int tag_edit_desc_callback(void *_old, int, char **cols, char **) -{ - char **old = _old; - assert(cols); - assert(cols[0]); - *old = strdup(cols[0]); - return 0; -} - -static void ftag_tag_edit_usage(void) -{ - puts("Usage: ftag tag edit [-h] [-n] NAME..."); -} - static void ftag_tag_edit(int argc, char **argv) { - int opt; - int edit_name = 0; - char *column_name; - char *optstring = "hn"; - char *tag_name = NULL; - sqlite3 *db; - int rc; - char sql[512]; - char *old; - char *new; - optind = 1; - while ((opt = getopt(argc, argv, optstring)) != -1) { - switch (opt) { - case 'h': - printf("Usage: ftag tag edit [-h] [-n] NAME...\n"); - exit(EXIT_SUCCESS); - case 'n': - edit_name = 1; - break; - case '?': - default: - ftag_tag_edit_usage(); - exit(EXIT_FAILURE); - } - } - if (argc - optind != 1) { - ftag_tag_edit_usage(); - exit(EXIT_FAILURE); - } - tag_name = strdup(argv[optind]); - sanitize_sql_str(&tag_name); - db = ftag_db_open(); - strbuild(sql, "SELECT name FROM tags WHERE name = '%s';", tag_name); - rc = sqlite3_exec(db, sql, ftag_tag_shall_exist_callback, (void *)1, NULL); - sqlite3_check(rc, db); - if (edit_name) { - column_name = "name"; - old = strdup(tag_name); - } - else { - column_name = "description"; - strbuild(sql, "SELECT description FROM tags WHERE name = '%s';", - tag_name); - rc = sqlite3_exec(db, sql, tag_edit_desc_callback, &old, NULL); - sqlite3_check(rc, db); - } - new = edit(old); - printf("%s: old content: %s\n", __func__, old); - printf("%s: new content: %s\n", __func__, new); - sanitize_sql_str(&new); - /* TODO: fix isse with UTF-8 and sanitize_sql_str */ - strbuild(sql, "UPDATE tags SET %s = '%s' WHERE name = '%s';", column_name, new, tag_name); - printf("debug: SQL query: \"%s\"\n", sql); - rc = sqlite3_exec(db, sql, NULL, NULL, NULL); - sqlite3_check(rc, db); - free(tag_name); - free(old); - free(new); - sqlite3_close(db); + ftag_common_edit(argc, argv, 0); } static void ftag_tag_help(int, char **) -- cgit v1.2.3