refactor a bit, add some comments
[platform/upstream/libsolv.git] / ext / repo_autopattern.c
1 /*
2  * Copyright (c) 2013, SUSE Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "util.h"
19 #include "repo_autopattern.h"
20
21 static void
22 unescape(char *p)
23 {
24   char *q = p;
25   while (*p)
26     {
27       if (*p == '%' && p[1] && p[2])
28         {
29           int d1 = p[1], d2 = p[2];
30           if (d1 >= '0' && d1 <= '9')
31             d1 -= '0';
32           else if (d1 >= 'a' && d1 <= 'f')
33             d1 -= 'a' - 10;
34           else if (d1 >= 'A' && d1 <= 'F')
35             d1 -= 'A' - 10;
36           else
37             d1 = -1;
38           if (d2 >= '0' && d2 <= '9')
39             d2 -= '0';
40           else if (d2 >= 'a' && d2 <= 'f')
41             d2 -= 'a' - 10;
42           else if (d2 >= 'A' && d2 <= 'F')
43             d2 -= 'A' - 10;
44           else
45             d2 = -1;
46           if (d1 != -1 && d2 != -1)
47             {
48               *q++ = d1 << 4 | d2;
49               p += 3;
50               continue;
51             }
52         }
53       *q++ = *p++;
54     }
55   *q = 0;
56 }
57
58 int
59 repo_add_autopattern(Repo *repo, int flags)
60 {
61   Pool *pool = repo->pool;
62   Repodata *data = 0;
63   Solvable *s, *s2;
64   Queue q, q2;
65   Id p;
66   Id pattern_id;
67   Id autopattern_id = 0;
68   int i, j;
69
70   queue_init(&q);
71   queue_init(&q2);
72
73   pattern_id = pool_str2id(pool, "pattern()", 9);
74   FOR_REPO_SOLVABLES(repo, p, s)
75     {
76       const char *n = pool_id2str(pool, s->name);
77       if (!strncmp("pattern:", n, 8))
78         queue_push(&q, p);
79       else if (s->provides)
80         {
81           Id prv, *prvp = repo->idarraydata + s->provides;
82           while ((prv = *prvp++) != 0)            /* go through all provides */
83             if (ISRELDEP(prv))
84               {
85                 Reldep *rd = GETRELDEP(pool, prv);
86                 if (rd->name == pattern_id && rd->flags == REL_EQ)
87                   {
88                     queue_push2(&q2, p, rd->evr);
89                     break;
90                   }
91               }
92         }
93     }
94   for (i = 0; i < q2.count; i += 2)
95     {
96       const char *pn = 0;
97       char *newname;
98       Id name, prv, *prvp;
99       const char *str;
100       unsigned long long num;
101
102       s = pool->solvables + q2.elements[i];
103       /* construct new name */
104       newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, q2.elements[i + 1]), 0);
105       unescape(newname);
106       name = pool_str2id(pool, newname, 0);
107       if (name)
108         {
109           /* check if we already have that pattern */
110           for (j = 0; j < q.count; j++)
111             {
112               s2 = pool->solvables + q.elements[j];
113               if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr)
114                 break;
115             }
116           if (j < q.count)
117             continue;   /* yes, do not add again */
118         }
119       /* new pattern */
120       if (!name)
121         name = pool_str2id(pool, newname, 1);
122       if (!data)
123         {
124           repo_internalize(repo);       /* to make that the lookups work */
125           data = repo_add_repodata(repo, flags);
126         }
127       s2 = pool_id2solvable(pool, repo_add_solvable(repo));
128       s = pool->solvables + q2.elements[i];     /* re-calc pointer */
129       s2->name = name;
130       s2->arch = s->arch;
131       s2->evr = s->evr;
132       s2->vendor = s->vendor;
133       /* add link requires */
134       s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0);
135       /* add autopattern provides */
136       if (!autopattern_id)
137         autopattern_id = pool_str2id(pool, "autopattern()", 1);
138       s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0);
139       /* add self provides */
140       s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
141       if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
142         repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num);
143       if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
144         repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
145       if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
146         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
147       if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
148         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
149       /* fill in stuff from provides */
150       prvp = repo->idarraydata + s->provides;
151       while ((prv = *prvp++) != 0)            /* go through all provides */
152         {
153           Id evr = 0;
154           if (ISRELDEP(prv))
155             {
156               Reldep *rd = GETRELDEP(pool, prv);
157               if (rd->flags != REL_EQ)
158                 continue;
159               prv = rd->name;
160               evr = rd->evr;
161             }
162           pn = pool_id2str(pool, prv);
163           if (strncmp("pattern-", pn, 8) != 0)
164             continue;
165           newname = 0;
166           if (evr)
167             {
168               newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
169               unescape(newname);
170             }
171           if (!strncmp(pn, "pattern-category(", 17) && evr)
172             {
173               char lang[9];
174               int l = strlen(pn);
175               Id langtag;
176               if (l > 17 + 9 || pn[l - 1] != ')')
177                 continue;
178               strncpy(lang, pn + 17, l - 17 - 1);
179               lang[l - 17 - 1] = 0;
180               langtag = SOLVABLE_CATEGORY;
181               if (*lang && strcmp(lang, "en") != 0)
182                 langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1);
183               repodata_set_str(data, s2 - pool->solvables, langtag, newname);
184             }
185           else if (!strcmp(pn, "pattern-includes()") && evr)
186             repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0));
187           else if (!strcmp(pn, "pattern-extends()") && evr)
188             repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0));
189           else if (!strcmp(pn, "pattern-icon()") && evr)
190             repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname);
191           else if (!strcmp(pn, "pattern-order()") && evr)
192             repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname);
193           else if (!strcmp(pn, "pattern-visible()") && !evr)
194             repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE);
195         }
196     }
197   queue_free(&q);
198   queue_free(&q2);
199   if (data && !(flags & REPO_NO_INTERNALIZE))
200     repodata_internalize(data);
201   else if (!data && !(flags & REPO_NO_INTERNALIZE))
202     repo_internalize(repo);
203   return 0;
204 }
205