aboutsummaryrefslogblamecommitdiffstats
path: root/src/edit.c
blob: e1c933ab5e68a4330e4abb043a1356d75c74025a (plain) (tree)
1
2
3
4
5
6
7
8
9
10





                                                                                
                                          


                                                                                

                   
                    

                     


                                                                                            






















                                                                 
                                                                                               








































                                                                                         
















                                                                                         
 






















































































































                                                                                          
                                        


                            




                          






                                                                    

               

                                      
                                      
                                                                                          
                                              


                                                                           





                                                                                 
                                                    





                                   


                                                                                         





                                                                                             
                           


                                                       
   





                        
                                                                                            

 
/* 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]");
}