/* edit.c - the edit action --------------------------------------------*- C -*-
*
* This file is part of ck, the config keeper
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2019 Anastasis Grammenos
* GPLv3 (see LICENCE for the full notice)
*
* -------------------------------------------------------------------------- */
#include <libgen.h>
#include "dblayer.h"
#include "ckerrlog.h"
ERRLOG(edit);
static int edit_get_prime_config_from_program(DB *db, char *pName, char *ret, int *secret) {
int pid = get_program_id(db, pName);
/* error */
if (pid == -2) {
return -1;
}
/* program exists */
if (pid > -1) {
char path[STR_M] = "";
if (program_has_primary_config(db, pid, path, secret) == 1) {
if (!str_is_empty(path)) {
if (ret) {
str_make_ck_config_name(ret, path, pName);
}
return 0;
}
}
}
/* No prime config found */
return -1;
}
static int edit_get_config(DB *db, const char *pName, char *ret, const char *cName, int *sec) {
int pid = get_program_id(db, pName);
/* error */
if (pid == -2) {
return -1;
}
/* program exists */
if (pid > -1) {
sqlite3_stmt *stmt;
int rc;
char selection[STR_M] = COL_CONFIG_PATH;
strcat(selection, ", ");
strcat(selection, COL_CONFIG_SECRET);
char condition[STR_M] = TBL_PROGRAM;
strcat(condition, ".");
strcat(condition, COL_PROGRAM_ID);
char sql[STR_L] = "";
dbh_form_query_select_from_joined_eq(sql, selection, condition);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
sqlite3_bind_int(stmt, 1, pid);
if (rc != SQLITE_OK) {
return -2;
}
int flag = -1;
while (sqlite3_step(stmt) == SQLITE_ROW) {
char confName[STR_M] = "";
if (cName) {
char *tmp = strdup((char *)sqlite3_column_text(stmt, 0));
if (strcmp(cName, basename(tmp)) == 0) {
flag = 0;
str_make_ck_config_name(confName, (char *)sqlite3_column_text(stmt, 0), pName);
strcpy(ret, confName);
if (sec) {
*sec = sqlite3_column_int(stmt, 1);
}
}
free(tmp);
}
else {
/* Since we are here, it means there is only 1 config for the selected program */
flag = 0;
str_make_ck_config_name(confName, (char *)sqlite3_column_text(stmt, 0), pName);
strcpy(ret, confName);
if (sec) {
*sec = sqlite3_column_int(stmt, 1);
}
break;
}
}
sqlite3_finalize(stmt);
return flag;
}
return -1;
}
static EditOpt edit_make_options(cklist *args) {
list_rewind(args);
EditOpt editOpt = {
.pName = NULL,
.cBasename = NULL,
.editor = NULL,
.cmd = NULL,
.sudo = 0,
.err = 0
};
if (list_size(args)) {
editOpt.pName = list_get(args);
}
else {
editOpt.err = 1;
sERR("Please specify the program to edit.")
goto done;
}
if (list_next(args)) {
/* if the next argument doesn't start with `-` treat it as
a config basename */
if (strncmp("-", list_get(args), strlen("-")) != 0) {
editOpt.cBasename = list_get(args);
if (!list_next(args)) {
goto done;
}
}
do {
if (strcmp(list_get(args), "-s") == 0) {
editOpt.sudo = 1;
}
else if (strcmp(list_get(args), "--editor") == 0) {
if (editOpt.cmd) {
sERR("Use only one of --command and --editor");
editOpt.err = 1;
break;
}
if (!list_next(args)) {
sERR("Specify the editor to use.")
editOpt.err = 1;
break;
}
editOpt.editor = list_get(args);
}
else if (strcmp(list_get(args), "--command") == 0) {
if (editOpt.editor) {
sERR("Use only one of --command and --editor");
editOpt.err = 1;
break;
}
if (!list_next(args)) {
sERR("Specify the command to use.")
editOpt.err = 1;
break;
}
editOpt.cmd = list_get(args);
}
else {
editOpt.err = 1;
ERR("Unknown argument %s", list_get(args));
break;
}
} while(list_next(args));
}
done:
list_rewind(args);
return editOpt;
}
static char * form_edit_command(char *ret, const EditOpt *editOpt, const char *confPath) {
char command[STR_L] = "";
if (editOpt->editor) {
char tmp[STR_L] = "which ";
strcat(tmp, editOpt->editor);
strcat(tmp, " > /dev/null 2>&1");
if (system(tmp) != 0) {
ERR("Editor %s not found.", editOpt->editor);
HELP("If you want to run the command either way use --command instead of --editor.")
return NULL;
}
else {
strcpy(command, editOpt->editor);
}
}
else if (editOpt->cmd) {
strcpy(command, editOpt->cmd);
}
else {
char *editor = getenv("EDITOR");
if (str_is_empty(editor)) {
if (system("which emacs > /dev/null 2>&1") != 0) {
ERR("No editor avaliable.");
HELP("Emacs not found. Please set $EDITOR to your desired editor,");
HELP("or use the --editor flag.")
return NULL;
}
strcpy(command, "nano");
}
else {
strcpy(command, editor);
}
}
strcat(command, " ");
strcat(command, confPath);
if (editOpt->sudo) {
char tmp[STR_L] = "sudo ";
strcat(tmp, command);
return strcpy(ret, tmp);
}
return strcpy(ret, command);
}
int run_EDIT(UserOpt *opt, Conf *conf) {
char confPath[STR_L] = "";
char confName[STR_M] = "";
int secret = 0;
DB db;
if (open_DB(&db, opt)) {
return -1;
}
EditOpt editOpt = edit_make_options(opt->args);
if (editOpt.err) {
goto error;
}
if (!program_exists(&db, editOpt.pName)) {
ERR("Program %s doesn't exist in the database.", editOpt.pName);
goto error;
}
/* If there is no config basename */
if (!editOpt.cBasename) {
/* If there is no primary config*/
if (edit_get_prime_config_from_program(&db, editOpt.pName, confName, &secret) == -1) {
/* If the program has only one config */
if (get_config_number(&db, editOpt.pName) == 1) {
if (edit_get_config(&db, editOpt.pName, confName, NULL, &secret)) {
ERR("Coudln't find config file for %s", editOpt.pName);
goto error;
}
}
/* If the program has many configs */
else {
HELP("Ambiguous config. Please type the config name after the program.");
print_suggested_configs(&db, editOpt.pName);
goto error;
}
}
}
/* If there are more arguments */
else {
if (edit_get_config(&db, editOpt.pName, confName, editOpt.cBasename, &secret)) {
ERR("Program %s doesn't have a config named %s", editOpt.pName, editOpt.cBasename);
print_suggested_configs(&db, editOpt.pName);
goto error;
}
}
close_DB(&db);
str_join_dirname_with_basename(confPath, secret ? conf->scrt_dir : conf->vc_dir, confName);
char command[STR_L] = "";
if (form_edit_command(command, &editOpt, confPath)) {
hLOG("Running: %s", command);
return system(command);
}
error:
close_DB(&db);
return -1;
}
void print_EDIT_help() {
HELP("ck edit PROGRAM_NAME [CONFIG_BASENAME] [--editor EDITOR] [--command COMMAND] [-s]");
}