451 lines
9.5 KiB
C
451 lines
9.5 KiB
C
|
|
#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;
|
||
|
|
}
|