diff --git a/libropkg/include/ropkg/manifest.h b/libropkg/include/ropkg/manifest.h new file mode 100644 index 0000000..904db29 --- /dev/null +++ b/libropkg/include/ropkg/manifest.h @@ -0,0 +1,87 @@ +#ifndef ROPKG_MANIFEST_H_ +#define ROPKG_MANIFEST_H_ + +#include +#include +#include +#include + +enum ropkg_manifest_value_type { + ROPKG_MANIFEST_VALUE_T_NONE = 0, + ROPKG_MANIFEST_VALUE_T_STRING, + ROPKG_MANIFEST_VALUE_T_INT, +}; + +enum ropkg_manifest_value_id { + ROPKG_MANIFEST_VALUE_N_NONE = 0, + ROPKG_MANIFEST_VALUE_N_NAME, + ROPKG_MANIFEST_VALUE_N_ARCHITECTURE, + ROPKG_MANIFEST_VALUE_N_VERSION, + ROPKG_MANIFEST_VALUE_N_PRIORITY, + ROPKG_MANIFEST_VALUE_N_CATEGORY, + ROPKG_MANIFEST_VALUE_N_MAINTAINER, + ROPKG_MANIFEST_VALUE_N_PROVIDES, + ROPKG_MANIFEST_VALUE_N_DEPENDS, + ROPKG_MANIFEST_VALUE_N_RECOMMENDS, + ROPKG_MANIFEST_VALUE_N_SUGGESTS, + ROPKG_MANIFEST_VALUE_N_CONFLICTS, + ROPKG_MANIFEST_VALUE_N_ENHANCES, + ROPKG_MANIFEST_VALUE_N_INSTALLED_SIZE, + ROPKG_MANIFEST_VALUE_N_DESCRIPTION, +}; + +struct ropkg_manifest; +struct ropkg_manifest_value; + +ROPKG_API enum ropkg_status ropkg_manifest_create(struct ropkg_manifest **out); +ROPKG_API void ropkg_manifest_destroy(struct ropkg_manifest *manifest); + +ROPKG_API b_result ropkg_manifest_parse(FILE *fp, struct ropkg_manifest *dest); + +ROPKG_API enum ropkg_status ropkg_manifest_get_by_name( + struct ropkg_manifest *manifest, + const char *name, + struct ropkg_manifest_value **out); +ROPKG_API enum ropkg_status ropkg_manifest_get_by_id( + struct ropkg_manifest *manifest, + enum ropkg_manifest_value_id id, + struct ropkg_manifest_value **out); +ROPKG_API enum ropkg_status ropkg_manifest_put( + struct ropkg_manifest *manifest, + struct ropkg_manifest_value *value); +ROPKG_API const struct ropkg_manifest_value *ropkg_manifest_get_first_value( + const struct ropkg_manifest *manifest); +ROPKG_API const struct ropkg_manifest_value *ropkg_manifest_get_next_value( + const struct ropkg_manifest *manifest, + const struct ropkg_manifest_value *value); + +ROPKG_API enum ropkg_status ropkg_manifest_value_create_int_with_name( + size_t value, + const char *name, + struct ropkg_manifest_value **out); +ROPKG_API enum ropkg_status ropkg_manifest_value_create_int_with_id( + size_t value, + enum ropkg_manifest_value_id id, + struct ropkg_manifest_value **out); +ROPKG_API enum ropkg_status ropkg_manifest_value_create_string_with_name( + const char *value, + const char *name, + struct ropkg_manifest_value **out); +ROPKG_API enum ropkg_status ropkg_manifest_value_create_string_with_id( + const char *value, + enum ropkg_manifest_value_id id, + struct ropkg_manifest_value **out); +ROPKG_API void ropkg_manifest_value_destroy(struct ropkg_manifest_value *value); + +ROPKG_API enum ropkg_manifest_value_type ropkg_manifest_value_get_type( + const struct ropkg_manifest_value *value); +ROPKG_API const char *ropkg_manifest_value_get_name( + const struct ropkg_manifest_value *value); +ROPKG_API enum ropkg_manifest_value_id ropkg_manifest_value_get_id( + const struct ropkg_manifest_value *value); +ROPKG_API const char *ropkg_manifest_value_get_string( + const struct ropkg_manifest_value *value); +ROPKG_API size_t +ropkg_manifest_value_get_int(const struct ropkg_manifest_value *value); + +#endif diff --git a/libropkg/include/ropkg/status.h b/libropkg/include/ropkg/status.h index 66c988b..f6dd004 100644 --- a/libropkg/include/ropkg/status.h +++ b/libropkg/include/ropkg/status.h @@ -4,11 +4,12 @@ #include #include -#define ROPKG_ERROR_VENDOR (ropkg_error_vendor()) +#define ROPKG_ERROR_VENDOR (ropkg_error_vendor()) +#define ROPKG_RESULT_SUCCESS B_RESULT_SUCCESS #define ROPKG_RESULT_ERR(code) \ b_error_with_code(ROPKG_ERROR_VENDOR, ROPKG_ERR_##code) -#define ROPKG_RESULT_SUCCESS B_RESULT_SUCCESS +#define ROPKG_RESULT_STATUS(code) b_error_with_code(ROPKG_ERROR_VENDOR, code) enum ropkg_status { ROPKG_SUCCESS = 0, @@ -18,11 +19,17 @@ enum ropkg_status { ROPKG_ERR_BAD_STATE, ROPKG_ERR_INTERNAL_FAILURE, ROPKG_ERR_IO_FAILURE, + ROPKG_ERR_NO_ENTRY, + ROPKG_ERR_NO_DATA, + ROPKG_ERR_NAME_EXISTS, ROPKG_ERR_DIR_OPEN_FAILED, ROPKG_ERR_INSTANCE_DIR_CREATE_FAILED, ROPKG_ERR_FILE_OPEN_FAILED, + ROPKG_ERR_INVALID_MANIFEST_FORMAT, ROPKG_ERR_INVALID_VERSION_FORMAT, + ROPKG_ERR_INVALID_PKG_EXPR, + ROPKG_ERR_INVALID_PKG_FILE, }; enum ropkg_error_msg { diff --git a/libropkg/manifest.c b/libropkg/manifest.c new file mode 100644 index 0000000..ce9b341 --- /dev/null +++ b/libropkg/manifest.c @@ -0,0 +1,450 @@ +#include "manifest.h" + +#include +#include +#include +#include + +static const char *value_id_names[] = { + [ROPKG_MANIFEST_VALUE_N_NAME] = "Name", + [ROPKG_MANIFEST_VALUE_N_ARCHITECTURE] = "Architecture", + [ROPKG_MANIFEST_VALUE_N_VERSION] = "Version", + [ROPKG_MANIFEST_VALUE_N_PRIORITY] = "Priority", + [ROPKG_MANIFEST_VALUE_N_CATEGORY] = "Category", + [ROPKG_MANIFEST_VALUE_N_MAINTAINER] = "Maintainer", + [ROPKG_MANIFEST_VALUE_N_PROVIDES] = "Provides", + [ROPKG_MANIFEST_VALUE_N_DEPENDS] = "Depends", + [ROPKG_MANIFEST_VALUE_N_RECOMMENDS] = "Recommends", + [ROPKG_MANIFEST_VALUE_N_SUGGESTS] = "Suggests", + [ROPKG_MANIFEST_VALUE_N_CONFLICTS] = "Conflicts", + [ROPKG_MANIFEST_VALUE_N_ENHANCES] = "Enhances", + [ROPKG_MANIFEST_VALUE_N_INSTALLED_SIZE] = "Installed-Size", + [ROPKG_MANIFEST_VALUE_N_DESCRIPTION] = "Description", +}; +static const size_t nr_value_id_names + = sizeof value_id_names / sizeof value_id_names[0]; + +static enum ropkg_manifest_value_id value_id_from_string(const char *s) +{ + for (size_t i = 0; i < nr_value_id_names; i++) { + const char *name = value_id_names[i]; + if (name && !strcmp(name, s)) { + return i; + } + } + + return ROPKG_MANIFEST_VALUE_N_NONE; +} + +enum ropkg_status ropkg_manifest_create(struct ropkg_manifest **out) +{ + struct ropkg_manifest *manifest = malloc(sizeof *manifest); + if (!manifest) { + return ROPKG_ERR_NO_MEMORY; + } + + memset(manifest, 0x0, sizeof *manifest); + + *out = manifest; + return ROPKG_SUCCESS; +} + +void ropkg_manifest_destroy(struct ropkg_manifest *manifest) +{ + b_queue_entry *entry = b_queue_pop_back(&manifest->m_values); + while (entry) { + struct ropkg_manifest_value *value + = b_unbox(struct ropkg_manifest_value, entry, v_entry); + ropkg_manifest_value_destroy(value); + entry = b_queue_pop_back(&manifest->m_values); + } + + free(manifest); +} + +static b_result create_manifest_value( + b_string *name, + b_string *value, + struct ropkg_manifest_value **out) +{ + const char *name_cstr = b_string_ptr(name); + enum ropkg_manifest_value_id id = value_id_from_string(name_cstr); + + const char *value_cstr = b_string_ptr(value); + char *ep; + size_t v = strtoull(value_cstr, &ep, 10); + struct ropkg_manifest_value *result = NULL; + enum ropkg_status status = ROPKG_SUCCESS; + + if (*ep == 0) { + if (id != ROPKG_MANIFEST_VALUE_N_NONE) { + status = ropkg_manifest_value_create_int_with_id( + v, + id, + &result); + } else { + status = ropkg_manifest_value_create_int_with_name( + v, + name_cstr, + &result); + } + } else { + if (id != ROPKG_MANIFEST_VALUE_N_NONE) { + status = ropkg_manifest_value_create_string_with_id( + value_cstr, + id, + &result); + } else { + status = ropkg_manifest_value_create_string_with_name( + value_cstr, + name_cstr, + &result); + } + } + + if (status != ROPKG_SUCCESS) { + return b_error_with_code(ROPKG_ERROR_VENDOR, status); + } + + *out = result; + return B_RESULT_SUCCESS; +} + +b_result ropkg_manifest_parse(FILE *fp, struct ropkg_manifest *dest) +{ + enum parser_state { + PARSER_STATE_NAME, + PARSER_STATE_VALUE, + } parser_state = PARSER_STATE_NAME; + + enum ropkg_status status = ROPKG_SUCCESS; + b_result result = B_RESULT_SUCCESS; + b_string *name = b_string_create(); + b_string *value_string = b_string_create(); + struct ropkg_manifest_value *value = NULL; + char s[2] = {0}; + + bool done = false; + + while (!done) { + char c = fgetc(fp); + + switch (c) { + case ':': + if (parser_state == PARSER_STATE_NAME) { + parser_state = PARSER_STATE_VALUE; + continue; + } + + s[0] = c; + b_string_append_cstr(value_string, s); + continue; + case '\n': + if (parser_state == PARSER_STATE_NAME) { + done = true; + break; + } + + result = create_manifest_value( + name, + value_string, + &value); + if (b_result_is_error(result)) { + done = true; + break; + } + + status = ropkg_manifest_put(dest, value); + if (status != ROPKG_SUCCESS) { + result = b_error_with_code( + ROPKG_ERROR_VENDOR, + status); + done = true; + break; + } + + b_string_clear(name); + b_string_clear(value_string); + parser_state = PARSER_STATE_NAME; + break; + case ' ': + case '\t': + if (parser_state == PARSER_STATE_NAME + && b_string_get_size(name, 0) == 0) { + break; + } + + if (parser_state == PARSER_STATE_VALUE + && b_string_get_size(value_string, 0) == 0) { + break; + } + default: + s[0] = c; + + if (parser_state == PARSER_STATE_NAME) { + b_string_append_cstr(name, s); + } else { + b_string_append_cstr(value_string, s); + } + + break; + } + } + + b_string_release(name); + b_string_release(value_string); + + return result; +} + +enum ropkg_status ropkg_manifest_get_by_name( + struct ropkg_manifest *manifest, + const char *name, + struct ropkg_manifest_value **out) +{ + b_queue_iterator it; + b_queue_foreach(&it, &manifest->m_values) + { + struct ropkg_manifest_value *value = b_unbox( + struct ropkg_manifest_value, + it.entry, + v_entry); + if (value->v_name && !strcmp(value->v_name, name)) { + *out = value; + return ROPKG_SUCCESS; + } + } + + return ROPKG_ERR_NO_ENTRY; +} + +enum ropkg_status ropkg_manifest_get_by_id( + struct ropkg_manifest *manifest, + enum ropkg_manifest_value_id id, + struct ropkg_manifest_value **out) +{ + b_queue_iterator it; + b_queue_foreach(&it, &manifest->m_values) + { + struct ropkg_manifest_value *value = b_unbox( + struct ropkg_manifest_value, + it.entry, + v_entry); + if (value->v_id != ROPKG_MANIFEST_VALUE_N_NONE + && value->v_id == id) { + *out = value; + return ROPKG_SUCCESS; + } + } + + return ROPKG_ERR_NO_ENTRY; +} + +enum ropkg_status ropkg_manifest_put( + struct ropkg_manifest *manifest, + struct ropkg_manifest_value *value) +{ + enum ropkg_status status = ROPKG_ERR_NO_ENTRY; + struct ropkg_manifest_value *tmp; + if (value->v_name) { + status = ropkg_manifest_get_by_name( + manifest, + value->v_name, + &tmp); + } else if (value->v_id != ROPKG_MANIFEST_VALUE_N_NONE) { + status = ropkg_manifest_get_by_id(manifest, value->v_id, &tmp); + } else { + return ROPKG_ERR_INVALID_ARGUMENT; + } + + if (status == ROPKG_SUCCESS) { + return ROPKG_ERR_NAME_EXISTS; + } + + b_queue_push_back(&manifest->m_values, &value->v_entry); + + return ROPKG_SUCCESS; +} + +const struct ropkg_manifest_value *ropkg_manifest_get_first_value( + const struct ropkg_manifest *manifest) +{ + b_queue_entry *entry = b_queue_first(&manifest->m_values); + if (!entry) { + return NULL; + } + + return b_unbox(struct ropkg_manifest_value, entry, v_entry); +} + +const struct ropkg_manifest_value *ropkg_manifest_get_next_value( + const struct ropkg_manifest *manifest, + const struct ropkg_manifest_value *value) +{ + b_queue_entry *entry = b_queue_next(&value->v_entry); + if (!entry) { + return NULL; + } + + return b_unbox(struct ropkg_manifest_value, entry, v_entry); +} + +enum ropkg_status ropkg_manifest_value_create_int_with_name( + size_t value, + const char *name, + struct ropkg_manifest_value **out) +{ + struct ropkg_manifest_value *vp = malloc(sizeof *vp); + if (!vp) { + return ROPKG_ERR_NO_MEMORY; + } + + memset(vp, 0x0, sizeof *vp); + + vp->v_type = ROPKG_MANIFEST_VALUE_T_INT; + vp->v_name = b_strdup(name); + + if (!vp->v_name) { + free(vp); + return ROPKG_ERR_NO_MEMORY; + } + + vp->v_value.i = value; + + *out = vp; + return ROPKG_SUCCESS; +} + +enum ropkg_status ropkg_manifest_value_create_int_with_id( + size_t value, + enum ropkg_manifest_value_id id, + struct ropkg_manifest_value **out) +{ + struct ropkg_manifest_value *vp = malloc(sizeof *vp); + if (!vp) { + return ROPKG_ERR_NO_MEMORY; + } + + memset(vp, 0x0, sizeof *vp); + + vp->v_type = ROPKG_MANIFEST_VALUE_T_INT; + vp->v_id = id; + + vp->v_value.i = value; + + *out = vp; + return ROPKG_SUCCESS; +} + +enum ropkg_status ropkg_manifest_value_create_string_with_name( + const char *value, + const char *name, + struct ropkg_manifest_value **out) +{ + struct ropkg_manifest_value *vp = malloc(sizeof *vp); + if (!vp) { + return ROPKG_ERR_NO_MEMORY; + } + + memset(vp, 0x0, sizeof *vp); + + vp->v_type = ROPKG_MANIFEST_VALUE_T_STRING; + vp->v_name = b_strdup(vp->v_name); + + if (!vp->v_name) { + free(vp); + return ROPKG_ERR_NO_MEMORY; + } + + vp->v_value.s = b_strdup(value); + if (!vp->v_value.s) { + free(vp); + return ROPKG_ERR_NO_MEMORY; + } + + *out = vp; + return ROPKG_SUCCESS; +} +enum ropkg_status ropkg_manifest_value_create_string_with_id( + const char *value, + enum ropkg_manifest_value_id id, + struct ropkg_manifest_value **out) +{ + struct ropkg_manifest_value *vp = malloc(sizeof *vp); + if (!vp) { + return ROPKG_ERR_NO_MEMORY; + } + + memset(vp, 0x0, sizeof *vp); + + vp->v_type = ROPKG_MANIFEST_VALUE_T_STRING; + vp->v_id = id; + + vp->v_value.s = b_strdup(value); + if (!vp->v_value.s) { + free(vp); + return ROPKG_ERR_NO_MEMORY; + } + + *out = vp; + return ROPKG_SUCCESS; +} + +void ropkg_manifest_value_destroy(struct ropkg_manifest_value *value) +{ + if (value->v_type == ROPKG_MANIFEST_VALUE_T_STRING + && value->v_value.s) { + free(value->v_value.s); + } + + if (value->v_name) { + free(value->v_name); + } + + free(value); +} + +enum ropkg_manifest_value_type ropkg_manifest_value_get_type( + const struct ropkg_manifest_value *value) +{ + return value->v_type; +} + +const char *ropkg_manifest_value_get_name( + const struct ropkg_manifest_value *value) +{ + if (value->v_name) { + return value->v_name; + } + + if (value->v_id == ROPKG_MANIFEST_VALUE_N_NONE) { + return NULL; + } + + return value_id_names[value->v_id]; +} + +enum ropkg_manifest_value_id ropkg_manifest_value_get_id( + const struct ropkg_manifest_value *value) +{ + return value->v_id; +} + +const char *ropkg_manifest_value_get_string( + const struct ropkg_manifest_value *value) +{ + if (value->v_type != ROPKG_MANIFEST_VALUE_T_STRING) { + return NULL; + } + + return value->v_value.s; +} + +size_t ropkg_manifest_value_get_int(const struct ropkg_manifest_value *value) +{ + if (value->v_type != ROPKG_MANIFEST_VALUE_T_INT) { + return 0; + } + + return value->v_value.i; +} diff --git a/libropkg/manifest.h b/libropkg/manifest.h new file mode 100644 index 0000000..fb3adb6 --- /dev/null +++ b/libropkg/manifest.h @@ -0,0 +1,24 @@ +#ifndef _MANIFEST_H_ +#define _MANIFEST_H_ + +#include +#include +#include + +struct ropkg_manifest_value { + enum ropkg_manifest_value_type v_type; + enum ropkg_manifest_value_id v_id; + char *v_name; + b_queue_entry v_entry; + + union { + size_t i; + char *s; + } v_value; +}; + +struct ropkg_manifest { + b_queue m_values; +}; + +#endif diff --git a/libropkg/status.c b/libropkg/status.c index 793ca39..7be37ef 100644 --- a/libropkg/status.c +++ b/libropkg/status.c @@ -18,6 +18,14 @@ static const b_error_definition ropkg_errors[] = { "INTERNAL_FAILURE", "Internal failure"), B_ERROR_DEFINITION(ROPKG_ERR_IO_FAILURE, "IO_FAILURE", "I/O failure"), + B_ERROR_DEFINITION( + ROPKG_ERR_NO_ENTRY, + "NO_ENTRY", + "Name does not exist"), + B_ERROR_DEFINITION( + ROPKG_ERR_NAME_EXISTS, + "NAME_EXISTS", + "Name already exist"), B_ERROR_DEFINITION_TEMPLATE( ROPKG_ERR_DIR_OPEN_FAILED, @@ -51,10 +59,20 @@ static const b_error_definition ropkg_errors[] = { B_ERROR_TEMPLATE_PARAM_STRING, "%s")), + B_ERROR_DEFINITION( + ROPKG_ERR_INVALID_MANIFEST_FORMAT, + "INVALID_MANIFSET_FORMAT", + "Invalid manifest format"), + B_ERROR_DEFINITION( ROPKG_ERR_INVALID_VERSION_FORMAT, "INVALID_VERSION_FORMAT", "Invalid version format"), + + B_ERROR_DEFINITION( + ROPKG_ERR_INVALID_PKG_EXPR, + "INVALID_PKG_EXPR", + "Invalid package expression"), }; static const b_error_msg ropkg_error_msg[] = {