libropkg: implement package manifest parsing
This commit is contained in:
450
libropkg/manifest.c
Normal file
450
libropkg/manifest.c
Normal file
@@ -0,0 +1,450 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user