- bring down memory usage by
[platform/upstream/libsolv.git] / tools / common_write.c
1 /*
2  * Copyright (c) 2007, Novell 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 <limits.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "pool.h"
16 #include "repo.h"
17 #include "repo_write.h"
18 #include "common_write.h"
19
20 static Id verticals[] = {
21   SOLVABLE_AUTHORS,
22   SOLVABLE_DESCRIPTION,
23   SOLVABLE_MESSAGEDEL,
24   SOLVABLE_MESSAGEINS,
25   SOLVABLE_EULA,
26   SOLVABLE_DISKUSAGE,
27   SOLVABLE_FILELIST,
28   0
29 };
30
31 static char *languagetags[] = {
32   "solvable:summary:",
33   "solvable:description:",
34   "solvable:messageins:",
35   "solvable:messagedel:",
36   "solvable:eula:",
37   0
38 };
39
40 static int test_separate = 0;
41
42 struct keyfilter_data {
43   char **languages;
44   int nlanguages;
45   int haveaddedfileprovides;
46   int haveexternal;
47 };
48
49 static int
50 keyfilter_solv(Repo *data, Repokey *key, void *kfdata)
51 {
52   struct keyfilter_data *kd = kfdata;
53   int i;
54   const char *keyname;
55
56   if (test_separate && key->storage != KEY_STORAGE_SOLVABLE)
57     return KEY_STORAGE_DROPPED;
58   if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
59     return KEY_STORAGE_DROPPED;
60   if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
61     return KEY_STORAGE_DROPPED;
62   for (i = 0; verticals[i]; i++)
63     if (key->name == verticals[i])
64       return KEY_STORAGE_VERTICAL_OFFSET;
65   keyname = id2str(data->pool, key->name);
66   for (i = 0; languagetags[i] != 0; i++)
67     if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
68       return KEY_STORAGE_VERTICAL_OFFSET;
69   return KEY_STORAGE_INCORE;
70 }
71
72 static int
73 keyfilter_attr(Repo *data, Repokey *key, void *kfdata)
74 {
75   int i;
76   const char *keyname;
77   if (key->storage == KEY_STORAGE_SOLVABLE)
78     return KEY_STORAGE_DROPPED;
79   /* those two must only be in the main solv file */
80   if (key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_ADDEDFILEPROVIDES)
81     return KEY_STORAGE_DROPPED;
82   for (i = 0; verticals[i]; i++)
83     if (key->name == verticals[i])
84       return KEY_STORAGE_VERTICAL_OFFSET;
85   keyname = id2str(data->pool, key->name);
86   for (i = 0; languagetags[i] != 0; i++)
87     if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
88       return KEY_STORAGE_VERTICAL_OFFSET;
89   return KEY_STORAGE_INCORE;
90 }
91
92 static int
93 keyfilter_language(Repo *repo, Repokey *key, void *kfdata)
94 {
95   Pool *pool = repo->pool;
96   const char *name, *p;
97   char *lang = kfdata;
98   int i;
99
100   name = id2str(repo->pool, key->name);
101   p = strrchr(name, ':');
102   if (!p || strcmp(p + 1, lang) != 0)
103     return KEY_STORAGE_DROPPED;
104   for (i = 0; verticals[i]; i++)
105     {
106       const char *vname = id2str(pool, verticals[i]);
107       if (!strncmp(name, vname, p - name) && vname[p - name] == 0)
108         return KEY_STORAGE_VERTICAL_OFFSET;
109     }
110   return KEY_STORAGE_INCORE;
111 }
112
113 static int
114 keyfilter_DU(Repo *repo, Repokey *key, void *kfdata)
115 {
116   int i;
117   if (key->name != SOLVABLE_DISKUSAGE)
118     return KEY_STORAGE_DROPPED;
119   for (i = 0; verticals[i]; i++)
120     if (key->name == verticals[i])
121       return KEY_STORAGE_VERTICAL_OFFSET;
122   return KEY_STORAGE_INCORE;
123 }
124
125 static int
126 keyfilter_FL(Repo *repo, Repokey *key, void *kfdata)
127 {
128   int i;
129   if (key->name != SOLVABLE_FILELIST)
130     return KEY_STORAGE_DROPPED;
131   for (i = 0; verticals[i]; i++)
132     if (key->name == verticals[i])
133       return KEY_STORAGE_VERTICAL_OFFSET;
134   return KEY_STORAGE_INCORE;
135 }
136
137 static int
138 keyfilter_other(Repo *repo, Repokey *key, void *kfdata)
139 {
140   const char *name, *p;
141   struct keyfilter_data *kd = kfdata;
142   int i;
143
144   if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
145     return KEY_STORAGE_DROPPED;
146   if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
147     return KEY_STORAGE_DROPPED;
148
149   if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE)
150     return KEY_STORAGE_DROPPED;
151
152   name = id2str(repo->pool, key->name);
153   p = strrchr(name, ':');
154   if (p)
155     {
156       for (i = 0; i < kd->nlanguages; i++)
157         if (!strcmp(p + 1, kd->languages[i]))
158           return KEY_STORAGE_DROPPED;
159     }
160   for (i = 0; verticals[i]; i++)
161     if (key->name == verticals[i])
162       return KEY_STORAGE_VERTICAL_OFFSET;
163   return KEY_STORAGE_INCORE;
164 }
165
166 /*
167  * Write <repo> to stdout
168  * If <attrname> is given, write attributes to <attrname>
169  * If <basename> is given, split attributes
170  */
171
172 #define REPODATAFILE_BLOCK 15
173
174 static void
175 write_info(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Repodata *info, const char *location)
176 {
177   Id h, *keyarray = 0;
178   int i;
179
180   repo_write(repo, fp, keyfilter, kfdata, &keyarray);
181   h = repodata_new_handle(info);
182   if (keyarray)
183     {
184       for (i = 0; keyarray[i]; i++)
185         repodata_add_idarray(info, h, REPOSITORY_KEYS, keyarray[i]);
186     }
187   sat_free(keyarray);
188   repodata_set_str(info, h, REPOSITORY_LOCATION, location);
189   repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h);
190 }
191
192 int
193 tool_write(Repo *repo, const char *basename, const char *attrname)
194 {
195   Repodata *data;
196   Repodata *info = 0;
197   Repokey *key;
198   char **languages = 0;
199   int nlanguages = 0;
200   int i, j, k, l;
201   Id *addedfileprovides = 0;
202   struct keyfilter_data kd;
203
204   memset(&kd, 0, sizeof(kd));
205   info = repo_add_repodata(repo, 0);
206   pool_addfileprovides_ids(repo->pool, 0, &addedfileprovides);
207   if (addedfileprovides && *addedfileprovides)
208     {
209       kd.haveaddedfileprovides = 1;
210       for (i = 0; addedfileprovides[i]; i++)
211         repodata_add_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[i]);
212     }
213   sat_free(addedfileprovides);
214
215   pool_freeidhashes(repo->pool);        /* free some mem */
216
217   if (basename)
218     {
219       char fn[4096];
220       FILE *fp;
221       int has_DU = 0;
222       int has_FL = 0;
223
224       /* find languages and other info */
225       for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
226         {
227           for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
228             {
229               const char *keyname = id2str(repo->pool, key->name);
230               if (key->name == SOLVABLE_DISKUSAGE)
231                 has_DU = 1;
232               if (key->name == SOLVABLE_FILELIST)
233                 has_FL = 1;
234               for (k = 0; languagetags[k] != 0; k++)
235                 if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
236                   break;
237               if (!languagetags[k])
238                 continue;
239               l = strlen(languagetags[k]);
240               if (strlen(keyname + l) > 5)
241                 continue;
242               for (k = 0; k < nlanguages; k++)
243                 if (!strcmp(languages[k], keyname + l))
244                   break;
245               if (k < nlanguages)
246                 continue;
247               languages = sat_realloc2(languages, nlanguages + 1, sizeof(char *));
248               languages[nlanguages++] = strdup(keyname + l);
249             }
250         }
251       /* write language subfiles */
252       for (i = 0; i < nlanguages; i++)
253         {
254           sprintf(fn, "%s.%s.solv", basename, languages[i]);
255           if (!(fp = fopen(fn, "w")))
256             {
257               perror(fn);
258               exit(1);
259             }
260           write_info(repo, fp, keyfilter_language, languages[i], info, fn);
261           fclose(fp);
262           kd.haveexternal = 1;
263         }
264       /* write DU subfile */
265       if (has_DU)
266         {
267           sprintf(fn, "%s.DU.solv", basename);
268           if (!(fp = fopen(fn, "w")))
269             {
270               perror(fn);
271               exit(1);
272             }
273           write_info(repo, fp, keyfilter_DU, 0, info, fn);
274           fclose(fp);
275           kd.haveexternal = 1;
276         }
277       /* write filelist */
278       if (has_FL)
279         {
280           sprintf(fn, "%s.FL.solv", basename);
281           if (!(fp = fopen(fn, "w")))
282             {
283               perror(fn);
284               exit(1);
285             }
286           write_info(repo, fp, keyfilter_FL, 0, info, fn);
287           fclose(fp);
288           kd.haveexternal = 1;
289         }
290       /* write everything else */
291       sprintf(fn, "%s.solv", basename);
292       if (!(fp = fopen(fn, "w")))
293         {
294           perror(fn);
295           exit(1);
296         }
297       kd.languages = languages;
298       kd.nlanguages = nlanguages;
299       repodata_internalize(info);
300       repo_write(repo, fp, keyfilter_other, &kd, 0);
301       fclose(fp);
302       for (i = 0; i < nlanguages; i++)
303         free(languages[i]);
304       sat_free(languages);
305       repodata_free(info);
306       return 0;
307     }
308   if (attrname)
309     {
310       test_separate = 1;
311       FILE *fp = fopen(attrname, "w");
312       write_info(repo, fp, keyfilter_attr, 0, info, attrname);
313       fclose(fp);
314       kd.haveexternal = 1;
315     }
316   repodata_internalize(info);
317   repo_write(repo, stdout, keyfilter_solv, &kd, 0);
318   repodata_free(info);
319   return 0;
320 }