summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Schroeder <mls@suse.de>2014-02-26 13:06:22 +0100
committerMichael Schroeder <mls@suse.de>2014-02-26 13:06:22 +0100
commit673b10389cfdea7282d2587a00a01c9b0cf713d9 (patch)
tree8153d6d8eb2fa5942323407d00bc2ca3045d9b9f
parent1692a946f563e1378d6fc6e8859c2638139999d6 (diff)
downloadlibsolv-673b10389cfdea7282d2587a00a01c9b0cf713d9.tar.gz
libsolv-673b10389cfdea7282d2587a00a01c9b0cf713d9.tar.bz2
libsolv-673b10389cfdea7282d2587a00a01c9b0cf713d9.zip
improve appdata.xml parsing
- ignore tags with a set language (for now) - read desktop file if name/summary is not present - the requires needs to be the full file name
-rw-r--r--ext/repo_appdata.c145
-rw-r--r--ext/repo_appdata.h1
2 files changed, 141 insertions, 5 deletions
diff --git a/ext/repo_appdata.c b/ext/repo_appdata.c
index 64f100d..96e114c 100644
--- a/ext/repo_appdata.c
+++ b/ext/repo_appdata.c
@@ -95,6 +95,13 @@ struct parsedata {
char *description;
int licnt;
+ int skip_tag;
+ int skip_tag_d;
+ int skip_tag_li;
+
+ int flags;
+ char *desktop_file;
+ int havesummary;
};
@@ -155,13 +162,38 @@ startElement(void *userData, const char *name, const char **atts)
case STATE_APPLICATION:
s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
pd->handle = s - pool->solvables;
+ pd->havesummary = 0;
+ break;
+ case STATE_NAME:
+ case STATE_SUMMARY:
+ pd->skip_tag = 0;
+ if (find_attr("xml:lang", atts))
+ pd->skip_tag = 1;
break;
case STATE_DESCRIPTION:
+ pd->skip_tag_d = 0;
+ if (find_attr("xml:lang", atts))
+ pd->skip_tag_d = 1;
pd->description = solv_free(pd->description);
break;
case STATE_OL:
+ case STATE_UL:
+ pd->skip_tag = 0;
+ if (find_attr("xml:lang", atts))
+ pd->skip_tag = 1;
pd->licnt = 0;
break;
+ case STATE_P:
+ pd->skip_tag = 0;
+ if (find_attr("xml:lang", atts))
+ pd->skip_tag = 1;
+ break;
+ case STATE_UL_LI:
+ case STATE_OL_LI:
+ pd->skip_tag_li = 0;
+ if (find_attr("xml:lang", atts))
+ pd->skip_tag_li = 1;
+ break;
default:
break;
}
@@ -216,6 +248,79 @@ indent(struct parsedata *pd, int il)
}
}
+static void
+add_missing_tags_from_desktop_file(struct parsedata *pd, Solvable *s, const char *desktop_file)
+{
+ Pool *pool = pd->pool;
+ FILE *fp;
+ const char *filepath;
+ char buf[1024];
+ char *p, *p2, *p3;
+ int inde = 0;
+
+ filepath = pool_tmpjoin(pool, "/usr/share/applications/", desktop_file, 0);
+ if (pd->flags & REPO_USE_ROOTDIR)
+ filepath = pool_prepend_rootdir_tmp(pool, filepath);
+ if (!(fp = fopen(filepath, "r")))
+ return;
+ while (fgets(buf, sizeof(buf), fp) > 0)
+ {
+ int c, l = strlen(buf);
+ if (!l)
+ continue;
+ if (buf[l - 1] != '\n')
+ {
+ /* ignore overlong lines */
+ while ((c = getc(fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c == EOF)
+ break;
+ continue;
+ }
+ buf[--l] = 0;
+ while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+ buf[--l] = 0;
+ p = buf;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!*p || *p == '#')
+ continue;
+ if (*p == '[')
+ inde = 0;
+ if (!strcmp(p, "[Desktop Entry]"))
+ {
+ inde = 1;
+ continue;
+ }
+ if (!inde)
+ continue;
+ p2 = strchr(p, '=');
+ if (!p2 || p2 == p)
+ continue;
+ *p2 = 0;
+ for (p3 = p2 - 1; *p3 == ' ' || *p3 == '\t'; p3--)
+ *p3 = 0;
+ p2++;
+ while (*p2 == ' ' || *p2 == '\t')
+ p2++;
+ if (!*p2)
+ continue;
+ if (!s->name && !strcmp(p, "Name"))
+ s->name = pool_str2id(pool, pool_tmpjoin(pool, "application:", p2, 0), 1);
+ else if (!pd->havesummary && !strcmp(p, "Comment"))
+ {
+ pd->havesummary = 1;
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, p2);
+ }
+ else
+ continue;
+ if (s->name && pd->havesummary)
+ break; /* our work is done */
+ }
+ fclose(fp);
+}
+
static void XMLCALL
endElement(void *userData, const char *name)
{
@@ -246,25 +351,42 @@ endElement(void *userData, const char *name)
s->arch = ARCH_NOARCH;
if (!s->evr)
s->evr = ID_EMPTY;
+ if ((!s->name || !pd->havesummary) && (pd->flags & APPDATA_CHECK_DESKTOP_FILE) != 0 && pd->desktop_file)
+ add_missing_tags_from_desktop_file(pd, s, pd->desktop_file);
+ if (!s->name && pd->desktop_file)
+ {
+ char *name = pool_tmpjoin(pool, "application:", pd->desktop_file, 0);
+ int l = strlen(name);
+ if (l > 8 && !strcmp(".desktop", name + l - 8))
+ l -= 8;
+ s->name = pool_strn2id(pool, name, l, 1);
+ }
if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
pd->solvable = 0;
+ pd->desktop_file = solv_free(pd->desktop_file);
break;
case STATE_ID:
+ pd->desktop_file = solv_strdup(pd->content);
if (pd->lcontent > 8 && !strcmp(".desktop", pd->content + pd->lcontent - 8))
pd->content[pd->lcontent - 8] = 0;
- id = pool_str2id(pd->pool, pool_tmpjoin(pool, "appdata(", pd->content, ")"), 1);
+ id = pool_str2id(pd->pool, pool_tmpjoin(pool, "appdata(", pd->content, ".appdata.xml)"), 1);
s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
- id = pool_str2id(pd->pool, pool_tmpjoin(pool, "application-appdata(", pd->content, ")"), 1);
+ id = pool_str2id(pd->pool, pool_tmpjoin(pool, "application-appdata(", pd->content, ".appdata.xml)"), 1);
s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
break;
case STATE_NAME:
+ if (pd->skip_tag)
+ break;
s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", pd->content, 0), 1);
break;
case STATE_LICENCE:
repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, pd->content);
break;
case STATE_SUMMARY:
+ if (pd->skip_tag)
+ break;
+ pd->havesummary = 1;
repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
break;
case STATE_URL:
@@ -274,7 +396,7 @@ endElement(void *userData, const char *name)
repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, pd->content);
break;
case STATE_DESCRIPTION:
- if (pd->description)
+ if (pd->description && !pd->skip_tag_d)
{
/* strip trailing newlines */
int l = strlen(pd->description);
@@ -284,16 +406,22 @@ endElement(void *userData, const char *name)
}
break;
case STATE_P:
+ if (pd->skip_tag)
+ break;
wsstrip(pd);
pd->description = solv_dupappend(pd->description, pd->content, "\n\n");
break;
case STATE_UL_LI:
+ if (pd->skip_tag || pd->skip_tag_li)
+ break;
wsstrip(pd);
indent(pd, 4);
pd->content[2] = '-';
pd->description = solv_dupappend(pd->description, pd->content, "\n");
break;
case STATE_OL_LI:
+ if (pd->skip_tag || pd->skip_tag_li)
+ break;
wsstrip(pd);
indent(pd, 4);
if (++pd->licnt >= 10)
@@ -304,6 +432,8 @@ endElement(void *userData, const char *name)
break;
case STATE_UL:
case STATE_OL:
+ if (pd->skip_tag)
+ break;
pd->description = solv_dupappend(pd->description, "\n", 0);
break;
default:
@@ -358,6 +488,7 @@ repo_add_appdata(Repo *repo, FILE *fp, int flags)
pd.repo = repo;
pd.pool = repo->pool;
pd.data = data;
+ pd.flags = flags;
pd.content = malloc(256);
pd.acontent = 256;
@@ -391,7 +522,9 @@ repo_add_appdata(Repo *repo, FILE *fp, int flags)
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
- free(pd.content);
+ solv_free(pd.content);
+ solv_free(pd.desktop_file);
+ solv_free(pd.description);
return ret;
}
@@ -427,10 +560,12 @@ repo_add_appdata_dir(Repo *repo, const char *appdatadir, int flags)
pool_error(repo->pool, 0, "%s: %s", n, strerror(errno));
continue;
}
- repo_add_appdata(repo, fp, flags | REPO_NO_INTERNALIZE | REPO_REUSE_REPODATA);
+ repo_add_appdata(repo, fp, flags | REPO_NO_INTERNALIZE | REPO_REUSE_REPODATA | APPDATA_CHECK_DESKTOP_FILE);
fclose(fp);
}
+ closedir(dir);
}
+ solv_free(dirpath);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
return 0;
diff --git a/ext/repo_appdata.h b/ext/repo_appdata.h
index eb51848..51b35b5 100644
--- a/ext/repo_appdata.h
+++ b/ext/repo_appdata.h
@@ -8,3 +8,4 @@
int repo_add_appdata(Repo *repo, FILE *fp, int flags);
int repo_add_appdata_dir(Repo *repo, const char *appdatadir, int flags);
+#define APPDATA_CHECK_DESKTOP_FILE (1 << 30) /* internal */