summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/CMakeLists.txt4
-rw-r--r--ext/libsolvext.ver6
-rw-r--r--ext/testcase.c682
-rw-r--r--ext/testcase.h18
4 files changed, 708 insertions, 2 deletions
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
index 9fc9034..679a74a 100644
--- a/ext/CMakeLists.txt
+++ b/ext/CMakeLists.txt
@@ -1,8 +1,8 @@
SET (libsolvext_SRCS
- repo_write.c solv_xfopen.c)
+ repo_write.c solv_xfopen.c testcase.c)
SET (libsolvext_HEADERS
- repo_write.h tools_util.h solv_xfopen.h)
+ repo_write.h tools_util.h solv_xfopen.h testcase.h)
IF (ENABLE_RPMDB)
SET (libsolvext_SRCS ${libsolvext_SRCS}
diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver
index c7bda48..ff02691 100644
--- a/ext/libsolvext.ver
+++ b/ext/libsolvext.ver
@@ -33,6 +33,12 @@ SOLV_1.0 {
rpm_query;
solv_xfopen;
solv_xfopen_fd;
+ testcase_job2str;
+ testcase_solvid2str;
+ testcase_str2dep;
+ testcase_str2job;
+ testcase_str2repo;
+ testcase_write_susetags;
local:
*;
};
diff --git a/ext/testcase.c b/ext/testcase.c
new file mode 100644
index 0000000..9c7612e
--- /dev/null
+++ b/ext/testcase.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "solver.h"
+#include "testcase.h"
+
+
+static struct job2str {
+ Id job;
+ const char *str;
+} job2str[] = {
+ { SOLVER_NOOP, "noop" },
+ { SOLVER_INSTALL, "install" },
+ { SOLVER_ERASE, "erase" },
+ { SOLVER_UPDATE, "update" },
+ { SOLVER_WEAKENDEPS, "weakendeps" },
+ { SOLVER_NOOBSOLETES, "noobsoletes" },
+ { SOLVER_LOCK, "lock" },
+ { SOLVER_DISTUPGRADE, "distupgrade" },
+ { SOLVER_VERIFY, "verify" },
+ { SOLVER_DROP_ORPHANED, "droporphaned" },
+ { SOLVER_USERINSTALLED, "userinstalled" },
+ { 0, 0 }
+};
+
+static struct jobflags2str {
+ Id flags;
+ const char *str;
+} jobflags2str[] = {
+ { SOLVER_WEAK, "weak" },
+ { SOLVER_ESSENTIAL, "essential" },
+ { SOLVER_CLEANDEPS, "cleandeps" },
+ { SOLVER_SETEV, "setev" },
+ { SOLVER_SETEVR, "setevr" },
+ { SOLVER_SETARCH, "setarch" },
+ { SOLVER_SETVENDOR, "setvendor" },
+ { SOLVER_SETREPO, "setrepo" },
+ { SOLVER_NOAUTOSET, "noautoset" },
+ { 0, 0 }
+};
+
+
+static inline int
+pool_isknownarch(Pool *pool, Id id)
+{
+ if (!id || id == ID_EMPTY)
+ return 0;
+ if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
+ return 1;
+ if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
+ return 0;
+ return 1;
+}
+
+Id
+testcase_str2dep(Pool *pool, char *s)
+{
+ char *n, *a;
+ Id id;
+ int flags;
+
+ if ((n = strchr(s, '|')) != 0)
+ {
+ id = testcase_str2dep(pool, n + 1);
+ *n = 0;
+ id = pool_rel2id(pool, testcase_str2dep(pool, s), id, REL_OR, 1);
+ *n = '|';
+ return id;
+ }
+ while (*s == ' ' || *s == '\t')
+ s++;
+ n = s;
+ while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
+ s++;
+ if ((a = strchr(n, '.')) != 0 && a + 1 < s)
+ {
+ Id archid = pool_strn2id(pool, a + 1, s - (a + 1), 0);
+ if (pool_isknownarch(pool, archid))
+ {
+ id = pool_strn2id(pool, n, a - n, 1);
+ id = pool_rel2id(pool, id, archid, REL_ARCH, 1);
+ }
+ else
+ id = pool_strn2id(pool, n, s - n, 1);
+ }
+ else
+ id = pool_strn2id(pool, n, s - n, 1);
+ if (!*s)
+ return id;
+ while (*s == ' ' || *s == '\t')
+ s++;
+ flags = 0;
+ for (;;s++)
+ {
+ if (*s == '<')
+ flags |= REL_LT;
+ else if (*s == '=')
+ flags |= REL_EQ;
+ else if (*s == '>')
+ flags |= REL_GT;
+ else
+ break;
+ }
+ if (!flags)
+ return id;
+ while (*s == ' ' || *s == '\t')
+ s++;
+ n = s;
+ while (*s && *s != ' ' && *s != '\t')
+ s++;
+ return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1);
+}
+
+const char *
+testcase_solvid2str(Pool *pool, Id p)
+{
+ Solvable *s = pool->solvables + p;
+ const char *str = pool_solvid2str(pool, p);
+ char buf[20];
+
+ if (!s->repo)
+ return pool_tmpappend(pool, str, "@", 0);
+ if (s->repo->name)
+ {
+ int l = strlen(str);
+ char *str2 = pool_tmpappend(pool, str, "@", s->repo->name);
+ for (; str2[l]; l++)
+ if (str2[l] == ' ' || str2[l] == '\t')
+ str2[l] = '_';
+ return str2;
+ }
+ sprintf(buf, "@#%d", s->repo->repoid);
+ return pool_tmpappend(pool, str, buf, 0);
+}
+
+Repo *
+testcase_str2repo(Pool *pool, const char *str)
+{
+ int repoid;
+ Repo *repo = 0;
+ if (str[0] == '#' && (str[1] >= '0' && str[1] <= '9'))
+ {
+ int j;
+ repoid = 0;
+ for (j = 1; str[j] >= '0' && str[j] <= '9'; j++)
+ repoid = repoid * 10 + (str[j] - '0');
+ if (!str[j] && repoid > 0 && repoid < pool->nrepos)
+ repo = pool_id2repo(pool, repoid);
+ }
+ if (!repo)
+ {
+ FOR_REPOS(repoid, repo)
+ {
+ int i, l;
+ if (!repo->name)
+ continue;
+ l = strlen(repo->name);
+ for (i = 0; i < l; i++)
+ {
+ int c = repo->name[i];
+ if (c == ' ' || c == '\t')
+ c = '_';
+ if (c != str[i])
+ break;
+ }
+ if (i == l && !str[l])
+ break;
+ }
+ if (repoid >= pool->nrepos)
+ repo = 0;
+ }
+ return repo;
+}
+
+Id
+testcase_str2solvid(Pool *pool, const char *str)
+{
+ int i, l = strlen(str);
+ int repostart;
+ Repo *repo;
+ Id arch;
+
+ if (!l)
+ return 0;
+ repo = 0;
+ for (i = l - 1; i >= 0; i--)
+ if (str[i] == '@' && (repo = testcase_str2repo(pool, str + i + 1)) != 0)
+ break;
+ if (i < 0)
+ i = l;
+ repostart = i;
+ /* now find the arch (if present) */
+ arch = 0;
+ for (i = repostart - 1; i > 0; i--)
+ if (str[i] == '.')
+ {
+ arch = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
+ if (arch)
+ repostart = i;
+ break;
+ }
+ /* now find the name */
+ for (i = repostart - 1; i > 0; i--)
+ {
+ if (str[i] == '-')
+ {
+ Id nid, evrid, p, pp;
+ nid = pool_strn2id(pool, str, i, 0);
+ if (!nid)
+ continue;
+ evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
+ if (!evrid)
+ continue;
+ FOR_PROVIDES(p, pp, nid)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name != nid || s->evr != evrid)
+ continue;
+ if (repo && s->repo != repo)
+ continue;
+ if (arch && s->arch != arch)
+ continue;
+ return p;
+ }
+ }
+ }
+ return 0;
+}
+
+const char *
+testcase_job2str(Pool *pool, Id how, Id what)
+{
+ char *ret;
+ const char *jobstr;
+ const char *selstr;
+ const char *pkgstr;
+ int i, o;
+ Id select = how & SOLVER_SELECTMASK;
+
+ for (i = 0; job2str[i].str; i++)
+ if ((how & SOLVER_JOBMASK) == job2str[i].job)
+ break;
+ jobstr = job2str[i].str ? job2str[i].str : "unknown";
+ if (select == SOLVER_SOLVABLE)
+ {
+ selstr = " pkg ";
+ pkgstr = testcase_solvid2str(pool, what);
+ }
+ else if (select == SOLVER_SOLVABLE_NAME)
+ {
+ selstr = " name ";
+ pkgstr = pool_dep2str(pool, what);
+ }
+ else if (select == SOLVER_SOLVABLE_PROVIDES)
+ {
+ selstr = " provides ";
+ pkgstr = pool_dep2str(pool, what);
+ }
+ else if (select == SOLVER_SOLVABLE_ONE_OF)
+ {
+ Id p;
+ selstr = " oneof ";
+ pkgstr = 0;
+ while ((p = pool->whatprovidesdata[what++]) != 0)
+ {
+ const char *s = testcase_solvid2str(pool, p);
+ if (pkgstr)
+ {
+ pkgstr = pool_tmpappend(pool, pkgstr, " ", s);
+ pool_freetmpspace(pool, s);
+ }
+ else
+ pkgstr = s;
+ }
+ if (!pkgstr)
+ pkgstr = "nothing";
+ }
+ else if (select == SOLVER_SOLVABLE_REPO)
+ {
+ Repo *repo = pool_id2repo(pool, what);
+ selstr = " repo ";
+ if (!repo->name)
+ {
+ char buf[20];
+ sprintf(buf, "#%d", repo->repoid);
+ pkgstr = pool_tmpjoin(pool, buf, 0, 0);
+ }
+ else
+ pkgstr = pool_tmpjoin(pool, repo->name, 0, 0);
+ }
+ else if (select == SOLVER_SOLVABLE_ALL)
+ {
+ selstr = " all ";
+ pkgstr = "packages";
+ }
+ else
+ {
+ selstr = " unknown ";
+ pkgstr = "unknown";
+ }
+ ret = pool_tmpjoin(pool, jobstr, selstr, pkgstr);
+ o = strlen(ret);
+ ret = pool_tmpappend(pool, ret, " ", 0);
+ for (i = 0; jobflags2str[i].str; i++)
+ if ((how & jobflags2str[i].flags) != 0)
+ ret = pool_tmpappend(pool, ret, ",", jobflags2str[i].str);
+ if (!ret[o + 1])
+ ret[o] = 0;
+ else
+ {
+ ret[o + 1] = '[';
+ ret = pool_tmpappend(pool, ret, "]", 0);
+ }
+ return ret;
+}
+
+Id
+testcase_str2job(Pool *pool, const char *str, Id *whatp)
+{
+ int i;
+ Id job;
+ Id what;
+ char *s;
+ char **pieces = 0;
+ int npieces = 0;
+
+ *whatp = 0;
+ /* so we can patch it */
+ s = pool_tmpjoin(pool, str, 0, 0);
+ /* split it in pieces */
+ for (;;)
+ {
+ while (*s == ' ' || *s == '\t')
+ s++;
+ if (!*s)
+ break;
+ pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
+ pieces[npieces++] = s;
+ while (*s && *s != ' ' && *s != '\t')
+ s++;
+ if (*s)
+ *s++ = 0;
+ }
+ if (npieces < 3)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
+ return 0;
+ }
+
+ for (i = 0; job2str[i].str; i++)
+ if (!strcmp(pieces[0], job2str[i].str))
+ break;
+ if (!job2str[i].str)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: unknown job '%s'\n", str);
+ return 0;
+ }
+ job = job2str[i].job;
+ if (npieces > 3)
+ {
+ char *flags = pieces[npieces - 1];
+ char *nf;
+ if (*flags == '[' && flags[strlen(flags) - 1] == ']')
+ {
+ npieces--;
+ flags++;
+ flags[strlen(flags) - 1] = ',';
+ while (*flags)
+ {
+ for (nf = flags; *nf != ','; nf++)
+ ;
+ *nf++ = 0;
+ for (i = 0; jobflags2str[i].str; i++)
+ if (!strcmp(flags, jobflags2str[i].str))
+ break;
+ if (!jobflags2str[i].str)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: unknown jobflags in '%s'\n", str);
+ return 0;
+ }
+ job |= jobflags2str[i].flags;
+ flags = nf;
+ }
+ }
+ }
+ if (!strcmp(pieces[1], "pkg"))
+ {
+ if (npieces != 3)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: bad pkg selector in '%s'\n", str);
+ return 0;
+ }
+ job |= SOLVER_SOLVABLE;
+ what = testcase_str2solvid(pool, pieces[2]);
+ if (!what)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[2]);
+ return 0;
+ }
+ }
+ else if (!strcmp(pieces[1], "name") || !strcmp(pieces[1], "provides"))
+ {
+ /* join em again for dep2str... */
+ char *sp;
+ for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
+ if (*sp == 0)
+ *sp = ' ';
+ what = testcase_str2dep(pool, pieces[2]);
+ if (pieces[1][0] == 'n')
+ job |= SOLVER_SOLVABLE_NAME;
+ else
+ job |= SOLVER_SOLVABLE_PROVIDES;
+ }
+ else if (!strcmp(pieces[1], "oneof"))
+ {
+ Queue q;
+ job |= SOLVER_SOLVABLE_ONE_OF;
+ queue_init(&q);
+ if (npieces > 3 && strcmp(pieces[2], "nothing") != 0)
+ {
+ for (i = 2; i < npieces; i++)
+ {
+ Id p = testcase_str2solvid(pool, pieces[i]);
+ if (!p)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[i]);
+ queue_free(&q);
+ return 0;
+ }
+ queue_push(&q, p);
+ }
+ }
+ what = pool_queuetowhatprovides(pool, &q);
+ queue_free(&q);
+ }
+ else if (!strcmp(pieces[1], "repo"))
+ {
+ Repo *repo;
+ if (npieces != 3)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
+ return 0;
+ }
+ repo = testcase_str2repo(pool, pieces[2]);
+ if (!repo)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: unknown repo '%s'\n", pieces[2]);
+ return 0;
+ }
+ job |= SOLVER_SOLVABLE_REPO;
+ what = repo->repoid;
+ }
+ else if (!strcmp(pieces[1], "all"))
+ {
+ if (npieces != 3 && strcmp(pieces[2], "packages") != 0)
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
+ return 0;
+ }
+ job |= SOLVER_SOLVABLE_ALL;
+ what = 0;
+ }
+ else
+ {
+ pool_debug(pool, SOLV_ERROR, "str2job: unknown selection in '%s'\n", str);
+ return 0;
+ }
+ *whatp = what;
+ return job;
+}
+
+static void
+writedeps(Repo *repo, FILE *fp, const char *tag, Id key, Solvable *s, Offset off)
+{
+ Pool *pool = repo->pool;
+ Id id, *dp;
+ int tagwritten = 0;
+ const char *idstr;
+
+ if (!off)
+ return;
+ dp = repo->idarraydata + off;
+ while ((id = *dp++) != 0)
+ {
+ if (key == SOLVABLE_REQUIRES && id == SOLVABLE_PREREQMARKER)
+ {
+ if (tagwritten)
+ fprintf(fp, "-%s\n", tag);
+ tagwritten = 0;
+ tag = "Prq:";
+ continue;
+ }
+ if (key == SOLVABLE_PROVIDES && id == SOLVABLE_FILEMARKER)
+ break;
+ idstr = pool_dep2str(pool, id);
+ if (ISRELDEP(id))
+ {
+ Reldep *rd = GETRELDEP(pool, id);
+ if (key == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
+ {
+ if (!strncmp(idstr, "namespace:", 10))
+ idstr += 10;
+ }
+ if (key == SOLVABLE_SUPPLEMENTS)
+ {
+ if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM)
+ {
+ if (!strncmp(idstr, "namespace:", 10))
+ idstr += 10;
+ }
+ else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS)
+ {
+ if (!strncmp(idstr, "namespace:", 10))
+ idstr += 10;
+ }
+ else if (rd->flags == REL_AND)
+ {
+ /* either packageand chain or modalias */
+ idstr = 0;
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *mrd = GETRELDEP(pool, rd->evr);
+ if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS)
+ {
+ idstr = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":");
+ idstr = pool_tmpappend(pool, idstr, pool_dep2str(pool, mrd->evr), ")");
+ }
+ else if (mrd->flags >= 8)
+ continue;
+ }
+ if (!idstr)
+ {
+ /* must be and chain */
+ idstr = pool_dep2str(pool, rd->evr);
+ for (;;)
+ {
+ id = rd->name;
+ if (!ISRELDEP(id))
+ break;
+ rd = GETRELDEP(pool, id);
+ if (rd->flags != REL_AND)
+ break;
+ idstr = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", idstr);
+ }
+ idstr = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", idstr);
+ idstr = pool_tmpjoin(pool, "packageand(", idstr, ")");
+ }
+ }
+ else if (rd->flags >= 8)
+ continue;
+ }
+ }
+ if (!tagwritten)
+ {
+ fprintf(fp, "+%s\n", tag);
+ tagwritten = 1;
+ }
+ fprintf(fp, "%s\n", idstr);
+ }
+ if (key == SOLVABLE_PROVIDES)
+ {
+ /* add the filelist */
+ Dataiterator di;
+ dataiterator_init(&di, pool, repo, s - pool->solvables, SOLVABLE_FILELIST, 0, 0);
+ while (dataiterator_step(&di))
+ {
+ if (!tagwritten)
+ {
+ fprintf(fp, "+%s", tag);
+ tagwritten = 1;
+ }
+ fprintf(fp, "%s\n", repodata_dir2str(di.data, di.kv.id, di.kv.str));
+ }
+ }
+ if (tagwritten)
+ fprintf(fp, "-%s\n", tag);
+}
+
+int
+testcase_write_susetags(Repo *repo, FILE *fp)
+{
+ Pool *pool = repo->pool;
+ Solvable *s;
+ Id p;
+ const char *name;
+ const char *evr;
+ const char *arch;
+ const char *release;
+#if 0
+ const char *chksum;
+ Id chksumtype, type;
+ unsigned int medianr;
+#endif
+ const char *tmp;
+ unsigned int ti;
+
+ fprintf(fp, "=Ver: 2.0\n");
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ name = pool_id2str(pool, s->name);
+ evr = pool_id2str(pool, s->evr);
+ arch = pool_id2str(pool, s->arch);
+ release = strrchr(evr, '-');
+ if (!release)
+ release = evr + strlen(evr);
+ fprintf(fp, "=Pkg: %s %.*s %s %s\n", name, release - evr, evr, *release && release[1] ? release + 1 : "0", arch);
+ tmp = solvable_lookup_str(s, SOLVABLE_SUMMARY);
+ if (tmp)
+ fprintf(fp, "=Sum: %s\n", tmp);
+#if 0
+ chksum = solvable_lookup_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
+ if (chksum)
+ fprintf(fp, "=Cks: %s %s\n", solv_chksum_type2str(chksumtype), chksum);
+#endif
+ writedeps(repo, fp, "Req:", SOLVABLE_REQUIRES, s, s->requires);
+ writedeps(repo, fp, "Prv:", SOLVABLE_PROVIDES, s, s->provides);
+ writedeps(repo, fp, "Obs:", SOLVABLE_OBSOLETES, s, s->obsoletes);
+ writedeps(repo, fp, "Con:", SOLVABLE_CONFLICTS, s, s->conflicts);
+ writedeps(repo, fp, "Rec:", SOLVABLE_RECOMMENDS, s, s->recommends);
+ writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements);
+ writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests);
+ writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances);
+#if 0
+ tmp = solvable_lookup_str(s, SOLVABLE_GROUP);
+ if (tmp)
+ fprintf(fp, "=Grp: %s\n", tmp);
+ tmp = solvable_lookup_str(s, SOLVABLE_LICENSE);
+ if (tmp)
+ fprintf(fp, "=Lic: %s\n", tmp);
+#endif
+ if (s->vendor)
+ fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor));
+#if 0
+ type = solvable_lookup_type(s, SOLVABLE_SOURCENAME);
+ if (type)
+ {
+ if (type != REPOKEY_TYPE_VOID)
+ name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
+ type = solvable_lookup_type(s, SOLVABLE_SOURCEEVR);
+ if (type)
+ {
+ if (type != REPOKEY_TYPE_VOID)
+ evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
+ release = strrchr(evr, '-');
+ if (!release)
+ release = evr + strlen(evr);
+ fprintf(fp, "=Src: %s %.*s %s %s\n", name, release - evr, evr, *release && release[1] ? release + 1 : "0", solvable_lookup_str(s, SOLVABLE_SOURCEARCH));
+ }
+ }
+#endif
+ ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
+ if (ti)
+ fprintf(fp, "=Tim: %u\n", ti);
+#if 0
+ tmp = solvable_get_location(s, &medianr);
+ if (tmp)
+ {
+ const char *base = strrchr(tmp, '/');
+ if (!base)
+ fprintf(fp, "=Loc: %d %s\n", medianr, tmp);
+ else if (strlen(arch) == base - tmp && !strncmp(tmp, arch, base - tmp))
+ fprintf(fp, "=Loc: %d %s\n", medianr, base + 1);
+ else
+ fprintf(fp, "=Loc: %d %s %.*s\n", medianr, base + 1, base - tmp, tmp);
+ }
+#endif
+ }
+ return 0;
+}
diff --git a/ext/testcase.h b/ext/testcase.h
new file mode 100644
index 0000000..048f48e
--- /dev/null
+++ b/ext/testcase.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include "pool.h"
+#include "repo.h"
+
+extern Id testcase_str2dep(Pool *pool, char *s);
+extern const char *testcase_solvid2str(Pool *pool, Id p);
+extern Repo *testcase_str2repo(Pool *pool, const char *str);
+extern Id testcase_str2solvid(Pool *pool, const char *str);
+extern const char *testcase_job2str(Pool *pool, Id how, Id what);
+extern Id testcase_str2job(Pool *pool, const char *str, Id *whatp);
+extern int testcase_write_susetags(Repo *repo, FILE *fp);
+