Files
ropkg/libropkg/manifest.c

451 lines
9.5 KiB
C
Raw Permalink Normal View History

#include "manifest.h"
#include <blue/object/string.h>
#include <ropkg/manifest.h>
#include <stdlib.h>
#include <string.h>
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;
}