aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c142
1 files changed, 131 insertions, 11 deletions
diff --git a/src/main.c b/src/main.c
index 2496f1d..9581d6e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -33,12 +33,20 @@ static void __sqlite3_check(int rc, sqlite3 *db, const char *file, int line, con
#define sqlite3_check(RC, DB) __sqlite3_check(RC, DB, __FILE__, __LINE__, __func__)
-static void assert_db_exists(void)
+static int file_exists(const char *path)
{
struct stat statbuf __attribute__((unused));
- int rc = stat(DATABASE_PATH, &statbuf);
-
+ int rc = stat(path, &statbuf);
if (rc == 0)
+ return 1;
+ else
+ return 0;
+}
+
+static void assert_db_exists(void)
+{
+ errno = 0;
+ if (file_exists(DATABASE_PATH) && (errno == 0))
return;
if (errno == ENOENT) {
@@ -53,6 +61,12 @@ static void assert_db_exists(void)
exit(EXIT_FAILURE);
}
+/* Make sure STR contains no single quote, not to break SQL queries. */
+static void assert_no_single_quote(const char *str)
+{
+ assert(strchr(str, '\'') == NULL);
+}
+
static void ftag_init(int, char **)
{
char cmd[1024];
@@ -71,7 +85,7 @@ static int ftag_print(void *, int, char **cols, char **)
return 0;
}
-static void ftag_list_table(const char *table)
+static void ftag_list_table(const char *table, const char *col)
{
char sql[64];
sqlite3 *db = NULL;
@@ -81,19 +95,123 @@ static void ftag_list_table(const char *table)
sqlite3_check(rc, db);
memset(sql, 0, sizeof(sql));
- snprintf(sql, sizeof(sql)-1, "SELECT name FROM %s;", table);
+ snprintf(sql, sizeof(sql)-1, "SELECT %s FROM %s;", col, table);
rc = sqlite3_exec(db, sql, ftag_print, NULL, NULL);
sqlite3_check(rc, db);
+ sqlite3_close(db);
+}
+
+static void canonicalize(char *out, const char *in)
+{
+ int i;
+ for (i = 0; i < strlen(in)-1; i++) {
+ if (in[i] > 'A' && in[i] < 'Z')
+ out[i] = in[i] - 'A' + 'a';
+ else if (in[i] == ' ')
+ out[i] = '_';
+ else
+ out[i] = in[i];
+ }
+ out[i] = '\0';
}
+static void ftag_add_one_file(sqlite3 *db,
+ int *last_id,
+ const char *file)
+{
+ char sql[2048];
+ int rc;
+ char *full_name = NULL;
+ char *canonical_name = NULL;
+ char *description = NULL;
+ size_t line_len = 0;
+ ssize_t read_len;
+
+ if (!file_exists(file)) {
+ perror(file);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("ftag file add: adding file \"%s\" to database\n", file);
+
+ printf("Enter the full name, a version of the name that\n"
+ "may contain blanks and every type of character.\n");
+ read_len = getline(&full_name, &line_len, stdin);
+ if (read_len == -1) {
+ perror("getline");
+ exit(EXIT_FAILURE);
+ }
+ assert_no_single_quote(full_name);
+
+ line_len = read_len+1;
+ canonical_name = malloc(line_len);
+ canonicalize(canonical_name, full_name);
+
+ printf("Enter the canonical name, a version of the name that\n"
+ "ideally contains no blank and, if possible, no upper\n"
+ "case letters and no symbols. If no input is given,\n"
+ "canonical name will be \"%s\".", canonical_name);
+ read_len = getline(&canonical_name, &line_len, stdin);
+ if (read_len == -1) {
+ perror("getline");
+ exit(EXIT_FAILURE);
+ }
+ assert_no_single_quote(canonical_name);
+
+ printf("Enter the description.");
+ line_len = 0;
+ read_len = getline(&description, &line_len, stdin);
+ if (read_len == -1) {
+ perror("getline");
+ exit(EXIT_FAILURE);
+ }
+ assert_no_single_quote(description);
+
+ memset(sql, 0, sizeof(sql));
+ snprintf(sql, sizeof(sql)-1,
+ "INSERT INTO files VALUES(%d, '%s', '%s', '%s')",
+ *last_id,
+ canonical_name,
+ full_name,
+ description);
+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+ sqlite3_check(rc, db);
+ (*last_id)++;
+ free(full_name);
+ free(canonical_name);
+ if(description)
+ free(description);
+}
+
+/* Add new files to the database. */
static void ftag_file_add(int argc, char **argv)
{
- ;
+ if (argc == 0) {
+ fprintf(stderr, "ftag file add: must supply file names\n");
+ exit(EXIT_FAILURE);
+ }
+ sqlite3 *db = NULL;
+ int rc;
+ int last_id;
+ rc = sqlite3_open(DATABASE_PATH, &db);
+ sqlite3_check(rc, db);
+ for (int i = 0; i < argc; i++)
+ ftag_add_one_file(db, &last_id, argv[i]);
+ sqlite3_close(db);
}
static void ftag_file_list(int argc, char **argv)
{
- ftag_list_table("files");
+ ftag_list_table("files", "full_name");
+}
+
+static void ftag_file_tag(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr,
+ "ftag file tag: must supply a file name and tags\n");
+ exit(EXIT_FAILURE);
+ }
}
static void ftag_file(int argc, char **argv)
@@ -101,7 +219,8 @@ static void ftag_file(int argc, char **argv)
assert_db_exists();
const struct ftag_command file_commands[] = {
{.name = "add", .func = ftag_file_add},
- {.name = "list", .func = ftag_file_list}
+ {.name = "list", .func = ftag_file_list},
+ {.name = "tag", .func = ftag_file_tag}
};
const int file_command_count = sizeof(file_commands) / sizeof(struct ftag_command);
parse_args(argc, argv, file_commands, file_command_count);
@@ -152,7 +271,7 @@ static void ftag_tag_add(int argc, char **argv)
}
const char *new_tag_name = argv[0];
assert(strlen(new_tag_name) <= 255);
- assert(strchr(new_tag_name, '\'') == NULL);
+ assert_no_single_quote(new_tag_name);
char sql[1024];
sqlite3 *db = NULL;
@@ -175,7 +294,7 @@ static void ftag_tag_add(int argc, char **argv)
const char *new_tag_desc = argv[1];
assert(strlen(new_tag_desc) <= 600);
- assert(strchr(new_tag_desc, '\'') == NULL);
+ assert_no_single_quote(new_tag_desc);
last_id++;
memset(sql, 0, sizeof(sql));
snprintf(sql, sizeof(sql)-1,
@@ -183,11 +302,12 @@ static void ftag_tag_add(int argc, char **argv)
last_id, new_tag_name, new_tag_desc);
rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
sqlite3_check(rc, db);
+ sqlite3_close(db);
}
static void ftag_tag_list(int argc, char **argv)
{
- ftag_list_table("tags");
+ ftag_list_table("tags", "name");
}
static void ftag_tag(int argc, char **argv)