2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 #include <sys/types.h>
21 #include "repo_diskusagexml.h"
27 * <duinfo name="3ddiag" ver="0.742" rel="45" arch="i586">
29 * <dir name="/" size="56" count="11"/>
30 * <dir name="usr/" size="56" count="11"/>
31 * <dir name="usr/bin/" size="38" count="10"/>
32 * <dir name="usr/share/" size="18" count="1"/>
33 * <dir name="usr/share/doc/" size="18" count="1"/>
36 * <duinfo name="915resolution" ver="0.5.3" rel="74" arch="i586">
38 * <dir name="/" size="27" count="7"/>
47 STATE_DISKUSAGE, /* 1 */
61 /* !! must be sorted by first column !! */
62 static struct stateswitch stateswitches[] = {
63 { STATE_START, "diskusage", STATE_DISKUSAGE, 0 },
64 { STATE_DISKUSAGE, "duinfo", STATE_DUINFO, 0 },
65 { STATE_DUINFO, "dirs", STATE_DIRS, 0 },
66 { STATE_DIRS, "dir", STATE_DIR, 0 },
83 struct stateswitch *swtab[NUMSTATES];
84 enum state sbtab[NUMSTATES];
91 Id (*dirs)[3]; // dirid, size, nfiles
102 id3_cmp (const void *v1, const void *v2)
106 return i1[0] - i2[0];
116 commit_diskusage (struct parsedata *pd, unsigned handle)
119 Dirpool *dp = &pd->data->dirpool;
120 /* Now sort in dirid order. This ensures that parents come before
123 qsort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp);
124 /* Substract leaf numbers from all parents to make the numbers
125 non-cumulative. This must be done post-order (i.e. all leafs
126 adjusted before parents). We ensure this by starting at the end of
127 the array moving to the start, hence seeing leafs before parents. */
128 for (i = pd->ndirs; i--;)
130 unsigned p = dirpool_parent(dp, pd->dirs[i][0]);
132 for (; p; p = dirpool_parent(dp, p))
135 if (pd->dirs[j][0] == p)
139 if (pd->dirs[j][1] < pd->dirs[i][1])
142 pd->dirs[j][1] -= pd->dirs[i][1];
143 if (pd->dirs[j][2] < pd->dirs[i][2])
146 pd->dirs[j][2] -= pd->dirs[i][2];
149 /* Haven't found this parent in the list, look further if
150 we maybe find the parents parent. */
157 unsigned slen = sizeof (sbuf);
158 for (i = 0; i < pd->ndirs; i++)
160 dir2str (attr, pd->dirs[i][0], &buf, &slen);
161 fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
166 for (i = 0; i < pd->ndirs; i++)
167 if (pd->dirs[i][1] || pd->dirs[i][2])
169 repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
180 find_attr(const char *txt, const char **atts)
182 for (; *atts; atts += 2)
184 if (!strcmp(*atts, txt))
192 * create evr (as Id) from 'epoch', 'version' and 'release' attributes
196 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
198 const char *e, *v, *r, *v2;
203 for (; *atts; atts += 2)
205 if (!strcmp(*atts, "epoch"))
207 else if (!strcmp(*atts, "version"))
209 else if (!strcmp(*atts, "release"))
212 if (e && !strcmp(e, "0"))
216 for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
218 if (v2 > v && *v2 == ':')
228 if (l > pd->acontent)
230 pd->content = realloc(pd->content, l + 256);
231 pd->acontent = l + 256;
255 fprintf(stderr, "evr: %s\n", pd->content);
257 return str2id(pool, pd->content, 1);
262 * XML callback: startElement
266 startElement(void *userData, const char *name, const char **atts)
268 struct parsedata *pd = userData;
269 Pool *pool = pd->pool;
270 struct stateswitch *sw;
274 fprintf(stderr, "start: [%d]%s\n", pd->state, name);
276 if (pd->depth != pd->statedepth)
283 for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
284 if (!strcmp(sw->ename, name))
287 if (sw->from != pd->state)
290 fprintf(stderr, "into unknown: [%d]%s (from: %d)\n", sw->to, name, sw->from);
296 pd->docontent = sw->docontent;
297 pd->statedepth = pd->depth;
306 pd->s = pool_id2solvable(pd->pool, repo_add_solvable(pd->repo));
307 repodata_extend(pd->data, pd->s - pd->pool->solvables);
308 pd->handle = repodata_get_handle(pd->data, pd->s - pd->pool->solvables - pd->repo->start);
309 if ( (str = find_attr("name", atts)) )
311 pd->s->name = str2id(pool, str, 1);
313 pd->s->evr = makeevr_atts(pool, pd, atts);
314 if ( (str = find_attr("arch", atts)) )
316 pd->s->arch = str2id(pool, str, 1);
322 long filesz = 0, filenum = 0;
324 if ( (str = find_attr("name", atts)) )
326 dirid = repodata_str2dir(pd->data, str, 1);
330 fprintf( stderr, "<dir .../> tag without 'name' attribute, atts = %p, *atts = %p\n", atts, *atts);
333 if ( (str = find_attr("size", atts)) )
335 filesz = strtol (str, 0, 0);
337 if ( (str = find_attr("count", atts)) )
339 filenum = strtol (str, 0, 0);
341 pd->dirs = sat_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
342 pd->dirs[pd->ndirs][0] = dirid;
343 pd->dirs[pd->ndirs][1] = filesz;
344 pd->dirs[pd->ndirs][2] = filenum;
356 endElement(void *userData, const char *name)
358 struct parsedata *pd = userData;
361 fprintf(stderr, "end: %s\n", name);
363 if (pd->depth != pd->statedepth)
367 fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
379 commit_diskusage (pd, pd->handle);
385 pd->state = pd->sbtab[pd->state];
393 characterData(void *userData, const XML_Char *s, int len)
395 struct parsedata *pd = userData;
398 if (!pd->docontent) {
400 char *dup = strndup( s, len );
401 fprintf(stderr, "Content: [%d]'%s'\n", pd->state, dup );
406 l = pd->lcontent + len + 1;
407 if (l > pd->acontent)
409 pd->content = realloc(pd->content, l + 256);
410 pd->acontent = l + 256;
412 c = pd->content + pd->lcontent;
419 #define BUFF_SIZE 8192
422 repo_add_diskusagexml(Repo *repo, FILE *fp, int flags)
424 Pool *pool = repo->pool;
428 struct stateswitch *sw;
430 memset(&pd, 0, sizeof(pd));
431 for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
433 if (!pd.swtab[sw->from])
434 pd.swtab[sw->from] = sw;
435 pd.sbtab[sw->to] = sw->from;
439 pd.data = repo_add_repodata(pd.repo, 0);
441 pd.content = malloc(256);
444 pd.tempstr = malloc(256);
448 XML_Parser parser = XML_ParserCreate(NULL);
449 XML_SetUserData(parser, &pd);
450 XML_SetElementHandler(parser, startElement, endElement);
451 XML_SetCharacterDataHandler(parser, characterData);
454 l = fread(buf, 1, sizeof(buf), fp);
455 if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
457 fprintf(stderr, "repo_diskusagexml: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
463 XML_ParserFree(parser);
466 repodata_internalize(pd.data);