Hi rpm people
I would like to ask you about adding functions for parsing information from nvr
and maybe nevra strings.
As hawkey library became obsolete, we didn't find any replacement for some its
functions as hy_split_nevra.
I am interested in function with api as:
int parse_nvr_name(const char *nvr, char **name); // to parse just name,
(allocates memory for it)
But you may want to add also something like: (hy_split_nevra equivalent)
int parse_nevra_all(const char *nevra, char **name, long int *epoch, char
**version, char **release, char **arch);
I attached implementations of mentioned functions.
Would it be possible to add such or similar functions into yours libraries?
Best Regards
Julius
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
void die_out_of_memory(void) { exit(1); } // placeholder
// Die if we can't copy a string to freshly allocated memory.
char* xstrdup(const char *s) // placeholder
{
char *t;
if (s == NULL)
return NULL;
t = strdup(s);
if (t == NULL)
die_out_of_memory();
return t;
}
// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
// the (possibly truncated to length n) string into it.
char* xstrndup(const char *s, int n) // placeholder
{
int m;
char *t;
/* We can just xmalloc(n+1) and strncpy into it, */
/* but think about xstrndup("abc", 10000) wastage! */
m = n;
t = (char*) s;
while (m)
{
if (!*t) break;
m--;
t++;
}
n -= m;
// t = (char*) xmalloc(n + 1);
t = (char*) malloc(n + 1);
t[n] = '\0';
return (char*) memcpy(t, s, n);
}
/* -------------------------------------------------------------------------- */
/**
* Parses only name from nevra
* nevra is RPM naming convention: name-version-release.architecture, where version may
* contain epoch at the beginning separated by colon
* Note: function allocates memory for output parameter, caller is responsible
* for freeing it.
*/
int
parse_nevra_name(const char *nevra, char **name)
{
const int len = strlen(nevra);
if (len <= 0)
return EINVAL; // or equivalent
const char *c = nevra + len - 1;
/* skip architecture */
for (; *c != '.'; --c)
{
if (c <= nevra)
return EINVAL;
}
/* skip release */
for (; *c != '-'; --c)
{
if (c <= nevra)
return EINVAL;
}
--c;
/* skip version */
for (; *c != '-'; --c)
{
if (c <= nevra)
return EINVAL;
}
*name = xstrndup(nevra, (c - nevra)); // your strndup wrapper
return 0;
}
/**
* Parses only name from nevra
* nvr is RPM naming convention: name-version-release
* Note: function allocates memory for output parameter, caller is responsible
* for freeing it.
*/
int
parse_nvr_name(const char *nvr, char **name)
{
const int len = strlen(nvr);
if (len <= 0)
return EINVAL; // or equivalent
const char *c = nvr + len - 1;
/* skip release */
for (; *c != '-'; --c)
{
if (c <= nvr)
return EINVAL;
}
--c;
/* skip version */
for (; *c != '-'; --c)
{
if (c <= nvr)
return EINVAL;
}
*name = xstrndup(nvr, (c - nvr)); // your strndup wrapper
return 0;
}
/**
* Parses all information from nevra. Threadsafe.
* nevra is RPM naming convention: name-version-release.architecture, where version may
* contain epoch at the beginning separated by colon
* Note: function allocates memory for output parameters, caller is responsible
* for freeing it.
*/
int
parse_nevra_all(const char *nevra, char **name, long int *epoch,
char **version, char **release, char **arch)
{
const int len = strlen(nevra);
if (len <= 0)
return EINVAL; // or equivalent
const char *p_name = NULL, *p_version = NULL, *p_release = NULL, *p_arch = NULL;
const char *c = nevra + len - 1;
for (; *c != '.'; --c)
{
if (c <= nevra)
return EINVAL;
}
p_arch = c + 1;
for (; *c != '-'; --c)
{
if (c <= nevra)
return EINVAL;
}
p_release = c + 1;
--c;
for (; *c != '-'; --c)
{
if (c <= nevra)
return EINVAL;
}
p_version = c + 1;
*name = xstrndup(nevra, (c - nevra)); // your strdup & strndup wrappers
*release = xstrndup(p_release, (p_arch - p_release - 1));
*arch = xstrdup(p_arch);
char *endptr;
long int converted;
errno = 0;
converted = strtol(p_version, &endptr, 10);
if (!errno && *endptr == ':')
{
*epoch = converted;
*version = xstrndup(endptr + 1, (p_release - endptr - 2));
} else {
*epoch = 0;
*version = xstrndup(p_version, (p_release - p_version - 1));
}
return 0;
}
/* original hawkey (<- obsolete library) function (just wrapers and return codes are replaced) */
int
hy_split_nevra(const char *nevra, char **name, long int *epoch,
char **version, char **release, char **arch)
{
const int len = strlen(nevra);
if (len <= 0)
return EINVAL;
const char *m1 = NULL, *m2 = NULL, *m3 = NULL;
const char *c;
for (c = nevra + len - 1; c > nevra; --c)
if (*c == '.') {
m3 = c;
break;
}
if (c == nevra)
return EINVAL;
for (; c > nevra; --c)
if (*c == '-') {
if (m2 == NULL)
m2 = c;
else if (m1 == NULL) {
m1 = c;
break;
}
}
if (c == nevra)
return EINVAL;
*arch = xstrdup(m3+1);
*name = xstrndup(nevra, (m1 - nevra));
*release = xstrndup(m2 + 1, (m3 - m2 - 1));
char *endptr;
long int converted;
errno = 0;
converted = strtol(m1 + 1, &endptr, 10);
if (!errno && *endptr == ':') {
*epoch = converted;
*version = xstrndup(endptr + 1, (m2 - endptr - 1));
} else {
*epoch = 0;
*version = xstrndup(m1 + 1, (m2 - m1 - 1));
}
return 0;
}
int main()
{
long int epoch;
char *name, *version, *release, *arch;
assert(0 == parse_nevra_all("meanwhile3.34.3-3:3.34-3.fc666.i686", &name,
&epoch, &version, &release, &arch));
assert(0 == strcmp("meanwhile3.34.3", name));
assert(3 == epoch);
assert(0 == strcmp("3.34", version));
assert(0 == strcmp("3.fc666", release));
assert(0 == strcmp("i686", arch));
free(name); free(version); free(release); free(arch);
assert(0 == parse_nevra_name("meanwhile3.34.3-3:3.34-3.fc666.i686", &name));
assert(0 == strcmp("meanwhile3.34.3", name));
free(name);
assert(0 == parse_nevra_all("python-meanwhile3.34.3-3:3.34-3.fc666.noarch", &name,
&epoch, &version, &release, &arch));
assert(0 == strcmp("python-meanwhile3.34.3", name));
assert(3 == epoch);
assert(0 == strcmp("3.34", version));
assert(0 == strcmp("3.fc666", release));
assert(0 == strcmp("noarch", arch));
free(name); free(version); free(release); free(arch);
assert(0 == parse_nevra_name("python-meanwhile3.34.3-3:3.34-3.fc666.noarch", &name));
assert(0 == strcmp("python-meanwhile3.34.3", name));
free(name);
assert(0 == parse_nevra_all("easy-1.2.3-4.fc18.x86_64", &name,
&epoch, &version, &release, &arch));
assert(0 == strcmp("easy", name));
assert(0 == epoch);
assert(0 == strcmp("1.2.3", version));
assert(0 == strcmp("4.fc18", release));
assert(0 == strcmp("x86_64", arch));
free(name); free(version); free(release); free(arch);
assert(0 == parse_nevra_name("easy-1.2.3-4.fc18.x86_64", &name));
assert(0 == strcmp("easy", name));
free(name);
// test nvr
assert(0 == parse_nvr_name("dnf-plugins-core-1000.1.21-2.fc24", &name));
assert(0 == strcmp("dnf-plugins-core", name));
free(name);
printf("Test passed\n");
return 0;
}
_______________________________________________
Rpm-ecosystem mailing list
[email protected]
http://lists.rpm.org/mailman/listinfo/rpm-ecosystem