diff --git a/ropkg/commands.h b/ropkg/commands.h index e6c5644..48750de 100644 --- a/ropkg/commands.h +++ b/ropkg/commands.h @@ -8,6 +8,7 @@ enum { CMD_QUERY, CMD_EXTRACT, CMD_INSTALL, + CMD_COMPARE_VERSION, }; #endif diff --git a/ropkg/compare-version.c b/ropkg/compare-version.c new file mode 100644 index 0000000..b3cd74f --- /dev/null +++ b/ropkg/compare-version.c @@ -0,0 +1,236 @@ +#include "commands.h" +#include "ropkg/version.h" + +#include +#include + +enum { + OPT_VERBOSE, + ARG_VERSION_LEFT, + ARG_OPERATOR, + ARG_VERSION_RIGHT, +}; + +static enum ropkg_status comparison_op_from_string( + const char *s, + enum ropkg_comparison_op *out) +{ + if (!strcmp(s, "==") || !strcmp(s, "eq")) { + *out = ROPKG_OP_EQUAL; + } else if (!strcmp(s, "<") || !strcmp(s, "lt")) { + *out = ROPKG_OP_LESS_THAN; + } else if (!strcmp(s, "<=") || !strcmp(s, "le")) { + *out = ROPKG_OP_LESS_EQUAL; + } else if (!strcmp(s, ">") || !strcmp(s, "gt")) { + *out = ROPKG_OP_GREATER_THAN; + } else if (!strcmp(s, ">=") || !strcmp(s, "ge")) { + *out = ROPKG_OP_GREATER_EQUAL; + } else if (!strcmp(s, "!=") || !strcmp(s, "ne")) { + *out = ROPKG_OP_NOT_EQUAL; + } else { + return ROPKG_ERR_INVALID_ARGUMENT; + } + + return ROPKG_SUCCESS; +} + +static int compare_version( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + int ret = -1; + bool verbose = false; + + struct ropkg_version *left = NULL, *right = NULL; + enum ropkg_status status = ropkg_version_create(&left); + if (!B_OK(status)) { + goto end; + } + + status = ropkg_version_create(&right); + if (!B_OK(status)) { + goto end; + } + + const char *left_string = NULL, *right_string = NULL, *op_string = NULL; + b_arglist_get_string( + opt, + B_COMMAND_INVALID_ID, + ARG_VERSION_LEFT, + 0, + &left_string); + b_arglist_get_string( + opt, + B_COMMAND_INVALID_ID, + ARG_VERSION_RIGHT, + 0, + &right_string); + b_arglist_get_string( + opt, + B_COMMAND_INVALID_ID, + ARG_OPERATOR, + 0, + &op_string); + verbose = b_arglist_get_count(opt, OPT_VERBOSE, B_COMMAND_INVALID_ID) + > 0; + + if (!left_string) { + b_arglist_report_missing_args( + opt, + B_COMMAND_INVALID_ID, + ARG_VERSION_LEFT, + 0); + goto end; + } + + if (!right_string) { + b_arglist_report_missing_args( + opt, + B_COMMAND_INVALID_ID, + ARG_VERSION_RIGHT, + 0); + goto end; + } + + if (!op_string) { + b_arglist_report_missing_args( + opt, + B_COMMAND_INVALID_ID, + ARG_OPERATOR, + 0); + goto end; + } + + b_result result = ropkg_version_parse(left, left_string); + if (b_result_is_error(result)) { + b_throw(result); + goto end; + } + + result = ropkg_version_parse(right, right_string); + if (b_result_is_error(result)) { + b_throw(result); + goto end; + } + + enum ropkg_comparison_op op; + status = comparison_op_from_string(op_string, &op); + if (status != ROPKG_SUCCESS) { + b_arglist_report_invalid_arg_value( + opt, + B_COMMAND_INVALID_ID, + ARG_OPERATOR, + op_string); + goto end; + } + + bool comparison_result = ropkg_version_compare(left, right, op); + ret = comparison_result ? 0 : 1; + + if (verbose) { + char temp[128]; + ropkg_version_to_string(left, temp, sizeof temp); + + printf("%s ", temp); + + switch (op) { + case ROPKG_OP_EQUAL: + printf("== "); + break; + case ROPKG_OP_NOT_EQUAL: + printf("!= "); + break; + case ROPKG_OP_LESS_THAN: + printf("< "); + break; + case ROPKG_OP_LESS_EQUAL: + printf("<= "); + break; + case ROPKG_OP_GREATER_THAN: + printf("> "); + break; + case ROPKG_OP_GREATER_EQUAL: + printf(">= "); + break; + default: + break; + } + + ropkg_version_to_string(right, temp, sizeof temp); + printf("%s -> %s\n", + temp, + comparison_result ? "true" : "false"); + } + +end: + if (left) { + ropkg_version_destroy(left); + } + + if (right) { + ropkg_version_destroy(right); + } + + return ret; +} + +B_COMMAND(CMD_COMPARE_VERSION, CMD_ROOT) +{ + B_COMMAND_NAME("compare-version"); + B_COMMAND_DESC("compare two package version identifiers."); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(compare_version); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_OPTION(OPT_VERBOSE) + { + B_OPTION_SHORT_NAME('v'); + B_OPTION_LONG_NAME("verbose"); + B_OPTION_DESC( + "print the result of the comparison to " + "standard out."); + } + + B_COMMAND_ARG(ARG_VERSION_LEFT) + { + B_ARG_NAME("left-version"); + B_ARG_DESC("the left-side of the comparison operation."); + B_ARG_NR_VALUES(1); + } + + B_COMMAND_ARG(ARG_OPERATOR) + { + B_ARG_NAME("operator"); + B_ARG_DESC("the comparison operator to use."); + B_ARG_ALLOWED_VALUES( + "==", + "!=", + "<", + "<=", + ">", + ">=", + "eq", + "ne", + "lt", + "le", + "gt", + "ge"); + B_ARG_NR_VALUES(1); + } + + B_COMMAND_ARG(ARG_VERSION_RIGHT) + { + B_ARG_NAME("right-version"); + B_ARG_DESC("the right-side of the comparison operation."); + B_ARG_NR_VALUES(1); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_ARG(ARG_VERSION_LEFT); + B_COMMAND_USAGE_ARG(ARG_OPERATOR); + B_COMMAND_USAGE_ARG(ARG_VERSION_RIGHT); + } +}