Start of an attribute store. It can hold arbitrary attributes for a
authorMichael Matz <matz@suse.de>
Sun, 28 Oct 2007 23:09:45 +0000 (23:09 +0000)
committerMichael Matz <matz@suse.de>
Sun, 28 Oct 2007 23:09:45 +0000 (23:09 +0000)
number of entities.  When those are build as mirroring the solvables in
a Repo, we can attach non-solver information to them.  Not yet really
integrated, uses too much in-core memory, and arbitrary blobs are not
yet supported (for descriptions and maybe large author lists).

tools/CMakeLists.txt
tools/attr_store.c [new file with mode: 0644]
tools/attr_store.h [new file with mode: 0644]
tools/attr_store_p.h [new file with mode: 0644]
tools/dumpattr.c [new file with mode: 0644]
tools/repo_susetags.c
tools/repo_susetags.h
tools/susetags2solv.c

index a09387f..f7718ea 100644 (file)
@@ -17,7 +17,7 @@ SET(helix2solv_REPOS helix2solv.c repo_helix.h repo_helix.c repo_write.c )
 ADD_EXECUTABLE( helix2solv ${helix2solv_REPOS} )
 TARGET_LINK_LIBRARIES( helix2solv satsolver ${EXPAT_LIBRARY})
 
-SET(susetags2solv_REPOS susetags2solv.c repo_susetags.h repo_susetags.c repo_write.c)
+SET(susetags2solv_REPOS susetags2solv.c repo_susetags.h repo_susetags.c repo_write.c attr_store.c)
 ADD_EXECUTABLE( susetags2solv ${susetags2solv_REPOS} )
 TARGET_LINK_LIBRARIES( susetags2solv satsolver)
 
@@ -41,4 +41,8 @@ TARGET_LINK_LIBRARIES( dumpsolv satsolver)
 
 SET(mergesolv_REPOS mergesolv.c repo_write.c)
 ADD_EXECUTABLE( mergesolv ${mergesolv_REPOS} )
-TARGET_LINK_LIBRARIES( mergesolv satsolver)
\ No newline at end of file
+TARGET_LINK_LIBRARIES( mergesolv satsolver)
+
+SET(dumpattr_REPOS dumpattr.c attr_store.c)
+ADD_EXECUTABLE( dumpattr ${dumpattr_REPOS} )
+TARGET_LINK_LIBRARIES( dumpattr satsolver)
diff --git a/tools/attr_store.c b/tools/attr_store.c
new file mode 100644 (file)
index 0000000..17da341
--- /dev/null
@@ -0,0 +1,803 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "attr_store.h"
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+
+#include "attr_store_p.h"
+
+#define NAME_WIDTH 12
+#define TYPE_WIDTH (16-NAME_WIDTH)
+typedef union
+{
+  struct {
+    unsigned short name : NAME_WIDTH;
+    unsigned short type : TYPE_WIDTH;
+  } nt;
+  unsigned short as_short;
+} NameType;
+
+typedef struct
+{
+  NameType n;
+  char val[0];
+} __attribute__((packed)) NameVal;
+
+#define STRINGSPACE_BLOCK 1023
+#define STRING_BLOCK 127
+#define LOCALID_NULL  0
+#define LOCALID_EMPTY 1
+
+Attrstore *
+new_store (Pool *pool)
+{
+  Attrstore *s = calloc (1, sizeof (Attrstore));
+  s->pool = pool;
+  s->nameids = calloc (128, sizeof (s->nameids[0]));
+  s->num_nameids = 2;
+  s->nameids[0] = 0;
+  s->nameids[1] = 1;
+
+  int totalsize = strlen ("<NULL>") + 1 + 1;
+  int count = 2;
+
+  // alloc appropriate space
+  s->stringspace = (char *)xmalloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
+  s->strings = (Offset *)xmalloc(((count + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset));
+
+  // now copy predefined strings into allocated space
+  s->sstrings = 0;
+  strcpy (s->stringspace + s->sstrings, "<NULL>");
+  s->strings[0] = s->sstrings;
+  s->sstrings += strlen (s->stringspace + s->strings[0]) + 1;
+  strcpy (s->stringspace + s->sstrings, "");
+  s->strings[1] = s->sstrings;
+  s->sstrings += strlen (s->stringspace + s->strings[1]) + 1;
+
+  s->nstrings = 2;
+
+  return s;
+}
+
+LocalId
+str2localid (Attrstore *s, const char *str, int create)
+{
+  Hashval h;
+  unsigned int hh;
+  Hashmask hashmask;
+  int i, space_needed;
+  LocalId id;
+  Hashtable hashtbl;
+
+  // check string
+  if (!str)
+    return LOCALID_NULL;
+  if (!*str)
+    return LOCALID_EMPTY;
+
+  hashmask = s->stringhashmask;
+  hashtbl = s->stringhashtbl;
+
+  // expand hashtable if needed
+  if (s->nstrings * 2 > hashmask)
+    {
+      xfree(hashtbl);
+
+      // realloc hash table
+      s->stringhashmask = hashmask = mkmask(s->nstrings + STRING_BLOCK);
+      s->stringhashtbl = hashtbl = (Hashtable)xcalloc(hashmask + 1, sizeof(Id));
+
+      // rehash all strings into new hashtable
+      for (i = 1; i < s->nstrings; i++)
+       {
+         h = strhash(s->stringspace + s->strings[i]) & hashmask;
+         hh = HASHCHAIN_START;
+         while (hashtbl[h] != 0)
+           h = HASHCHAIN_NEXT(h, hh, hashmask);
+         hashtbl[h] = i;
+       }
+    }
+
+  // compute hash and check for match
+
+  h = strhash(str) & hashmask;
+  hh = HASHCHAIN_START;
+  while ((id = hashtbl[h]) != 0)
+    {
+      // break if string already hashed
+      if(!strcmp(s->stringspace + s->strings[id], str))
+       break;
+      h = HASHCHAIN_NEXT(h, hh, hashmask);
+    }
+  if (id || !create)    // exit here if string found
+    return id;
+
+  // generate next id and save in table
+  id = s->nstrings++;
+  hashtbl[h] = id;
+
+  if ((id & STRING_BLOCK) == 0)
+    s->strings = xrealloc(s->strings, ((s->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Hashval));
+  // 'pointer' into stringspace is Offset of next free pos: sstrings
+  s->strings[id] = s->sstrings;
+
+  space_needed = strlen(str) + 1;
+
+  // resize string buffer if needed
+  if (((s->sstrings + space_needed - 1) | STRINGSPACE_BLOCK) != ((s->sstrings - 1) | STRINGSPACE_BLOCK))
+    s->stringspace = xrealloc(s->stringspace, (s->sstrings + space_needed + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
+  // copy new string into buffer
+  memcpy(s->stringspace + s->sstrings, str, space_needed);
+  // next free pos is behind new string
+  s->sstrings += space_needed;
+
+  return id;
+}
+
+const char *
+localid2str(Attrstore *s, LocalId id)
+{
+  return s->stringspace + s->strings[id];
+}
+
+static NameId
+id2nameid (Attrstore *s, Id id)
+{
+  unsigned int i;
+  for (i = 0; i < s->num_nameids; i++)
+    if (s->nameids[i] == id)
+      return i;
+  if (s->num_nameids >= (1 << NAME_WIDTH))
+    {
+      fprintf (stderr, "Too many attribute names\n");
+      exit (1);
+    }
+  if ((s->num_nameids & 127) == 0)
+    s->nameids = realloc (s->nameids, ((s->num_nameids+128) * sizeof (s->nameids[0])));
+  s->nameids[s->num_nameids++] = id;
+  return s->num_nameids - 1;
+}
+
+NameId
+str2nameid (Attrstore *s, const char *str)
+{
+  return id2nameid (s, str2id (s->pool, str, 1));
+}
+
+void
+ensure_entry (Attrstore *s, unsigned int entry)
+{
+  unsigned int old_num = s->entries;
+  if (entry < s->entries)
+    return;
+  s->entries = entry + 1;
+  if (((old_num + 127) & ~127) != ((s->entries + 127) & ~127))
+    {
+      if (s->attrs)
+        s->attrs = realloc (s->attrs, (((s->entries+127) & ~127) * sizeof (s->attrs[0])));
+      else
+        s->attrs = malloc (((s->entries+127) & ~127) * sizeof (s->attrs[0]));
+    }
+  memset (s->attrs + old_num, 0, (s->entries - old_num) * sizeof (s->attrs[0]));
+}
+
+unsigned int
+new_entry (Attrstore *s)
+{
+  if ((s->entries & 127) == 0)
+    {
+      if (s->attrs)
+        s->attrs = realloc (s->attrs, ((s->entries+128) * sizeof (s->attrs[0])));
+      else
+        s->attrs = malloc ((s->entries+128) * sizeof (s->attrs[0]));
+    }
+  s->attrs[s->entries++] = 0;
+  return s->entries - 1;
+}
+
+static LongNV *
+find_attr (Attrstore *s, unsigned int entry, NameId name)
+{
+  LongNV *nv;
+  if (entry >= s->entries)
+    return 0;
+  if (name >= s->num_nameids)
+    return 0;
+  nv = s->attrs[entry];
+  if (nv)
+    {
+      while (nv->name && nv->name != name)
+       nv++;
+      if (nv->name)
+        return nv;
+    }
+  return 0;
+}
+
+static void
+add_attr (Attrstore *s, unsigned int entry, LongNV attr)
+{
+  LongNV *nv;
+  unsigned int len;
+  if (entry >= s->entries)
+    return;
+  if (attr.name >= s->num_nameids)
+    return;
+  nv = s->attrs[entry];
+  len = 0;
+  if (nv)
+    {
+      while (nv->name && nv->name != attr.name)
+       nv++;
+      if (nv->name)
+        return;
+      len = nv - s->attrs[entry];
+    }
+  len += 2;
+  if (s->attrs[entry])
+    s->attrs[entry] = realloc (s->attrs[entry], len * sizeof (LongNV));
+  else
+    s->attrs[entry] = malloc (len * sizeof (LongNV));
+  nv = s->attrs[entry] + len - 2;
+  *nv++ = attr;
+  nv->name = 0;
+}
+
+void
+add_attr_int (Attrstore *s, unsigned int entry, NameId name, unsigned int val)
+{
+  LongNV nv;
+  nv.name = name;
+  nv.type = ATTR_INT;
+  nv.v.i[0] = val;
+  add_attr (s, entry, nv);
+}
+
+void
+add_attr_chunk (Attrstore *s, unsigned int entry, NameId name, unsigned int ofs, unsigned int len)
+{
+  LongNV nv;
+  nv.name = name;
+  nv.type = ATTR_CHUNK;
+  nv.v.i[0] = ofs;
+  nv.v.i[1] = len;
+  add_attr (s, entry, nv);
+}
+
+void
+add_attr_string (Attrstore *s, unsigned int entry, NameId name, const char *val)
+{
+  LongNV nv;
+  nv.name = name;
+  nv.type = ATTR_STRING;
+  nv.v.str = strdup (val);
+  add_attr (s, entry, nv);
+}
+
+void
+add_attr_id (Attrstore *s, unsigned int entry, NameId name, Id val)
+{
+  LongNV nv;
+  nv.name = name;
+  nv.type = ATTR_ID;
+  nv.v.i[0] = val;
+  add_attr (s, entry, nv);
+}
+
+void
+add_attr_intlist_int (Attrstore *s, unsigned int entry, NameId name, int val)
+{
+  LongNV *nv = find_attr (s, entry, name);
+  if (val == 0)
+    return;
+  if (nv)
+    {
+      unsigned len = 0;
+      while (nv->v.intlist[len])
+        len++;
+      nv->v.intlist = realloc (nv->v.intlist, (len + 2) * sizeof (nv->v.intlist[0]));
+      nv->v.intlist[len] = val;
+      nv->v.intlist[len+1] = 0;
+    }
+  else
+    {
+      LongNV mynv;
+      mynv.name = name;
+      mynv.type = ATTR_INTLIST;
+      mynv.v.intlist = malloc (2 * sizeof (mynv.v.intlist[0]));
+      mynv.v.intlist[0] = val;
+      mynv.v.intlist[1] = 0;
+      add_attr (s, entry, mynv);
+    }
+}
+
+void
+add_attr_localids_id (Attrstore *s, unsigned int entry, NameId name, LocalId id)
+{
+  LongNV *nv = find_attr (s, entry, name);
+  if (nv)
+    {
+      unsigned len = 0;
+      while (nv->v.localids[len])
+        len++;
+      nv->v.localids = realloc (nv->v.localids, (len + 2) * sizeof (nv->v.localids[0]));
+      nv->v.localids[len] = id;
+      nv->v.localids[len+1] = 0;
+    }
+  else
+    {
+      LongNV mynv;
+      mynv.name = name;
+      mynv.type = ATTR_LOCALIDS;
+      mynv.v.localids = malloc (2 * sizeof (mynv.v.localids[0]));
+      mynv.v.localids[0] = id;
+      mynv.v.localids[1] = 0;
+      add_attr (s, entry, mynv);
+    }
+}
+
+static void
+write_u32(FILE *fp, unsigned int x)
+{
+  if (putc(x >> 24, fp) == EOF ||
+      putc(x >> 16, fp) == EOF ||
+      putc(x >> 8, fp) == EOF ||
+      putc(x, fp) == EOF)
+    {
+      perror("write error");
+      exit(1);
+    }
+}
+
+static void
+write_u8(FILE *fp, unsigned int x)
+{
+  if (putc(x, fp) == EOF)
+    {
+      perror("write error");
+      exit(1);
+    }
+}
+
+static void
+write_id(FILE *fp, Id x)
+{
+  if (x >= (1 << 14))
+    {
+      if (x >= (1 << 28))
+       putc((x >> 28) | 128, fp);
+      if (x >= (1 << 21))
+       putc((x >> 21) | 128, fp);
+      putc((x >> 14) | 128, fp);
+    }
+  if (x >= (1 << 7))
+    putc((x >> 7) | 128, fp);
+  if (putc(x & 127, fp) == EOF)
+    {
+      perror("write error");
+      exit(1);
+    }
+}
+
+static void
+write_idarray(FILE *fp, Id *ids)
+{
+  Id id;
+  if (!ids)
+    return;
+  if (!*ids)
+    {
+      write_u8(fp, 0);
+      return;
+    }
+  for (;;)
+    {
+      id = *ids++;
+      if (id >= 64)
+       id = (id & 63) | ((id & ~63) << 1);
+      if (!*ids)
+       {
+         write_id(fp, id);
+         return;
+       }
+      write_id(fp, id | 64);
+    }
+}
+
+static void
+write_attrs (FILE *fp, LongNV *nv)
+{
+  if (!nv)
+    {
+      write_id (fp, 0);
+      return;
+    }
+  while (nv->name)
+    {
+      write_id (fp, nv->name);
+      write_u8 (fp, nv->type);
+      switch (nv->type)
+       {
+         case ATTR_INT:
+         case ATTR_ID:
+           write_id (fp, nv->v.i[0]);
+           break;
+         case ATTR_CHUNK:
+           write_id (fp, nv->v.i[0]);
+           write_id (fp, nv->v.i[1]);
+           break;
+         case ATTR_STRING:
+           if (fputs (nv->v.str, fp) == EOF
+               || putc (0, fp) == EOF)
+             {
+               perror ("write error");
+               exit (1);
+             }
+           break;
+         case ATTR_INTLIST:
+           {
+             write_idarray (fp, nv->v.intlist);
+             break;
+           }
+         case ATTR_LOCALIDS:
+           {
+             write_idarray (fp, nv->v.localids);
+             break;
+           }
+         default:
+           break;
+       }
+      nv++;
+    }
+  write_id (fp, 0);
+}
+
+void
+write_attr_store (FILE *fp, Attrstore *s)
+{
+  unsigned i;
+  unsigned local_ssize;
+  write_u32 (fp, s->entries);
+  write_u32 (fp, s->num_nameids);
+  write_u32 (fp, s->nstrings);
+  for (i = 2; i < s->num_nameids; i++)
+    {
+      const char *str = id2str (s->pool, s->nameids[i]);
+      if (fwrite(str, strlen(str) + 1, 1, fp) != 1)
+       {
+         perror("write error");
+         exit(1);
+       }
+    }
+
+  for (i = 2, local_ssize = 0; i < (unsigned)s->nstrings; i++)
+    local_ssize += strlen (localid2str (s, i)) + 1;
+
+  write_u32 (fp, local_ssize);
+  for (i = 2; i < (unsigned)s->nstrings; i++)
+    {
+      const char *str = localid2str (s, i);
+      if (fwrite(str, strlen(str) + 1, 1, fp) != 1)
+       {
+         perror("write error");
+         exit(1);
+       }
+    }
+
+  for (i = 0; i < s->entries; i++)
+    write_attrs (fp, s->attrs[i]);
+}
+
+static unsigned int
+read_u32(FILE *fp)
+{
+  int c, i;
+  unsigned int x = 0;
+
+  for (i = 0; i < 4; i++)
+    {
+      c = getc(fp);
+      if (c == EOF)
+       {
+         fprintf(stderr, "unexpected EOF\n");
+         exit(1);
+       }
+      x = (x << 8) | c;
+    }
+  return x;
+}
+
+static unsigned int
+read_u8(FILE *fp)
+{
+  int c;
+  c = getc(fp);
+  if (c == EOF)
+    {
+      fprintf(stderr, "unexpected EOF\n");
+      exit(1);
+    }
+  return c;
+}
+
+static const char *
+read_string (FILE *fp)
+{
+  char *buf;
+  size_t buflen;
+  buflen = 128;
+  buf = malloc (buflen);
+  size_t p = 0;
+  while (1)
+    {
+      int c = getc (fp);
+      if (c == EOF)
+       {
+         perror ("error reading string");
+         exit (1);
+       }
+      if (p == buflen)
+       {
+         buflen += 128;
+         buf = realloc (buf, buflen);
+       }
+      buf[p++] = c;
+      if (!c)
+       break;
+    }
+  buf = realloc (buf, p);
+  return buf;
+}
+
+static Id
+read_id(FILE *fp, Id max)
+{
+  unsigned int x = 0;
+  int c, i;
+
+  for (i = 0; i < 5; i++)
+    {
+      c = getc(fp);
+      if (c == EOF)
+       {
+         fprintf(stderr, "unexpected EOF\n");
+         exit(1);
+       }
+      if (!(c & 128))
+       {
+         x = (x << 7) | c;
+         if (max && x >= max)
+           {
+             fprintf(stderr, "read_id: id too large (%u/%u)\n", x, max);
+             exit(1);
+           }
+         return x;
+       }
+      x = (x << 7) ^ c ^ 128;
+    }
+  fprintf(stderr, "read_id: id too long\n");
+  exit(1);
+}
+
+static Id *
+read_idarray (FILE *fp, Id max)
+{
+  Id *ret, id;
+  unsigned int len, num_elem;
+
+  id = read_id (fp, 0);
+  if (!id)
+    {
+      ret = malloc (sizeof (ret[0]));
+      ret[0] = 0;
+      return ret;
+    }
+
+  num_elem = 0;
+  len = 8;
+  ret = malloc (len * sizeof (ret[0]));
+  for (;;)
+    {
+      Id real = (id & 63) | ((id >> 1) & ~63);
+      if (max && real >= max)
+       {
+         fprintf(stderr, "read_id: id too large (%u/%u)\n", real, max);
+         exit(1);
+       }
+      ret[num_elem++] = real;
+      if (num_elem == len)
+        {
+         len += 8;
+         ret = realloc (ret, len * sizeof (ret[0]));
+       }
+      if ((id & 64) == 0)
+        {
+          ret[num_elem++] = 0;
+         break;
+       }
+      id = read_id (fp, 0);
+    }
+  ret = realloc (ret, num_elem * sizeof (ret[0]));
+  return ret;
+}
+
+static LongNV *
+read_attrs (FILE *fp, Attrstore *s)
+{
+  LongNV *ret, *nv;
+  unsigned int len, num_elem;
+  Id id = read_id (fp, s->num_nameids);
+  if (!id)
+    return 0;
+  len = 16;
+  num_elem = 0;
+  ret = malloc (len * sizeof (ret[0]));
+  nv = ret;
+  while (id)
+    {
+      nv->name = id;
+      nv->type = read_u8 (fp);
+      switch (nv->type)
+       {
+         case ATTR_INT:
+         case ATTR_ID:
+           nv->v.i[0] = read_id (fp, 0);
+           break;
+         case ATTR_CHUNK:
+           nv->v.i[0] = read_id (fp, 0);
+           nv->v.i[1] = read_id (fp, 0);
+           break;
+         case ATTR_STRING:
+           nv->v.str = read_string (fp);
+           break;
+         case ATTR_INTLIST:
+           {
+             nv->v.intlist = read_idarray (fp, 0);
+             break;
+           }
+         case ATTR_LOCALIDS:
+           {
+             nv->v.localids = read_idarray (fp, s->nstrings);
+             break;
+           }
+         default:
+           break;
+       }
+      num_elem++;
+      if (num_elem == len)
+        {
+         len += 16;
+         ret = realloc (ret, len * sizeof (ret[0]));
+       }
+      nv = ret + num_elem;
+      id = read_id (fp, s->num_nameids);
+    }
+  nv->name = 0;
+  num_elem++;
+  ret = realloc (ret, num_elem * sizeof (ret[0]));
+  return ret;
+}
+
+Attrstore *
+attr_store_read (FILE *fp, Pool *pool)
+{
+  unsigned nentries;
+  unsigned i;
+  unsigned local_ssize;
+  unsigned nstrings;
+  char *buf;
+  size_t buflen;
+  Attrstore *s = new_store (pool);
+
+  nentries = read_u32 (fp);
+  s->num_nameids = read_u32 (fp);
+  nstrings = read_u32 (fp);
+
+  ensure_entry (s, nentries);
+
+  buflen = 128;
+  buf = malloc (buflen);
+
+  s->nameids = realloc (s->nameids, (((s->num_nameids+127) & ~127) * sizeof (s->nameids[0])));
+  for (i = 2; i < s->num_nameids; i++)
+    {
+      size_t p = 0;
+      while (1)
+        {
+         int c = getc (fp);
+         if (c == EOF)
+           {
+             perror ("error reading namestrings");
+             exit (1);
+           }
+         if (p == buflen)
+           {
+             buflen += 128;
+             buf = realloc (buf, buflen);
+           }
+         buf[p++] = c;
+         if (!c)
+           break;
+       }
+      s->nameids[i] = str2id (s->pool, buf, 1);
+    }
+
+  local_ssize = read_u32 (fp);
+  char *strsp = (char *)xrealloc(s->stringspace, s->sstrings + local_ssize + 1);
+  Offset *str = (Offset *)xrealloc(s->strings, (nstrings) * sizeof(Offset));
+
+  s->stringspace = strsp;
+  s->strings = str;
+  strsp += s->sstrings;
+
+  if (fread(strsp, local_ssize, 1, fp) != 1)
+    {
+      perror ("read error while reading strings");
+      exit(1);
+    }
+  strsp[local_ssize] = 0;
+
+  s->stringhashmask = mkmask(nstrings);
+  xfree (s->stringhashtbl);
+  s->stringhashtbl = (Hashtable)xcalloc(s->stringhashmask + 1, sizeof(Id));
+
+  strsp = s->stringspace;
+  s->nstrings = nstrings;
+  for (i = 0; i < nstrings; i++)
+    {
+      str[i] = strsp - s->stringspace;
+      Hashval h = strhash(strsp) & s->stringhashmask;
+      unsigned int hh = HASHCHAIN_START;
+      while (s->stringhashtbl[h] != 0)
+       h = HASHCHAIN_NEXT(h, hh, s->stringhashmask);
+      s->stringhashtbl[h] = i;
+      strsp += strlen (strsp) + 1;
+    }
+  s->sstrings = strsp - s->stringspace;
+
+  for (i = 0; i < nentries; i++)
+    s->attrs[i] = read_attrs (fp, s);
+
+  s->entries = nentries;
+
+  free (buf);
+
+  return s;
+}
+
+#ifdef MAIN
+int
+main (void)
+{
+  Pool *pool = pool_create ();
+  Attrstore *s = new_store (pool);
+  unsigned int id1 = new_entry (s);
+  unsigned int id2 = new_entry (s);
+  unsigned int id3 = new_entry (s);
+  unsigned int id4 = new_entry (s);
+  add_attr_int (s, id1, str2nameid (s, "name1"), 42);
+  add_attr_chunk (s, id1, str2nameid (s, "name2"), 9876, 1024);
+  add_attr_string (s, id1, str2nameid (s, "name3"), "hallo");
+  add_attr_int (s, id1, str2nameid (s, "name1"), 43);
+  add_attr_id (s, id1, str2nameid (s, "id1"), 100);
+  add_attr_intlist_int (s, id1, str2nameid (s, "intlist1"), 3);
+  add_attr_intlist_int (s, id1, str2nameid (s, "intlist1"), 14);
+  add_attr_intlist_int (s, id1, str2nameid (s, "intlist1"), 1);
+  add_attr_intlist_int (s, id1, str2nameid (s, "intlist1"), 59);
+  add_attr_localids_id (s, id1, str2nameid (s, "l_ids1"), str2localid (s, "one", 1));
+  add_attr_localids_id (s, id1, str2nameid (s, "l_ids1"), str2localid (s, "two", 1));
+  add_attr_localids_id (s, id1, str2nameid (s, "l_ids1"), str2localid (s, "three", 1));
+  add_attr_localids_id (s, id1, str2nameid (s, "l_ids2"), str2localid (s, "three", 1));
+  add_attr_localids_id (s, id1, str2nameid (s, "l_ids2"), str2localid (s, "two", 1));
+  add_attr_localids_id (s, id1, str2nameid (s, "l_ids2"), str2localid (s, "one", 1));
+  write_attr_store (stdout, s);
+  return 0;
+}
+#endif
diff --git a/tools/attr_store.h b/tools/attr_store.h
new file mode 100644 (file)
index 0000000..daa91c6
--- /dev/null
@@ -0,0 +1,32 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "poolid.h"
+
+struct _Pool;
+struct _Attrstore;
+typedef struct _Attrstore Attrstore;
+typedef unsigned short NameId;
+typedef Id LocalId;
+
+Attrstore * new_store (struct _Pool *pool);
+unsigned int new_entry (Attrstore *s);
+Attrstore * attr_store_read (FILE *fp, struct _Pool *pool);
+void ensure_entry (Attrstore *s, unsigned int entry);
+void write_attr_store (FILE *fp, Attrstore *s);
+
+NameId  str2nameid (Attrstore *s, const char *str);
+LocalId str2localid (Attrstore *s, const char *str, int create);
+const char * localid2str(Attrstore *s, LocalId id);
+
+void add_attr_int (Attrstore *s, unsigned int entry, NameId name, unsigned int val);
+void add_attr_chunk (Attrstore *s, unsigned int entry, NameId name, unsigned int ofs, unsigned int len);
+void add_attr_string (Attrstore *s, unsigned int entry, NameId name, const char *val);
+void add_attr_id (Attrstore *s, unsigned int entry, NameId name, Id val);
+void add_attr_intlist_int (Attrstore *s, unsigned int entry, NameId name, int val);
+void add_attr_localids_id (Attrstore *s, unsigned int entry, NameId name, LocalId id);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tools/attr_store_p.h b/tools/attr_store_p.h
new file mode 100644 (file)
index 0000000..d455e81
--- /dev/null
@@ -0,0 +1,36 @@
+typedef struct
+{
+  NameId name;
+  unsigned type;
+#define ATTR_INT      0
+#define ATTR_CHUNK    1
+#define ATTR_STRING   2
+#define ATTR_ID       3
+#define ATTR_INTLIST  4
+#define ATTR_LOCALIDS 5
+  union {
+    unsigned int i[2];
+    const char *str;
+    int *intlist;
+    LocalId *localids;
+  } v;
+} LongNV;
+
+struct _Attrstore
+{
+  Pool *pool;
+  unsigned int entries;
+  LongNV **attrs;
+  unsigned int num_nameids;
+  Id *nameids;
+  char *big_store;
+
+  Offset *strings;
+  int nstrings;
+  char *stringspace;
+  Offset sstrings;
+  Hashtable stringhashtbl;
+  Hashmask stringhashmask;
+
+  unsigned int packed:1;
+};
diff --git a/tools/dumpattr.c b/tools/dumpattr.c
new file mode 100644 (file)
index 0000000..b3947c0
--- /dev/null
@@ -0,0 +1,77 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "attr_store.h"
+#include "pool.h"
+#include "attr_store_p.h"
+
+static void
+dump_attrs (Attrstore *s, unsigned int entry)
+{
+  LongNV *nv = s->attrs[entry];
+  if (nv)
+    {
+      while (nv->name)
+        {
+         fprintf (stdout, "%s:", id2str (s->pool, s->nameids[nv->name]));
+         switch (nv->type)
+           {
+             case ATTR_INT:
+               fprintf (stdout, "int  %u\n", nv->v.i[0]);
+               break;
+             case ATTR_CHUNK:
+               fprintf (stdout, "blob %u+%u\n", nv->v.i[0], nv->v.i[1]);
+               break;
+             case ATTR_STRING:
+               fprintf (stdout, "str  %s\n", nv->v.str);
+               break;
+             case ATTR_ID:
+               fprintf (stdout, "id   %u\n", nv->v.i[0]);
+               break;
+             case ATTR_INTLIST:
+               {
+                 unsigned i = 0;
+                 int val;
+                 fprintf (stdout, "lint\n ");
+                 while ((val = nv->v.intlist[i++]))
+                   fprintf (stdout, " %d", val);
+                 fprintf (stdout, "\n");
+                 break;
+               }
+             case ATTR_LOCALIDS:
+               {
+                 unsigned i = 0;
+                 LocalId id;
+                 fprintf (stdout, "lids");
+                 while ((id = nv->v.localids[i++]))
+                   fprintf (stdout, "\n  %s(%d)", localid2str (s, id), id);
+                 fprintf (stdout, "\n");
+                 break;
+               }
+             default:
+               break;
+           }
+         nv++;
+       }
+    }
+}
+
+int
+main (void)
+{
+  unsigned int i;
+  Pool *pool = pool_create ();
+  Attrstore *s = attr_store_read (stdin, pool);
+  fprintf (stdout, "attribute store contains %d entities\n", s->entries);
+  for (i = 0; i < s->entries; i++)
+    {
+      fprintf (stdout, "\nentity %u:\n", i);
+      dump_attrs (s, i);
+    }
+  return 0;
+}
index d7b0624..36d8f66 100644 (file)
@@ -6,6 +6,7 @@
 #include <string.h>
 
 #include "pool.h"
+#include "attr_store.h"
 #include "repo_susetags.h"
 
 #define PACK_BLOCK 255
@@ -126,8 +127,11 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, int i
   return repo_addid_dep(pd->repo, olddeps, id, isreq);
 }
 
+/* #define AUTHOR_STR */
+Attrstore *attr;
+
 Repo *
-pool_addrepo_susetags(Pool *pool, FILE *fp)
+pool_addrepo_susetags(Pool *pool, FILE *fp, int with_attr)
 {
   char *line, *linep;
   int aline;
@@ -140,6 +144,7 @@ pool_addrepo_susetags(Pool *pool, FILE *fp)
   struct parsedata pd;
 
   repo = pool_addrepo_empty(pool);
+  attr = new_store (pool);
   memset(&pd, 0, sizeof(pd));
   line = malloc(1024);
   aline = 1024;
@@ -176,6 +181,8 @@ pool_addrepo_susetags(Pool *pool, FILE *fp)
          if (cummulate && isend)
            {
              linep[-intag - 2] = 0;
+             if (linep[-intag - 3] == '\n')
+               linep[-intag - 3] = 0;
              linep = line;
              intag = 0;
            }
@@ -199,6 +206,12 @@ pool_addrepo_susetags(Pool *pool, FILE *fp)
              exit(1);
            }
          intag = tagend - (line + 1);
+#ifdef AUTHOR_STR
+         if (!strncmp (line, "+Aut:", 5))
+           cummulate = 1;
+         else
+           cummulate = 0;
+#endif
          line[0] = '=';
          line[intag + 2] = ' ';
          linep = line + intag + 3;
@@ -299,6 +312,36 @@ pool_addrepo_susetags(Pool *pool, FILE *fp)
          s->suggests = adddep(pool, &pd, s->suggests, line, 0, 0);
          continue;
        }
+      if (!with_attr)
+        continue;
+      if (!strncmp(line, "=Grp:", 5))
+        {
+         ensure_entry (attr, pack);
+         add_attr_localids_id (attr, pack, str2nameid (attr, "group"), str2localid (attr, line + 6, 1));
+         continue;
+       }
+      if (!strncmp(line, "=Lic:", 5))
+        {
+         ensure_entry (attr, pack);
+         add_attr_localids_id (attr, pack, str2nameid (attr, "license"), str2localid (attr, line + 6, 1));
+         continue;
+       }
+      if (!strncmp(line, "=Kwd:", 5))
+        {
+         ensure_entry (attr, pack);
+         add_attr_localids_id (attr, pack, str2nameid (attr, "keywords"), str2localid (attr, line + 6, 1));
+         continue;
+       }
+      if (!strncmp(line, "=Aut:", 5))
+        {
+         ensure_entry (attr, pack);
+#ifdef AUTHOR_STR
+         add_attr_string (attr, pack, str2nameid (attr, "authors"), line + 6);
+#else
+         add_attr_localids_id (attr, pack, str2nameid (attr, "authors"), str2localid (attr, line + 6, 1));
+#endif
+         continue;
+       }
     }
   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
index 1019583..06b220c 100644 (file)
@@ -1 +1 @@
-extern Repo *pool_addrepo_susetags(Pool *pool, FILE *fp);
+extern Repo *pool_addrepo_susetags(Pool *pool, FILE *fp, int with_attr);
index 3666f6e..f83bf69 100644 (file)
@@ -8,13 +8,37 @@
 #include "pool.h"
 #include "repo_susetags.h"
 #include "repo_write.h"
+#include "attr_store.h"
+
+extern Attrstore *attr;
 
 int
 main(int argc, char **argv)
 {
+  int with_attr = 0;
+  argv++;
+  argc--;
+  while (argc--)
+    {
+      const char *s = argv[0];
+      if (*s++ == '-')
+        while (*s)
+          switch (*s++)
+           {
+             case 'a': with_attr = 1; break;
+             default : break;
+           }
+      argv++;
+    }
   Pool *pool = pool_create();
-  Repo *repo = pool_addrepo_susetags(pool, stdin);
+  Repo *repo = pool_addrepo_susetags(pool, stdin, with_attr);
   pool_writerepo(pool, repo, stdout);
+  if (with_attr && attr)
+    {
+      FILE *fp = fopen ("test.attr", "w");
+      write_attr_store (fp, attr);
+      fclose (fp);
+    }
   pool_free(pool);
   exit(0);
 }