aboutsummaryrefslogblamecommitdiffstats
path: root/src/actionparser.c
blob: 33e8ccc251606660a8d3fd6ea054ad06290d8450 (plain) (tree)
















































































































































































































































                                                                                                                                                  
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "actionparser.h"

/* --------------------------------------------------------------------------
 * The following code is resposinble for parsing the command line arguments
 * and report any errors that might come up.
 * -------------------------------------------------------------------------- */

/* accepted commands */
/* [0] is the count */
const char* const strINIT[] = {"2", "init", "-i"};
const char* const strADD[] = {"2", "add", "-a"};
const char* const strDEL[] = {"2", "del", "-d"};
const char* const strEDIT[] = {"3", "edit", "e", "-e"};
const char* const strLIST[] = {"3", "list", "ls", "-ls"};
const char* const strSEARCH[] = {"3", "search", "s", "-s"};
const char* const strHELP[] = {"4", "help", "?", "-h", "--help"};

/* Number of opts */
static int optNum;
/* holds the list of the opts
   as given by the user */
static char **opts;
/* points to the current token */
static char *token;
/* points to the position
 * to be read */
static int pos = 0;

/* Reads the next token and returns it's position
 * Returns -1 otherwise */
int nextToken() {
  if (pos < optNum) {
    token = opts[pos];
    return pos++;
  }
  else {
    token = "";
    return -1;
  }
}

void getOpt(int position, UserOpt *opt) {
    // get arg
    nextToken();

    // allocate memory
    opt->argv[position] = (char *)malloc((strlen(token)+1)*sizeof(char));
    strcpy(opt->argv[position], token);
}

/* When starting to parse the action,
 * `pos` should be at 2
 * like so "ck ACTION ..."
 *                    ^               */
int parseINIT(UserOpt *opt) {
  // if db exists init should fail before checking for args

  // INIT expects 2 arguments
  // starting from 0
  opt->argc = 2;
  if (optNum != pos /* already consumed */ + opt->argc) {
    opt->err = PERR_INIT_WRONG;
    return -1;
  }

  for (int i = 0; i < opt->argc; i++) {
    getOpt(i, opt);
  }
  return 1;
}

int parseADD(UserOpt *opt) {
  // ADD expects 2 to 4 arguments
  if (optNum <= pos + 1
      || optNum > pos + 4) {
    opt->err = PERR_ADD_WRONG;
    return -1;
  }
  return 1;
}

int parseDEL(UserOpt *opt) {
}
int parseEDIT(UserOpt *opt) {
}
int parseLIST(UserOpt *opt) {
}
int parseSEARCH(UserOpt *opt) {
}
int parseHELP(UserOpt *opt) {
}


int parseVals(UserOpt *opt) {
  switch (opt->action) {
#define X(ACTION)                             \
    case CKA_##ACTION:                           \
      return parse##ACTION(opt);
    CK_ACTIONS
#undef X
  default:
    // can't end up here, but it prevents a compiler warning
    opt->err = PERR_UNKONW_ACTION;
    return -1;
    break;
  }
  return 1;
}

CkAction determineAction() {
  int i = 0;
#define X(ACTION)                                                    \
  for (i = 1; i < atoi(str##ACTION[0]) + 1; i++) {                      \
    if (strcmp(token, str##ACTION[i]) == 0) {                           \
      return CKA_##ACTION;                                              \
    }                                                                   \
  }
  CK_ACTIONS
#undef X
  return -1;
}

UserOpt initUserOpt() {
  UserOpt uo;
  uo.action = -1;
  uo.err = PERR_NOERR;
  uo.argc = 0;
  for (int i = 0; i < 10; i++) {
    uo.argv[i] = NULL;
  }
  return uo;
}

ParseResult parseAction(int argc, char* argv[], UserOpt *opt) {
  *opt = initUserOpt();
  if (argc < 2) {
    return OPR_HELP;
  }
  opts = argv;
  optNum = argc;

  // skip the program nake
  nextToken();

  // get action
  nextToken();
  opt->action = determineAction();
  if (opt->action == -1) {
    opt->err = PERR_UNKONW_ACTION;
    return OPR_ERR;
  }
  if (opt->action == CKA_HELP) {
    return OPR_HELP;
  }

  // parse values
  if (!parseVals(opt)) {
    return OPR_ERR;
  }

  if (opt->err == PERR_NOERR) {
    return OPR_OK;
  }
  else {
    return OPR_ERR;
  }
}

const char * getPossibleActionName(const char* const strAction[]) {
  char *names;
  size_t size = 2; // first chars "{ "
  for (int i = 1; i < atoi(strAction[0]) + 1; i++) {
    size += strlen(strAction[i]) + 2; // comma and space for each entry and " }" for the last one
  }
  if ((names = malloc(size)) != NULL) {
    strcpy(names, "{ ");
    int i = 1;
    for (; i < atoi(strAction[0]); i++) {
      strcat(names, strAction[i]);
      strcat(names, ", ");
    }
    // last one
    strcat(names, strAction[atoi(strAction[0])]);
    strcat(names, " }");
    return names;
  }
  return NULL;
}

void printParserError(UserOpt *opt) {
  char *errStr = NULL;
  switch (opt->err) {
  case PERR_NOERR:
    return;
  case PERR_UNKONW_ACTION:
    asprintf(&errStr, "Unknown action: %s", token);
    break;
  case PERR_INIT_WRONG:
    asprintf(&errStr, "Initialize database\nUsage: %s VC_dir SCRT_dir DB_dir", getPossibleActionName(strINIT));
    break;
  case PERR_ADD_WRONG:
    asprintf(&errStr, "Add config (new or existing)\nUsage: %s ProgramName ConfigPath [-s](secret) [-p](primary)", getPossibleActionName(strADD));
    break;
  case PERR_DEL_WRONG:
    asprintf(&errStr, "Delete config or program\nUsage: %s ProgramName ConfigPath [-s](secret) [-p](primary)", getPossibleActionName(strDEL));
    break;
  case PERR_EDIT_WRONG:
    asprintf(&errStr, "Edit config\nUsage: add ProgramName ConfigPath [-s](secret) [-p](primary)");
    break;
  case PERR_LIST_WRONG:
    asprintf(&errStr, "Usage: add ProgramName ConfigPath [-s](secret) [-p](primary)");
    break;
  case PERR_SEARCH_WRONG:
    asprintf(&errStr, "Usage: add ProgramName ConfigPath [-s](secret) [-p](primary)");
    break;
  case PERR_HELP_WRONG:
    asprintf(&errStr, "Usage: add ProgramName ConfigPath [-s](secret) [-p](primary)");
    break;
  }
  printf("Parsing error\n%s\n", errStr);
  exit(1);
}

void printParserHelp() {
  printf("ck - the config keeper");
  printf("\n----------------------");
  printf("\n----------------------\n");
  printf("Usage:\n");
  printf("Initialize: \t%s\n", getPossibleActionName(strINIT));
  printf("Add config: \t%s\n", getPossibleActionName(strADD));
  printf("Delete config: \t%s\n", getPossibleActionName(strDEL));
  printf("Edit config: \t%s\n", getPossibleActionName(strEDIT));
  printf("List configs: \t%s\n", getPossibleActionName(strLIST));
  printf("Search: \t%s\n", getPossibleActionName(strSEARCH));
  printf("Print this: \t%s\n", getPossibleActionName(strHELP));
  exit(0);
}