2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
18 #include "attr_store.h"
20 #include "tools_util.h"
21 #include "repo_susetags.h"
27 struct parsedata_common common;
30 int last_found_source;
33 Id (*dirs)[3]; // dirid, size, nfiles
37 static char *flagtab[] = {
49 * create and add dependency
53 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker, solvable_kind kind)
59 i = split(line + 5, sp, 4); /* name, ?, evr, ? */
60 if (i != 1 && i != 3) /* expect either 'name' or 'name' '-' 'evr' */
62 fprintf(stderr, "Bad dependency line: %s\n", line);
66 id = str2id(pool, join2(kind_prefix(kind), sp[0], 0), 1);
68 id = str2id(pool, sp[0], 1);
71 evrid = makeevr(pool, sp[2]);
72 for (flags = 0; flags < 6; flags++)
73 if (!strcmp(sp[1], flagtab[flags]))
77 fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
80 id = rel2id(pool, id, evrid, flags + 1, 1);
82 return repo_addid_dep(pd->repo, olddeps, id, marker);
95 add_location(struct parsedata *pd, char *line, Solvable *s, unsigned entry)
97 Pool *pool = s->repo->pool;
101 i = split(line, sp, 3);
102 if (i != 2 && i != 3)
104 fprintf(stderr, "Bad location line: %s\n", line);
107 /* If we have a dirname, let's see if it's the same as arch. In that
108 case don't store it. */
109 if (i == 3 && !strcmp (sp[2], id2str (pool, s->arch)))
113 /* medianr filename dir
114 don't optimize this one */
116 add_attr_special_int (attr, entry, id_medianr, atoi (sp[0]));
117 add_attr_localids_id (attr, entry, id_mediadir, str2localid (attr, sp[2], 1));
118 add_attr_string (attr, entry, id_mediafile, sp[1]);
120 repodata_set_constant(pd->data, entry, id_medianr, atoi(sp[0]));
121 repodata_set_poolstr(pd->data, entry, id_mediadir, sp[2]);
122 repodata_set_str(pd->data, entry, id_mediafile, sp[1]);
128 /* Let's see if we can optimize this a bit. If the media file name
129 can be formed by the base rpm information we don't store it, but
130 only a flag that we've seen it. */
131 unsigned int medianr = atoi (sp[0]);
132 const char *n1 = sp[1];
133 const char *n2 = id2str (pool, s->name);
134 for (n2 = id2str (pool, s->name); *n2; n1++, n2++)
137 if (*n2 || *n1 != '-')
141 for (n2 = id2str (pool, s->evr); *n2; n1++, n2++)
144 if (*n2 || *n1 != '.')
147 for (n2 = id2str (pool, s->arch); *n2; n1++, n2++)
150 if (*n2 || strcmp (n1, ".rpm"))
153 add_attr_special_int (attr, entry, id_medianr, medianr);
154 add_attr_void (attr, entry, id_mediafile);
156 repodata_set_constant(pd->data, entry, id_medianr, medianr);
157 repodata_set_void(pd->data, entry, id_mediafile);
163 add_attr_special_int (attr, entry, id_medianr, medianr);
164 add_attr_string (attr, entry, id_mediafile, sp[1]);
166 repodata_set_constant(pd->data, entry, id_medianr, medianr);
167 repodata_set_str(pd->data, entry, id_mediafile, sp[1]);
181 add_source(struct parsedata *pd, char *line, Solvable *s, unsigned entry, int first)
183 Repo *repo = s->repo;
184 Pool *pool = repo->pool;
187 if (split(line, sp, 5) != 4)
189 fprintf(stderr, "Bad source line: %s\n", line);
193 Id name = str2id(pool, sp[0], 1);
194 Id evr = makeevr(pool, join(pd, sp[1], "-", sp[2]));
195 Id arch = str2id(pool, sp[3], 1);
197 /* Now, if the source of a package only differs in architecture
198 (src or nosrc), code only that fact. */
199 if (s->name == name && s->evr == evr
200 && (arch == ARCH_SRC || arch == ARCH_NOSRC))
202 add_attr_void (attr, entry, arch == ARCH_SRC ? id_source : id_nosource);
206 if (entry >= pd->nsources)
210 pd->sources = realloc (pd->sources, (entry + 256) * sizeof (*pd->sources));
211 memset (pd->sources + pd->nsources, 0, (entry + 256 - pd->nsources) * sizeof (*pd->sources));
214 pd->sources = calloc (entry + 256, sizeof (*pd->sources));
215 pd->nsources = entry + 256;
217 /* Uarrr. Unsplit. */
218 sp[0][strlen (sp[0])] = ' ';
219 sp[1][strlen (sp[1])] = ' ';
220 sp[2][strlen (sp[2])] = ' ';
221 pd->sources[entry] = strdup (sp[0]);
227 /* Otherwise we may find a solvable with exactly matching name, evr, arch
228 in the repository already. In that case encode its ID. */
229 for (n = repo->start, nn = repo->start + pd->last_found_source;
230 n < repo->end; n++, nn++)
234 found = pool->solvables + nn;
235 if (found->repo == repo
236 && found->name == name
238 && found->arch == arch)
240 pd->last_found_source = nn - repo->start;
245 add_attr_int (attr, entry, id_sourceid, nn - repo->start);
248 add_attr_localids_id (attr, entry, id_source, str2localid (attr, sp[0], 1));
249 add_attr_localids_id (attr, entry, id_source, str2localid (attr, join (pd, sp[1], "-", sp[2]), 1));
250 add_attr_localids_id (attr, entry, id_source, str2localid (attr, sp[3], 1));
258 * add a line with directory information
263 add_dirline (struct parsedata *pd, char *line)
266 if (split (line, sp, 6) != 5)
268 pd->dirs = sat_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
269 long filesz = strtol (sp[1], 0, 0);
270 filesz += strtol (sp[2], 0, 0);
271 long filenum = strtol (sp[3], 0, 0);
272 filenum += strtol (sp[4], 0, 0);
273 /* hack: we know that there's room for a / */
276 unsigned dirid = repodata_str2dir(pd->data, sp[0], 1);
278 fprintf(stderr, "%s -> %d\n", sp[0], dirid);
280 pd->dirs[pd->ndirs][0] = dirid;
281 pd->dirs[pd->ndirs][1] = filesz;
282 pd->dirs[pd->ndirs][2] = filenum;
294 id3_cmp (const void *v1, const void *v2)
298 return i1[0] - i2[0];
308 commit_diskusage (struct parsedata *pd, unsigned entry)
311 Dirpool *dp = &pd->data->dirpool;
312 /* Now sort in dirid order. This ensures that parents come before
315 qsort (pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp);
316 /* Substract leaf numbers from all parents to make the numbers
317 non-cumulative. This must be done post-order (i.e. all leafs
318 adjusted before parents). We ensure this by starting at the end of
319 the array moving to the start, hence seeing leafs before parents. */
320 for (i = pd->ndirs; i--;)
322 unsigned p = dirpool_parent(dp, pd->dirs[i][0]);
324 for (; p; p = dirpool_parent(dp, p))
327 if (pd->dirs[j][0] == p)
331 if (pd->dirs[j][1] < pd->dirs[i][1])
334 pd->dirs[j][1] -= pd->dirs[i][1];
335 if (pd->dirs[j][2] < pd->dirs[i][2])
338 pd->dirs[j][2] -= pd->dirs[i][2];
341 /* Haven't found this parent in the list, look further if
342 we maybe find the parents parent. */
349 unsigned slen = sizeof (sbuf);
350 for (i = 0; i < pd->ndirs; i++)
352 dir2str (attr, pd->dirs[i][0], &buf, &slen);
353 fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
358 for (i = 0; i < pd->ndirs; i++)
359 if (pd->dirs[i][1] || pd->dirs[i][2])
361 repodata_add_dirnumnum(pd->data, entry, id_diskusage, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
363 add_attr_intlist_int (attr, entry, id_diskusage, pd->dirs[i][0]);
364 add_attr_intlist_int (attr, entry, id_diskusage, pd->dirs[i][1]);
365 add_attr_intlist_int (attr, entry, id_diskusage, pd->dirs[i][2]);
372 /* Unfortunately "a"[0] is no constant expression in the C languages,
373 so we need to pass the four characters individually :-/ */
374 #define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \
375 | ((unsigned char)b << 16) \
376 | ((unsigned char)c << 8) \
377 | ((unsigned char)d))
384 static inline unsigned
385 tag_from_string (char *cs)
387 unsigned char *s = (unsigned char*) cs;
388 return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]);
394 * Parse susetags file passed in fp, fill solvables into repo
399 repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr)
401 Pool *pool = repo->pool;
408 int last_found_pack = 0;
417 attr = new_store(pool);
419 data = repo_add_repodata(repo);
424 memset(&pd, 0, sizeof(pd));
428 pd.repo = pd.common.repo = repo;
430 pd.common.pool = pool;
438 if (linep - line + 16 > aline)
440 aline = linep - line;
441 line = realloc(line, aline + 512);
442 linep = line + aline;
445 if (!fgets(linep, aline - (linep - line), fp))
447 linep += strlen(linep);
448 if (linep == line || linep[-1] != '\n')
453 int isend = linep[-intag - 2] == '-' && linep[-1] == ':' && !strncmp(linep - 1 - intag, line + 1, intag) && (linep == line + 1 + intag + 1 + 1 + 1 + intag + 1 || linep[-intag - 3] == '\n');
454 if (cummulate && !isend)
459 if (cummulate && isend)
461 linep[-intag - 2] = 0;
462 if (linep[-intag - 3] == '\n')
463 linep[-intag - 3] = 0;
467 if (!cummulate && isend)
473 if (!cummulate && !isend)
474 linep = line + intag + 3;
478 if (!intag && line[0] == '+' && line[1] && line[1] != ':')
480 char *tagend = strchr(line, ':');
483 fprintf(stderr, "bad line: %s\n", line);
486 intag = tagend - (line + 1);
488 switch (tag_from_string (line))
490 case CTAG('+', 'D', 'e', 's'):
491 case CTAG('+', 'E', 'u', 'l'):
492 case CTAG('+', 'I', 'n', 's'):
493 case CTAG('+', 'D', 'e', 'l'):
494 case CTAG('+', 'A', 'u', 't'):
499 line[intag + 2] = ' ';
500 linep = line + intag + 3;
503 if (*line == '#' || !*line)
505 if (! (line[0] && line[1] && line[2] && line[3] && line[4] == ':'))
507 tag = tag_from_string (line);
510 if ((tag == CTAG('=', 'P', 'k', 'g')
511 || tag == CTAG('=', 'P', 'a', 't')))
514 /* If we have an old solvable, complete it by filling in some
518 /* A self provide, except for source packages. This is harmless
519 to do twice (in case we see the same package twice). */
520 if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
521 s->provides = repo_addid_dep(repo, s->provides,
522 rel2id(pool, s->name, s->evr,
524 /* XXX This uses repo_addid_dep internally, so should also be
525 harmless to do twice. */
526 s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
528 commit_diskusage (&pd, last_found_pack);
531 pd.kind = KIND_PACKAGE;
533 pd.kind = KIND_PATTERN;
534 if (split(line + 5, sp, 5) != 4)
536 fprintf(stderr, "Bad line: %s\n", line);
539 /* Lookup (but don't construct) the name and arch. */
541 name = str2id(pool, join2(kind_prefix(pd.kind), sp[0], 0), 0);
543 name = str2id(pool, sp[0], 0);
544 arch = str2id(pool, sp[3], 0);
545 evr = makeevr(pool, join2(sp[1], "-", sp[2]));
549 /* Now see if we know this solvable already. If we found neither
550 the name nor the arch at all in this repo
551 there's no chance of finding the exact solvable either. */
552 if (indesc >= 2 && name && arch)
555 /* Now look for a solvable with the given name,evr,arch.
556 Our input is structured so, that the second set of =Pkg
557 lines comes in roughly the same order as the first set, so we
558 have a hint at where to start our search, namely were we found
560 for (n = repo->start, nn = n + last_found_pack; n < repo->end; n++, nn++)
564 s = pool->solvables + nn;
565 if (s->repo == repo && s->name == name && s->evr == evr && s->arch == arch)
571 last_found_pack = nn - repo->start;
574 /* And if we still don't have a solvable, create a new one. */
577 s = pool_id2solvable(pool, repo_add_solvable(repo));
578 last_found_pack = (s - pool->solvables) - repo->start;
580 repodata_extend(data, s - pool->solvables);
585 s->name = str2id(pool, join2(kind_prefix(pd.kind), sp[0], 0), 1);
587 s->name = str2id(pool, sp[0], 1);
592 s->arch = str2id(pool, sp[3], 1);
597 /* If we have no current solvable to add to, ignore all further lines
598 for it. Probably invalid input data in the second set of
600 if (indesc >= 2 && !s)
602 fprintf (stderr, "Huh?\n");
607 case CTAG('=', 'P', 'r', 'v'):
608 s->provides = adddep(pool, &pd, s->provides, line, 0, pd.kind);
610 case CTAG('=', 'R', 'e', 'q'):
611 s->requires = adddep(pool, &pd, s->requires, line, -SOLVABLE_PREREQMARKER, pd.kind);
613 case CTAG('=', 'P', 'r', 'q'):
615 s->requires = adddep(pool, &pd, s->requires, line, 0, 0); /* Huh? No PreReq for non-packages ? */
617 s->requires = adddep(pool, &pd, s->requires, line, SOLVABLE_PREREQMARKER, 0);
619 case CTAG('=', 'O', 'b', 's'):
620 s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, pd.kind);
622 case CTAG('=', 'C', 'o', 'n'):
623 s->conflicts = adddep(pool, &pd, s->conflicts, line, 0, pd.kind);
625 case CTAG('=', 'R', 'e', 'c'):
626 s->recommends = adddep(pool, &pd, s->recommends, line, 0, pd.kind);
628 case CTAG('=', 'S', 'u', 'p'):
629 s->supplements = adddep(pool, &pd, s->supplements, line, 0, pd.kind);
631 case CTAG('=', 'E', 'n', 'h'):
632 s->enhances = adddep(pool, &pd, s->enhances, line, 0, pd.kind);
634 case CTAG('=', 'S', 'u', 'g'):
635 s->suggests = adddep(pool, &pd, s->suggests, line, 0, pd.kind);
637 case CTAG('=', 'F', 'r', 'e'):
638 s->freshens = adddep(pool, &pd, s->freshens, line, 0, pd.kind);
640 case CTAG('=', 'P', 'r', 'c'):
641 s->recommends = adddep(pool, &pd, s->recommends, line, 0, 0);
643 case CTAG('=', 'P', 's', 'g'):
644 s->suggests = adddep(pool, &pd, s->suggests, line, 0, 0);
646 case CTAG('=', 'V', 'e', 'r'):
655 case CTAG('=', 'G', 'r', 'p'):
656 repodata_set_poolstr(data, last_found_pack, id_group, line + 6);
658 case CTAG('=', 'L', 'i', 'c'):
659 repodata_set_poolstr(data, last_found_pack, id_license, line + 6);
661 case CTAG('=', 'L', 'o', 'c'):
662 add_location(&pd, line + 6, s, last_found_pack);
665 case CTAG('=', 'S', 'r', 'c'):
666 add_source(&pd, line + 6, s, last_found_pack, 1);
669 case CTAG('=', 'S', 'i', 'z'):
670 if (split (line + 6, sp, 3) == 2)
672 repodata_set_num(data, last_found_pack, id_downloadsize, (atoi(sp[0]) + 1023) / 1024);
673 repodata_set_num(data, last_found_pack, id_installsize, (atoi(sp[1]) + 1023) / 1024);
676 case CTAG('=', 'T', 'i', 'm'):
678 unsigned int t = atoi (line + 6);
681 repodata_set_num(data, last_found_pack, id_time, t);
685 case CTAG('=', 'K', 'w', 'd'):
686 repodata_set_poolstr(data, last_found_pack, id_keywords, line + 6);
688 case CTAG('=', 'A', 'u', 't'):
689 repodata_set_str(data, last_found_pack, id_authors, line + 6);
691 case CTAG('=', 'S', 'u', 'm'):
692 repodata_set_str(data, last_found_pack, id_summary, line + 6);
694 case CTAG('=', 'D', 'e', 's'):
695 repodata_set_str(data, last_found_pack, id_description, line + 6);
697 case CTAG('=', 'E', 'u', 'l'):
698 repodata_set_str(data, last_found_pack, id_eula, line + 6);
700 case CTAG('=', 'I', 'n', 's'):
701 repodata_set_str(data, last_found_pack, id_messageins, line + 6);
703 case CTAG('=', 'D', 'e', 'l'):
704 repodata_set_str(data, last_found_pack, id_messagedel, line + 6);
706 case CTAG('=', 'S', 'h', 'r'):
707 if (last_found_pack >= pd.nshare)
711 pd.share_with = realloc (pd.share_with, (last_found_pack + 256) * sizeof (*pd.share_with));
712 memset (pd.share_with + pd.nshare, 0, (last_found_pack + 256 - pd.nshare) * sizeof (*pd.share_with));
715 pd.share_with = calloc (last_found_pack + 256, sizeof (*pd.share_with));
716 pd.nshare = last_found_pack + 256;
718 pd.share_with[last_found_pack] = strdup (line + 6);
720 case CTAG('=', 'D', 'i', 'r'):
721 add_dirline (&pd, line + 6);
725 if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
726 s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
728 s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
731 commit_diskusage(&pd, last_found_pack);
737 for (i = 0; i < pd.nsources; i++)
740 add_source(&pd, pd.sources[i], pool->solvables + repo->start + i, i, 0);
741 free (pd.sources[i]);
751 for (i = 0; i < pd.nshare; i++)
752 if (pd.share_with[i])
754 if (split(pd.share_with[i], sp, 5) != 4)
756 fprintf(stderr, "Bad =Shr line: %s\n", pd.share_with[i]);
760 Id name = str2id(pool, sp[0], 1);
761 Id evr = makeevr(pool, join2(sp[1], "-", sp[2]));
762 Id arch = str2id(pool, sp[3], 1);
765 for (n = repo->start, nn = repo->start + last_found;
766 n < repo->end; n++, nn++)
770 found = pool->solvables + nn;
771 if (found->repo == repo
772 && found->name == name
774 && found->arch == arch)
776 last_found = nn - repo->start;
781 repodata_merge_attrs (data, i, last_found);
783 free (pd.share_with);
787 repodata_internalize(data);